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 "picture_napi.h"
17 #include "media_errors.h"
18 #include "image_log.h"
19 #include "image_napi_utils.h"
20 #include "image_napi.h"
21 #include "pixel_map_napi.h"
22 #include "auxiliary_picture_napi.h"
23 #include "auxiliary_picture.h"
24 #include "napi_message_sequence.h"
25 #include "metadata.h"
26 #include "metadata_napi.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 "PictureNapi"
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 }
40 
41 namespace OHOS {
42 namespace Media {
43 static const std::string CREATE_PICTURE_FROM_PARCEL = "createPictureFromParcel";
44 static const std::map<std::string, std::set<uint32_t>> ETS_API_ERROR_CODE = {
45     {CREATE_PICTURE_FROM_PARCEL, {62980096, 62980105, 62980115, 62980097,
46         62980177, 62980178, 62980179, 62980180, 62980246}}
47 };
48 static const std::string CLASS_NAME = "Picture";
49 thread_local napi_ref PictureNapi::sConstructor_ = nullptr;
50 thread_local std::shared_ptr<Picture> PictureNapi::sPicture_ = nullptr;
51 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
52 NAPI_MessageSequence* messageSequence = nullptr;
53 #endif
54 
55 struct PictureAsyncContext {
56     napi_env env;
57     napi_async_work work;
58     napi_deferred deferred;
59     napi_ref callbackRef;
60     napi_ref error = nullptr;
61     uint32_t status;
62     std::shared_ptr<Picture> rPicture;
63     PictureNapi *nConstructor;
64     std::shared_ptr<PixelMap> rPixelMap;
65     MetadataNapi *metadataNapi;
66     std::shared_ptr<ImageMetadata> imageMetadata;
67     MetadataType metadataType = MetadataType::EXIF;
68 };
69 
70 using PictureAsyncContextPtr = std::unique_ptr<PictureAsyncContext>;
71 
72 napi_ref PictureNapi::auxiliaryPictureTypeRef_ = nullptr;
73 napi_ref PictureNapi::metadataTypeRef_ = nullptr;
74 
75 struct PictureEnum {
76     std::string name;
77     int32_t numVal;
78     std::string strVal;
79 };
80 
81 static std::vector<struct PictureEnum> auxiliaryPictureTypeMap = {
82     {"GAINMAP", static_cast<uint32_t>(AuxiliaryPictureType::GAINMAP), ""},
83     {"DEPTH_MAP", static_cast<uint32_t>(AuxiliaryPictureType::DEPTH_MAP), ""},
84     {"UNREFOCUS_MAP", static_cast<uint32_t>(AuxiliaryPictureType::UNREFOCUS_MAP), ""},
85     {"LINEAR_MAP", static_cast<uint32_t>(AuxiliaryPictureType::LINEAR_MAP), ""},
86     {"FRAGMENT_MAP", static_cast<uint32_t>(AuxiliaryPictureType::FRAGMENT_MAP), ""},
87 };
88 
89 static std::vector<struct PictureEnum> metadataTypeMap = {
90     {"EXIF_METADATA", static_cast<uint32_t>(MetadataType::EXIF), ""},
91     {"FRAGMENT_METADATA", static_cast<uint32_t>(MetadataType::FRAGMENT), ""},
92 };
93 
94 struct NapiValues {
95     napi_status status;
96     napi_value thisVar = nullptr;
97     napi_value result = nullptr;
98     napi_value* argv = nullptr;
99     size_t argc;
100     int32_t refCount = 1;
101     std::unique_ptr<PictureAsyncContext> context;
102 };
103 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct PictureEnum> pictureEnumMap)104 static napi_value CreateEnumTypeObject(napi_env env,
105     napi_valuetype type, napi_ref* ref, std::vector<struct PictureEnum> pictureEnumMap)
106 {
107     napi_value result = nullptr;
108     napi_status status;
109     std::string propName;
110     status = napi_create_object(env, &result);
111     if (status == napi_ok) {
112         for (auto imgEnum : pictureEnumMap) {
113             napi_value enumNapiValue = nullptr;
114             if (type == napi_string) {
115                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(),
116                     NAPI_AUTO_LENGTH, &enumNapiValue);
117             } else if (type == napi_number) {
118                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
119             } else {
120                 IMAGE_LOGE("Unsupported type %{public}d!", type);
121                 break;
122             }
123             if (status == napi_ok && enumNapiValue != nullptr) {
124                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
125             }
126             if (status != napi_ok) {
127                 IMAGE_LOGE("Failed to add named prop!");
128                 break;
129             }
130         }
131 
132         if (status == napi_ok) {
133             int32_t refCount = 1;
134             status = napi_create_reference(env, result, refCount, ref);
135             if (status == napi_ok) {
136                 return result;
137             }
138         }
139     }
140     IMAGE_LOGE("CreateEnumTypeObject is Failed!");
141     napi_get_undefined(env, &result);
142     return result;
143 }
144 
CommonCallbackRoutine(napi_env env,PictureAsyncContext * & asyncContext,const napi_value & valueParam)145 static void CommonCallbackRoutine(napi_env env, PictureAsyncContext* &asyncContext, const napi_value &valueParam)
146 {
147     napi_value result[NUM_2] = {0};
148 
149     napi_get_undefined(env, &result[NUM_0]);
150     napi_get_undefined(env, &result[NUM_1]);
151 
152     napi_handle_scope scope = nullptr;
153     napi_open_handle_scope(env, &scope);
154     if (scope == nullptr) {
155         return;
156     }
157 
158     if (asyncContext == nullptr) {
159         napi_close_handle_scope(env, scope);
160         return;
161     }
162     if (asyncContext->status == SUCCESS) {
163         result[NUM_1] = valueParam;
164     } else if (asyncContext->error != nullptr) {
165         napi_get_reference_value(env, asyncContext->error, &result[NUM_0]);
166         napi_delete_reference(env, asyncContext->error);
167     } else {
168         napi_create_uint32(env, asyncContext->status, &result[NUM_0]);
169     }
170 
171     if (asyncContext->deferred) {
172         if (asyncContext->status == SUCCESS) {
173             napi_resolve_deferred(env, asyncContext->deferred, result[NUM_1]);
174         } else {
175             napi_reject_deferred(env, asyncContext->deferred, result[NUM_0]);
176         }
177     }
178 
179     napi_delete_async_work(env, asyncContext->work);
180     napi_close_handle_scope(env, scope);
181 
182     delete asyncContext;
183     asyncContext = nullptr;
184 }
185 
ParserImageType(napi_env env,napi_value argv)186 static ImageType ParserImageType(napi_env env, napi_value argv)
187 {
188     napi_value constructor = nullptr;
189     napi_value global = nullptr;
190     bool isInstance = false;
191     napi_status ret = napi_invalid_arg;
192 
193     ret = napi_get_global(env, &global);
194     if (ret != napi_ok) {
195         IMAGE_LOGI("Get global failed!");
196         return ImageType::TYPE_UNKNOWN;
197     }
198 
199     ret = napi_get_named_property(env, global, "PixelMap", &constructor);
200     if (ret != napi_ok) {
201         IMAGE_LOGI("Get PixelMapNapi property failed!");
202     }
203 
204     ret = napi_instanceof(env, argv, constructor, &isInstance);
205     if (ret == napi_ok && isInstance) {
206         return ImageType::TYPE_PIXEL_MAP;
207     }
208 
209     IMAGE_LOGI("InValued type!");
210     return ImageType::TYPE_UNKNOWN;
211 }
212 
prepareNapiEnv(napi_env env,napi_callback_info info,struct NapiValues * nVal)213 static bool prepareNapiEnv(napi_env env, napi_callback_info info, struct NapiValues* nVal)
214 {
215     napi_get_undefined(env, &(nVal->result));
216     nVal->status = napi_get_cb_info(env, info, &(nVal->argc), nVal->argv, &(nVal->thisVar), nullptr);
217     if (nVal->status != napi_ok) {
218         IMAGE_LOGE("Fail to napi_get_cb_info");
219         return false;
220     }
221     nVal->context = std::make_unique<PictureAsyncContext>();
222     nVal->status = napi_unwrap(env, nVal->thisVar, reinterpret_cast<void**>(&(nVal->context->nConstructor)));
223     if (nVal->status != napi_ok) {
224         IMAGE_LOGE("Fail to unwrap context");
225         return false;
226     }
227     nVal->context->status = SUCCESS;
228     return true;
229 }
230 
PictureNapi()231 PictureNapi::PictureNapi():env_(nullptr)
232 {
233     static std::atomic<uint32_t> currentId = 0;
234     uniqueId_ = currentId.fetch_add(1, std::memory_order_relaxed);
235 }
236 
~PictureNapi()237 PictureNapi::~PictureNapi()
238 {
239     release();
240 }
241 
Init(napi_env env,napi_value exports)242 napi_value PictureNapi::Init(napi_env env, napi_value exports)
243 {
244     napi_property_descriptor props[] = {
245         DECLARE_NAPI_FUNCTION("getMainPixelmap", GetMainPixelmap),
246         DECLARE_NAPI_FUNCTION("getHdrComposedPixelmap", GetHdrComposedPixelMap),
247         DECLARE_NAPI_FUNCTION("getGainmapPixelmap", GetGainmapPixelmap),
248         DECLARE_NAPI_FUNCTION("getAuxiliaryPicture", GetAuxiliaryPicture),
249         DECLARE_NAPI_FUNCTION("setAuxiliaryPicture", SetAuxiliaryPicture),
250         DECLARE_NAPI_FUNCTION("release", Release),
251         DECLARE_NAPI_FUNCTION("marshalling", Marshalling),
252         DECLARE_NAPI_FUNCTION("getMetadata", GetMetadata),
253         DECLARE_NAPI_FUNCTION("setMetadata", SetMetadata),
254     };
255     napi_property_descriptor static_prop[] = {
256         DECLARE_NAPI_STATIC_FUNCTION("createPicture", CreatePicture),
257         DECLARE_NAPI_STATIC_FUNCTION("createPictureFromParcel", CreatePictureFromParcel),
258         DECLARE_NAPI_PROPERTY("AuxiliaryPictureType", CreateEnumTypeObject(env, napi_number,
259             &auxiliaryPictureTypeRef_, auxiliaryPictureTypeMap)),
260         DECLARE_NAPI_PROPERTY("MetadataType", CreateEnumTypeObject(env, napi_number,
261             &metadataTypeRef_, metadataTypeMap)),
262     };
263 
264     napi_value constructor = nullptr;
265 
266     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
267         napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH, Constructor, nullptr, IMG_ARRAY_SIZE(props),
268         props, &constructor)), nullptr, IMAGE_LOGE("define class fail")
269     );
270 
271     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(napi_create_reference(env, constructor, 1, &sConstructor_)),
272         nullptr, IMAGE_LOGE("create reference fail")
273     );
274 
275     napi_value global = nullptr;
276     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(napi_get_global(env, &global)), nullptr, IMAGE_LOGE("Init:get global fail"));
277 
278     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
279         napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)),
280         nullptr, IMAGE_LOGE("Init:set global named property fail")
281     );
282 
283     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
284         napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
285         nullptr, IMAGE_LOGE("set named property fail")
286     );
287 
288     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
289         napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
290         nullptr, IMAGE_LOGE("define properties fail")
291     );
292 
293     IMAGE_LOGD("Init success");
294     return exports;
295 }
296 
Constructor(napi_env env,napi_callback_info info)297 napi_value PictureNapi::Constructor(napi_env env, napi_callback_info info)
298 {
299     napi_value undefineVar = nullptr;
300     napi_get_undefined(env, &undefineVar);
301 
302     napi_status status;
303     napi_value thisVar = nullptr;
304     napi_get_undefined(env, &thisVar);
305     IMAGE_LOGD("Constructor IN");
306     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
307     IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar);
308     std::unique_ptr<PictureNapi> pPictureNapi = std::make_unique<PictureNapi>();
309     if (pPictureNapi != nullptr) {
310         pPictureNapi->env_ = env;
311         pPictureNapi->nativePicture_ = std::move(sPicture_);
312         if (pPictureNapi->nativePicture_ == nullptr) {
313             IMAGE_LOGE("Failed to set nativePicture_ with null. Maybe a reentrancy error");
314         }
315         status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pPictureNapi.release()),
316                            PictureNapi::Destructor, nullptr, nullptr);
317         if (status != napi_ok) {
318             IMAGE_LOGE("Failure wrapping js to native napi");
319             return undefineVar;
320         }
321     }
322     return thisVar;
323 }
324 
Destructor(napi_env env,void * nativeObject,void * finalize)325 void PictureNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
326 {
327     if (nativeObject != nullptr) {
328         IMAGE_LOGD("Destructor PictureNapi");
329         delete reinterpret_cast<PictureNapi*>(nativeObject);
330         nativeObject = nullptr;
331     }
332 }
333 
CreatePicture(napi_env env,std::shared_ptr<Picture> & picture)334 napi_value PictureNapi::CreatePicture(napi_env env, std::shared_ptr<Picture> &picture)
335 {
336     if (sConstructor_ == nullptr) {
337         napi_value exports = nullptr;
338         napi_create_object(env, &exports);
339         PictureNapi::Init(env, exports);
340     }
341     napi_value constructor = nullptr;
342     napi_value result = nullptr;
343     napi_status status = napi_get_reference_value(env, sConstructor_, &constructor);
344     if (IMG_IS_OK(status)) {
345         if (picture != nullptr) {
346             sPicture_ = std::move(picture);
347             status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
348         } else {
349             status = napi_invalid_arg;
350             IMAGE_LOGE("New PictureNapi Instance picture is nullptr");
351             napi_get_undefined(env, &result);
352         }
353     }
354     if (!IMG_IS_OK(status)) {
355         IMAGE_LOGE("CreatePicture | New instance could not be obtained");
356         napi_get_undefined(env, &result);
357     }
358     return result;
359 }
360 
ParseAuxiliaryPictureType(int32_t val)361 static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val)
362 {
363     if (val >= static_cast<int32_t>(AuxiliaryPictureType::GAINMAP)
364         && val<= static_cast<int32_t>(AuxiliaryPictureType::FRAGMENT_MAP)) {
365         return AuxiliaryPictureType(val);
366     }
367 
368     return AuxiliaryPictureType::NONE;
369 }
370 
PreparePicNapiEnv(napi_env env)371 static void PreparePicNapiEnv(napi_env env)
372 {
373     napi_value globalValue;
374     napi_get_global(env, &globalValue);
375     napi_value func;
376     napi_get_named_property(env, globalValue, "requireNapi", &func);
377 
378     napi_value picture;
379     napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &picture);
380     napi_value funcArgv[NUM_1] = { picture };
381     napi_value returnValue;
382     napi_call_function(env, globalValue, func, NUM_1, funcArgv, &returnValue);
383 }
384 
CreatePictureNapi(napi_env env,napi_value * result)385 int32_t PictureNapi::CreatePictureNapi(napi_env env, napi_value* result)
386 {
387     napi_value constructor = nullptr;
388     napi_status status = napi_ok;
389     PreparePicNapiEnv(env);
390 
391     status = napi_get_reference_value(env, sConstructor_, &constructor);
392     if (status == napi_ok && constructor != nullptr) {
393         status = napi_new_instance(env, constructor, NUM_0, nullptr, result);
394     }
395 
396     if (status != napi_ok || result == nullptr) {
397         IMAGE_LOGE("CreatePictureNapi new instance failed");
398         napi_get_undefined(env, result);
399         return ERR_IMAGE_DATA_ABNORMAL;
400     }
401     return SUCCESS;
402 }
403 
SetNativePicture(std::shared_ptr<Picture> picture)404 void PictureNapi::SetNativePicture(std::shared_ptr<Picture> picture)
405 {
406     nativePicture_ = picture;
407 }
408 
GetAuxiliaryPicture(napi_env env,napi_callback_info info)409 napi_value PictureNapi::GetAuxiliaryPicture(napi_env env, napi_callback_info info)
410 {
411     napi_value result = nullptr;
412     napi_get_undefined(env, &result);
413     napi_status status;
414     napi_value thisVar = nullptr;
415     napi_value argValue[NUM_1] = {0};
416     size_t argCount = NUM_1;
417     uint32_t auxiType = 0;
418 
419     IMAGE_LOGD("GetAuxiliaryPicture IN");
420     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
421     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to arg info"));
422     PictureNapi* pictureNapi = nullptr;
423     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&pictureNapi));
424     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi), result, IMAGE_LOGE("fail to unwrap PictureNapi"));
425     status = napi_get_value_uint32(env, argValue[NUM_0], &auxiType);
426     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
427         "Fail to get auxiliary picture type!"), IMAGE_LOGE("Fail to get auxiliary picture type."));
428     AuxiliaryPictureType type = ParseAuxiliaryPictureType(auxiType);
429     if (type == AuxiliaryPictureType::NONE) {
430         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
431             "The type does not match the auxiliary picture type!");
432     }
433     if (pictureNapi->nativePicture_ != nullptr) {
434         auto auxiliaryPic = pictureNapi->nativePicture_->GetAuxiliaryPicture(type);
435         if (auxiliaryPic != nullptr) {
436             result = AuxiliaryPictureNapi::CreateAuxiliaryPicture(env, std::move(auxiliaryPic));
437         } else {
438             IMAGE_LOGE("native auxiliary picture is nullptr!");
439         }
440     } else {
441         IMAGE_LOGE("native picture is nullptr!");
442     }
443     return result;
444 }
445 
GetPicture(napi_env env,napi_value picture)446 std::shared_ptr<Picture> PictureNapi::GetPicture(napi_env env, napi_value picture)
447 {
448     PictureNapi *pictureNapi = nullptr;
449     napi_status status = napi_unwrap(env, picture, reinterpret_cast<void**>(&pictureNapi));
450     if (!IMG_IS_OK(status)) {
451         IMAGE_LOGE("GetPicture napi unwrap failed");
452         return nullptr;
453     }
454     if (pictureNapi == nullptr) {
455         IMAGE_LOGE("GetPixelMap pixmapNapi is nullptr");
456         return nullptr;
457     }
458     return pictureNapi->nativePicture_;
459 }
460 
SetAuxiliaryPicture(napi_env env,napi_callback_info info)461 napi_value PictureNapi::SetAuxiliaryPicture(napi_env env, napi_callback_info info)
462 {
463     napi_value result = nullptr;
464     napi_get_undefined(env, &result);
465     napi_status status;
466     napi_value thisVar = nullptr;
467     napi_value argValue[NUM_2] = {0};
468     size_t argCount = NUM_2;
469     uint32_t auxiType = 0;
470 
471     IMAGE_LOGD("SetAuxiliaryPictureSync IN");
472     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
473     PictureNapi* pictureNapi = nullptr;
474     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&pictureNapi));
475     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi), result, IMAGE_LOGE("fail to unwrap PictureNapi"));
476 
477     status = napi_get_value_uint32(env, argValue[NUM_0], &auxiType);
478     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
479         "Fail to get auxiliary picture type!"), IMAGE_LOGE("Fail to get auxiliary picture Type"));
480     AuxiliaryPictureType type = ParseAuxiliaryPictureType(auxiType);
481     if (type == AuxiliaryPictureType::NONE) {
482         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
483             "The type does not match the auxiliary picture type!");
484     }
485 
486     AuxiliaryPictureNapi* auxiliaryPictureNapi = nullptr;
487     status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&auxiliaryPictureNapi));
488     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, pictureNapi),
489         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to unwrap AuxiliaryPictureNapi!"),
490         IMAGE_LOGE("Fail to unwrap AuxiliaryPictureNapi"));
491 
492     if (pictureNapi->nativePicture_ != nullptr) {
493         auto auxiliaryPicturePtr = auxiliaryPictureNapi->GetNativeAuxiliaryPic();
494         if (auxiliaryPicturePtr != nullptr) {
495             if (type != auxiliaryPicturePtr->GetAuxiliaryPictureInfo().auxiliaryPictureType) {
496                 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
497                     "The type does not match the auxiliary picture type!");
498             } else {
499                 pictureNapi->nativePicture_->SetAuxiliaryPicture(auxiliaryPicturePtr);
500             }
501         } else {
502             return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
503                 "Native auxiliary picture is nullptr!");
504         }
505     } else {
506         IMAGE_LOGE("native picture is nullptr!");
507     }
508 
509     return result;
510 }
511 
STATIC_EXEC_FUNC(CreatePicture)512 STATIC_EXEC_FUNC(CreatePicture)
513 {
514     IMAGE_INFO("CreatePictureEX IN");
515     auto context = static_cast<PictureAsyncContext*>(data);
516     auto picture = Picture::Create(context->rPixelMap);
517     context->rPicture = std::move(picture);
518     IMAGE_INFO("CreatePictureEX OUT");
519     if (IMG_NOT_NULL(context->rPicture)) {
520         context->status = SUCCESS;
521     } else {
522         context->status = ERROR;
523     }
524 }
525 
CreatePicture(napi_env env,napi_callback_info info)526 napi_value PictureNapi::CreatePicture(napi_env env, napi_callback_info info)
527 {
528     IMAGE_INFO("CreatePicture IN");
529     if (sConstructor_ == nullptr) {
530         napi_value exports = nullptr;
531         napi_create_object(env, &exports);
532         PictureNapi::Init(env, exports);
533     }
534     napi_value result = nullptr;
535     napi_get_undefined(env, &result);
536     napi_value constructor = nullptr;
537     napi_status status;
538     napi_value thisVar = nullptr;
539     napi_value argValue[NUM_1] = {0};
540     size_t argCount = NUM_1;
541     IMAGE_LOGD("CreatePicture IN");
542     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
543     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
544         "Invalid args"), IMAGE_LOGE("fail to napi_get_cb_info"));
545     IMG_NAPI_CHECK_RET_D(argCount == NUM_1, ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
546         "Invalid args count"), IMAGE_LOGE("Invalid args count %{public}zu", argCount));
547     std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
548     if (ParserImageType(env, argValue[NUM_0]) == ImageType::TYPE_PIXEL_MAP) {
549         asyncContext->rPixelMap = PixelMapNapi::GetPixelMap(env, argValue[NUM_0]);
550         if (asyncContext->rPixelMap == nullptr) {
551             return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Get arg pixelmap failed");
552         }
553     } else {
554         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Input image type mismatch");
555     }
556     CreatePictureExec(env, static_cast<void*>((asyncContext).get()));
557     status = napi_get_reference_value(env, sConstructor_, &constructor);
558     if (IMG_IS_OK(status)) {
559         sPicture_ = std::move(asyncContext->rPicture);
560         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
561     }
562     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to create picture sync"));
563     IMAGE_INFO("CreatePicture OUT");
564     return result;
565 }
566 
ThrowExceptionError(napi_env env,const std::string & tag,const std::uint32_t & code,const std::string & info)567 napi_value PictureNapi::ThrowExceptionError(napi_env env,
568     const std::string &tag, const std::uint32_t &code, const std::string &info)
569 {
570     auto errNode = ETS_API_ERROR_CODE.find(tag);
571     if (errNode != ETS_API_ERROR_CODE.end() &&
572         errNode->second.find(code) != errNode->second.end()) {
573         return ImageNapiUtils::ThrowExceptionError(env, code, info);
574     }
575     return ImageNapiUtils::ThrowExceptionError(env, ERROR, "Operation failed");
576 }
577 
CreatePictureFromParcel(napi_env env,napi_callback_info info)578 napi_value PictureNapi::CreatePictureFromParcel(napi_env env, napi_callback_info info)
579 {
580     if (sConstructor_ == nullptr) {
581         napi_value exports = nullptr;
582         napi_create_object(env, &exports);
583         PictureNapi::Init(env, exports);
584     }
585     napi_value result = nullptr;
586     napi_get_undefined(env, &result);
587     napi_status status;
588     napi_value thisVar = nullptr;
589     napi_value argValue[NUM_1] = {0};
590     size_t argCount = NUM_1;
591     IMAGE_LOGD("Call CreatePictureFromParcel");
592     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
593     if (!IMG_IS_OK(status) || argCount != NUM_1) {
594         return PictureNapi::ThrowExceptionError(env,
595             CREATE_PICTURE_FROM_PARCEL, IMAGE_BAD_PARAMETER, "Fail to napi_get_cb_info");
596     }
597     napi_unwrap(env, argValue[NUM_0], (void **)&messageSequence);
598     if (messageSequence == nullptr) {
599         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to unwrap messageSequence");
600     }
601     auto messageParcel = messageSequence->GetMessageParcel();
602     if (messageParcel == nullptr) {
603         return ImageNapiUtils::ThrowExceptionError(env, ERR_IPC, "Get parcel failed");
604     }
605     PICTURE_ERR error;
606     auto picture = Picture::Unmarshalling(*messageParcel, error);
607     if (!IMG_NOT_NULL(picture)) {
608         return ImageNapiUtils::ThrowExceptionError(env, ERR_IPC, "Unmarshalling picture failed");
609     }
610     std::shared_ptr<OHOS::Media::Picture> picturePtr(picture);
611     sPicture_ = std::move(picturePtr);
612     napi_value constructor = nullptr;
613     status = napi_get_reference_value(env, sConstructor_, &constructor);
614     if (IMG_IS_OK(status)) {
615         if (sPicture_ == nullptr) {
616             status = napi_invalid_arg;
617             IMAGE_LOGE("NewPictureNapiInstance picture is nullptr");
618         } else {
619             status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
620         }
621     }
622     if (!IMG_IS_OK(status)) {
623         IMAGE_LOGE("New instance could not be obtained");
624         return PictureNapi::ThrowExceptionError(env,
625             CREATE_PICTURE_FROM_PARCEL, ERR_IMAGE_NAPI_ERROR, "New instance could not be obtained");
626     }
627     return result;
628 }
GetMainPixelmap(napi_env env,napi_callback_info info)629 napi_value PictureNapi::GetMainPixelmap(napi_env env, napi_callback_info info)
630 {
631     NapiValues nVal;
632     napi_get_undefined(env, &nVal.result);
633     nVal.argc = NUM_0;
634     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
635     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to arg info"));
636 
637     PictureNapi* pictureNapi = nullptr;
638     nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&pictureNapi));
639 
640     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, pictureNapi), nVal.result, IMAGE_LOGE("Fail to unwrap context"));
641 
642     if (pictureNapi->nativePicture_ != nullptr) {
643         auto pixelmap = pictureNapi->nativePicture_->GetMainPixel();
644         nVal.result = PixelMapNapi::CreatePixelMap(env, pixelmap);
645     } else {
646         IMAGE_LOGE("Native picture is nullptr!");
647     }
648     return nVal.result;
649 }
650 
Release(napi_env env,napi_callback_info info)651 napi_value PictureNapi::Release(napi_env env, napi_callback_info info)
652 {
653     NapiValues nVal;
654     nVal.result = nullptr;
655     napi_get_undefined(env, &nVal.result);
656     nVal.argc = NUM_0;
657     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
658     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to arg info"));
659 
660     PictureNapi *picturenapi = nullptr;
661     nVal.status = napi_remove_wrap(env, nVal.thisVar, reinterpret_cast<void**>(&picturenapi));
662 
663     return nVal.result;
664 }
665 
Marshalling(napi_env env,napi_callback_info info)666 napi_value PictureNapi::Marshalling(napi_env env, napi_callback_info info)
667 {
668 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
669     NapiValues nVal;
670     nVal.argc = NUM_1;
671     napi_value argValue[NUM_1] = {0};
672     nVal.argv = argValue;
673     if (!prepareNapiEnv(env, info, &nVal)) {
674         return ImageNapiUtils::ThrowExceptionError(
675             env, IMAGE_BAD_PARAMETER, "Fail to unwrap context");
676     }
677     nVal.context->rPicture = nVal.context->nConstructor->nativePicture_;
678     if (nVal.argc != NUM_0 && nVal.argc != NUM_1) {
679         return ImageNapiUtils::ThrowExceptionError(
680             env, IMAGE_BAD_PARAMETER, "Invalid args count");
681     }
682     NAPI_MessageSequence *napiSequence = nullptr;
683     napi_get_cb_info(env, info, &nVal.argc, nVal.argv, nullptr, nullptr);
684     napi_unwrap(env, nVal.argv[0], reinterpret_cast<void**>(&napiSequence));
685     if (napiSequence == nullptr) {
686         return ImageNapiUtils::ThrowExceptionError(
687             env, IMAGE_BAD_PARAMETER, "Marshalling picture napi_unwrap failed.");
688     }
689     auto messageParcel = napiSequence->GetMessageParcel();
690     if (messageParcel == nullptr) {
691         return ImageNapiUtils::ThrowExceptionError(
692             env, ERR_IPC, "Marshalling picture to parcel failed.");
693     }
694     bool st = nVal.context->rPicture->Marshalling(*messageParcel);
695     if (!st) {
696         return ImageNapiUtils::ThrowExceptionError(
697             env, ERR_IPC, "Marshalling picture to parcel failed.");
698     }
699     return nVal.result;
700 #else
701     return napi_value(nullptr);
702 #endif
703 }
704 
CreateHDRComposedPixelmapComplete(napi_env env,napi_status status,void * data)705 static void CreateHDRComposedPixelmapComplete(napi_env env, napi_status status, void *data)
706 {
707     napi_value result = nullptr;
708     napi_get_undefined(env, &result);
709     auto context = static_cast<PictureAsyncContext*>(data);
710 
711     if (context->rPixelMap != nullptr) {
712         result = PixelMapNapi::CreatePixelMap(env, context->rPixelMap);
713         context->status = SUCCESS;
714     } else {
715         context->status = ERROR;
716     }
717     CommonCallbackRoutine(env, context, result);
718 }
719 
GetHdrComposedPixelMap(napi_env env,napi_callback_info info)720 napi_value PictureNapi::GetHdrComposedPixelMap(napi_env env, napi_callback_info info)
721 {
722     napi_value result = nullptr;
723     napi_get_undefined(env, &result);
724 
725     napi_status status;
726     napi_value thisVar = nullptr;
727     size_t argCount = NUM_0;
728 
729     IMAGE_LOGD("GetHdrComposedPixelMap IN");
730     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
731 
732     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to napi_get_cb_info"));
733 
734     std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
735     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
736     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor), result,
737                          IMAGE_LOGE("Fail to napi_unwrap context"));
738     asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
739     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture),
740         nullptr, IMAGE_LOGE("Empty native pixelmap"));
741     if (asyncContext->rPicture->GetAuxiliaryPicture(AuxiliaryPictureType::GAINMAP) == nullptr) {
742         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "There is no GAINMAP");
743     }
744     if (asyncContext->rPicture->GetMainPixel()->GetAllocatorType() != AllocatorType::DMA_ALLOC) {
745         return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_OPERATION, "Unsupported operations");
746     }
747     napi_create_promise(env, &(asyncContext->deferred), &result);
748 
749     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetHdrComposedPixelMap",
750         [](napi_env env, void *data) {
751             auto context = static_cast<PictureAsyncContext*>(data);
752             auto tmpixel = context->rPicture->GetHdrComposedPixelMap();
753             context->rPixelMap = std::move(tmpixel);
754             context->status = SUCCESS;
755         }, CreateHDRComposedPixelmapComplete, asyncContext, asyncContext->work);
756     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
757         nullptr, IMAGE_LOGE("Fail to create async work"));
758 
759     return result;
760 }
761 
GetGainmapPixelmap(napi_env env,napi_callback_info info)762 napi_value PictureNapi::GetGainmapPixelmap(napi_env env, napi_callback_info info)
763 {
764     NapiValues nVal;
765     napi_get_undefined(env, &nVal.result);
766     IMAGE_LOGD("GetGainmapPixelmap");
767     nVal.argc = NUM_0;
768     IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
769     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Parameter acquisition failed"));
770 
771     PictureNapi* pictureNapi = nullptr;
772     nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&pictureNapi));
773     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, pictureNapi),
774         nVal.result, IMAGE_LOGE("Failed to retrieve native pointer"));
775 
776     if (pictureNapi->nativePicture_ != nullptr) {
777         auto gainpixelmap = pictureNapi->nativePicture_->GetGainmapPixelMap();
778         nVal.result = PixelMapNapi::CreatePixelMap(env, gainpixelmap);
779     } else {
780         return ImageNapiUtils::ThrowExceptionError(env, ERR_MEDIA_UNKNOWN, "Picture is a null pointer");
781     }
782     return nVal.result;
783 }
784 
GetMetadataComplete(napi_env env,napi_status status,void * data)785 static void GetMetadataComplete(napi_env env, napi_status status, void *data)
786 {
787     IMAGE_LOGD("[Picture]GetMetadata IN");
788     napi_value result = nullptr;
789     napi_get_undefined(env, &result);
790     auto context = static_cast<PictureAsyncContext*>(data);
791     if (context->imageMetadata != nullptr) {
792         result = MetadataNapi::CreateMetadata(env, context->imageMetadata);
793     }
794 
795     if (!IMG_IS_OK(status)) {
796         context->status = ERROR;
797         IMAGE_LOGE("Get Metadata failed!");
798     } else {
799         context->status = SUCCESS;
800     }
801     IMAGE_LOGD("[Picture]GetMetadata OUT");
802     CommonCallbackRoutine(env, context, result);
803 }
804 
GetMetadata(napi_env env,napi_callback_info info)805 napi_value PictureNapi::GetMetadata(napi_env env, napi_callback_info info)
806 {
807     napi_value result = nullptr;
808     napi_get_undefined(env, &result);
809     napi_status status;
810     napi_value thisVar = nullptr;
811     size_t argCount = NUM_1;
812     napi_value argValue[NUM_1] = {0};
813     uint32_t metadataType = 0;
814 
815     IMAGE_LOGD("GetMetadata IN");
816     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
817     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argment from info"));
818     std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
819     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
820     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
821         nullptr, IMAGE_LOGE("Fail to unwrap context"));
822     asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
823     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), nullptr, IMAGE_LOGE("Empty native picture"));
824     status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
825     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
826         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
827         "Fail to get metadata type"), IMAGE_LOGE("Fail to get metadata type"));
828     if (metadataType != static_cast<uint32_t>(MetadataType::EXIF)) {
829         return ImageNapiUtils::ThrowExceptionError(
830             env, IMAGE_UNSUPPORTED_METADATA, "Unsupport MetadataType");
831     }
832 
833     napi_create_promise(env, &(asyncContext->deferred), &result);
834     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetMetadata",
835         [](napi_env env, void* data) {
836             auto context = static_cast<PictureAsyncContext*>(data);
837             context->imageMetadata = std::reinterpret_pointer_cast<ImageMetadata>(context->rPicture->GetExifMetadata());
838         }, GetMetadataComplete, asyncContext, asyncContext->work);
839     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
840         nullptr, IMAGE_LOGE("Fail to create async work"));
841     return result;
842 }
843 
SetMetadataComplete(napi_env env,napi_status status,void * data)844 static void SetMetadataComplete(napi_env env, napi_status status, void *data)
845 {
846     IMAGE_LOGD("[Picture]SetMetadata IN");
847     auto context = static_cast<PictureAsyncContext*>(data);
848     napi_value result = nullptr;
849     napi_get_undefined(env, &result);
850 
851     if (!IMG_IS_OK(status)) {
852         context->status = ERROR;
853         IMAGE_LOGE("Set Metadata failed!");
854     }
855     IMAGE_LOGD("[Picture]SetMetadata OUT");
856     CommonCallbackRoutine(env, context, result);
857 }
858 
SetMetadata(napi_env env,napi_callback_info info)859 napi_value PictureNapi::SetMetadata(napi_env env, napi_callback_info info)
860 {
861     napi_value result = nullptr;
862     napi_get_undefined(env, &result);
863     napi_status status;
864     napi_value thisVar = nullptr;
865     size_t argCount = NUM_2;
866     napi_value argValue[NUM_2] = {0};
867     uint32_t metadataType = 0;
868 
869     IMAGE_LOGD("SetMetadata IN");
870     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
871     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argments from info"));
872     std::unique_ptr<PictureAsyncContext> asyncContext = std::make_unique<PictureAsyncContext>();
873     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
874     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
875         nullptr, IMAGE_LOGE("Fail to unwrap context"));
876     asyncContext->rPicture = asyncContext->nConstructor->nativePicture_;
877     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rPicture), nullptr, IMAGE_LOGE("Empty native picture"));
878 
879     status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
880     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
881         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
882         "Fail to get metadata type"), IMAGE_LOGE("Fail to get metadata type"));
883     if (metadataType == static_cast<uint32_t>(MetadataType::EXIF)) {
884         asyncContext->metadataType = MetadataType(metadataType);
885     } else {
886         return ImageNapiUtils::ThrowExceptionError(
887             env, IMAGE_UNSUPPORTED_METADATA, "Unsupport MetadataType");
888     }
889 
890     status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&asyncContext->metadataNapi));
891     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
892         ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
893         "Fail to unwrap MetadataNapi"), IMAGE_LOGE("Fail to unwrap MetadataNapi"));
894     if (asyncContext->metadataNapi != nullptr) {
895         asyncContext->imageMetadata = asyncContext->metadataNapi->GetNativeMetadata();
896     } else {
897         return ImageNapiUtils::ThrowExceptionError(
898             env, IMAGE_BAD_PARAMETER, "Invalid args Metadata");
899     }
900 
901     napi_create_promise(env, &(asyncContext->deferred), &result);
902     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetMetadata",
903         [](napi_env env, void* data) {
904             auto context = static_cast<PictureAsyncContext*>(data);
905             context->status = context->rPicture->SetExifMetadata(
906                 std::reinterpret_pointer_cast<ExifMetadata>(context->imageMetadata));
907         }, SetMetadataComplete, asyncContext, asyncContext->work);
908     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
909         nullptr, IMAGE_LOGE("Fail to create async work"));
910     return result;
911 }
912 
release()913 void PictureNapi::release()
914 {
915     if (!isRelease) {
916         if (nativePicture_ != nullptr) {
917             nativePicture_ = nullptr;
918         }
919         isRelease = true;
920     }
921 }
922 }  // namespace Media
923 }  // namespace OHOS
924