* Copyright (C) 2024 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 "picture_napi.h"
#include "media_errors.h"
#include "image_log.h"
#include "image_napi_utils.h"
#include "image_napi.h"
#include "pixel_map_napi.h"
#include "auxiliary_picture_napi.h"
#include "auxiliary_picture.h"
#include "napi_message_sequence.h"
#include "metadata.h"
#include "metadata_napi.h"
#include "image_common.h"
#undef LOG_DOMAIN
#define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
#undef LOG_TAG
#define LOG_TAG "PictureNapi"
namespace {
constexpr uint32_t NUM_0 = 0;
constexpr uint32_t NUM_1 = 1;
constexpr uint32_t NUM_2 = 2;
constexpr uint32_t NUM_3 = 3;
}
namespace OHOS {
namespace Media {
static const std::string CREATE_PICTURE_FROM_PARCEL = "createPictureFromParcel";
static const std::map<std::string, std::set<uint32_t>> ETS_API_ERROR_CODE = {
{CREATE_PICTURE_FROM_PARCEL, {62980096, 62980105, 62980115, 62980097,
62980177, 62980178, 62980179, 62980180, 62980246}}
};
static const std::string CLASS_NAME = "Picture";
thread_local napi_ref PictureNapi::sConstructor_ = nullptr;
thread_local std::shared_ptr<Picture> PictureNapi::sPicture_ = nullptr;
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
NAPI_MessageSequence* messageSequence = nullptr;
#endif
struct PictureAsyncContext {
napi_env env;
napi_async_work work;
napi_deferred deferred;
napi_ref callbackRef;
napi_ref error = nullptr;
uint32_t status;
std::shared_ptr<Picture> rPicture;
PictureNapi *nConstructor;
std::shared_ptr<PixelMap> rPixelMap;
std::shared_ptr<PixelMap> rHdrPixelMap;
MetadataNapi *metadataNapi;
std::shared_ptr<ImageMetadata> imageMetadata;
MetadataType metadataType = MetadataType::EXIF;
PixelFormat hdrFormat = PixelFormat::UNKNOWN;
bool withOptions = false;
GainmapParams gainmapParams;
HdrDecomposeOption decomposeOption;
};
using PictureAsyncContextPtr = std::unique_ptr<PictureAsyncContext>;
static std::vector<struct ImageEnum> auxiliaryPictureTypeMap = {
{"GAINMAP", static_cast<uint32_t>(AuxiliaryPictureType::GAINMAP), ""},
{"DEPTH_MAP", static_cast<uint32_t>(AuxiliaryPictureType::DEPTH_MAP), ""},
{"UNREFOCUS_MAP", static_cast<uint32_t>(AuxiliaryPictureType::UNREFOCUS_MAP), ""},
{"LINEAR_MAP", static_cast<uint32_t>(AuxiliaryPictureType::LINEAR_MAP), ""},
{"FRAGMENT_MAP", static_cast<uint32_t>(AuxiliaryPictureType::FRAGMENT_MAP), ""},
{"THUMBNAIL", static_cast<uint32_t>(AuxiliaryPictureType::THUMBNAIL), ""},
{"LHDR_GAINMAP", static_cast<uint32_t>(AuxiliaryPictureType::LHDR_GAINMAP), ""},
};
static std::vector<struct ImageEnum> metadataTypeMap = {
{"EXIF_METADATA", static_cast<uint32_t>(MetadataType::EXIF), ""},
{"FRAGMENT_METADATA", static_cast<uint32_t>(MetadataType::FRAGMENT), ""},
{"XTSTYLE_METADATA", static_cast<uint32_t>(MetadataType::XTSTYLE), ""},
{"RFDATAB_METADATA", static_cast<uint32_t>(MetadataType::RFDATAB), ""},
{"GIF_METADATA", static_cast<uint32_t>(MetadataType::GIF), ""},
{"HEIFS_METADATA", static_cast<uint32_t>(MetadataType::HEIFS), ""},
{"DNG_METADATA", static_cast<uint32_t>(MetadataType::DNG), ""},
{"WEBP_METADATA", static_cast<uint32_t>(MetadataType::WEBP), ""},
{"PNG_METADATA", static_cast<uint32_t>(MetadataType::PNG), ""},
{"JFIF_METADATA", static_cast<uint32_t>(MetadataType::JFIF), ""},
{"TIFF_METADATA", static_cast<uint32_t>(MetadataType::TIFF), ""},
{"XMP_METADATA", static_cast<uint32_t>(MetadataType::XMP), ""},
{"AVIS_METADATA", static_cast<uint32_t>(MetadataType::AVIS), ""},
};
static std::vector<struct ImageEnum> gifPropertyKeyMap = {
{"GIF_DELAY_TIME", 0, "GifDelayTime"},
{"GIF_DISPOSAL_TYPE", 0, "GifDisposalType"},
{"GIF_CANVAS_WIDTH", 0, "GifCanvasWidth"},
{"GIF_CANVAS_HEIGHT", 0, "GifCanvasHeight"},
{"GIF_HAS_GLOBAL_COLOR_MAP", 0, "GifHasGlobalColorMap"},
{"GIF_UNCLAMPED_DELAY_TIME", 0, "GifUnclampedDelayTime"},
{"GIF_LOOP_COUNT", 0, "GifLoopCount"},
};
static std::vector<struct ImageEnum> heifsPropertyKeyMap = {
{"HEIFS_DELAY_TIME", 0, "HeifsDelayTime"},
{"HEIFS_UNCLAMPED_DELAY_TIME", 0, "HeifsUnclampedDelayTime"},
{"HEIFS_CANVAS_HEIGHT", 0, "HeifsCanvasHeight"},
{"HEIFS_CANVAS_WIDTH", 0, "HeifsCanvasWidth"},
};
static std::vector<struct ImageEnum> webpPropertyKeyMap = {
{"CANVAS_HEIGHT", 0, "WebPCanvasHeight"},
{"CANVAS_WIDTH", 0, "WebPCanvasWidth"},
{"DELAY_TIME", 0, "WebPDelayTime"},
{"UNCLAMPED_DELAY_TIME", 0, "WebPUnclampedDelayTime"},
{"LOOP_COUNT", 0, "WebPLoopCount"},
};
static std::vector<struct ImageEnum> avisPropertyKeyMap = {
{"DELAY_TIME", 0, "AvisDelayTime"},
};
struct NapiValues {
napi_status status;
napi_value thisVar = nullptr;
napi_value result = nullptr;
napi_value* argv = nullptr;
size_t argc;
int32_t refCount = 1;
std::unique_ptr<PictureAsyncContext> context;
};
static void CommonCallbackRoutine(napi_env env, PictureAsyncContext* &asyncContext, const napi_value &valueParam)
{
napi_value result[NUM_2] = {0};
napi_get_undefined(env, &result[NUM_0]);
napi_get_undefined(env, &result[NUM_1]);
napi_handle_scope scope = nullptr;
napi_open_handle_scope(env, &scope);
if (scope == nullptr) {
if (asyncContext != nullptr) {
napi_delete_async_work(env, asyncContext->work);
delete asyncContext;
asyncContext = nullptr;
}
return;
}
if (asyncContext == nullptr) {
napi_close_handle_scope(env, scope);
return;
}
if (asyncContext->status == SUCCESS) {
result[NUM_1] = valueParam;
} else if (asyncContext->error != nullptr) {
napi_get_reference_value(env, asyncContext->error, &result[NUM_0]);
napi_delete_reference(env, asyncContext->error);
} else {
napi_create_uint32(env, asyncContext->status, &result[NUM_0]);
}
if (asyncContext->deferred) {
if (asyncContext->status == SUCCESS) {
napi_resolve_deferred(env, asyncContext->deferred, result[NUM_1]);
} else {
napi_reject_deferred(env, asyncContext->deferred, result[NUM_0]);
}
}
napi_delete_async_work(env, asyncContext->work);
napi_close_handle_scope(env, scope);
delete asyncContext;
asyncContext = nullptr;
}
static ImageType ParserImageType(napi_env env, napi_value argv)
{
napi_value constructor = nullptr;
napi_value global = nullptr;
bool isInstance = false;
napi_status ret = napi_invalid_arg;
ret = napi_get_global(env, &global);
if (ret != napi_ok) {
IMAGE_LOGI("Get global failed!");
return ImageType::TYPE_UNKNOWN;
}
ret = napi_get_named_property(env, global, "PixelMap", &constructor);
if (ret != napi_ok) {
IMAGE_LOGI("Get PixelMapNapi property failed!");
}
ret = napi_instanceof(env, argv, constructor, &isInstance);
if (ret == napi_ok && isInstance) {
return ImageType::TYPE_PIXEL_MAP;
}
IMAGE_LOGI("InValued type!");
return ImageType::TYPE_UNKNOWN;
}
static bool prepareNapiEnv(napi_env env, napi_callback_info info, struct NapiValues* nVal)
{
napi_get_undefined(env, &(nVal->result));
nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr);
if (nVal->status != napi_ok) {
IMAGE_LOGE("Fail to napi_get_cb_info");
return false;
}
nVal->context = std::make_unique<PictureAsyncContext>();
nVal->status = napi_unwrap(env, nVal->thisVar, reinterpret_cast<void**>(&(nVal->context->nConstructor)));
if (nVal->status != napi_ok) {
IMAGE_LOGE("Fail to unwrap context");
return false;
}
nVal->context->status = SUCCESS;
return true;
}
PictureNapi::PictureNapi():env_(nullptr)
{
static std::atomic<uint32_t> currentId = 0;
uniqueId_ = currentId.fetch_add(1, std::memory_order_relaxed);
}
PictureNapi::~PictureNapi()
{
release();
}
napi_value PictureNapi::Init(napi_env env, napi_value exports)
{
napi_property_descriptor props[] = {
DECLARE_NAPI_FUNCTION("getMainPixelmap", GetMainPixelmap),
DECLARE_NAPI_FUNCTION("setMainPixelmap", SetMainPixelmap),
DECLARE_NAPI_FUNCTION("getHdrComposedPixelmap", GetHdrComposedPixelMap),
DECLARE_NAPI_FUNCTION("getHdrComposedPixelmapWithOptions", GetHdrComposedPixelMapWithOptions),
DECLARE_NAPI_FUNCTION("getGainmapPixelmap", GetGainmapPixelmap),
DECLARE_NAPI_FUNCTION("getAuxiliaryPicture", GetAuxiliaryPicture),
DECLARE_NAPI_FUNCTION("setAuxiliaryPicture", SetAuxiliaryPicture),
DECLARE_NAPI_FUNCTION("release", Release),
DECLARE_NAPI_FUNCTION("marshalling", Marshalling),
DECLARE_NAPI_FUNCTION("getMetadata", GetMetadata),
DECLARE_NAPI_FUNCTION("setMetadata", SetMetadata),
DECLARE_NAPI_FUNCTION("hdrComposeToMainPixelmap", HdrComposeToMainPixelmap),
};
napi_property_descriptor static_prop[] = {
DECLARE_NAPI_STATIC_FUNCTION("createPicture", CreatePicture),
DECLARE_NAPI_STATIC_FUNCTION("createPictureFromParcel", CreatePictureFromParcel),
DECLARE_NAPI_STATIC_FUNCTION("createPictureByHdrAndSdrPixelMap", CreatePictureByHdrAndSdrPixelMap),
DECLARE_NAPI_STATIC_FUNCTION("decomposeToPicture", DecomposeToPicture),
DECLARE_NAPI_PROPERTY("AuxiliaryPictureType",
ImageNapiUtils::CreateEnumTypeObject(env, napi_number, auxiliaryPictureTypeMap)),
DECLARE_NAPI_PROPERTY("MetadataType",
ImageNapiUtils::CreateEnumTypeObject(env, napi_number, metadataTypeMap)),
DECLARE_NAPI_PROPERTY("GifPropertyKey",
ImageNapiUtils::CreateEnumTypeObject(env, napi_string, gifPropertyKeyMap)),
DECLARE_NAPI_PROPERTY("HeifsPropertyKey",
ImageNapiUtils::CreateEnumTypeObject(env, napi_string, heifsPropertyKeyMap)),
DECLARE_NAPI_PROPERTY("WebPPropertyKey",
ImageNapiUtils::CreateEnumTypeObject(env, napi_string, webpPropertyKeyMap)),
DECLARE_NAPI_PROPERTY("AvisPropertyKey",
ImageNapiUtils::CreateEnumTypeObject(env, napi_string, avisPropertyKeyMap)),
};
napi_value constructor = nullptr;
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, IMG_ARRAY_SIZE(props),
props, &constructor)), nullptr, IMAGE_LOGE("define class fail")
);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(napi_create_reference(env, constructor, 1, &sConstructor_)),
nullptr, IMAGE_LOGE("create reference fail")
);
auto ctorContext = new NapiConstructorContext();
ctorContext->env_ = env;
ctorContext->ref_ = sConstructor_;
napi_add_env_cleanup_hook(env, ImageNapiUtils::CleanUpConstructorContext, ctorContext);
napi_value global = nullptr;
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(napi_get_global(env, &global)), nullptr, IMAGE_LOGE("Init:get global fail"));
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)),
nullptr, IMAGE_LOGE("Init:set global named property fail")
);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
nullptr, IMAGE_LOGE("set named property fail")
);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
nullptr, IMAGE_LOGE("define properties fail")
);
IMAGE_LOGD("Init success");
return exports;
}
napi_value PictureNapi::Constructor(napi_env env, napi_callback_info info)
{
napi_value undefineVar = nullptr;
napi_get_undefined(env, &undefineVar);
napi_status status;
napi_value thisVar = nullptr;
napi_get_undefined(env, &thisVar);
IMAGE_LOGD("Constructor IN");
status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar);
std::unique_ptr<PictureNapi> pPictureNapi = std::make_unique<PictureNapi>();
if (pPictureNapi != nullptr) {
pPictureNapi->env_ = env;
pPictureNapi->nativePicture_ = std::move(sPicture_);
if (pPictureNapi->nativePicture_ == nullptr) {
IMAGE_LOGE("Failed to set nativePicture_ with null. Maybe a reentrancy error");
}
status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pPictureNapi.get()),
PictureNapi::Destructor, nullptr, nullptr);
if (status == napi_ok) {
pPictureNapi.release();
return thisVar;
} else {
IMAGE_LOGE("Failure wrapping js to native napi");
return undefineVar;
}
}
return thisVar;
}
void PictureNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
{
if (nativeObject != nullptr) {
IMAGE_LOGD("Destructor PictureNapi");
delete reinterpret_cast<PictureNapi*>(nativeObject);
nativeObject = nullptr;
}
}
napi_value PictureNapi::CreatePicture(napi_env env, std::shared_ptr<Picture> &picture)
{
if (sConstructor_ == nullptr) {
napi_value exports = nullptr;
napi_create_object(env, &exports);
PictureNapi::Init(env, exports);
}
napi_value constructor = nullptr;
napi_value result = nullptr;
napi_status status = napi_get_reference_value(env, sConstructor_, &constructor);
if (IMG_IS_OK(status)) {
if (picture != nullptr) {
sPicture_ = std::move(picture);
status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
} else {
status = napi_invalid_arg;
IMAGE_LOGE("New PictureNapi Instance picture is nullptr");
napi_get_undefined(env, &result);
}
}
if (!IMG_IS_OK(status)) {
IMAGE_LOGE("CreatePicture | New instance could not be obtained");
napi_get_undefined(env, &result);
}
return result;
}
extern "C" {
napi_value GetPictureNapi(napi_env env, std::shared_ptr<Picture> picture)
{
return PictureNapi::CreatePicture(env, picture);
}
bool GetNativePicture(void *pictureNapi, std::shared_ptr<Picture> &picture)
{
if (pictureNapi == nullptr) {
IMAGE_LOGE("%{public}s pictureNapi is nullptr", __func__);
return false;
}
picture = reinterpret_cast<PictureNapi*>(pictureNapi)->GetNativePicture();
return true;
}
}
static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val)
{
if (!ImageNapiUtils::GetNapiSupportedAuxiliaryPictureType().count(static_cast<AuxiliaryPictureType>(val))) {
IMAGE_LOGE("%{public}s auxiliaryPictureType is invalid: %{public}d", __func__, val);
return AuxiliaryPictureType::NONE;
}
return AuxiliaryPictureType(val);
}
static void PreparePicNapiEnv(napi_env env)
{
napi_value globalValue;
napi_get_global(env, &globalValue);
napi_value func;
napi_get_named_property(env, globalValue, "requireNapi", &func);
napi_value picture;
napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &picture);
napi_value funcArgv[NUM_1] = { picture };
napi_value returnValue;
napi_call_function(env, globalValue, func, NUM_1, funcArgv, &returnValue);
}
int32_t PictureNapi::CreatePictureNapi(napi_env env, napi_value* result)
{
napi_value constructor = nullptr;
napi_status status = napi_ok;
PreparePicNapiEnv(env);
status = napi_get_reference_value(env, sConstructor_, &constructor);
if (status == napi_ok && constructor != nullptr) {
status = napi_new_instance(env, constructor, NUM_0, nullptr, result);
}
if (status != napi_ok || result == nullptr) {
IMAGE_LOGE("CreatePictureNapi new instance failed");
napi_get_undefined(env, result);
return ERR_IMAGE_DATA_ABNORMAL;
}
return SUCCESS;
}
void PictureNapi::SetNativePicture(std::shared_ptr<Picture> picture)
{
nativePicture_ = picture;
}
std::shared_ptr<Picture> PictureNapi::GetNativePicture()
{
return nativePicture_;
}
napi_value PictureNapi::GetAuxiliaryPicture(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_null(env, &result);
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_1] = {0};
size_t argCount = NUM_1;
uint32_t auxiType = 0;
IMAGE_LOGD("GetAuxiliaryPicture IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to arg info"));
PictureNapi* pictureNapi = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&pictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi), result, IMAGE_LOGE("fail to unwrap PictureNapi"));
status = napi_get_value_uint32(env, argValue[NUM_0], &auxiType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to get auxiliary picture type!"), IMAGE_LOGE("Fail to get auxiliary picture type."));
AuxiliaryPictureType type = ParseAuxiliaryPictureType(auxiType);
if (type == AuxiliaryPictureType::NONE) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"The type does not match the auxiliary picture type!");
}
if (pictureNapi->nativePicture_ != nullptr) {
auto auxiliaryPic = pictureNapi->nativePicture_->GetAuxiliaryPicture(type);
if (auxiliaryPic != nullptr) {
result = AuxiliaryPictureNapi::CreateAuxiliaryPicture(env, std::move(auxiliaryPic));
} else {
IMAGE_LOGE("native auxiliary picture is nullptr!");
}
} else {
IMAGE_LOGE("native picture is nullptr!");
}
return result;
}
std::shared_ptr<Picture> PictureNapi::GetPicture(napi_env env, napi_value picture)
{
PictureNapi *pictureNapi = nullptr;
napi_status status = napi_unwrap(env, picture, reinterpret_cast<void**>(&pictureNapi));
if (!IMG_IS_OK(status)) {
IMAGE_LOGE("GetPicture napi unwrap failed");
return nullptr;
}
if (pictureNapi == nullptr) {
IMAGE_LOGE("GetPixelMap pixmapNapi is nullptr");
return nullptr;
}
return pictureNapi->nativePicture_;
}
napi_value PictureNapi::SetAuxiliaryPicture(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_2] = {0};
size_t argCount = NUM_2;
uint32_t auxiType = 0;
IMAGE_LOGD("SetAuxiliaryPictureSync IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
PictureNapi* pictureNapi = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&pictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi), result, IMAGE_LOGE("fail to unwrap PictureNapi"));
status = napi_get_value_uint32(env, argValue[NUM_0], &auxiType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to get auxiliary picture type!"), IMAGE_LOGE("Fail to get auxiliary picture Type"));
AuxiliaryPictureType type = ParseAuxiliaryPictureType(auxiType);
if (type == AuxiliaryPictureType::NONE) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"The type does not match the auxiliary picture type!");
}
AuxiliaryPictureNapi* auxiliaryPictureNapi = nullptr;
status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&auxiliaryPictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, auxiliaryPictureNapi),
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to unwrap AuxiliaryPictureNapi!"),
IMAGE_LOGE("Fail to unwrap AuxiliaryPictureNapi"));
if (pictureNapi->nativePicture_ != nullptr) {
auto auxiliaryPicturePtr = auxiliaryPictureNapi->GetNativeAuxiliaryPic();
if (auxiliaryPicturePtr != nullptr) {
if (type != auxiliaryPicturePtr->GetAuxiliaryPictureInfo().auxiliaryPictureType) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"The type does not match the auxiliary picture type!");
} else {
pictureNapi->nativePicture_->SetAuxiliaryPicture(auxiliaryPicturePtr);
}
} else {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Native auxiliary picture is nullptr!");
}
} else {
IMAGE_LOGE("native picture is nullptr!");
}
return result;
}
STATIC_EXEC_FUNC(CreatePicture)
{
IMAGE_LOGD("CreatePictureEX IN");
auto context = static_cast<PictureAsyncContext*>(data);
auto picture = Picture::Create(context->rPixelMap);
context->rPicture = std::move(picture);
IMAGE_LOGD("CreatePictureEX OUT");
if (IMG_NOT_NULL(context->rPicture)) {
context->status = SUCCESS;
} else {
context->status = ERR_MEDIA_UNSUPPORT_OPERATION;
}
}
napi_value PictureNapi::CreatePicture(napi_env env, napi_callback_info info)
{
IMAGE_LOGD("CreatePicture IN");
if (sConstructor_ == nullptr) {
napi_value exports = nullptr;
napi_create_object(env, &exports);
PictureNapi::Init(env, exports);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_value constructor = nullptr;
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_1] = {0};
size_t argCount = NUM_1;
IMAGE_LOGD("CreatePicture IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid args"), IMAGE_LOGE("fail to napi_get_cb_info"));
IMG_NAPI_CHECK_RET_D(argCount == NUM_1, ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid args count"), IMAGE_LOGE("Invalid args count %{public}zu", argCount));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
if (ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP) {
asyncContext->rPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
if (asyncContext->rPixelMap == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Get arg pixelmap failed");
}
} else {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Input image type mismatch");
}
CreatePictureExec(env, static_cast<void*>((asyncContext).get()));
status = napi_get_reference_value(env, sConstructor_, &constructor);
if (IMG_IS_OK(status)) {
sPicture_ = std::move(asyncContext->rPicture);
status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
}
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create picture sync"));
IMAGE_LOGD("CreatePicture OUT");
return result;
}
STATIC_EXEC_FUNC(CreatePictureByHdrAndSdrPixelMap)
{
IMAGE_LOGD("CreatePictureByHdrAndSdrPixelMapEX IN");
auto context = static_cast<PictureAsyncContext*>(data);
auto picture =
Picture::CreatePictureByHdrAndSdrPixelMap(context->rHdrPixelMap, context->rPixelMap, context->gainmapParams);
context->rPicture = std::move(picture);
IMAGE_LOGD("CreatePictureByHdrAndSdrPixelMapEX OUT");
if (IMG_NOT_NULL(context->rPicture)) {
context->status = SUCCESS;
} else {
context->status = ERROR;
}
}
bool ParseGainmapParams(napi_env env, napi_value root, GainmapParams *gainmapParams)
{
if (root == nullptr || gainmapParams == nullptr) {
IMAGE_LOGE("ParseGainmapParams: invalid input parameters");
return false;
}
napi_valuetype valueType;
napi_status status = napi_typeof(env, root, &valueType);
if (status != napi_ok || valueType != napi_object) {
IMAGE_LOGE("ParseGainmapParams: root is not a valid object");
return false;
}
bool isFullSizeGainmap = false;
bool getSuccess = GET_BOOL_BY_NAME(root, "isFullSizeGainmap", isFullSizeGainmap);
if (getSuccess) {
gainmapParams->isFullSizeGainmap = isFullSizeGainmap;
IMAGE_LOGD("ParseGainmapParams: isFullSizeGainmap = %{public}d", isFullSizeGainmap);
} else {
gainmapParams->isFullSizeGainmap = false;
IMAGE_LOGD("ParseGainmapParams: isFullSizeGainmap not found, using default false");
}
return true;
}
bool ParseDecomposeOptions(napi_env env, napi_value root, HdrDecomposeOption *decomposeOption)
{
if (root == nullptr || decomposeOption == nullptr) {
IMAGE_LOGE("ParseDecomposeOptions: invalid input parameters");
return false;
}
napi_valuetype valueType;
napi_status status = napi_typeof(env, root, &valueType);
if (status != napi_ok || valueType != napi_object) {
IMAGE_LOGE("ParseDecomposeOptions: root is not a valid object");
return false;
}
bool isFullSizeGainmap = false;
bool getSuccess = GET_BOOL_BY_NAME(root, "isFullSizeGainmap", isFullSizeGainmap);
if (getSuccess) {
decomposeOption->isFullSizeGainmap = isFullSizeGainmap;
IMAGE_LOGD("ParseDecomposeOptions: isFullSizeGainmap = %{public}d", isFullSizeGainmap);
} else {
decomposeOption->isFullSizeGainmap = false;
IMAGE_LOGD("ParseDecomposeOptions: isFullSizeGainmap not found, using default false");
}
uint32_t desiredPixelFormat = 3;
getSuccess = GET_UINT32_BY_NAME(root, "desiredPixelFormat", desiredPixelFormat);
if (getSuccess) {
decomposeOption->desiredPixelFormat = static_cast<PixelFormat>(desiredPixelFormat);
IMAGE_LOGD("ParseDecomposeOptions: desiredPixelFormat = %{public}d", desiredPixelFormat);
} else {
decomposeOption->desiredPixelFormat = PixelFormat::RGBA_8888;
IMAGE_LOGD("ParseDecomposeOptions: desiredPixelFormat not found, using default RGBA_8888");
}
return true;
}
bool ParsePixelMapParameter(
napi_env env, napi_value arg, const char *paramName, std::shared_ptr<PixelMap> &outputPixelMap)
{
if (ParserImageType(env, arg) != ImageType::TYPE_PIXEL_MAP) {
IMAGE_LOGE("ParsePixelMapParameter: Input %s image type mismatch", paramName);
return false;
}
outputPixelMap = PixelMapNapi::GetPixelMap(env, arg);
if (outputPixelMap == nullptr) {
IMAGE_LOGE("ParsePixelMapParameter: Get %s Pixelmap failed", paramName);
return false;
}
return true;
}
napi_value PictureNapi::CreatePictureByHdrAndSdrPixelMap(napi_env env, napi_callback_info info)
{
IMAGE_LOGD("CreatePictureByHdrAndSdrPixelMap IN");
if (!ImageSystemProperties::IsSystemApp()) {
IMAGE_LOGE("This interface can be called only by system apps");
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_PERMISSIONS_FAILED,
"This interface can be called only by system apps", true);
}
if (sConstructor_ == nullptr) {
napi_value exports = nullptr;
napi_create_object(env, &exports);
PictureNapi::Init(env, exports);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_value constructor = nullptr;
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_3] = {0};
size_t argCount = NUM_3;
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid args"), IMAGE_LOGE("fail to napi_get_cb_info"));
const bool codeAsNumber = argCount >= NUM_3;
IMG_NAPI_CHECK_RET_D(argCount >= NUM_2 && argCount <= NUM_3,
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args count", codeAsNumber),
IMAGE_LOGE("Invalid args count %{public}zu", argCount));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
if (!ParsePixelMapParameter(env, argValue[NUM_0], "hdr", asyncContext->rHdrPixelMap)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid hdr PixelMap parameter", codeAsNumber);
}
if (!ParsePixelMapParameter(env, argValue[NUM_1], "sdr", asyncContext->rPixelMap)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid sdr PixelMap parameter", codeAsNumber);
}
GainmapParams gainmapParams;
if (argCount == NUM_3 && !ParseGainmapParams(env, argValue[NUM_2], &gainmapParams)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid gainmap params", codeAsNumber);
}
asyncContext->gainmapParams = gainmapParams;
CreatePictureByHdrAndSdrPixelMapExec(env, static_cast<void*>((asyncContext).get()));
status = napi_get_reference_value(env, sConstructor_, &constructor);
if (IMG_IS_OK(status)) {
sPicture_ = std::move(asyncContext->rPicture);
status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
}
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create picture sync"));
IMAGE_LOGD("CreatePictureByHdrAndSdrPixelMap OUT");
return result;
}
STATIC_EXEC_FUNC(DecomposeToPicture)
{
IMAGE_LOGD("DecomposeToPictureExec IN");
auto context = static_cast<PictureAsyncContext*>(data);
if (context == nullptr) {
IMAGE_LOGE("DecomposeToPictureExec: context is nullptr");
return;
}
int32_t errCode = SUCCESS;
auto picture = Picture::DecomposeToPicture(context->rHdrPixelMap, context->decomposeOption, errCode);
context->rPicture = std::move(picture);
if (errCode != SUCCESS) {
context->status = static_cast<uint32_t>(errCode);
} else if (context->rPicture == nullptr) {
context->status = ERR_IMAGE_DECOMPOSE_FAILED;
} else {
context->status = SUCCESS;
}
IMAGE_LOGD("DecomposeToPictureExec OUT");
}
static void CreateDecomposeToPictureComplete(napi_env env, napi_status status, void *data)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
auto context = static_cast<PictureAsyncContext*>(data);
if (context == nullptr) {
IMAGE_LOGE("CreateDecomposeToPictureComplete: context is nullptr");
return;
}
if (!IMG_IS_OK(status)) {
IMAGE_LOGE("CreateDecomposeToPictureComplete: async work failed");
context->status = ERROR;
CommonCallbackRoutine(env, context, result);
return;
}
if (context->status == SUCCESS && context->rPicture != nullptr) {
result = PictureNapi::CreatePicture(env, context->rPicture);
} else if (context->status == SUCCESS) {
context->status = ERR_IMAGE_DECOMPOSE_FAILED;
}
if (context->status != SUCCESS && context->error == nullptr) {
napi_value errorObj;
napi_value codeValue;
napi_value msgValue;
napi_create_int32(env, static_cast<int32_t>(context->status), &codeValue);
napi_create_string_utf8(env, "HDR image decomposition failed",
NAPI_AUTO_LENGTH, &msgValue);
napi_create_error(env, nullptr, msgValue, &errorObj);
napi_set_named_property(env, errorObj, "code", codeValue);
napi_create_reference(env, errorObj, 1, &context->error);
}
CommonCallbackRoutine(env, context, result);
}
napi_value PictureNapi::DecomposeToPicture(napi_env env, napi_callback_info info)
{
IMAGE_LOGD("DecomposeToPicture IN");
if (!ImageSystemProperties::IsSystemApp()) {
IMAGE_LOGE("PictureNapi::DecomposeToPicture can be called only by system apps");
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_PERMISSIONS_FAILED,
"DecomposeToPicture can be called only by system apps", true);
}
if (sConstructor_ == nullptr) {
napi_value exports = nullptr;
napi_create_object(env, &exports);
PictureNapi::Init(env, exports);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_2] = {0};
size_t argCount = NUM_2;
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid args", true), IMAGE_LOGE("fail to napi_get_cb_info"));
IMG_NAPI_CHECK_RET_D(argCount >= NUM_1 && argCount <= NUM_2,
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args count", true),
IMAGE_LOGE("Invalid args count %{public}zu", argCount));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
if (!ParsePixelMapParameter(env, argValue[NUM_0], "hdr", asyncContext->rHdrPixelMap)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_INVALID_PARAMETER,
"hdrPixelMap is empty", true);
}
if (argCount == NUM_2 && !ParseDecomposeOptions(env, argValue[NUM_1], &asyncContext->decomposeOption)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Invalid DecomposeOptions parameter", true);
}
napi_create_promise(env, &(asyncContext->deferred), &result);
asyncContext->status = SUCCESS;
IMG_CREATE_CREATE_ASYNC_WORK(env, status, "DecomposeToPicture",
DecomposeToPictureExec, CreateDecomposeToPictureComplete, asyncContext, asyncContext->work);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
nullptr, IMAGE_LOGE("Fail to create DecomposeToPicture async work"));
IMAGE_LOGD("DecomposeToPicture OUT");
return result;
}
napi_value PictureNapi::ThrowExceptionError(napi_env env,
const std::string &tag, const std::uint32_t &code, const std::string &info)
{
auto errNode = ETS_API_ERROR_CODE.find(tag);
if (errNode != ETS_API_ERROR_CODE.end() &&
errNode->second.find(code) != errNode->second.end()) {
return ImageNapiUtils::ThrowExceptionError(env, code, info);
}
return ImageNapiUtils::ThrowExceptionError(env, ERROR, "Operation failed");
}
napi_value PictureNapi::CreatePictureFromParcel(napi_env env, napi_callback_info info)
{
if (sConstructor_ == nullptr) {
napi_value exports = nullptr;
napi_create_object(env, &exports);
PictureNapi::Init(env, exports);
}
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_1] = {0};
size_t argCount = NUM_1;
IMAGE_LOGD("Call CreatePictureFromParcel");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
if (!IMG_IS_OK(status) || argCount != NUM_1) {
return PictureNapi::ThrowExceptionError(env,
CREATE_PICTURE_FROM_PARCEL, IMAGE_BAD_PARAMETER, "Fail to napi_get_cb_info");
}
napi_unwrap(env, argValue[NUM_0], (void **)&messageSequence);
if (messageSequence == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to unwrap messageSequence");
}
auto messageParcel = messageSequence->GetMessageParcel();
if (messageParcel == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env, ERR_IPC, "Get parcel failed");
}
PICTURE_ERR error;
auto picture = Picture::Unmarshalling(*messageParcel, error);
if (!IMG_NOT_NULL(picture)) {
return ImageNapiUtils::ThrowExceptionError(env, ERR_IPC, "Unmarshalling picture failed");
}
std::shared_ptr<OHOS::Media::Picture> picturePtr(picture);
sPicture_ = std::move(picturePtr);
napi_value constructor = nullptr;
status = napi_get_reference_value(env, sConstructor_, &constructor);
if (IMG_IS_OK(status)) {
if (sPicture_ == nullptr) {
status = napi_invalid_arg;
IMAGE_LOGE("NewPictureNapiInstance picture is nullptr");
} else {
status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
}
}
if (!IMG_IS_OK(status)) {
IMAGE_LOGE("New instance could not be obtained");
return PictureNapi::ThrowExceptionError(env,
CREATE_PICTURE_FROM_PARCEL, ERR_IMAGE_NAPI_ERROR, "New instance could not be obtained");
}
return result;
}
napi_value PictureNapi::GetMainPixelmap(napi_env env, napi_callback_info info)
{
NapiValues nVal;
napi_get_undefined(env, &nVal.result);
nVal.argc = NUM_0;
IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to arg info"));
PictureNapi* pictureNapi = nullptr;
nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&pictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, pictureNapi), nVal.result, IMAGE_LOGE("Fail to unwrap context"));
if (pictureNapi->nativePicture_ != nullptr) {
auto pixelmap = pictureNapi->nativePicture_->GetMainPixel();
nVal.result = PixelMapNapi::CreatePixelMap(env, pixelmap);
} else {
IMAGE_LOGE("Native picture is nullptr!");
}
return nVal.result;
}
napi_value PictureNapi::SetMainPixelmap(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
napi_value argValue[NUM_1] = {0};
size_t argCount = NUM_1;
IMAGE_LOGD("SetMainPixelmap IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get arguments from info"));
IMG_NAPI_CHECK_RET_D(argCount == NUM_1, ImageNapiUtils::ThrowExceptionError(env, IMAGE_SOURCE_INVALID_PARAMETER,
"Invalid args count", true), IMAGE_LOGE("Invalid args count %{public}zu", argCount));
PictureNapi* pictureNapi = nullptr;
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&pictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi), result, IMAGE_LOGE("Fail to unwrap context"));
if (ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP) {
auto pixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
if (pixelMap == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env,
IMAGE_SOURCE_INVALID_PARAMETER, "Get arg pixelmap failed", true);
}
if (pictureNapi->nativePicture_ != nullptr) {
pictureNapi->nativePicture_->SetMainPixel(pixelMap);
} else {
IMAGE_LOGE("Native picture is nullptr!");
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_SOURCE_INVALID_PARAMETER,
"Picture is a null pointer", true);
}
} else {
return ImageNapiUtils::ThrowExceptionError(env,
IMAGE_SOURCE_INVALID_PARAMETER, "Input image type mismatch", true);
}
return result;
}
napi_value PictureNapi::Release(napi_env env, napi_callback_info info)
{
NapiValues nVal;
nVal.result = nullptr;
napi_get_undefined(env, &nVal.result);
nVal.argc = NUM_0;
IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to arg info"));
PictureNapi *picturenapi = nullptr;
nVal.status = napi_remove_wrap(env, nVal.thisVar, reinterpret_cast<void**>(&picturenapi));
return nVal.result;
}
napi_value PictureNapi::Marshalling(napi_env env, napi_callback_info info)
{
#if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
NapiValues nVal;
nVal.argc = NUM_1;
napi_value argValue[NUM_1] = {0};
nVal.argv = argValue;
if (!prepareNapiEnv(env, info, &nVal)) {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_BAD_PARAMETER, "Fail to unwrap context");
}
nVal.context->rPicture = nVal.context->nConstructor->nativePicture_;
if (nVal.argc != NUM_0 && nVal.argc != NUM_1) {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_BAD_PARAMETER, "Invalid args count");
}
NAPI_MessageSequence *napiSequence = nullptr;
napi_get_cb_info(env, info, &nVal.argc, nVal.argv, nullptr, nullptr);
napi_unwrap(env, nVal.argv[0], reinterpret_cast<void**>(&napiSequence));
if (napiSequence == nullptr) {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_BAD_PARAMETER, "Marshalling picture napi_unwrap failed.");
}
auto messageParcel = napiSequence->GetMessageParcel();
if (messageParcel == nullptr) {
return ImageNapiUtils::ThrowExceptionError(
env, ERR_IPC, "Marshalling picture to parcel failed.");
}
bool st = nVal.context->rPicture->Marshalling(*messageParcel);
if (!st) {
return ImageNapiUtils::ThrowExceptionError(
env, ERR_IPC, "Marshalling picture to parcel failed.");
}
return nVal.result;
#else
return napi_value(nullptr);
#endif
}
static void CreateHDRComposedPixelmapComplete(napi_env env, napi_status status, void *data)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
auto context = static_cast<PictureAsyncContext*>(data);
if (context->rPixelMap != nullptr) {
result = PixelMapNapi::CreatePixelMap(env, context->rPixelMap);
context->status = SUCCESS;
} else {
context->status = context->withOptions ? IMAGE_UNSUPPORTED_OPERATION : ERROR;
}
CommonCallbackRoutine(env, context, result);
}
static bool ParseHdrComposeOptions(napi_env env, napi_value root, std::unique_ptr<PictureAsyncContext> &asyncContext)
{
uint32_t format = 0;
if (!ImageNapiUtils::GetUint32ByName(env, root, "desiredPixelFormat", &format)) {
IMAGE_LOGD("no desiredPixelFormat");
}
asyncContext->hdrFormat = static_cast<PixelFormat>(format);
return true;
}
napi_value PictureNapi::GetHdrComposedPixelMapNapi(napi_env env, napi_callback_info info, bool withOptions)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
size_t argCount = NUM_1;
napi_value argValue[NUM_1] = {0};
int32_t format = 0;
IMAGE_LOGD("GetHdrComposedPixelMap IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to napi_get_cb_info"));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), result,
IMAGE_LOGE("Fail to napi_unwrap context"));
asyncContext->withOptions = withOptions;
asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), nullptr, IMAGE_LOGE("Empty native pixelmap"));
if (asyncContext->rPicture->GetAuxiliaryPicture(AuxiliaryPictureType::GAINMAP) == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "There is no GAINMAP");
}
if (asyncContext->rPicture->GetMainPixel()->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "Unsupported operations");
}
if (argCount == NUM_1) {
if (asyncContext->withOptions) {
if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object &&
!ParseHdrComposeOptions(env, argValue[NUM_0], asyncContext)) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION,
"HdrComposeOptions mismatch");
}
} else {
status = napi_get_value_int32(env, argValue[NUM_0], &format);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to get format"), IMAGE_LOGE("Fail to get format"));
asyncContext->hdrFormat = static_cast<PixelFormat>(format);
}
}
napi_create_promise(env, &(asyncContext->deferred), &result);
IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetHdrComposedPixelMap",
[](napi_env env, void *data) {
auto context = static_cast<PictureAsyncContext*>(data);
auto tmpixel = context->rPicture->GetHdrComposedPixelMap(context->hdrFormat);
context->rPixelMap = std::move(tmpixel);
context->status = SUCCESS;
}, CreateHDRComposedPixelmapComplete, asyncContext, asyncContext->work);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
nullptr, IMAGE_LOGE("Fail to create async work"));
return result;
}
napi_value PictureNapi::GetHdrComposedPixelMap(napi_env env, napi_callback_info info)
{
return GetHdrComposedPixelMapNapi(env, info, false);
}
napi_value PictureNapi::GetHdrComposedPixelMapWithOptions(napi_env env, napi_callback_info info)
{
return GetHdrComposedPixelMapNapi(env, info, true);
}
napi_value PictureNapi::GetGainmapPixelmap(napi_env env, napi_callback_info info)
{
NapiValues nVal;
napi_get_null(env, &nVal.result);
IMAGE_LOGD("GetGainmapPixelmap");
nVal.argc = NUM_0;
IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Parameter acquisition failed"));
PictureNapi* pictureNapi = nullptr;
nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&pictureNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, pictureNapi),
nVal.result, IMAGE_LOGE("Failed to retrieve native pointer"));
if (pictureNapi->nativePicture_ != nullptr) {
auto gainpixelmap = pictureNapi->nativePicture_->GetGainmapPixelMap();
if (gainpixelmap == nullptr) {
return nVal.result;
}
nVal.result = PixelMapNapi::CreatePixelMap(env, gainpixelmap);
} else {
return ImageNapiUtils::ThrowExceptionError(env, ERR_MEDIA_UNKNOWN, "Picture is a null pointer");
}
return nVal.result;
}
static void GetMetadataComplete(napi_env env, napi_status status, void *data)
{
IMAGE_LOGD("[Picture]GetMetadata IN");
napi_value result = nullptr;
napi_get_undefined(env, &result);
auto context = static_cast<PictureAsyncContext*>(data);
if (context->imageMetadata != nullptr) {
result = MetadataNapi::CreateMetadata(env, context->imageMetadata);
}
if (!IMG_IS_OK(status)) {
context->status = ERROR;
IMAGE_LOGE("Get Metadata failed!");
} else {
context->status = SUCCESS;
}
IMAGE_LOGD("[Picture]GetMetadata OUT");
CommonCallbackRoutine(env, context, result);
}
void CreateGetMetadataAsyncWork(napi_env env, napi_status& status,
std::unique_ptr<PictureAsyncContext>& asyncContext,
napi_value& result, uint32_t metadataType)
{
asyncContext->metadataType = static_cast<MetadataType>(metadataType);
napi_create_promise(env, &(asyncContext->deferred), &result);
IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetMetadata",
[](napi_env env, void* data) {
auto context = static_cast<PictureAsyncContext*>(data);
context->imageMetadata = context->rPicture->GetMetadata(context->metadataType);
}, GetMetadataComplete, asyncContext, asyncContext->work);
}
napi_value PictureNapi::GetMetadata(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
size_t argCount = NUM_1;
napi_value argValue[NUM_1] = {0};
uint32_t metadataType = 0;
IMAGE_LOGD("GetMetadata IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argment from info"));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
nullptr, IMAGE_LOGE("Fail to unwrap context"));
asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), nullptr, IMAGE_LOGE("Empty native picture"));
status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to get metadata type"), IMAGE_LOGE("Fail to get metadata type"));
if (!Picture::IsValidPictureMetadataType(static_cast<MetadataType>(metadataType))) {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_UNSUPPORTED_METADATA, "Unsupport MetadataType");
}
CreateGetMetadataAsyncWork(env, status, asyncContext, result, metadataType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
nullptr, IMAGE_LOGE("Fail to create async work"));
return result;
}
static void SetMetadataComplete(napi_env env, napi_status status, void *data)
{
IMAGE_LOGD("[Picture]SetMetadata IN");
auto context = static_cast<PictureAsyncContext*>(data);
napi_value result = nullptr;
napi_get_undefined(env, &result);
if (!IMG_IS_OK(status)) {
context->status = ERROR;
IMAGE_LOGE("Set Metadata failed!");
}
IMAGE_LOGD("[Picture]SetMetadata OUT");
CommonCallbackRoutine(env, context, result);
}
void CreateSetMetadataAsyncWork(napi_env env, napi_status& status,
std::unique_ptr<PictureAsyncContext>& asyncContext,
napi_value& result, uint32_t metadataType)
{
asyncContext->metadataType = static_cast<MetadataType>(metadataType);
napi_create_promise(env, &(asyncContext->deferred), &result);
IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetMetadata",
[](napi_env env, void* data) {
auto context = static_cast<PictureAsyncContext*>(data);
context->status = context->rPicture->SetMetadata(context->metadataType, context->imageMetadata);
}, SetMetadataComplete, asyncContext, asyncContext->work);
}
napi_value PictureNapi::SetMetadata(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
size_t argCount = NUM_2;
napi_value argValue[NUM_2] = {0};
uint32_t metadataType = 0;
IMAGE_LOGD("SetMetadata IN");
IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argments from info"));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
nullptr, IMAGE_LOGE("Fail to unwrap context"));
asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), nullptr, IMAGE_LOGE("Empty native picture"));
status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to get metadata type"), IMAGE_LOGE("Fail to get metadata type"));
if (Picture::IsValidPictureMetadataType(static_cast<MetadataType>(metadataType))) {
asyncContext->metadataType = MetadataType(metadataType);
} else {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_UNSUPPORTED_METADATA, "Unsupport MetadataType");
}
status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&asyncContext->metadataNapi));
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
"Fail to unwrap MetadataNapi"), IMAGE_LOGE("Fail to unwrap MetadataNapi"));
if (asyncContext->metadataNapi != nullptr) {
asyncContext->imageMetadata = asyncContext->metadataNapi->GetNativeMetadata();
} else {
return ImageNapiUtils::ThrowExceptionError(
env, IMAGE_BAD_PARAMETER, "Invalid args Metadata");
}
CreateSetMetadataAsyncWork(env, status, asyncContext, result, metadataType);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
nullptr, IMAGE_LOGE("Fail to create async work"));
return result;
}
static void HdrComposeToMainPixelmapComplete(napi_env env, napi_status status, void *data)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
auto context = static_cast<PictureAsyncContext*>(data);
if (!IMG_IS_OK(status)) {
context->status = IMAGE_UNSUPPORTED_OPERATION;
IMAGE_LOGE("HdrComposeToMainPixelmapComplete failed!");
} else {
context->status = SUCCESS;
}
CommonCallbackRoutine(env, context, result);
}
napi_value PictureNapi::HdrComposeToMainPixelmap(napi_env env, napi_callback_info info)
{
napi_value result = nullptr;
napi_get_undefined(env, &result);
napi_status status;
napi_value thisVar = nullptr;
IMAGE_LOGD("HdrComposeToMainPixelmap IN");
IMG_JS_NO_ARGS(env, info, status, thisVar);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get arguments from info"));
std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
result, IMAGE_LOGE("Fail to unwrap context"));
asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), result, IMAGE_LOGE("Empty native picture"));
if (asyncContext->rPicture->GetAuxiliaryPicture(AuxiliaryPictureType::GAINMAP) == nullptr) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "There is no GAINMAP", true);
}
if (asyncContext->rPicture->GetMainPixel()->GetAllocatorType() != AllocatorType::DMA_ALLOC ||
asyncContext->rPicture->GetGainmapPixelMap()->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "Pixelmap is not DMA", true);
}
napi_create_promise(env, &(asyncContext->deferred), &result);
IMG_CREATE_CREATE_ASYNC_WORK(env, status, "HdrComposeToMainPixelmap",
[](napi_env env, void* data) {
auto context = static_cast<PictureAsyncContext*>(data);
bool result = context->rPicture->HdrComposeToMainPixel();
context->status = result ? SUCCESS : IMAGE_UNSUPPORTED_OPERATION;
}, HdrComposeToMainPixelmapComplete, asyncContext, asyncContext->work);
IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to create async work"));
IMAGE_LOGD("HdrComposeToMainPixelmap OUT");
return result;
}
void PictureNapi::release()
{
if (!isRelease) {
if (nativePicture_ != nullptr) {
nativePicture_ = nullptr;
}
isRelease = true;
}
}
}
}