* 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 <string>
#include <hilog/log.h>
#include <multimedia/image_framework/image/image_source_native.h>
#include <multimedia/image_framework/image/image_common.h>
#include <multimedia/image_framework/image/pixelmap_native.h>
#include "napi/native_api.h"
#include <imageKits.h>
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0x3200
#define LOG_TAG "IMAGE_SAMPLE"
static ImageAnimatedNative *g_thisAnimated = new ImageAnimatedNative();
const int ANIMATED_MAX_STRING_LENGTH = 1024;
static napi_value ReturnAnimatedErrorCode(napi_env env, Image_ErrorCode errCode, const std::string &funcName)
{
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "%{public}s failed, errCode: %{public}d.", funcName.c_str(), errCode);
}
return GetJsResult(env, errCode);
}
static void ReleaseAnimatedPixelmapList()
{
if (g_thisAnimated->pixelMapList == nullptr) {
return;
}
for (size_t index = 0; index < g_thisAnimated->pixelMapListSize; index++) {
if (g_thisAnimated->pixelMapList[index] != nullptr) {
OH_PixelmapNative_Release(g_thisAnimated->pixelMapList[index]);
g_thisAnimated->pixelMapList[index] = nullptr;
}
}
delete[] g_thisAnimated->pixelMapList;
g_thisAnimated->pixelMapList = nullptr;
g_thisAnimated->pixelMapListSize = 0;
}
napi_value CreateAnimatedImageSource(napi_env env, napi_callback_info info)
{
napi_value argValue[1] = {nullptr};
size_t argCount = 1;
if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
argCount < 1 || argValue[0] == nullptr) {
OH_LOG_ERROR(LOG_APP, "CreateAnimatedImageSource napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
char filePath[ANIMATED_MAX_STRING_LENGTH];
size_t pathSize = ANIMATED_MAX_STRING_LENGTH;
napi_get_value_string_utf8(env, argValue[0], filePath, ANIMATED_MAX_STRING_LENGTH, &pathSize);
if (g_thisAnimated->source != nullptr) {
ReleaseAnimatedImageSource(env, info);
}
Image_ErrorCode errCode = OH_ImageSourceNative_CreateFromUri(filePath, pathSize, &g_thisAnimated->source);
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreateFromUri");
}
napi_value GetAnimatedFrameCount(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr) {
OH_LOG_ERROR(LOG_APP, "ImageSource is nullptr.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
Image_ErrorCode errCode = OH_ImageSourceNative_GetFrameCount(g_thisAnimated->source, &g_thisAnimated->frameCnt);
if (errCode != IMAGE_SUCCESS) {
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_GetFrameCount");
}
OH_LOG_INFO(LOG_APP, "Frame count: %{public}u.", g_thisAnimated->frameCnt);
return GetJsResult(env, g_thisAnimated->frameCnt);
}
napi_value GetAnimatedDelayTimeList(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
int32_t *delayTimeList = new int32_t[g_thisAnimated->frameCnt];
size_t size = g_thisAnimated->frameCnt;
Image_ErrorCode errCode = OH_ImageSourceNative_GetDelayTimeList(g_thisAnimated->source, delayTimeList, size);
if (errCode == IMAGE_SUCCESS) {
for (size_t index = 0; index < size; index++) {
OH_LOG_INFO(LOG_APP, "Frame %{public}zu delay time: %{public}d ms.", index, delayTimeList[index]);
}
}
delete[] delayTimeList;
delayTimeList = nullptr;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_GetDelayTimeList");
}
napi_value CreateAnimatedPixelmapList(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
ReleaseAnimatedPixelmapList();
OH_DecodingOptions *opts = nullptr;
Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
if (errCode != IMAGE_SUCCESS || opts == nullptr) {
return ReturnAnimatedErrorCode(env, errCode, "OH_DecodingOptions_Create");
}
g_thisAnimated->pixelMapList = new OH_PixelmapNative *[g_thisAnimated->frameCnt]();
g_thisAnimated->pixelMapListSize = g_thisAnimated->frameCnt;
errCode = OH_ImageSourceNative_CreatePixelmapList(g_thisAnimated->source, opts,
g_thisAnimated->pixelMapList, g_thisAnimated->pixelMapListSize);
OH_DecodingOptions_Release(opts);
opts = nullptr;
if (errCode != IMAGE_SUCCESS) {
ReleaseAnimatedPixelmapList();
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmapList");
}
OH_LOG_INFO(LOG_APP, "Create %{public}zu pixelmaps.", g_thisAnimated->pixelMapListSize);
return GetJsResult(env, errCode);
}
napi_value CreateAnimatedPixelmapByIndex(napi_env env, napi_callback_info info)
{
if (g_thisAnimated->source == nullptr || g_thisAnimated->frameCnt == 0) {
OH_LOG_ERROR(LOG_APP, "Invalid ImageSource or frame count.");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
napi_value argValue[1] = {nullptr};
size_t argCount = 1;
if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok ||
argCount < 1 || argValue[0] == nullptr) {
OH_LOG_ERROR(LOG_APP, "CreateAnimatedPixelmapByIndex napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
uint32_t index = 0;
napi_get_value_uint32(env, argValue[0], &index);
if (index >= g_thisAnimated->frameCnt) {
OH_LOG_ERROR(LOG_APP, "Invalid frame index: %{public}u.", index);
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
OH_DecodingOptions *opts = nullptr;
Image_ErrorCode errCode = OH_DecodingOptions_Create(&opts);
if (errCode != IMAGE_SUCCESS || opts == nullptr) {
return ReturnAnimatedErrorCode(env, errCode, "OH_DecodingOptions_Create");
}
OH_DecodingOptions_SetIndex(opts, index);
if (g_thisAnimated->pixelMap != nullptr) {
OH_PixelmapNative_Release(g_thisAnimated->pixelMap);
g_thisAnimated->pixelMap = nullptr;
}
errCode = OH_ImageSourceNative_CreatePixelmap(g_thisAnimated->source, opts, &g_thisAnimated->pixelMap);
OH_DecodingOptions_Release(opts);
opts = nullptr;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmap");
}
napi_value ReleaseAnimatedImageSource(napi_env env, napi_callback_info info)
{
ReleaseAnimatedPixelmapList();
if (g_thisAnimated->pixelMap != nullptr) {
OH_PixelmapNative_Release(g_thisAnimated->pixelMap);
g_thisAnimated->pixelMap = nullptr;
}
Image_ErrorCode errCode = IMAGE_SUCCESS;
if (g_thisAnimated->source != nullptr) {
errCode = OH_ImageSourceNative_Release(g_thisAnimated->source);
g_thisAnimated->source = nullptr;
}
g_thisAnimated->frameCnt = 0;
return ReturnAnimatedErrorCode(env, errCode, "OH_ImageSourceNative_Release");
}