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