* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "drawable_manager.h"
#include "rawfile/raw_file_manager.h"
#include <arkui/drawable_descriptor.h>
#include <arkui/native_interface.h>
#include <arkui/native_node.h>
#include <arkui/native_node_napi.h>
#include <hilog/log.h>
#include <multimedia/image_framework/image/image_common.h>
#include <multimedia/image_framework/image/image_source_native.h>
#include <multimedia/image_framework/image_pixel_map_mdk.h>
#include <multimedia/image_framework/image/pixelmap_native.h>
#include <napi/native_api.h>
#include <native_drawing/drawing_pixel_map.h>
#include <resourcemanager/ohresmgr.h>
enum class PixelMapFormat { RGBA_8888 = PIXEL_FORMAT_BGRA_8888 };
class DecodingOptions {
public:
DecodingOptions()
{
OH_DecodingOptions *options;
OH_DecodingOptions_Create(&options);
options_ = options;
}
~DecodingOptions() = default;
void SetPixelFormat(PixelMapFormat format)
{
OH_DecodingOptions_SetPixelFormat(options_, static_cast<int32_t>(PixelMapFormat::RGBA_8888));
}
OH_DecodingOptions *GetNativePointer() { return options_; }
private:
OH_DecodingOptions *options_;
};
struct PixelMaps {
OH_PixelmapNative** pixelMaps;
size_t size;
};
static ArkUI_NodeHandle mainPageScroll = nullptr;
static ArkUI_NodeHandle scrollNode = nullptr;
static ArkUI_NativeNodeAPI_1* GetNodeApi()
{
static ArkUI_NativeNodeAPI_1* nodeApi = reinterpret_cast<ArkUI_NativeNodeAPI_1*>(
OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
return nodeApi;
}
static ArkUI_NodeHandle GetMainPageSroll()
{
if (mainPageScroll == nullptr) {
ArkUI_NativeNodeAPI_1* nodeApi = GetNodeApi();
mainPageScroll = nodeApi->createNode(ARKUI_NODE_SCROLL);
}
return mainPageScroll;
}
static napi_value CreateFromPixelMap(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
void *temp = nullptr;
napi_unwrap(env, args[0], &temp);
OH_PixelmapNative *nativePixelMap = reinterpret_cast<OH_PixelmapNative *>(temp);
ArkUI_DrawableDescriptor *descriptor = OH_ArkUI_DrawableDescriptor_CreateFromPixelMap(nativePixelMap);
if (descriptor == nullptr) {
return nullptr;
}
OH_PixelmapNative *newHandle = OH_ArkUI_DrawableDescriptor_GetStaticPixelMap(descriptor);
if (nativePixelMap == newHandle) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "GetStaticPixelMap success");
}
int32_t imagePixelMapId = DrawableManager::GetInstance().AddDrawable(descriptor);
napi_value result;
napi_create_int32(env, imagePixelMapId, &result);
return result;
}
static napi_value CreateFromAnimatedPixelMap(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
void *temp = nullptr;
napi_unwrap(env, args[0], &temp);
OH_PixelmapNative *nativePixelMapArray = reinterpret_cast<OH_PixelmapNative *>(temp);
int32_t size;
napi_get_value_int32(env, args[1], &size);
ArkUI_DrawableDescriptor *descriptor = OH_ArkUI_DrawableDescriptor_CreateFromAnimatedPixelMap(
&nativePixelMapArray, size);
if (descriptor == nullptr) {
return nullptr;
}
OH_PixelmapNativeHandle *newHandle = OH_ArkUI_DrawableDescriptor_GetAnimatedPixelMapArray(descriptor);
if (nativePixelMapArray == *newHandle) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "GetAnimatedPixelMapArray success");
}
int32_t arraySize = OH_ArkUI_DrawableDescriptor_GetAnimatedPixelMapArraySize(descriptor);
if (arraySize == size) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "GetAnimatedPixelMapArraySize success");
}
int32_t imagePixelMapId = DrawableManager::GetInstance().AddDrawable(descriptor);
DrawableManager::GetInstance().RemoveDrawable(imagePixelMapId);
return nullptr;
}
static napi_value DisposeDrawable(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t imagePixelMapId;
napi_get_value_int32(env, args[0], &imagePixelMapId);
DrawableManager::GetInstance().RemoveDrawable(imagePixelMapId);
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "Dispose success");
return nullptr;
}
static napi_value SetAnimationDuration(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t imagePixelMapId;
napi_get_value_int32(env, args[0], &imagePixelMapId);
int32_t duration;
napi_get_value_int32(env, args[1], &duration);
ArkUI_DrawableDescriptor* descriptor = DrawableManager::GetInstance().GetDrawable(imagePixelMapId);
if (descriptor == nullptr) {
return nullptr;
}
OH_ArkUI_DrawableDescriptor_SetAnimationDuration(descriptor, duration);
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test SetAnimationDuration, %{public}d", duration);
return nullptr;
}
static napi_value GetAnimationDuration(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t imagePixelMapId;
napi_get_value_int32(env, args[0], &imagePixelMapId);
ArkUI_DrawableDescriptor* descriptor = DrawableManager::GetInstance().GetDrawable(imagePixelMapId);
if (descriptor == nullptr) {
return nullptr;
}
int32_t duration = OH_ArkUI_DrawableDescriptor_GetAnimationDuration(descriptor);
napi_value result;
napi_create_int32(env, duration, &result);
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test GetAnimationDuration, %{public}d", duration);
return result;
}
static napi_value SetAnimationIteration(napi_env env, napi_callback_info info)
{
size_t argc = 2;
napi_value args[2] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t imagePixelMapId;
napi_get_value_int32(env, args[0], &imagePixelMapId);
int32_t iteration;
napi_get_value_int32(env, args[1], &iteration);
ArkUI_DrawableDescriptor* descriptor = DrawableManager::GetInstance().GetDrawable(imagePixelMapId);
if (descriptor == nullptr) {
return nullptr;
}
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test SetAnimationIteration, %{public}d", iteration);
OH_ArkUI_DrawableDescriptor_SetAnimationIteration(descriptor, iteration);
return nullptr;
}
static napi_value GetAnimationIteration(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value args[1] = {nullptr};
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int32_t imagePixelMapId;
napi_get_value_int32(env, args[0], &imagePixelMapId);
ArkUI_DrawableDescriptor* descriptor = DrawableManager::GetInstance().GetDrawable(imagePixelMapId);
if (descriptor == nullptr) {
return nullptr;
}
int32_t iteration = OH_ArkUI_DrawableDescriptor_GetAnimationIteration(descriptor);
napi_value result;
napi_create_int32(env, iteration, &result);
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test GetAnimationIteration, %{public}d", iteration);
return result;
}
PixelMaps CreatePixelMapList(OH_ImageSourceNative *source, DecodingOptions options)
{
if (source == nullptr) {
return {nullptr, 0};
}
uint32_t count = 0;
OH_ImageSourceNative_GetFrameCount(source, &count);
if (count <= 1) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test CreatePixelMapList failed, count = %{public}d", count);
return {nullptr, 0};
}
OH_PixelmapNative **resPixMapList = new OH_PixelmapNative *[count];
auto code = OH_ImageSourceNative_CreatePixelmapList(source, options.GetNativePointer(), resPixMapList,
static_cast<size_t>(count));
if (code != Image_ErrorCode::IMAGE_SUCCESS) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test CreatePixelMapList failed, code = %{public}d", code);
delete[] resPixMapList;
return {nullptr, 0};
}
PixelMaps maps;
maps.pixelMaps = resPixMapList;
maps.size = count;
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test CreatePixelMapList succ, count = %{public}d", count);
return maps;
}
ArkUI_DrawableDescriptor* GetPixelMapArray(napi_env env, napi_callback_info info, size_t &size)
{
size_t argc = 2;
napi_value argv[2] = {nullptr};
napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
uint8_t *data = nullptr;
uint64_t dataLen = 0;
NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[1]);
OH_ResourceManager_GetMediaByName(mNativeResMgr, "test1", &data, &dataLen);
OH_ImageSourceNative *source = nullptr;
auto code = OH_ImageSourceNative_CreateFromData(data, dataLen, &source);
DecodingOptions options;
PixelMaps maps = CreatePixelMapList(source, options);
auto descriptor = OH_ArkUI_DrawableDescriptor_CreateFromAnimatedPixelMap(maps.pixelMaps, maps.size);
if (descriptor == nullptr) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test CreateFromAnimatedPixelMap failed");
}
size = maps.size;
return descriptor;
}
static napi_value AddPixelMapArray(napi_env env, napi_callback_info info, ArkUI_NodeHandle sroll)
{
ArkUI_NativeNodeAPI_1* nodeApi = GetNodeApi();
size_t mapSize = 0;
ArkUI_DrawableDescriptor* pixelArrayDes = GetPixelMapArray(env, info, mapSize);
ArkUI_NodeHandle imageNode = nodeApi->createNode(ARKUI_NODE_IMAGE);
ArkUI_AttributeItem item = {.object = pixelArrayDes};
ArkUI_NumberValue value[] = {{.f32 = 200.0f}};
ArkUI_AttributeItem sizeItem = {value, sizeof(value) / sizeof(ArkUI_NumberValue)};
nodeApi->setAttribute(imageNode, NODE_WIDTH, &sizeItem);
nodeApi->setAttribute(imageNode, NODE_HEIGHT, &sizeItem);
nodeApi->setAttribute(imageNode, NODE_IMAGE_SRC, &item);
nodeApi->addChild(sroll, imageNode);
int32_t imagePixelMapId = DrawableManager::GetInstance().AddDrawable(pixelArrayDes);
napi_value result;
napi_create_int32(env, imagePixelMapId, &result);
return result;
}
static napi_value CreateNodePage(napi_env env, napi_callback_info info)
{
if ((env == nullptr) || (info == nullptr)) {
return nullptr;
}
size_t argCnt = 2;
napi_value args[2] = {nullptr};
if (napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, 0, "Drawable", "---test napi_get_cb_info failed");
}
ArkUI_NodeContentHandle nodeContentHandle = nullptr;
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &nodeContentHandle);
ArkUI_NativeNodeAPI_1* nodeApi = GetNodeApi();
if (scrollNode != nullptr && nodeContentHandle != nullptr) {
OH_ArkUI_NodeContent_RemoveNode(nodeContentHandle, scrollNode);
nodeApi->disposeNode(scrollNode);
mainPageScroll = nullptr;
}
if (nodeApi != nullptr) {
if (nodeApi->createNode != nullptr && nodeApi->addChild != nullptr) {
scrollNode = GetMainPageSroll();
napi_value mapArrayId = AddPixelMapArray(env, info, scrollNode);
OH_ArkUI_NodeContent_AddNode(nodeContentHandle, scrollNode);
return mapArrayId;
}
}
return nullptr;
}
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
{"createFromPixelMap", nullptr, CreateFromPixelMap, nullptr, nullptr, nullptr, napi_default, nullptr},
{"createFromAnimatedPixelMap", nullptr, CreateFromAnimatedPixelMap, nullptr, nullptr, nullptr,
napi_default, nullptr},
{"disposeDrawable", nullptr, DisposeDrawable, nullptr, nullptr, nullptr, napi_default, nullptr},
{"setAnimationDuration", nullptr, SetAnimationDuration, nullptr, nullptr, nullptr, napi_default, nullptr},
{"getAnimationDuration", nullptr, GetAnimationDuration, nullptr, nullptr, nullptr, napi_default, nullptr},
{"setAnimationIteration", nullptr, SetAnimationIteration, nullptr, nullptr, nullptr, napi_default, nullptr},
{"getAnimationIteration", nullptr, GetAnimationIteration, nullptr, nullptr, nullptr, napi_default, nullptr},
{"createNodePage", nullptr, CreateNodePage, nullptr, nullptr, nullptr, napi_default, nullptr},
};
napi_define_properties(env, exports, sizeof(desc)/sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
static napi_module demoModule = {
.nm_version = 1,
.nm_flags = 0,
.nm_filename = nullptr,
.nm_register_func = Init,
.nm_modname = "entry",
.nm_priv = ((void*)0),
.reserved = { 0 },
};
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
}