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