1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <memory.h>
17 #include "auxiliary_picture_napi.h"
18 #include "media_errors.h"
19 #include "image_log.h"
20 #include "image_napi.h"
21 #include "image_napi_utils.h"
22 #include "pixel_map_napi.h"
23 #include "pixel_map.h"
24 #include "metadata_napi.h"
25 #include "color_space_object_convertor.h"
26 #include "image_utils.h"
27 #include "image_common.h"
28 
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
31 
32 #undef LOG_TAG
33 #define LOG_TAG "AuxiliaryPictureNapi"
34 
35 namespace {
36     constexpr uint32_t NUM_0 = 0;
37     constexpr uint32_t NUM_1 = 1;
38     constexpr uint32_t NUM_2 = 2;
39     constexpr uint32_t NUM_3 = 3;
40 }
41 
42 namespace OHOS {
43 namespace Media {
44 static const std::string CLASS_NAME = "AuxiliaryPicture";
45 thread_local napi_ref AuxiliaryPictureNapi::sConstructor_ = nullptr;
46 thread_local std::shared_ptr<AuxiliaryPicture> AuxiliaryPictureNapi::sAuxiliaryPic_ = nullptr;
47 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
48 #endif
49 
50 struct AuxiliaryPictureNapiAsyncContext {
51     napi_env env;
52     napi_async_work work;
53     napi_deferred deferred;
54     napi_ref callbackRef;
55     napi_ref error = nullptr;
56     uint32_t status;
57     AuxiliaryPictureNapi *nConstructor;
58     std::shared_ptr<PixelMap> rPixelmap;
59     std::shared_ptr<Picture> rPicture;
60     std::shared_ptr<AuxiliaryPicture> auxPicture;
61     void *arrayBuffer;
62     size_t arrayBufferSize;
63     Size size;
64     AuxiliaryPictureType type;
65     MetadataNapi *metadataNapi;
66     std::shared_ptr<AuxiliaryPicture> rAuxiliaryPicture;
67     std::shared_ptr<ImageMetadata> imageMetadata;
68     MetadataType metadataType = MetadataType::EXIF;
69     AuxiliaryPictureNapi *auxiliaryPictureNapi;
70     AuxiliaryPictureInfo auxiliaryPictureInfo;
71     std::shared_ptr<OHOS::ColorManager::ColorSpace> AuxColorSpace = nullptr;
72 };
73 
74 using AuxiliaryPictureNapiAsyncContextPtr = std::unique_ptr<AuxiliaryPictureNapiAsyncContext>;
75 
76 struct NapiValues {
77     napi_status status;
78     napi_value thisVar = nullptr;
79     napi_value result = nullptr;
80     napi_value* argv = nullptr;
81     size_t argc;
82     int32_t refCount = 1;
83     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> context;
84 };
85 
AuxiliaryPictureNapi()86 AuxiliaryPictureNapi::AuxiliaryPictureNapi():env_(nullptr)
87 {
88     static std::atomic<uint32_t> currentId = 0;
89     uniqueId_ = currentId.fetch_add(1, std::memory_order_relaxed);
90 }
91 
~AuxiliaryPictureNapi()92 AuxiliaryPictureNapi::~AuxiliaryPictureNapi()
93 {
94     release();
95 }
96 
Init(napi_env env,napi_value exports)97 napi_value AuxiliaryPictureNapi::Init(napi_env env, napi_value exports)
98 {
99     napi_property_descriptor props[] = {
100         DECLARE_NAPI_FUNCTION("readPixelsToBuffer", ReadPixelsToBuffer),
101         DECLARE_NAPI_FUNCTION("writePixelsFromBuffer", WritePixelsFromBuffer),
102         DECLARE_NAPI_FUNCTION("getType", GetType),
103         DECLARE_NAPI_FUNCTION("getMetadata", GetMetadata),
104         DECLARE_NAPI_FUNCTION("setMetadata", SetMetadata),
105         DECLARE_NAPI_FUNCTION("getAuxiliaryPictureInfo", GetAuxiliaryPictureInfo),
106         DECLARE_NAPI_FUNCTION("setAuxiliaryPictureInfo", SetAuxiliaryPictureInfo),
107         DECLARE_NAPI_FUNCTION("release", Release),
108     };
109     napi_property_descriptor static_prop[] = {
110         DECLARE_NAPI_STATIC_FUNCTION("createAuxiliaryPicture", CreateAuxiliaryPicture),
111     };
112 
113     napi_value constructor = nullptr;
114 
115     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
116         napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
117                           Constructor, nullptr, IMG_ARRAY_SIZE(props),
118                           props, &constructor)),
119         nullptr, IMAGE_LOGE("define class fail")
120     );
121 
122     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
123         napi_create_reference(env, constructor, 1, &sConstructor_)),
124         nullptr, IMAGE_LOGE("create reference fail")
125     );
126 
127     napi_value global = nullptr;
128     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
129         napi_get_global(env, &global)),
130         nullptr, IMAGE_LOGE("Init:get global fail")
131     );
132 
133     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
134         napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)),
135         nullptr, IMAGE_LOGE("Init:set global named property fail")
136     );
137 
138     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
139         napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
140         nullptr, IMAGE_LOGE("set named property fail")
141     );
142 
143     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
144         napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
145         nullptr, IMAGE_LOGE("define properties fail")
146     );
147 
148     IMAGE_LOGD("Init success");
149     return exports;
150 }
151 
Constructor(napi_env env,napi_callback_info info)152 napi_value AuxiliaryPictureNapi::Constructor(napi_env env, napi_callback_info info)
153 {
154     napi_value undefineVar = nullptr;
155     napi_get_undefined(env, &undefineVar);
156 
157     napi_status status;
158     napi_value thisVar = nullptr;
159     napi_get_undefined(env, &thisVar);
160     IMAGE_LOGD("Constructor IN");
161     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
162     IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar);
163     std::unique_ptr<AuxiliaryPictureNapi> pAuxiliaryPictureNapi = std::make_unique<AuxiliaryPictureNapi>();
164     if (pAuxiliaryPictureNapi != nullptr) {
165         pAuxiliaryPictureNapi->env_ = env;
166         pAuxiliaryPictureNapi->nativeAuxiliaryPicture_ = sAuxiliaryPic_;
167         if (pAuxiliaryPictureNapi->nativeAuxiliaryPicture_ == nullptr) {
168             IMAGE_LOGE("Failed to set nativeAuxiliaryPicture_ with null. Maybe a reentrancy error");
169         }
170         status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pAuxiliaryPictureNapi.release()),
171                            AuxiliaryPictureNapi::Destructor, nullptr, nullptr);
172         if (status != napi_ok) {
173             IMAGE_LOGE("Failure wrapping js to native napi");
174             return undefineVar;
175         }
176     }
177     return thisVar;
178 }
179 
Destructor(napi_env env,void * nativeObject,void * finalize)180 void AuxiliaryPictureNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
181 {
182     if (nativeObject != nullptr) {
183         IMAGE_LOGD("Destructor PictureNapi");
184         delete reinterpret_cast<AuxiliaryPictureNapi*>(nativeObject);
185         nativeObject = nullptr;
186     }
187 }
188 
CreateAuxiliaryPicture(napi_env env,std::shared_ptr<AuxiliaryPicture> auxiliaryPic)189 napi_value AuxiliaryPictureNapi::CreateAuxiliaryPicture(napi_env env, std::shared_ptr<AuxiliaryPicture> auxiliaryPic)
190 {
191     if (AuxiliaryPictureNapi::GetConstructor() == nullptr) {
192         napi_value exports = nullptr;
193         napi_create_object(env, &exports);
194         AuxiliaryPictureNapi::Init(env, exports);
195     }
196 
197     napi_value constructor = nullptr;
198     napi_value result = nullptr;
199     napi_status status;
200     IMAGE_LOGD("CreateAuxiliaryPicture IN");
201     status = napi_get_reference_value(env, sConstructor_, &constructor);
202     if (IMG_IS_OK(status)) {
203         sAuxiliaryPic_ = auxiliaryPic;
204         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
205     }
206     if (!IMG_IS_OK(status)) {
207         IMAGE_LOGE("CreateAuxiliaryPicture | New instance could not be obtained");
208         napi_get_undefined(env, &result);
209     }
210 
211     return result;
212 }
213 
STATIC_EXEC_FUNC(CreateAuxiliaryPicture)214 STATIC_EXEC_FUNC(CreateAuxiliaryPicture)
215 {
216     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
217     InitializationOptions opts;
218     opts.size = context->size;
219     opts.editable = true;
220     opts.useDMA = true;
221     auto colors = static_cast<uint32_t*>(context->arrayBuffer);
222     if (colors == nullptr) {
223         return;
224     }
225     auto tmpPixelmap = PixelMap::Create(colors, context->arrayBufferSize, opts);
226     std::shared_ptr<PixelMap> pixelmap = std::move(tmpPixelmap);
227     auto picture = AuxiliaryPicture::Create(pixelmap, context->type, context->size);
228     context->auxPicture = std::move(picture);
229     if (IMG_NOT_NULL(context->auxPicture)) {
230         context->status = SUCCESS;
231     } else {
232         context->status = ERROR;
233     }
234 }
235 
ParseSize(napi_env env,napi_value root,int32_t & width,int32_t & height)236 static bool ParseSize(napi_env env, napi_value root, int32_t& width, int32_t& height)
237 {
238     if (!GET_INT32_BY_NAME(root, "width", width) || !GET_INT32_BY_NAME(root, "height", height)) {
239         return false;
240     }
241     if (width <= 0 || height <= 0) {
242         return false;
243     }
244     return true;
245 }
246 
ParseBuffer(napi_env env,napi_value argValue,std::unique_ptr<AuxiliaryPictureNapiAsyncContext> & context)247 static bool ParseBuffer(napi_env env, napi_value argValue,
248     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> &context)
249 {
250     napi_status status;
251     if (context == nullptr) {
252         return false;
253     }
254     status = napi_get_arraybuffer_info(env, argValue, &(context->arrayBuffer),
255         &(context->arrayBufferSize));
256     if (!IMG_IS_OK(status)) {
257         return false;
258     }
259     if (context->arrayBuffer == nullptr || context->arrayBufferSize < NUM_0) {
260         return false;
261     }
262     return true;
263 }
264 
ParseAuxiliaryPictureType(int32_t val)265 static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val)
266 {
267     if (val >= static_cast<int32_t>(AuxiliaryPictureType::GAINMAP)
268         && val <= static_cast<int32_t>(AuxiliaryPictureType::FRAGMENT_MAP)) {
269         return AuxiliaryPictureType(val);
270     }
271     return AuxiliaryPictureType::NONE;
272 }
273 
CreateAuxiliaryPicture(napi_env env,napi_callback_info info)274 napi_value AuxiliaryPictureNapi::CreateAuxiliaryPicture(napi_env env, napi_callback_info info)
275 {
276     if (AuxiliaryPictureNapi::GetConstructor() == nullptr) {
277         napi_value exports = nullptr;
278         napi_create_object(env, &exports);
279         AuxiliaryPictureNapi::Init(env, exports);
280     }
281 
282     napi_value result = nullptr;
283     napi_get_undefined(env, &result);
284 
285     napi_value constructor = nullptr;
286     napi_status status;
287     napi_value thisVar = nullptr;
288     size_t argCount = NUM_3;
289     napi_value argValue[NUM_3] = {0};
290     uint32_t auxiType = 0;
291     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
292         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
293     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
294     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
295         "Invalid args"), IMAGE_LOGE("Call napi_get_cb_info failed"));
296 
297     IMG_NAPI_CHECK_RET_D(argCount == NUM_3, ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
298         "Invalid args count"), IMAGE_LOGE("Invalid args count %{public}zu", argCount));
299 
300     if (!ParseBuffer(env, argValue[NUM_0], asyncContext)) {
301         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to get arrayBuffer.");
302     }
303 
304     if (!ParseSize(env, argValue[NUM_1], asyncContext->size.width, asyncContext->size.height)) {
305         IMAGE_LOGE("Fail to get auxiliary picture size");
306         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args.");
307     }
308     status = napi_get_value_uint32(env, argValue[NUM_2], &auxiType);
309     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get auxiliary picture Type"));
310     if (auxiType < static_cast<uint32_t>(AuxiliaryPictureType::GAINMAP)
311         || auxiType > static_cast<uint32_t>(AuxiliaryPictureType::FRAGMENT_MAP)) {
312         IMAGE_LOGE("AuxiliaryFigureType is invalid");
313         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args.");
314     }
315     asyncContext->type = ParseAuxiliaryPictureType(auxiType);
316     if (asyncContext->type == AuxiliaryPictureType::NONE) {
317         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid auxiliary picture Type.");
318     }
319     CreateAuxiliaryPictureExec(env, static_cast<void*>((asyncContext).get()));
320     status = napi_get_reference_value(env, sConstructor_, &constructor);
321     if (IMG_IS_OK(status)) {
322         sAuxiliaryPic_ = std::move(asyncContext->auxPicture);
323         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
324     }
325     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to create picture sync"));
326     return result;
327 }
328 
GetType(napi_env env,napi_callback_info info)329 napi_value AuxiliaryPictureNapi::GetType(napi_env env, napi_callback_info info)
330 {
331     NapiValues nVal;
332     napi_get_undefined(env, &nVal.result);
333     nVal.argc = NUM_0;
334     IMAGE_LOGD("Call GetType");
335     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
336     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to call napi_get_cb_info"));
337 
338     AuxiliaryPictureNapi* auxPictureNapi = nullptr;
339     nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxPictureNapi));
340     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxPictureNapi), nVal.result, IMAGE_LOGE("Fail to unwrap context"));
341     if (auxPictureNapi->nativeAuxiliaryPicture_ != nullptr) {
342         auto auxType = auxPictureNapi->nativeAuxiliaryPicture_->GetType();
343         IMAGE_LOGD("AuxiliaryPictureNapi::GetType %{public}d", auxType);
344         if (static_cast<int32_t>(auxType) >= NUM_0 && auxType <= AuxiliaryPictureType::FRAGMENT_MAP) {
345             napi_create_int32(env, static_cast<int32_t>(auxType), &nVal.result);
346         }
347     } else {
348         IMAGE_LOGE("Native picture is nullptr!");
349     }
350     return nVal.result;
351 }
352 
Release(napi_env env,napi_callback_info info)353 napi_value AuxiliaryPictureNapi::Release(napi_env env, napi_callback_info info)
354 {
355     NapiValues nVal;
356     nVal.result = nullptr;
357     napi_get_undefined(env, &nVal.result);
358     nVal.argc = NUM_0;
359     IMAGE_LOGD("Call Release");
360     AuxiliaryPictureNapi *auxiliaryPicture = nullptr;
361 
362     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
363     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to call napi_get_cb_info"));
364     nVal.status = napi_remove_wrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxiliaryPicture));
365 
366     return nVal.result;
367 }
368 
CommonCallbackRoutine(napi_env env,AuxiliaryPictureNapiAsyncContext * & connect,const napi_value & valueParam)369 static void CommonCallbackRoutine(napi_env env, AuxiliaryPictureNapiAsyncContext* &connect,
370                                   const napi_value &valueParam)
371 {
372     napi_value result[NUM_2] = {0};
373 
374     napi_get_undefined(env, &result[NUM_0]);
375     napi_get_undefined(env, &result[NUM_1]);
376 
377     if (connect->status == SUCCESS) {
378         result[NUM_1] = valueParam;
379     } else {
380         ImageNapiUtils::CreateErrorObj(env, result[0], connect->status,
381                                        "There is generic napi failure!");
382         napi_get_undefined(env, &result[1]);
383     }
384 
385     if (connect->deferred) {
386         if (connect->status == SUCCESS) {
387             napi_resolve_deferred(env, connect->deferred, result[NUM_1]);
388         } else {
389             napi_reject_deferred(env, connect->deferred, result[NUM_0]);
390         }
391     }
392 
393     napi_delete_async_work(env, connect->work);
394 
395     delete connect;
396     connect = nullptr;
397 }
398 
CheckMetadataType(const AuxiliaryPictureNapiAsyncContext * context)399 static bool CheckMetadataType(const AuxiliaryPictureNapiAsyncContext* context)
400 {
401     if (context == nullptr || context->rAuxiliaryPicture == nullptr) {
402         IMAGE_LOGE("Auxiliary picture is null");
403         return false;
404     }
405     return !(context->rAuxiliaryPicture->GetType() != AuxiliaryPictureType::FRAGMENT_MAP &&
406         context->metadataType == MetadataType::FRAGMENT);
407 }
408 
GetMetadataComplete(napi_env env,napi_status status,void * data)409 static void GetMetadataComplete(napi_env env, napi_status status, void *data)
410 {
411     IMAGE_LOGD("[AuxiliaryPicture]GetMetadata IN");
412     napi_value result = nullptr;
413     napi_get_undefined(env, &result);
414     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
415     if (context->imageMetadata != nullptr) {
416         result = MetadataNapi::CreateMetadata(env, context->imageMetadata);
417     }
418 
419     if (!IMG_IS_OK(status)) {
420         context->status = ERROR;
421         IMAGE_LOGE("Get Metadata failed!");
422     } else {
423         context->status = SUCCESS;
424     }
425     IMAGE_LOGD("[AuxiliaryPicture]GetMetadata OUT");
426     CommonCallbackRoutine(env, context, result);
427 }
428 
GetMetadata(napi_env env,napi_callback_info info)429 napi_value AuxiliaryPictureNapi::GetMetadata(napi_env env, napi_callback_info info)
430 {
431     napi_value result = nullptr;
432     napi_get_undefined(env, &result);
433     napi_status status;
434     napi_value thisVar = nullptr;
435     size_t argCount = NUM_1;
436     napi_value argValue[NUM_1] = {0};
437     uint32_t metadataType = 0;
438 
439     IMAGE_LOGD("GetMetadata IN");
440     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
441     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argment from info"));
442     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
443         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
444     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
445     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
446         nullptr, IMAGE_LOGE("Fail to unwrap context"));
447     asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
448     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
449         nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
450     status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
451     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env,
452         IMAGE_BAD_PARAMETER, "Invalid args metadata type."), IMAGE_LOGE("Fail to get metadata type"));
453     if (metadataType >= static_cast<uint32_t>(MetadataType::EXIF)
454         && metadataType <= static_cast<uint32_t>(MetadataType::FRAGMENT)) {
455         asyncContext->metadataType = MetadataType(metadataType);
456     } else {
457         return ImageNapiUtils::ThrowExceptionError(
458             env, IMAGE_BAD_PARAMETER, "Invalid args metadata type");
459     }
460 
461     if (!CheckMetadataType(asyncContext.get()) || asyncContext->metadataType == MetadataType::EXIF) {
462         return ImageNapiUtils::ThrowExceptionError(
463             env, IMAGE_UNSUPPORTED_METADATA, "Unsupported metadata");
464     }
465     napi_create_promise(env, &(asyncContext->deferred), &result);
466     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetMetadata",
467         [](napi_env env, void* data) {
468             auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
469             context->imageMetadata = context->rAuxiliaryPicture->GetMetadata(context->metadataType);
470         }, GetMetadataComplete, asyncContext, asyncContext->work);
471     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
472         nullptr, IMAGE_LOGE("Fail to create async work"));
473     return result;
474 }
475 
SetMetadataComplete(napi_env env,napi_status status,void * data)476 static void SetMetadataComplete(napi_env env, napi_status status, void *data)
477 {
478     IMAGE_LOGD("[AuxiliaryPicture]GetMetadata IN");
479     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
480     napi_value result = nullptr;
481     napi_get_undefined(env, &result);
482 
483     if (!IMG_IS_OK(status)) {
484         context->status = ERROR;
485         IMAGE_LOGE("Set Metadata failed!");
486     } else {
487         context->status = SUCCESS;
488     }
489     IMAGE_LOGD("[AuxiliaryPicture]GetMetadata OUT");
490     CommonCallbackRoutine(env, context, result);
491 }
492 
SetMetadata(napi_env env,napi_callback_info info)493 napi_value AuxiliaryPictureNapi::SetMetadata(napi_env env, napi_callback_info info)
494 {
495     napi_value result = nullptr;
496     napi_get_undefined(env, &result);
497     napi_status status;
498     napi_value thisVar = nullptr;
499     size_t argCount = NUM_2;
500     napi_value argValue[NUM_2] = {0};
501     uint32_t metadataType = 0;
502 
503     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
504     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argments from info"));
505     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
506         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
507     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
508     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
509         nullptr, IMAGE_LOGE("Fail to unwrap context"));
510     asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
511     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
512         nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
513 
514     status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
515     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env,
516         IMAGE_BAD_PARAMETER, "Fail to get metadata type."), IMAGE_LOGE("Fail to get metadata type."));
517     if (metadataType >= static_cast<uint32_t>(MetadataType::EXIF)
518         && metadataType <= static_cast<uint32_t>(MetadataType::FRAGMENT)) {
519         asyncContext->metadataType = MetadataType(metadataType);
520     } else {
521         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args metadata type.");
522     }
523 
524     if (!CheckMetadataType(asyncContext.get())) {
525         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_METADATA, "Unsupported metadata");
526     }
527     status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&asyncContext->metadataNapi));
528     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->metadataNapi), ImageNapiUtils::ThrowExceptionError(env,
529         IMAGE_BAD_PARAMETER, "Fail to unwrap MetadataNapi."), IMAGE_LOGE("Fail to unwrap MetadataNapi"));
530     asyncContext->imageMetadata = asyncContext->metadataNapi->GetNativeMetadata();
531     if (asyncContext->imageMetadata == nullptr) {
532         IMAGE_LOGE("Empty native metadata");
533     }
534 
535     napi_create_promise(env, &(asyncContext->deferred), &result);
536     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetMetadata",
537         [](napi_env env, void* data) {
538             auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
539             context->rAuxiliaryPicture->SetMetadata(context->metadataType, context->imageMetadata);
540             context->status = SUCCESS;
541         }, SetMetadataComplete, asyncContext, asyncContext->work);
542     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to create async work"));
543     return result;
544 }
545 
GetAuxiliaryPictureInfoNapiValue(napi_env env,void * data,std::shared_ptr<AuxiliaryPicture> picture)546 static napi_value GetAuxiliaryPictureInfoNapiValue(napi_env env, void* data, std::shared_ptr<AuxiliaryPicture> picture)
547 {
548     napi_value result = nullptr;
549     auto auxiliaryPictureInfo = static_cast<AuxiliaryPictureInfo*>(data);
550     napi_create_object(env, &result);
551     napi_value auxiliaryPictureTypeValue = nullptr;
552     napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->auxiliaryPictureType),
553         &auxiliaryPictureTypeValue);
554     napi_set_named_property(env, result, "auxiliaryPictureType", auxiliaryPictureTypeValue);
555 
556     napi_value size = nullptr;
557     napi_create_object(env, &size);
558 
559     napi_value sizeWidth = nullptr;
560     napi_create_int32(env, auxiliaryPictureInfo->size.width, &sizeWidth);
561     napi_set_named_property(env, size, "width", sizeWidth);
562 
563     napi_value sizeHeight = nullptr;
564     napi_create_int32(env, auxiliaryPictureInfo->size.height, &sizeHeight);
565     napi_set_named_property(env, size, "height", sizeHeight);
566 
567     napi_set_named_property(env, result, "size", size);
568 
569     napi_value rowStrideValue = nullptr;
570     napi_create_int32(env, auxiliaryPictureInfo->rowStride, &rowStrideValue);
571     napi_set_named_property(env, result, "rowStride", rowStrideValue);
572 
573     napi_value pixelFormatValue = nullptr;
574     napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->pixelFormat), &pixelFormatValue);
575     napi_set_named_property(env, result, "pixelFormat", pixelFormatValue);
576     std::shared_ptr<PixelMap> rPixelmap = nullptr;
577 
578     if (picture->GetContentPixel() == nullptr) {
579         return ImageNapiUtils::ThrowExceptionError(
580             env, ERR_IMAGE_DATA_ABNORMAL, "Invalid pixelmap");
581     }
582     auto grCS = picture->GetContentPixel()->InnerGetGrColorSpacePtr();
583     if (grCS == nullptr) {
584         return ImageNapiUtils::ThrowExceptionError(
585             env, ERR_IMAGE_DATA_UNSUPPORT, "No colorspace in pixelmap");
586     }
587     auto resultValue = ColorManager::CreateJsColorSpaceObject(env, grCS);
588     napi_value colorSpaceValue = reinterpret_cast<napi_value>(resultValue);
589     napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->colorSpace), &colorSpaceValue);
590     napi_set_named_property(env, result, "colorSpace", colorSpaceValue);
591     return result;
592 }
593 
GetAuxiliaryPictureInfo(napi_env env,napi_callback_info info)594 napi_value AuxiliaryPictureNapi::GetAuxiliaryPictureInfo(napi_env env, napi_callback_info info)
595 {
596     NapiValues nVal;
597     napi_get_undefined(env, &nVal.result);
598     nVal.argc = NUM_0;
599     IMAGE_LOGD("Call GetAuxiliaryPictureInfo");
600     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
601     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nullptr, IMAGE_LOGE("Call napi_get_cb_info failed"));
602     AuxiliaryPictureNapi *auxiliaryPictureNapi = nullptr;
603     nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxiliaryPictureNapi));
604     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxiliaryPictureNapi),
605         nullptr, IMAGE_LOGE("Fail to unwrap context"));
606     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxiliaryPictureNapi->nativeAuxiliaryPicture_),
607         nullptr, IMAGE_LOGE("Empty native auxiliarypicture"));
608     if (auxiliaryPictureNapi->nativeAuxiliaryPicture_ != nullptr) {
609         AuxiliaryPictureInfo auxiliaryPictureInfo =
610             auxiliaryPictureNapi->nativeAuxiliaryPicture_->GetAuxiliaryPictureInfo();
611         nVal.result = GetAuxiliaryPictureInfoNapiValue(env, &auxiliaryPictureInfo,
612             auxiliaryPictureNapi->nativeAuxiliaryPicture_);
613     } else {
614         IMAGE_LOGE("Native auxiliarypicture is nullptr!");
615     }
616     return nVal.result;
617 }
618 
ParsePixelFormat(int32_t val)619 static PixelFormat ParsePixelFormat(int32_t val)
620 {
621     if (val >= static_cast<int32_t>(PixelFormat::ARGB_8888) && val <= static_cast<int32_t>(PixelFormat::CMYK)) {
622         return PixelFormat(val);
623     }
624     return PixelFormat::UNKNOWN;
625 }
626 
ParseColorSpace(napi_env env,napi_value val,AuxiliaryPictureNapiAsyncContext * context)627 static void ParseColorSpace(napi_env env, napi_value val, AuxiliaryPictureNapiAsyncContext* context)
628 {
629 #ifdef IMAGE_COLORSPACE_FLAG
630     context->AuxColorSpace = ColorManager::GetColorSpaceByJSObject(env, val);
631     if (context->AuxColorSpace == nullptr) {
632         ImageNapiUtils::ThrowExceptionError(
633             env, ERR_IMAGE_INVALID_PARAMETER, "ColorSpace mismatch");
634         return;
635     }
636     context->rPixelmap->InnerSetColorSpace(*(context->AuxColorSpace));
637 #else
638     ImageNapiUtils::ThrowExceptionError(
639         env, ERR_INVALID_OPERATION, "Unsupported operation");
640 #endif
641 }
642 
ParseAuxiliaryPictureInfo(napi_env env,napi_value result,napi_value root,AuxiliaryPictureNapiAsyncContext * auxiliaryPictureNapiAsyncContext)643 static bool ParseAuxiliaryPictureInfo(napi_env env, napi_value result, napi_value root,
644     AuxiliaryPictureNapiAsyncContext* auxiliaryPictureNapiAsyncContext)
645 {
646     uint32_t tmpNumber = 0;
647     int32_t tmpInt32 = 0;
648     napi_value tmpValue = nullptr;
649     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(auxiliaryPictureNapiAsyncContext);
650 
651     if (!GET_UINT32_BY_NAME(root, "auxiliaryPictureType", tmpNumber)) {
652         IMAGE_LOGI("No auxiliaryPictureType in auxiliaryPictureInfo");
653         return false;
654     }
655     context->auxiliaryPictureInfo.auxiliaryPictureType = ParseAuxiliaryPictureType(tmpNumber);
656 
657     if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
658         return false;
659     }
660     if (!ParseSize(env, tmpValue, context->auxiliaryPictureInfo.size.width,
661         context->auxiliaryPictureInfo.size.height)) {
662         return false;
663     }
664 
665     if (!GET_INT32_BY_NAME(root, "rowStride", tmpInt32) || tmpInt32 < 0) {
666         IMAGE_LOGI("Invalid rowStride in auxiliaryPictureInfo");
667         return false;
668     }
669     context->auxiliaryPictureInfo.rowStride = static_cast<uint32_t>(tmpInt32);
670 
671     tmpNumber = 0;
672     if (!GET_UINT32_BY_NAME(root, "pixelFormat", tmpNumber)) {
673         IMAGE_LOGI("No pixelFormat in auxiliaryPictureInfo");
674         return false;
675     }
676     context->auxiliaryPictureInfo.pixelFormat = ParsePixelFormat(tmpNumber);
677 
678     context->rPixelmap = context->auxPicture->GetContentPixel();
679     napi_value auxColorSpace = nullptr;
680     if (!GET_NODE_BY_NAME(root, "colorSpace", auxColorSpace)) {
681         IMAGE_LOGI("No colorSpace in auxiliaryPictureInfo");
682         return false;
683     }
684     ParseColorSpace(env, auxColorSpace, context);
685     return true;
686 }
687 
SetAuxiliaryPictureInfo(napi_env env,napi_callback_info info)688 napi_value AuxiliaryPictureNapi::SetAuxiliaryPictureInfo(napi_env env, napi_callback_info info)
689 {
690     napi_value result = nullptr;
691     napi_get_undefined(env, &result);
692     napi_status status;
693     napi_value thisVar = nullptr;
694     size_t argCount = NUM_2;
695     napi_value argValue[NUM_2] = {0};
696 
697     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
698 
699     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(
700         env, IMAGE_BAD_PARAMETER, "Parameter error."), IMAGE_LOGE("Call napi_get_cb_info failed."));
701     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
702         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
703     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
704     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
705         nullptr, IMAGE_LOGE("Fail to unwrap context"));
706     asyncContext->auxPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
707     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->auxPicture),
708         nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
709     IMG_NAPI_CHECK_RET_D(ParseAuxiliaryPictureInfo(env, result, argValue[NUM_0], asyncContext.get()),
710         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Parameter error."),
711         IMAGE_LOGE("AuxiliaryPictureInfo mismatch"));
712 
713     if (status == napi_ok) {
714         uint32_t res = asyncContext->auxPicture->SetAuxiliaryPictureInfo(asyncContext->auxiliaryPictureInfo);
715         if (res != SUCCESS) {
716             ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Parameter error.");
717         }
718     } else {
719         IMAGE_LOGE("Failed to call napi_unwrap for auxilianypictureinfo");
720     }
721     return result;
722 }
723 
ReadPixelsToBufferComplete(napi_env env,napi_status status,void * data)724 static void ReadPixelsToBufferComplete(napi_env env, napi_status status, void *data)
725 {
726     napi_value result = nullptr;
727     napi_get_undefined(env, &result);
728     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
729 
730     if (context->status == SUCCESS &&
731         !ImageNapiUtils::CreateArrayBuffer(env, context->arrayBuffer, context->arrayBufferSize, &result)) {
732         context->status = ERROR;
733         IMAGE_LOGE("Fail to create napi arraybuffer!");
734         napi_get_undefined(env, &result);
735     }
736 
737     delete[] static_cast<uint8_t*>(context->arrayBuffer);
738     context->arrayBuffer = nullptr;
739     context->arrayBufferSize = 0;
740     CommonCallbackRoutine(env, context, result);
741 }
742 
ReadPixelsToBuffer(napi_env env,napi_callback_info info)743 napi_value AuxiliaryPictureNapi::ReadPixelsToBuffer(napi_env env, napi_callback_info info)
744 {
745     napi_value result = nullptr;
746     napi_get_undefined(env, &result);
747     napi_status status;
748     napi_value thisVar = nullptr;
749     size_t argCount = NUM_0;
750 
751     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
752     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to get argments from info"));
753 
754     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
755         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
756     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
757     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
758         nullptr, IMAGE_LOGE("Fail to unwrap context"));
759     asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
760     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
761         nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
762 
763     napi_create_promise(env, &(asyncContext->deferred), &result);
764     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ReadPixelsToBuffer",
765         [](napi_env env, void *data) {
766             auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
767             AuxiliaryPictureInfo info = context->rAuxiliaryPicture->GetAuxiliaryPictureInfo();
768             context->arrayBufferSize = info.size.width * info.size.height * ImageUtils::GetPixelBytes(info.pixelFormat);
769             context->arrayBuffer = new uint8_t[context->arrayBufferSize];
770             if (context->arrayBuffer != nullptr) {
771                 context->status = context->rAuxiliaryPicture->ReadPixels(
772                     context->arrayBufferSize, static_cast<uint8_t*>(context->arrayBuffer));
773             } else {
774                 context->status = ERR_MEDIA_MALLOC_FAILED;
775                 ImageNapiUtils::ThrowExceptionError(env, IMAGE_ALLOC_FAILED, "Memory alloc failed.");
776             }
777         }, ReadPixelsToBufferComplete, asyncContext, asyncContext->work);
778 
779     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
780         nullptr, IMAGE_LOGE("Fail to create async work"));
781     return result;
782 }
783 
EmptyResultComplete(napi_env env,napi_status status,void * data)784 static void EmptyResultComplete(napi_env env, napi_status status, void *data)
785 {
786     napi_value result = nullptr;
787     napi_get_undefined(env, &result);
788     auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
789     CommonCallbackRoutine(env, context, result);
790 }
791 
WritePixelsFromBuffer(napi_env env,napi_callback_info info)792 napi_value AuxiliaryPictureNapi::WritePixelsFromBuffer(napi_env env, napi_callback_info info)
793 {
794     napi_value result = nullptr;
795     napi_get_undefined(env, &result);
796     napi_status status;
797     napi_value thisVar = nullptr;
798     size_t argCount = NUM_1;
799     napi_value argValue[NUM_1] = {0};
800 
801     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
802     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to get argments from info"));
803 
804     std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
805         std::make_unique<AuxiliaryPictureNapiAsyncContext>();
806     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
807     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
808         nullptr, IMAGE_LOGE("Fail to unwrap context"));
809     asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
810     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
811         nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
812     status = napi_get_arraybuffer_info(env, argValue[NUM_0],
813         &(asyncContext->arrayBuffer), &(asyncContext->arrayBufferSize));
814     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
815         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
816             "Invalid args."), IMAGE_LOGE("Fail to get buffer info"));
817 
818     napi_create_promise(env, &(asyncContext->deferred), &result);
819     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "WritePixelsFromBuffer",
820         [](napi_env env, void *data) {
821             auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
822             context->status = context->rAuxiliaryPicture->WritePixels(
823                 static_cast<uint8_t*>(context->arrayBuffer), context->arrayBufferSize);
824         }, EmptyResultComplete, asyncContext, asyncContext->work);
825 
826     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
827         nullptr, IMAGE_LOGE("Fail to create async work"));
828     return result;
829 }
830 
release()831 void AuxiliaryPictureNapi::release()
832 {
833     if (!isRelease) {
834         if (nativeAuxiliaryPicture_ != nullptr) {
835             nativeAuxiliaryPicture_ = nullptr;
836         }
837         isRelease = true;
838     }
839 }
840 }  // namespace Media
841 }  // namespace OHOS
842