* 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 "napi/native_api.h"
#include <multimedia/image_framework/image/image_common.h>
#include <multimedia/image_framework/image/pixelmap_native.h>
#include <set>
#include <multimedia/image_framework/image/image_packer_native.h>
#include <imageKits.h>
#undef LOG_DOMAIN
#undef LOG_TAG
#define LOG_DOMAIN 0x3200
#define LOG_TAG "IMAGE_SAMPLE"
static std::set<std::string> g_encodeSupportedFormats;
static ImageSourceNative *g_thisImageSource = new ImageSourceNative();
const int MAX_STRING_LENGTH = 1024;
napi_value ReturnErrorCode(napi_env env, Image_ErrorCode errCode, 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);
}
return GetJsResult(env, errCode);
}
napi_value GetSupportedFormats(napi_env env, napi_callback_info info)
{
Image_MimeType* mimeType = nullptr;
size_t length = 0;
Image_ErrorCode errCode = OH_ImageSourceNative_GetSupportedFormats(&mimeType, &length);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceNative_GetSupportedFormats failed, "
"errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
for (size_t count = 0; count < length; count++) {
OH_LOG_INFO(LOG_APP, "Decode supportedFormats: %{public}s", mimeType[count].data);
}
return GetJsResult(env, errCode);
}
napi_value CreateImageSource(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, "CreateImageSource napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
char name[MAX_STRING_LENGTH];
size_t nameSize = MAX_STRING_LENGTH;
napi_get_value_string_utf8(env, argValue[0], name, MAX_STRING_LENGTH, &nameSize);
Image_ErrorCode errCode = OH_ImageSourceNative_CreateFromUri(name, nameSize, &g_thisImageSource->source);
return ReturnErrorCode(env, errCode, "OH_ImageSourceNative_CreateFromUri");
}
napi_value GetImageInfo(napi_env env, napi_callback_info info)
{
OH_ImageSourceInfo_Create(&g_thisImageSource->imageInfo);
Image_ErrorCode errCode = OH_ImageSourceNative_GetImageInfo(g_thisImageSource->source,
0, g_thisImageSource->imageInfo);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceInfo_Create failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
uint32_t width;
uint32_t height;
errCode = OH_ImageSourceInfo_GetWidth(g_thisImageSource->imageInfo, &width);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceInfo_GetWidth failed, errCode: %{public}d.", errCode);
OH_ImageSourceInfo_Release(g_thisImageSource->imageInfo);
g_thisImageSource->imageInfo = nullptr;
return GetJsResult(env, errCode);
}
errCode = OH_ImageSourceInfo_GetHeight(g_thisImageSource->imageInfo, &height);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceInfo_GetHeight failed, errCode: %{public}d.", errCode);
OH_ImageSourceInfo_Release(g_thisImageSource->imageInfo);
g_thisImageSource->imageInfo = nullptr;
return GetJsResult(env, errCode);
}
OH_LOG_INFO(LOG_APP, "OH_ImageSourceNative_GetImageInfo success,"
"width: %{public}d, height: %{public}d.", width, height);
OH_ImageSourceInfo_Release(g_thisImageSource->imageInfo);
g_thisImageSource->imageInfo = nullptr;
return GetJsResult(env, width);
}
napi_value GetImageProperty(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, "GetImageProperty napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
char key[MAX_STRING_LENGTH];
size_t keySize = MAX_STRING_LENGTH;
napi_get_value_string_utf8(env, argValue[0], (char *)key, sizeof(key), &keySize);
Image_String getKey;
getKey.data = key;
getKey.size = keySize;
Image_String getValue = {nullptr, 0};
OH_LOG_INFO(LOG_APP, "OH_ImageSourceNative_GetImageProperty key: %{public}s.", getKey.data);
Image_ErrorCode errCode = OH_ImageSourceNative_GetImagePropertyWithNull(g_thisImageSource->source,
&getKey, &getValue);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceNative_GetImageProperty failed, errCode: %{public}d.", errCode);
if (getValue.data != nullptr) {
free(getValue.data);
getValue.data = nullptr;
}
return GetJsResult(env, errCode);
}
napi_value resultNapi = nullptr;
napi_create_string_utf8(env, getValue.data, getValue.size, &resultNapi);
free(getValue.data);
getValue.data = nullptr;
return resultNapi;
}
napi_value ModifyImageProperty(napi_env env, napi_callback_info info)
{
napi_value argValue[2] = {nullptr};
size_t argCount = 2;
const size_t minCount = 2;
if (napi_get_cb_info(env, info, &argCount, argValue, nullptr, nullptr) != napi_ok || argCount < minCount ||
argValue[0] == nullptr || argValue[1] == nullptr) {
OH_LOG_ERROR(LOG_APP, "ModifyImageProperty napi_get_cb_info failed!");
return GetJsResult(env, IMAGE_BAD_PARAMETER);
}
char key[MAX_STRING_LENGTH];
size_t keySize = MAX_STRING_LENGTH;
napi_get_value_string_utf8(env, argValue[0], (char *)key, sizeof(key), &keySize);
Image_String setKey;
setKey.data = key;
setKey.size = keySize;
OH_LOG_INFO(LOG_APP, "ModifyImageProperty key: %{public}s.", setKey.data);
char value[MAX_STRING_LENGTH];
size_t valueSize;
napi_get_value_string_utf8(env, argValue[1], (char *)value, MAX_STRING_LENGTH, &valueSize);
Image_String setValue;
setValue.data = value;
setValue.size = valueSize;
OH_LOG_INFO(LOG_APP, "ModifyImageProperty value: %{public}s.", setValue.data);
Image_ErrorCode errCode = OH_ImageSourceNative_ModifyImageProperty(g_thisImageSource->source, &setKey, &setValue);
return GetJsResult(env, errCode);
}
napi_value CreatePixelMap(napi_env env, napi_callback_info info)
{
OH_DecodingOptions *ops = nullptr;
OH_DecodingOptions_Create(&ops);
OH_DecodingOptions_SetDesiredDynamicRange(ops, IMAGE_DYNAMIC_RANGE_AUTO);
OH_PixelmapNative_Release(g_thisImageSource->resPixMap);
g_thisImageSource->resPixMap = nullptr;
Image_ErrorCode errCode = OH_ImageSourceNative_CreatePixelmap(g_thisImageSource->source,
ops, &g_thisImageSource->resPixMap);
OH_DecodingOptions_Release(ops);
ops = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceNative_CreatePixelmap failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
OH_PixelmapImageInfo_Create(&g_thisImageSource->pixelmapImageInfo);
OH_PixelmapNative_GetImageInfo(g_thisImageSource->resPixMap, g_thisImageSource->pixelmapImageInfo);
bool pixelmapIsHdr;
OH_PixelmapImageInfo_GetDynamicRange(g_thisImageSource->pixelmapImageInfo, &pixelmapIsHdr);
if (pixelmapIsHdr) {
OH_LOG_INFO(LOG_APP, "The pixelMap's dynamicRange is HDR.");
}
OH_PixelmapImageInfo_Release(g_thisImageSource->pixelmapImageInfo);
g_thisImageSource->pixelmapImageInfo = nullptr;
return GetJsResult(env, errCode);
}
napi_value DecodeRegion(napi_env env, napi_callback_info info)
{
OH_DecodingOptions *ops = nullptr;
OH_DecodingOptions_Create(&ops);
Image_Region region = {
.x = 0,
.y = 0,
.width = 1000,
.height = 1000
};
OH_DecodingOptions_SetCropRegion(ops, ®ion);
OH_PixelmapNative_Release(g_thisImageSource->resPixMap);
g_thisImageSource->resPixMap = nullptr;
Image_ErrorCode errCode = OH_ImageSourceNative_CreatePixelmap(g_thisImageSource->source,
ops, &g_thisImageSource->resPixMap);
OH_DecodingOptions_Release(ops);
ops = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "DecodeRegion failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
OH_LOG_INFO(LOG_APP, "DecodeRegion succeeded.");
return GetJsResult(env, errCode);
}
napi_value DownsampleDecode(napi_env env, napi_callback_info info)
{
OH_DecodingOptions *ops = nullptr;
OH_DecodingOptions_Create(&ops);
Image_Size desiredSize = {
.width = 512,
.height = 512
};
OH_DecodingOptions_SetDesiredSize(ops, &desiredSize);
OH_PixelmapNative_Release(g_thisImageSource->resPixMap);
g_thisImageSource->resPixMap = nullptr;
Image_ErrorCode errCode = OH_ImageSourceNative_CreatePixelmap(g_thisImageSource->source,
ops, &g_thisImageSource->resPixMap);
OH_DecodingOptions_Release(ops);
ops = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "DownsampleDecode failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
OH_LOG_INFO(LOG_APP, "DownsampleDecode succeeded.");
return GetJsResult(env, errCode);
}
napi_value CombinedDecode(napi_env env, napi_callback_info info)
{
OH_DecodingOptions *ops = nullptr;
OH_DecodingOptions_Create(&ops);
Image_Region region = {
.x = 1000,
.y = 500,
.width = 2000,
.height = 2000
};
OH_DecodingOptions_SetCropRegion(ops, ®ion);
Image_Size desiredSize = {
.width = 512,
.height = 512
};
OH_DecodingOptions_SetDesiredSize(ops, &desiredSize);
OH_DecodingOptions_SetCropAndScaleStrategy(ops, IMAGE_CROP_AND_SCALE_STRATEGY_CROP_FIRST);
OH_PixelmapNative_Release(g_thisImageSource->resPixMap);
g_thisImageSource->resPixMap = nullptr;
Image_ErrorCode errCode = OH_ImageSourceNative_CreatePixelmap(g_thisImageSource->source,
ops, &g_thisImageSource->resPixMap);
OH_DecodingOptions_Release(ops);
ops = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "CombinedDecode failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
OH_LOG_INFO(LOG_APP, "CombinedDecode succeeded.");
return GetJsResult(env, errCode);
}
napi_value GetFrameCount(napi_env env, napi_callback_info info)
{
Image_ErrorCode errCode = OH_ImageSourceNative_GetFrameCount(g_thisImageSource->source,
&g_thisImageSource->frameCnt);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImageSourceNative_GetFrameCount failed, errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
}
return GetJsResult(env, g_thisImageSource->frameCnt);
}
napi_value CreatePixelmapList(napi_env env, napi_callback_info info)
{
OH_DecodingOptions *opts = nullptr;
OH_DecodingOptions_Create(&opts);
OH_PixelmapNative** resVecPixMap = new OH_PixelmapNative* [g_thisImageSource->frameCnt]();
size_t outSize = g_thisImageSource->frameCnt;
Image_ErrorCode errCode = OH_ImageSourceNative_CreatePixelmapList(g_thisImageSource->source,
opts, resVecPixMap, outSize);
OH_DecodingOptions_Release(opts);
opts = nullptr;
for (size_t index = 0; index < outSize; index++) {
if (resVecPixMap[index] != nullptr) {
OH_PixelmapNative_Release(resVecPixMap[index]);
resVecPixMap[index] = nullptr;
}
}
delete[] resVecPixMap;
return ReturnErrorCode(env, errCode, "OH_ImageSourceNative_CreatePixelmapList");
}
napi_value GetDelayTimeList(napi_env env, napi_callback_info info)
{
int32_t *delayTimeList = new int32_t[g_thisImageSource->frameCnt];
size_t size = g_thisImageSource->frameCnt;
OH_LOG_INFO(LOG_APP, "GetDelayTimeList size: %{public}zu.", size);
Image_ErrorCode errCode = OH_ImageSourceNative_GetDelayTimeList(g_thisImageSource->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 ReturnErrorCode(env, errCode, "OH_ImageSourceNative_GetDelayTimeList");
}
napi_value ReleaseImageSource(napi_env env, napi_callback_info info)
{
Image_ErrorCode errCode = OH_ImageSourceNative_Release(g_thisImageSource->source);
g_thisImageSource->source = nullptr;
OH_PixelmapNative_Release(g_thisImageSource->resPixMap);
g_thisImageSource->resPixMap = nullptr;
return ReturnErrorCode(env, errCode, "OH_ImageSourceNative_Release");
}
Image_ErrorCode GetEncodeSupportedFormats()
{
Image_MimeType* mimeType = nullptr;
size_t length = 0;
Image_ErrorCode errCode = OH_ImagePackerNative_GetSupportedFormats(&mimeType, &length);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "OH_ImagePackerNative_GetSupportedFormats failed,"
"errCode: %{public}d.", errCode);
return errCode;
}
for (size_t count = 0; count < length; count++) {
if (mimeType[count].data != nullptr) {
g_encodeSupportedFormats.insert(std::string(mimeType[count].data));
OH_LOG_INFO(LOG_APP, "Encode supportedFormats: %{public}s", mimeType[count].data);
}
}
return IMAGE_SUCCESS;
}
Image_MimeType GetMimeTypeIfEncodable(const char *format)
{
auto it = g_encodeSupportedFormats.find(format);
if (it == g_encodeSupportedFormats.end()) {
return {const_cast<char *>(""), 0};
}
return {const_cast<char *>(format), strlen(format)};
}
static Image_ErrorCode ReleaseImageSourcePackingResources(OH_ImagePackerNative *testPacker,
OH_PackingOptions *option)
{
Image_ErrorCode errCode = OH_ImagePackerNative_Release(testPacker);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromImageSourceTest OH_ImagePackerNative_Release failed,"
"errCode: %{public}d.", errCode);
OH_PackingOptions_Release(option);
return errCode;
}
errCode = OH_PackingOptions_Release(option);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromImageSourceTest OH_PackingOptions_Release failed,"
"errCode: %{public}d.", errCode);
}
return errCode;
}
Image_ErrorCode packToFileFromImageSourceTest(int fd, OH_ImageSourceNative* imageSource)
{
OH_ImagePackerNative *testPacker = nullptr;
Image_ErrorCode errCode = OH_ImagePackerNative_Create(&testPacker);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromImageSourceTest OH_ImagePackerNative_Create failed,"
"errCode: %{public}d.", errCode);
return errCode;
}
errCode = GetEncodeSupportedFormats();
if (errCode != IMAGE_SUCCESS) {
OH_ImagePackerNative_Release(testPacker);
return errCode;
}
OH_PackingOptions *option = nullptr;
errCode = OH_PackingOptions_Create(&option);
if (errCode != IMAGE_SUCCESS || option == nullptr) {
OH_ImagePackerNative_Release(testPacker);
return errCode == IMAGE_SUCCESS ? IMAGE_BAD_PARAMETER : errCode;
}
Image_MimeType image_MimeType = GetMimeTypeIfEncodable(MIME_TYPE_JPEG);
if (image_MimeType.data == nullptr || image_MimeType.size == 0) {
OH_LOG_ERROR(LOG_APP, "packToFileFromImageSourceTest GetMimeTypeIfEncodable failed,"
"format can't support encode.");
OH_PackingOptions_Release(option);
OH_ImagePackerNative_Release(testPacker);
return IMAGE_BAD_PARAMETER;
}
OH_PackingOptions_SetMimeType(option, &image_MimeType);
OH_PackingOptions_SetDesiredDynamicRange(option, IMAGE_PACKER_DYNAMIC_RANGE_AUTO);
uint32_t quality = 90;
OH_PackingOptions_SetQuality(option, quality);
errCode = OH_ImagePackerNative_PackToFileFromImageSource(testPacker, option, imageSource, fd);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromImageSourceTest OH_ImagePackerNative_PackToFileFromImageSource failed,"
"errCode: %{public}d.", errCode);
OH_PackingOptions_Release(option);
OH_ImagePackerNative_Release(testPacker);
return errCode;
}
return ReleaseImageSourcePackingResources(testPacker, option);
}
Image_ErrorCode packToFileFromPixelmapTest(int fd, OH_PixelmapNative *pixelmap)
{
OH_ImagePackerNative *testPacker = nullptr;
Image_ErrorCode errCode = OH_ImagePackerNative_Create(&testPacker);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromPixelmapTest CreatePacker OH_ImagePackerNative_Create failed,"
"errCode: %{public}d.", errCode);
return errCode;
}
OH_PackingOptions *option = nullptr;
errCode = OH_PackingOptions_Create(&option);
if (errCode != IMAGE_SUCCESS || option == nullptr) {
OH_ImagePackerNative_Release(testPacker);
return errCode == IMAGE_SUCCESS ? IMAGE_BAD_PARAMETER : errCode;
}
char type[] = "image/jpeg";
Image_MimeType image_MimeType = {type, strlen(type)};
errCode = OH_PackingOptions_SetMimeType(option, &image_MimeType);
if (errCode != IMAGE_SUCCESS) {
OH_PackingOptions_Release(option);
OH_ImagePackerNative_Release(testPacker);
return errCode;
}
uint32_t quality = 90;
OH_PackingOptions_SetQuality(option, quality);
errCode = OH_ImagePackerNative_PackToFileFromPixelmap(testPacker, option, pixelmap, fd);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromPixelmapTest OH_ImagePackerNative_PackToFileFromPixelmap failed,"
"errCode: %{public}d.", errCode);
OH_PackingOptions_Release(option);
OH_ImagePackerNative_Release(testPacker);
return errCode;
}
errCode = OH_ImagePackerNative_Release(testPacker);
testPacker = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromPixelmapTest ReleasePacker OH_ImagePackerNative_Release failed,"
"errCode: %{public}d.", errCode);
OH_PackingOptions_Release(option);
return errCode;
}
errCode = OH_PackingOptions_Release(option);
option = nullptr;
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromPixelmapTest OH_PackingOptions_Release failed,"
"errCode: %{public}d.", errCode);
return errCode;
}
return IMAGE_SUCCESS;
}
napi_value PackToFileFromImageSourceTestJs(napi_env env, napi_callback_info info)
{
napi_value argv[1] = {0};
size_t argc = 1;
if (napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok) {
OH_LOG_ERROR(LOG_APP, "PackToFileFromImageSourceTestJs napi_get_cb_info failed.");
return nullptr;
}
int fd;
napi_get_value_int32(env, argv[0], &fd);
Image_ErrorCode errCode = packToFileFromImageSourceTest(fd, g_thisImageSource->source);
if (errCode == IMAGE_SUCCESS) {
OH_LOG_INFO(LOG_APP, "ImagePackerNativeCTest PackToFileFromImageSourceTestJs successfully.");
}
return GetJsResult(env, errCode);
}
napi_value PackToFileFromPixelmapTestJs(napi_env env, napi_callback_info info)
{
napi_value argv[1] = {0};
size_t argc = 1;
if (napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr) != napi_ok) {
OH_LOG_ERROR(LOG_APP, "PackToFileFromImageSourceTestJs napi_get_cb_info failed.");
return nullptr;
}
int fd;
napi_get_value_int32(env, argv[0], &fd);
Image_ErrorCode errCode = packToFileFromPixelmapTest(fd, g_thisImageSource->resPixMap);
if (errCode != IMAGE_SUCCESS) {
OH_LOG_ERROR(LOG_APP, "packToFileFromPixelmapTest failed,"
"errCode: %{public}d.", errCode);
return GetJsResult(env, errCode);
} else {
OH_LOG_INFO(LOG_APP, "PackToFileFromPixelmapTestJs successfully.");
}
return GetJsResult(env, errCode);
}