• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "image_packer_napi.h"
17 #include "hilog/log.h"
18 #include "media_errors.h"
19 #include "image_napi_utils.h"
20 #include "image_packer.h"
21 #include "image_source.h"
22 #include "image_source_napi.h"
23 #include "pixel_map_napi.h"
24 
25 using OHOS::HiviewDFX::HiLog;
26 namespace {
27     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "ImagePackerNapi"};
28     constexpr uint32_t NUM_0 = 0;
29     constexpr uint32_t NUM_1 = 1;
30     constexpr uint32_t NUM_2 = 2;
31 }
32 
33 namespace OHOS {
34 namespace Media {
35 static const std::string CLASS_NAME_IMAGEPACKER = "ImagePacker";
36 std::shared_ptr<ImagePacker> ImagePackerNapi::sImgPck_ = nullptr;
37 std::shared_ptr<ImageSource> ImagePackerNapi::sImgSource_ = nullptr;
38 thread_local napi_ref ImagePackerNapi::sConstructor_ = nullptr;
39 
40 const int ARGS_THREE = 3;
41 const int PARAM0 = 0;
42 const int PARAM1 = 1;
43 const int PARAM2 = 2;
44 const int PARAM3 = 3;
45 const uint8_t BYTE_FULL = 0xFF;
46 const int32_t SIZE = 100;
47 const int32_t TYPE_IMAGE_SOURCE = 1;
48 const int32_t TYPE_PIXEL_MAP = 2;
49 const int64_t DEFAULT_BUFFER_SIZE = 10 * 1024 * 1024; // 10M is the maximum default packedSize
50 
51 struct ImagePackerAsyncContext {
52     napi_env env;
53     napi_async_work work;
54     napi_deferred deferred;
55     napi_ref callbackRef = nullptr;
56     napi_ref errorMsg = nullptr;
57     ImagePackerNapi *constructor_;
58     bool status = false;
59     std::shared_ptr<ImageSource> rImageSource;
60     PackOption packOption;
61     std::shared_ptr<ImagePacker> rImagePacker;
62     std::shared_ptr<PixelMap> rPixelMap;
63     std::unique_ptr<uint8_t[]> resultBuffer;
64     int32_t packType = TYPE_IMAGE_SOURCE;
65     int64_t resultBufferSize = 0;
66     int64_t packedSize = 0;
67 };
68 
69 struct PackingOption {
70     std::string format;
71     uint8_t quality = 100;
72 };
73 
ImagePackerNapi()74 ImagePackerNapi::ImagePackerNapi()
75     :env_(nullptr), wrapper_(nullptr)
76 {}
77 
~ImagePackerNapi()78 ImagePackerNapi::~ImagePackerNapi()
79 {
80     if (wrapper_ != nullptr) {
81         napi_delete_reference(env_, wrapper_);
82     }
83 }
84 
CommonCallbackRoutine(napi_env env,ImagePackerAsyncContext * & connect,const napi_value & valueParam)85 static void CommonCallbackRoutine(napi_env env, ImagePackerAsyncContext* &connect, const napi_value &valueParam)
86 {
87     HiLog::Debug(LABEL, "CommonCallbackRoutine enter");
88     napi_value result[NUM_2] = {0};
89     napi_value retVal;
90     napi_value callback = nullptr;
91 
92     napi_get_undefined(env, &result[NUM_0]);
93     napi_get_undefined(env, &result[NUM_1]);
94 
95     if (connect->status == SUCCESS) {
96         result[NUM_1] = valueParam;
97     } else if (connect->errorMsg != nullptr) {
98         napi_get_reference_value(env, connect->errorMsg, &result[NUM_0]);
99         napi_delete_reference(env, connect->errorMsg);
100     } else {
101         napi_create_string_utf8(env, "Internal error", NAPI_AUTO_LENGTH, &(result[NUM_0]));
102     }
103 
104     if (connect->deferred) {
105         if (connect->status == SUCCESS) {
106             napi_resolve_deferred(env, connect->deferred, result[NUM_1]);
107         } else {
108             napi_reject_deferred(env, connect->deferred, result[NUM_0]);
109         }
110     } else {
111         napi_get_reference_value(env, connect->callbackRef, &callback);
112         napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
113         napi_delete_reference(env, connect->callbackRef);
114     }
115 
116     napi_delete_async_work(env, connect->work);
117 
118     delete connect;
119     connect = nullptr;
120     HiLog::Debug(LABEL, "CommonCallbackRoutine exit");
121 }
122 
BuildMsgOnError(napi_env env,ImagePackerAsyncContext * context,bool assertion,const std::string msg)123 static void BuildMsgOnError(napi_env env,
124     ImagePackerAsyncContext* context, bool assertion, const std::string msg)
125 {
126     napi_value tmpError;
127     napi_status status;
128     if (!assertion) {
129         HiLog::Error(LABEL, "%{public}s", msg.c_str());
130         status = napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &tmpError);
131         if (status != napi_ok) {
132             HiLog::Error(LABEL, "Create error msg error");
133             return;
134         }
135         napi_create_reference(env, tmpError, NUM_1, &(context->errorMsg));
136     }
137 }
138 
STATIC_EXEC_FUNC(Packing)139 STATIC_EXEC_FUNC(Packing)
140 {
141     HiLog::Debug(LABEL, "PackingExec enter");
142     int64_t packedSize = 0;
143     auto context = static_cast<ImagePackerAsyncContext*>(data);
144     HiLog::Debug(LABEL, "image packer get supported format");
145     std::set<std::string> formats;
146     uint32_t ret = context->rImagePacker->GetSupportedFormats(formats);
147     if (ret != SUCCESS) {
148         HiLog::Error(LABEL, "image packer get supported format failed, ret=%{public}u.", ret);
149     }
150     HiLog::Info(LABEL, "ImagePacker BufferSize %{public}" PRId64, context->resultBufferSize);
151     context->resultBuffer = std::make_unique<uint8_t[]>(
152         (context->resultBufferSize <= 0)?DEFAULT_BUFFER_SIZE:context->resultBufferSize);
153     if (context->resultBuffer == nullptr) {
154         BuildMsgOnError(env, context, context->resultBuffer == nullptr, "ImagePacker buffer alloc error");
155         return;
156     }
157     context->rImagePacker->StartPacking(context->resultBuffer.get(),
158         context->resultBufferSize, context->packOption);
159     if (context->packType == TYPE_IMAGE_SOURCE) {
160         HiLog::Info(LABEL, "ImagePacker set image source");
161         if (context->rImageSource == nullptr) {
162             BuildMsgOnError(env, context, context->rImageSource == nullptr, "ImageSource is nullptr");
163             return;
164         }
165         context->rImagePacker->AddImage(*(context->rImageSource));
166     } else {
167         HiLog::Info(LABEL, "ImagePacker set pixelmap");
168         if (context->rPixelMap == nullptr) {
169             BuildMsgOnError(env, context, context->rImageSource == nullptr, "Pixelmap is nullptr");
170             return;
171         }
172         context->rImagePacker->AddImage(*(context->rPixelMap));
173     }
174     context->rImagePacker->FinalizePacking(packedSize);
175     HiLog::Debug(LABEL, "packedSize=%{public}" PRId64, packedSize);
176     if (packedSize > 0 && (packedSize < context->resultBufferSize)) {
177         context->packedSize = packedSize;
178         context->status = SUCCESS;
179     } else {
180         context->status = ERROR;
181         HiLog::Error(LABEL, "Packing failed, packedSize outside size.");
182     }
183     HiLog::Debug(LABEL, "PackingExec exit");
184 }
185 
STATIC_COMPLETE_FUNC(PackingError)186 STATIC_COMPLETE_FUNC(PackingError)
187 {
188     HiLog::Debug(LABEL, "PackingErrorComplete IN");
189     napi_value result = nullptr;
190     napi_get_undefined(env, &result);
191     auto context = static_cast<ImagePackerAsyncContext*>(data);
192     context->status = ERROR;
193     HiLog::Debug(LABEL, "PackingErrorComplete OUT");
194     CommonCallbackRoutine(env, context, result);
195 }
196 
STATIC_COMPLETE_FUNC(Packing)197 STATIC_COMPLETE_FUNC(Packing)
198 {
199     HiLog::Debug(LABEL, "PackingComplete enter");
200     napi_value result = nullptr;
201     napi_get_undefined(env, &result);
202     auto context = static_cast<ImagePackerAsyncContext*>(data);
203 
204     if (!ImageNapiUtils::CreateArrayBuffer(env, context->resultBuffer.get(),
205                                            context->packedSize, &result)) {
206         context->status = ERROR;
207         HiLog::Error(LABEL, "napi_create_arraybuffer failed!");
208         napi_get_undefined(env, &result);
209     } else {
210         context->status = SUCCESS;
211     }
212     context->resultBuffer = nullptr;
213     context->resultBufferSize = 0;
214     HiLog::Debug(LABEL, "PackingComplete exit");
215     CommonCallbackRoutine(env, context, result);
216 }
217 
Init(napi_env env,napi_value exports)218 napi_value ImagePackerNapi::Init(napi_env env, napi_value exports)
219 {
220     napi_property_descriptor props[] = {
221         DECLARE_NAPI_FUNCTION("packing", Packing),
222         DECLARE_NAPI_FUNCTION("packingFromPixelMap", Packing),
223         DECLARE_NAPI_FUNCTION("release", Release),
224         DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats),
225     };
226     napi_property_descriptor static_prop[] = {
227         DECLARE_NAPI_STATIC_FUNCTION("createImagePacker", CreateImagePacker),
228     };
229 
230     napi_value constructor = nullptr;
231 
232     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
233         napi_define_class(env, CLASS_NAME_IMAGEPACKER.c_str(), NAPI_AUTO_LENGTH, Constructor,
234         nullptr, IMG_ARRAY_SIZE(props), props, &constructor)), nullptr,
235         HiLog::Error(LABEL, "define class fail")
236     );
237 
238     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
239         napi_create_reference(env, constructor, 1, &sConstructor_)),
240         nullptr,
241         HiLog::Error(LABEL, "create reference fail")
242     );
243 
244     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
245         napi_set_named_property(env, exports, CLASS_NAME_IMAGEPACKER.c_str(), constructor)),
246         nullptr,
247         HiLog::Error(LABEL, "set named property fail")
248     );
249     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
250         napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
251         nullptr,
252         HiLog::Error(LABEL, "define properties fail")
253     );
254 
255     HiLog::Debug(LABEL, "Init success");
256     return exports;
257 }
258 
Constructor(napi_env env,napi_callback_info info)259 napi_value ImagePackerNapi::Constructor(napi_env env, napi_callback_info info)
260 {
261     napi_value undefineVar = nullptr;
262     napi_get_undefined(env, &undefineVar);
263 
264     napi_status status;
265     napi_value thisVar = nullptr;
266 
267     HiLog::Debug(LABEL, "Constructor in");
268     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
269     if (status == napi_ok && thisVar != nullptr) {
270         std::unique_ptr<ImagePackerNapi> pImgPackerNapi = std::make_unique<ImagePackerNapi>();
271         if (pImgPackerNapi != nullptr) {
272             pImgPackerNapi->env_ = env;
273             pImgPackerNapi->nativeImgPck = sImgPck_;
274             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgPackerNapi.get()),
275                                ImagePackerNapi::Destructor, nullptr, &(pImgPackerNapi->wrapper_));
276             if (status == napi_ok) {
277                 pImgPackerNapi.release();
278                 return thisVar;
279             } else {
280                 HiLog::Error(LABEL, "Failure wrapping js to native napi");
281             }
282         }
283     }
284 
285     return undefineVar;
286 }
287 
CreateImagePacker(napi_env env,napi_callback_info info)288 napi_value ImagePackerNapi::CreateImagePacker(napi_env env, napi_callback_info info)
289 {
290     napi_value constructor = nullptr;
291     napi_value result = nullptr;
292     napi_status status;
293 
294     HiLog::Debug(LABEL, "CreateImagePacker IN");
295     std::shared_ptr<ImagePacker> imagePacker = std::make_shared<ImagePacker>();
296     status = napi_get_reference_value(env, sConstructor_, &constructor);
297     if (IMG_IS_OK(status)) {
298         sImgPck_ = imagePacker;
299         status = napi_new_instance(env, constructor, 0, nullptr, &result);
300         if (status == napi_ok) {
301             return result;
302         } else {
303             HiLog::Error(LABEL, "New instance could not be obtained");
304         }
305     }
306     return result;
307 }
308 
Destructor(napi_env env,void * nativeObject,void * finalize)309 void ImagePackerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
310 {
311     ImagePackerNapi *pImagePackerNapi = reinterpret_cast<ImagePackerNapi*>(nativeObject);
312 
313     if (IMG_NOT_NULL(pImagePackerNapi)) {
314         pImagePackerNapi->nativeImgPck = nullptr;
315         pImagePackerNapi->~ImagePackerNapi();
316     }
317 }
318 
parseBufferSize(napi_env env,napi_value root)319 static int64_t parseBufferSize(napi_env env, napi_value root)
320 {
321     napi_value tempValue = nullptr;
322     int64_t tmpNumber = DEFAULT_BUFFER_SIZE;
323     if (napi_get_named_property(env, root, "bufferSize", &tempValue) != napi_ok) {
324         HiLog::Info(LABEL, "No bufferSize, Using default");
325         return tmpNumber;
326     }
327     napi_get_value_int64(env, tempValue, &tmpNumber);
328     HiLog::Info(LABEL, "BufferSize is %{public}" PRId64, tmpNumber);
329     if (tmpNumber < 0) {
330         return DEFAULT_BUFFER_SIZE;
331     }
332     return tmpNumber;
333 }
334 
parsePackOptions(napi_env env,napi_value root,PackOption * opts)335 static bool parsePackOptions(napi_env env, napi_value root, PackOption* opts)
336 {
337     napi_value tmpValue = nullptr;
338     uint32_t tmpNumber = 0;
339 
340     HiLog::Debug(LABEL, "parsePackOptions IN");
341     if (!GET_NODE_BY_NAME(root, "format", tmpValue)) {
342         HiLog::Error(LABEL, "No format in pack option");
343         return false;
344     }
345 
346     bool isFormatArray = false;
347     napi_is_array(env, tmpValue, &isFormatArray);
348     auto formatType = ImageNapiUtils::getType(env, tmpValue);
349 
350     HiLog::Debug(LABEL, "parsePackOptions format type %{public}d, is array %{public}d",
351         formatType, isFormatArray);
352 
353     char buffer[SIZE] = {0};
354     size_t res = 0;
355     if (napi_string == formatType) {
356         if (napi_get_value_string_utf8(env, tmpValue, buffer, SIZE, &res) != napi_ok) {
357             HiLog::Error(LABEL, "Parse pack option format failed");
358             return false;
359         }
360         opts->format = std::string(buffer);
361     } else if (isFormatArray) {
362         uint32_t len = 0;
363         if (napi_get_array_length(env, tmpValue, &len) != napi_ok) {
364             HiLog::Error(LABEL, "Parse pack napi_get_array_length failed");
365             return false;
366         }
367         HiLog::Debug(LABEL, "Parse pack array_length=%{public}u", len);
368         for (size_t i = 0; i < len; i++) {
369             napi_value item;
370             napi_get_element(env, tmpValue, i, &item);
371             if (napi_get_value_string_utf8(env, item, buffer, SIZE, &res) != napi_ok) {
372                 HiLog::Error(LABEL, "Parse format in item failed %{public}zu", i);
373                 continue;
374             }
375             opts->format = std::string(buffer);
376             HiLog::Debug(LABEL, "format is %{public}s.", opts->format.c_str());
377         }
378     } else {
379         HiLog::Error(LABEL, "Invalid pack option format type");
380         return false;
381     }
382     HiLog::Debug(LABEL, "parsePackOptions format:[%{public}s]", opts->format.c_str());
383 
384     if (!GET_UINT32_BY_NAME(root, "quality", tmpNumber)) {
385         HiLog::Error(LABEL, "No quality in pack option");
386         return false;
387     }
388     if (tmpNumber > SIZE) {
389         HiLog::Error(LABEL, "Invalid quality");
390         opts->quality = BYTE_FULL;
391     } else {
392         opts->quality = static_cast<uint8_t>(tmpNumber & 0xff);
393     }
394     HiLog::Debug(LABEL, "parsePackOptions OUT");
395     return true;
396 }
397 
ParserPackingArgumentType(napi_env env,napi_value argv)398 static int32_t ParserPackingArgumentType(napi_env env, napi_value argv)
399 {
400     napi_value constructor = nullptr;
401     napi_value global = nullptr;
402     bool isInstance = false;
403     napi_status ret = napi_invalid_arg;
404 
405     napi_get_global(env, &global);
406 
407     ret = napi_get_named_property(env, global, "ImageSource", &constructor);
408     if (ret != napi_ok) {
409         HiLog::Error(LABEL, "Get ImageSourceNapi property failed!");
410     }
411 
412     ret = napi_instanceof(env, argv, constructor, &isInstance);
413     if (ret == napi_ok && isInstance) {
414         HiLog::Debug(LABEL, "This is ImageSourceNapi type!");
415         return TYPE_IMAGE_SOURCE;
416     }
417 
418     ret = napi_get_named_property(env, global, "PixelMap", &constructor);
419     if (ret != napi_ok) {
420         HiLog::Error(LABEL, "Get PixelMapNapi property failed!");
421     }
422 
423     ret = napi_instanceof(env, argv, constructor, &isInstance);
424     if (ret == napi_ok && isInstance) {
425         HiLog::Debug(LABEL, "This is PixelMapNapi type!");
426         return TYPE_PIXEL_MAP;
427     }
428 
429     HiLog::Error(LABEL, "Inalued type!");
430     return TYPE_IMAGE_SOURCE;
431 }
432 
GetImageSourceFromNapi(napi_env env,napi_value value)433 static std::shared_ptr<ImageSource> GetImageSourceFromNapi(napi_env env, napi_value value)
434 {
435     if (env == nullptr || value == nullptr) {
436         HiLog::Error(LABEL, "GetImageSourceFromNapi input is null");
437     }
438     std::unique_ptr<ImageSourceNapi> imageSourceNapi = std::make_unique<ImageSourceNapi>();
439     napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&imageSourceNapi));
440     if (!IMG_IS_OK(status)) {
441         HiLog::Error(LABEL, "GetImageSourceFromNapi napi unwrap failed");
442         return nullptr;
443     }
444     if (imageSourceNapi == nullptr) {
445         HiLog::Error(LABEL, "GetImageSourceFromNapi imageSourceNapi is nullptr");
446         return nullptr;
447     }
448     return imageSourceNapi->nativeImgSrc;
449 }
450 
ParserPackingArguments(napi_env env,napi_value * argv,size_t argc,ImagePackerAsyncContext * context)451 static void ParserPackingArguments(napi_env env,
452     napi_value* argv, size_t argc, ImagePackerAsyncContext* context)
453 {
454     int32_t refCount = 1;
455     if (argc < PARAM1 || argc > PARAM3) {
456         BuildMsgOnError(env, context, (argc < PARAM1 || argc > PARAM3), "Arguments Count error");
457     }
458     context->packType = ParserPackingArgumentType(env, argv[PARAM0]);
459     if (context->packType == TYPE_IMAGE_SOURCE) {
460         context->rImageSource = GetImageSourceFromNapi(env, argv[PARAM0]);
461         BuildMsgOnError(env, context, context->rImageSource != nullptr, "ImageSource mismatch");
462     } else {
463         context->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[PARAM0]);
464         BuildMsgOnError(env, context, context->rPixelMap != nullptr, "PixelMap mismatch");
465     }
466     if (argc > PARAM1 && ImageNapiUtils::getType(env, argv[PARAM1]) == napi_object) {
467         BuildMsgOnError(env, context,
468             parsePackOptions(env, argv[PARAM1], &(context->packOption)), "PackOptions mismatch");
469         context->resultBufferSize = parseBufferSize(env, argv[PARAM1]);
470     }
471     if (argc > PARAM2 && ImageNapiUtils::getType(env, argv[PARAM2]) == napi_function) {
472         napi_create_reference(env, argv[PARAM2], refCount, &(context->callbackRef));
473     }
474 }
475 
Packing(napi_env env,napi_callback_info info)476 napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info)
477 {
478     napi_status status;
479     napi_value result = nullptr;
480     size_t argc = ARGS_THREE;
481     napi_value argv[ARGS_THREE] = {0};
482     napi_value thisVar = nullptr;
483 
484     HiLog::Debug(LABEL, "Packing IN");
485     napi_get_undefined(env, &result);
486 
487     IMG_JS_ARGS(env, info, status, argc, argv, thisVar);
488     NAPI_ASSERT(env, IMG_IS_OK(status), "fail to napi_get_cb_info");
489 
490     std::unique_ptr<ImagePackerAsyncContext> asyncContext = std::make_unique<ImagePackerAsyncContext>();
491     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
492     NAPI_ASSERT(env, IMG_IS_READY(status, asyncContext->constructor_), "fail to unwrap constructor_");
493 
494     asyncContext->rImagePacker = std::move(asyncContext->constructor_->nativeImgPck);
495     ParserPackingArguments(env, argv, argc, asyncContext.get());
496     if (asyncContext->callbackRef == nullptr) {
497         napi_create_promise(env, &(asyncContext->deferred), &result);
498     }
499 
500     ImageNapiUtils::HicheckerReport();
501 
502     if (asyncContext->errorMsg != nullptr) {
503         IMG_CREATE_CREATE_ASYNC_WORK(env, status, "PackingError",
504             [](napi_env env, void *data) {}, PackingErrorComplete, asyncContext, asyncContext->work);
505     } else {
506         IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Packing",
507             PackingExec, PackingComplete, asyncContext, asyncContext->work);
508     }
509 
510     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
511         nullptr, HiLog::Error(LABEL, "fail to create async work"));
512     return result;
513 }
514 
GetSupportedFormats(napi_env env,napi_callback_info info)515 napi_value ImagePackerNapi::GetSupportedFormats(napi_env env, napi_callback_info info)
516 {
517     napi_value result = nullptr;
518     napi_get_undefined(env, &result);
519 
520     napi_status status;
521     napi_value thisVar = nullptr;
522     size_t argCount = 0;
523     HiLog::Debug(LABEL, "GetSupportedFormats IN");
524 
525     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
526 
527     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
528 
529     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
530     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
531 
532     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
533         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
534     std::set<std::string> formats;
535     uint32_t ret = context->constructor_->nativeImgPck->GetSupportedFormats(formats);
536 
537     IMG_NAPI_CHECK_RET_D((ret == SUCCESS),
538         nullptr, HiLog::Error(LABEL, "fail to get supported formats"));
539 
540     napi_create_array(env, &result);
541     size_t i = 0;
542     for (const std::string& formatStr: formats) {
543         napi_value format = nullptr;
544         napi_create_string_latin1(env, formatStr.c_str(), formatStr.length(), &format);
545         napi_set_element(env, result, i, format);
546         i++;
547     }
548     return result;
549 }
550 
ReleaseComplete(napi_env env,napi_status status,void * data)551 static void ReleaseComplete(napi_env env, napi_status status, void *data)
552 {
553     HiLog::Debug(LABEL, "ReleaseComplete IN");
554     napi_value result = nullptr;
555     napi_get_undefined(env, &result);
556 
557     auto context = static_cast<ImagePackerAsyncContext*>(data);
558     context->constructor_->~ImagePackerNapi();
559     HiLog::Debug(LABEL, "ReleaseComplete OUT");
560     CommonCallbackRoutine(env, context, result);
561 }
562 
Release(napi_env env,napi_callback_info info)563 napi_value ImagePackerNapi::Release(napi_env env, napi_callback_info info)
564 {
565     HiLog::Debug(LABEL, "Release enter");
566     napi_value result = nullptr;
567     napi_get_undefined(env, &result);
568 
569     int32_t refCount = 1;
570     napi_status status;
571     napi_value thisVar = nullptr;
572     napi_value argValue[NUM_1] = {0};
573     size_t argCount = 1;
574 
575     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
576     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
577     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
578 
579     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
580     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
581 
582     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_), result,
583         HiLog::Error(LABEL, "fail to unwrap context"));
584     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
585     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
586         napi_create_reference(env, argValue[NUM_0], refCount, &context->callbackRef);
587     }
588 
589     if (context->callbackRef == nullptr) {
590         napi_create_promise(env, &(context->deferred), &result);
591     }
592 
593     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Release",
594         [](napi_env env, void *data) {}, ReleaseComplete, context, context->work);
595     HiLog::Debug(LABEL, "Release exit");
596     return result;
597 }
598 }  // namespace Media
599 }  // namespace OHOS
600