• 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 
18 #include "image_common.h"
19 #include "image_log.h"
20 #include "image_napi_utils.h"
21 #include "image_packer.h"
22 #include "image_source.h"
23 #include "image_source_napi.h"
24 #include "image_trace.h"
25 #include "media_errors.h"
26 #include "pixel_map_napi.h"
27 
28 #undef LOG_DOMAIN
29 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
30 
31 #undef LOG_TAG
32 #define LOG_TAG "ImagePackerNapi"
33 
34 namespace {
35     constexpr uint32_t NUM_0 = 0;
36     constexpr uint32_t NUM_1 = 1;
37     constexpr uint32_t NUM_2 = 2;
38     constexpr int32_t INVALID_FD = -1;
39     constexpr int32_t SIZE_256 = 256;
40     constexpr int32_t SIZE_512 = 512;
41     constexpr int32_t SIZE_1024 = 1024;
42     constexpr int32_t SIZE_1440 = 1440;
43     constexpr int32_t SIZE_1920 = 1920;
44     constexpr int64_t FILE_SIZE_300K = 300 * 1024;
45     constexpr int64_t FILE_SIZE_1M = 1 * 1024 * 1024;
46     constexpr int64_t FILE_SIZE_4M = 4 * 1024 * 1024;
47     constexpr int64_t FILE_SIZE_10M = 10 * 1024 * 1024;
48 }
49 
50 namespace OHOS {
51 namespace Media {
52 static const std::string CLASS_NAME_IMAGEPACKER = "ImagePacker";
53 thread_local std::shared_ptr<ImagePacker> ImagePackerNapi::sImgPck_ = nullptr;
54 thread_local napi_ref ImagePackerNapi::sConstructor_ = nullptr;
55 napi_ref ImagePackerNapi::packingDynamicRangeRef_ = nullptr;
56 struct ImageEnum {
57     std::string name;
58     int32_t numVal;
59     std::string strVal;
60 };
61 static std::vector<struct ImageEnum> sPackingDynamicRangeMap = {
62     {"AUTO", 0, ""},
63     {"SDR", 1, ""},
64 };
65 
66 const int ARGS_THREE = 3;
67 const int ARGS_FOUR = 4;
68 const int PARAM0 = 0;
69 const int PARAM1 = 1;
70 const int PARAM2 = 2;
71 const int PARAM3 = 3;
72 const int PARAM4 = 4;
73 const uint8_t BYTE_FULL = 0xFF;
74 const int32_t SIZE = 100;
75 const int32_t TYPE_IMAGE_SOURCE = 1;
76 const int32_t TYPE_PIXEL_MAP = 2;
77 const int32_t TYPE_PICTURE = 3;
78 const int32_t TYPE_ARRAY = 4;
79 const int64_t DEFAULT_BUFFER_SIZE = 25 * 1024 * 1024; // 25M is the maximum default packedSize
80 const int MASK_3 = 0x3;
81 const int MASK_16 = 0xffff;
82 
83 struct ImagePackerError {
84     bool hasErrorCode = false;
85     int32_t errorCode = SUCCESS;
86     std::string msg;
87 };
88 
89 struct ImagePackerAsyncContext {
90     napi_env env;
91     napi_async_work work;
92     napi_deferred deferred;
93     napi_ref callbackRef = nullptr;
94     ImagePackerNapi *constructor_;
95     bool status = false;
96     std::shared_ptr<ImageSource> rImageSource;
97     PackOption packOption;
98     std::shared_ptr<ImagePacker> rImagePacker;
99     std::shared_ptr<PixelMap> rPixelMap;
100 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
101     std::shared_ptr<Picture> rPicture;
102 #endif
103     std::shared_ptr<std::vector<std::shared_ptr<PixelMap>>> rPixelMaps;
104     std::unique_ptr<uint8_t[]> resultBuffer;
105     int32_t packType = TYPE_IMAGE_SOURCE;
106     int64_t resultBufferSize = 0;
107     int64_t packedSize = 0;
108     int fd = INVALID_FD;
109     ImagePackerError error;
110     bool needReturnErrorCode = true;
111     uint32_t frameCount;
112 };
113 
114 struct PackingOption {
115     std::string format;
116     uint8_t quality = 100;
117 };
118 
ImagePackerNapi()119 ImagePackerNapi::ImagePackerNapi():env_(nullptr)
120 {}
121 
~ImagePackerNapi()122 ImagePackerNapi::~ImagePackerNapi()
123 {
124     release();
125 }
126 
IsImagePackerErrorOccur(ImagePackerAsyncContext * ctx)127 static bool IsImagePackerErrorOccur(ImagePackerAsyncContext *ctx)
128 {
129     if (ctx == nullptr) {
130         return true;
131     }
132     if (ctx->error.hasErrorCode) {
133         return ctx->error.errorCode != SUCCESS;
134     }
135     return !ctx->error.msg.empty();
136 }
137 
ImagePackerErrorToNapiError(napi_env env,ImagePackerAsyncContext * ctx,napi_value & out)138 static void ImagePackerErrorToNapiError(napi_env env, ImagePackerAsyncContext *ctx, napi_value &out)
139 {
140     if (ctx == nullptr || ctx->status == SUCCESS) {
141         napi_get_undefined(env, &out);
142         return;
143     }
144 
145     auto msg = (ctx->error.msg.empty()) ? "Internal error" : ctx->error.msg;
146     if (!ctx->error.hasErrorCode) {
147         if (napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &out) != napi_ok) {
148             IMAGE_LOGE("Create error msg only error");
149         }
150         return;
151     }
152 
153     auto errorCode = (ctx->error.errorCode != SUCCESS) ? ctx->error.errorCode : ctx->status;
154     napi_value message;
155     napi_value code;
156     if (napi_create_object(env, &out) != napi_ok) {
157         IMAGE_LOGE("Create error object error");
158         return;
159     }
160     if (napi_create_int32(env, errorCode, &code) != napi_ok ||
161         napi_set_named_property(env, out, "code", code) != napi_ok) {
162         IMAGE_LOGE("Create error code error");
163         return;
164     }
165     if (napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &message) != napi_ok ||
166         napi_set_named_property(env, out, "message", message) != napi_ok) {
167         IMAGE_LOGE("Create error msg error");
168         return;
169     }
170 }
171 
CommonCallbackRoutine(napi_env env,ImagePackerAsyncContext * & connect,const napi_value & valueParam)172 static void CommonCallbackRoutine(napi_env env, ImagePackerAsyncContext* &connect, const napi_value &valueParam)
173 {
174     if (connect == nullptr) {
175         return;
176     }
177     napi_value result[NUM_2] = {0};
178     napi_value retVal;
179     napi_value callback = nullptr;
180 
181     napi_get_undefined(env, &result[NUM_0]);
182     napi_get_undefined(env, &result[NUM_1]);
183 
184     if (connect->status == SUCCESS) {
185         result[NUM_1] = valueParam;
186     } else {
187         ImagePackerErrorToNapiError(env, connect, result[NUM_0]);
188     }
189 
190     if (connect->deferred) {
191         if (connect->status == SUCCESS) {
192             napi_resolve_deferred(env, connect->deferred, result[NUM_1]);
193         } else {
194             napi_reject_deferred(env, connect->deferred, result[NUM_0]);
195         }
196     } else {
197         napi_get_reference_value(env, connect->callbackRef, &callback);
198         napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
199         napi_delete_reference(env, connect->callbackRef);
200     }
201 
202     napi_delete_async_work(env, connect->work);
203 
204     delete connect;
205     connect = nullptr;
206 }
207 
BuildMsgOnError(ImagePackerAsyncContext * ctx,bool assertion,const std::string msg,int32_t errorCode)208 static void BuildMsgOnError(ImagePackerAsyncContext* ctx, bool assertion,
209     const std::string msg, int32_t errorCode)
210 {
211     if (ctx == nullptr || assertion) {
212         return;
213     }
214     IMAGE_LOGE("%{public}s", msg.c_str());
215     ctx->error.hasErrorCode = ctx->needReturnErrorCode;
216     ctx->error.errorCode = errorCode;
217     ctx->error.msg = msg;
218 }
219 
getDefaultBufferSize(int32_t width,int32_t height)220 static int64_t getDefaultBufferSize(int32_t width, int32_t height)
221 {
222     if (width <= SIZE_256 && height <= SIZE_256) {
223         return FILE_SIZE_300K;
224     }
225     if (width <= SIZE_512 && height <= SIZE_512) {
226         return FILE_SIZE_1M;
227     }
228     if (width <= SIZE_1024 && height <= SIZE_1024) {
229         return FILE_SIZE_4M;
230     }
231     if (width <= SIZE_1440 && height <= SIZE_1920) {
232         return FILE_SIZE_10M;
233     }
234     return DEFAULT_BUFFER_SIZE;
235 }
236 
getDefaultBufferSize(ImagePackerAsyncContext * context)237 static int64_t getDefaultBufferSize(ImagePackerAsyncContext *context)
238 {
239     if (context == nullptr) {
240         return DEFAULT_BUFFER_SIZE;
241     }
242     ImageInfo imageInfo {};
243     if (context->packType == TYPE_IMAGE_SOURCE) {
244         if (context->rImageSource == nullptr) {
245             return DEFAULT_BUFFER_SIZE;
246         }
247         context->rImageSource->GetImageInfo(imageInfo);
248     } else if (context->packType == TYPE_PIXEL_MAP) {
249         if (context->rPixelMap == nullptr) {
250             return DEFAULT_BUFFER_SIZE;
251         }
252         context->rPixelMap->GetImageInfo(imageInfo);
253     }
254     if (imageInfo.size.width <= 0 || imageInfo.size.height <= 0) {
255         return DEFAULT_BUFFER_SIZE;
256     }
257     return getDefaultBufferSize(imageInfo.size.width, imageInfo.size.height);
258 }
259 
260 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
SetPicture(ImagePackerAsyncContext * context)261 bool SetPicture(ImagePackerAsyncContext *context)
262 {
263     IMAGE_LOGD("ImagePacker set picture");
264     if (context->rPicture == nullptr) {
265         BuildMsgOnError(context, context->rImageSource == nullptr,
266             "Picture is nullptr", IMAGE_BAD_PARAMETER);
267         return false;
268     }
269     context->rImagePacker->AddPicture(*(context->rPicture));
270     return true;
271 }
272 #endif
273 
SetArrayPixel(ImagePackerAsyncContext * context)274 bool SetArrayPixel(ImagePackerAsyncContext *context)
275 {
276     IMAGE_LOGD("ImagePacker set pixelmap array");
277     if (!context->rPixelMaps) {
278         BuildMsgOnError(context, false, "PixelmapList is nullptr", COMMON_ERR_INVALID_PARAMETER);
279         return false;
280     }
281     for (auto &pixelMap : *context->rPixelMaps.get()) {
282         context->rImagePacker->AddImage(*(pixelMap.get()));
283     }
284     return true;
285 }
286 
STATIC_EXEC_FUNC(Packing)287 STATIC_EXEC_FUNC(Packing)
288 {
289     int64_t packedSize = 0;
290     auto context = static_cast<ImagePackerAsyncContext*>(data);
291     IMAGE_LOGD("ImagePacker BufferSize %{public}" PRId64, context->resultBufferSize);
292     context->resultBuffer = std::make_unique<uint8_t[]>(
293         (context->resultBufferSize <= 0) ? getDefaultBufferSize(context) : context->resultBufferSize);
294     int32_t innerEncodeErrorCode = static_cast<int32_t>(
295         context->packType == TYPE_PICTURE ? IMAGE_ENCODE_FAILED : ERR_IMAGE_ENCODE_FAILED);
296     if (context->resultBuffer == nullptr) {
297         BuildMsgOnError(context, false, "ImagePacker buffer alloc error", innerEncodeErrorCode);
298         return;
299     }
300     auto startRes = context->rImagePacker->StartPacking(context->resultBuffer.get(),
301         context->resultBufferSize, context->packOption);
302     if (startRes != SUCCESS) {
303         context->status = ERROR;
304         BuildMsgOnError(context, false, "Packing start packing failed",
305             startRes == ERR_IMAGE_INVALID_PARAMETER ? COMMON_ERR_INVALID_PARAMETER : innerEncodeErrorCode);
306         return;
307     }
308     if (context->packType == TYPE_IMAGE_SOURCE) {
309         IMAGE_LOGI("ImagePacker set image source");
310         if (context->rImageSource == nullptr) {
311             BuildMsgOnError(context, false, "ImageSource is nullptr", COMMON_ERR_INVALID_PARAMETER);
312             return;
313         }
314         context->rImagePacker->AddImage(*(context->rImageSource));
315     } else if (context->packType == TYPE_PIXEL_MAP) {
316         IMAGE_LOGD("ImagePacker set pixelmap");
317         if (context->rPixelMap == nullptr) {
318             BuildMsgOnError(context, false, "Pixelmap is nullptr", COMMON_ERR_INVALID_PARAMETER);
319             return;
320         }
321         context->rImagePacker->AddImage(*(context->rPixelMap));
322 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
323     } else if (context->packType == TYPE_PICTURE) {
324         if (!SetPicture(context)) {
325             return;
326         }
327 #endif
328     } else if (context->packType == TYPE_ARRAY) {
329         if (!SetArrayPixel(context)) {
330             return;
331         }
332     }
333     auto packRes = context->rImagePacker->FinalizePacking(packedSize);
334     IMAGE_LOGD("packedSize=%{public}" PRId64, packedSize);
335     if (packRes == SUCCESS) {
336         context->packedSize = packedSize;
337         context->status = SUCCESS;
338     } else if (packedSize == context->resultBufferSize) {
339         context->status = ERROR;
340         if (context->packType == TYPE_PICTURE) {
341             BuildMsgOnError(context, false, "output buffer is not enough", IMAGE_ENCODE_FAILED);
342         } else {
343             BuildMsgOnError(context, false, "output buffer is not enough", ERR_IMAGE_TOO_LARGE);
344         }
345         IMAGE_LOGE("output buffer is not enough.");
346     } else {
347         context->status = ERROR;
348         IMAGE_LOGE("Packing failed, packedSize outside size.");
349         BuildMsgOnError(context, false, "Packing failed",
350             packRes == ERR_IMAGE_INVALID_PARAMETER ? COMMON_ERR_INVALID_PARAMETER : innerEncodeErrorCode);
351     }
352 }
353 
PackingErrorSendEvent(napi_env env,ImagePackerAsyncContext * context,napi_event_priority prio)354 static bool PackingErrorSendEvent(napi_env env, ImagePackerAsyncContext* context,
355                                   napi_event_priority prio)
356 {
357     auto task = [env, context]() {
358         napi_value result = nullptr;
359         napi_get_undefined(env, &result);
360         context->status = ERROR;
361         CommonCallbackRoutine(env, const_cast<ImagePackerAsyncContext *&>(context), result);
362     };
363     if (napi_status::napi_ok != napi_send_event(env, task, prio)) {
364         IMAGE_LOGE("PackingErrorSendEvent: failed to SendEvent!");
365         return false;
366     }
367     return true;
368 }
369 
STATIC_COMPLETE_FUNC(Packing)370 STATIC_COMPLETE_FUNC(Packing)
371 {
372     napi_value result = nullptr;
373     napi_get_undefined(env, &result);
374     auto context = static_cast<ImagePackerAsyncContext*>(data);
375 
376     if (!ImageNapiUtils::CreateArrayBuffer(env, context->resultBuffer.get(),
377                                            context->packedSize, &result)) {
378         context->status = ERROR;
379         IMAGE_LOGE("napi_create_arraybuffer failed!");
380         napi_get_undefined(env, &result);
381     } else {
382         context->status = SUCCESS;
383     }
384     context->resultBuffer = nullptr;
385     context->resultBufferSize = 0;
386     CommonCallbackRoutine(env, context, result);
387 }
388 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct ImageEnum> imageEnumMap)389 static napi_value CreateEnumTypeObject(napi_env env,
390     napi_valuetype type, napi_ref* ref, std::vector<struct ImageEnum> imageEnumMap)
391 {
392     napi_value result = nullptr;
393     napi_status status;
394     int32_t refCount = 1;
395     std::string propName;
396     status = napi_create_object(env, &result);
397     if (status == napi_ok) {
398         for (auto imgEnum : imageEnumMap) {
399             napi_value enumNapiValue = nullptr;
400             if (type == napi_string) {
401                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(),
402                     NAPI_AUTO_LENGTH, &enumNapiValue);
403             } else if (type == napi_number) {
404                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
405             } else {
406                 IMAGE_LOGE("Unsupported type %{public}d!", type);
407             }
408             if (status == napi_ok && enumNapiValue != nullptr) {
409                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
410             }
411             if (status != napi_ok) {
412                 IMAGE_LOGE("Failed to add named prop!");
413                 break;
414             }
415         }
416 
417         if (status == napi_ok) {
418             status = napi_create_reference(env, result, refCount, ref);
419             if (status == napi_ok) {
420                 return result;
421             }
422         }
423     }
424     IMAGE_LOGE("CreateEnumTypeObject is Failed!");
425     napi_get_undefined(env, &result);
426     return result;
427 }
428 
Init(napi_env env,napi_value exports)429 napi_value ImagePackerNapi::Init(napi_env env, napi_value exports)
430 {
431     napi_property_descriptor props[] = {
432         DECLARE_NAPI_FUNCTION("packing", Packing),
433         DECLARE_NAPI_FUNCTION("packToData", PackToData),
434         DECLARE_NAPI_FUNCTION("packToFile", PackToFile),
435         DECLARE_NAPI_FUNCTION("packingFromPixelMap", Packing),
436         DECLARE_NAPI_FUNCTION("packToDataFromPixelmapSequence", PackToData),
437         DECLARE_NAPI_FUNCTION("packToFileFromPixelmapSequence", PackToFile),
438         DECLARE_NAPI_FUNCTION("release", Release),
439         DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats),
440     };
441     napi_property_descriptor static_prop[] = {
442         DECLARE_NAPI_STATIC_FUNCTION("createImagePacker", CreateImagePacker),
443         DECLARE_NAPI_PROPERTY("PackingDynamicRange",
444             CreateEnumTypeObject(env, napi_number, &packingDynamicRangeRef_, sPackingDynamicRangeMap)),
445     };
446 
447     napi_value constructor = nullptr;
448 
449     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
450         napi_define_class(env, CLASS_NAME_IMAGEPACKER.c_str(), NAPI_AUTO_LENGTH, Constructor,
451         nullptr, IMG_ARRAY_SIZE(props), props, &constructor)), nullptr,
452         IMAGE_LOGE("define class fail")
453     );
454 
455     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
456         napi_create_reference(env, constructor, 1, &sConstructor_)),
457         nullptr,
458         IMAGE_LOGE("create reference fail")
459     );
460 
461     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
462         napi_set_named_property(env, exports, CLASS_NAME_IMAGEPACKER.c_str(), constructor)),
463         nullptr,
464         IMAGE_LOGE("set named property fail")
465     );
466     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
467         napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
468         nullptr,
469         IMAGE_LOGE("define properties fail")
470     );
471 
472     IMAGE_LOGD("Init success");
473     return exports;
474 }
475 
Constructor(napi_env env,napi_callback_info info)476 napi_value ImagePackerNapi::Constructor(napi_env env, napi_callback_info info)
477 {
478     napi_value undefineVar = nullptr;
479     napi_get_undefined(env, &undefineVar);
480 
481     napi_status status;
482     napi_value thisVar = nullptr;
483 
484     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
485     if (status == napi_ok && thisVar != nullptr) {
486         std::unique_ptr<ImagePackerNapi> pImgPackerNapi = std::make_unique<ImagePackerNapi>();
487         if (pImgPackerNapi != nullptr) {
488             pImgPackerNapi->env_ = env;
489             pImgPackerNapi->nativeImgPck = sImgPck_;
490             sImgPck_ = nullptr;
491             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgPackerNapi.get()),
492                                ImagePackerNapi::Destructor, nullptr, nullptr);
493             if (status == napi_ok) {
494                 pImgPackerNapi.release();
495                 return thisVar;
496             } else {
497                 IMAGE_LOGE("Failure wrapping js to native napi");
498             }
499         }
500     }
501 
502     return undefineVar;
503 }
504 
CreateImagePacker(napi_env env,napi_callback_info info)505 napi_value ImagePackerNapi::CreateImagePacker(napi_env env, napi_callback_info info)
506 {
507     ImageTrace imageTrace("ImagePackerNapi::CreateImagePacker");
508     napi_value constructor = nullptr;
509     napi_value result = nullptr;
510     napi_status status;
511 
512     std::shared_ptr<ImagePacker> imagePacker = std::make_shared<ImagePacker>();
513     status = napi_get_reference_value(env, sConstructor_, &constructor);
514     if (IMG_IS_OK(status)) {
515         sImgPck_ = imagePacker;
516         status = napi_new_instance(env, constructor, 0, nullptr, &result);
517         if (status == napi_ok) {
518             return result;
519         } else {
520             IMAGE_LOGE("New instance could not be obtained");
521         }
522     }
523     return result;
524 }
525 
Destructor(napi_env env,void * nativeObject,void * finalize)526 void ImagePackerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
527 {
528 }
529 
parseDynamicRange(napi_env env,napi_value root)530 static EncodeDynamicRange parseDynamicRange(napi_env env, napi_value root)
531 {
532     uint32_t tmpNumber = 0;
533     if (!GET_UINT32_BY_NAME(root, "desiredDynamicRange", tmpNumber)) {
534         return EncodeDynamicRange::SDR;
535     }
536     if (tmpNumber <= static_cast<uint32_t>(EncodeDynamicRange::SDR)) {
537         return EncodeDynamicRange(tmpNumber);
538     }
539     return EncodeDynamicRange::SDR;
540 }
541 
parseNeedsPackProperties(napi_env env,napi_value root)542 static bool parseNeedsPackProperties(napi_env env, napi_value root)
543 {
544     bool tmpNeedsPackProperties = false;
545     if (!GET_BOOL_BY_NAME(root, "needsPackProperties", tmpNeedsPackProperties)) {
546         IMAGE_LOGD("No needsPackProperties in pack option");
547     }
548     return tmpNeedsPackProperties;
549 }
550 
parseBufferSize(napi_env env,napi_value root,ImagePackerAsyncContext * context=nullptr)551 static int64_t parseBufferSize(napi_env env, napi_value root, ImagePackerAsyncContext *context = nullptr)
552 {
553     napi_value tempValue = nullptr;
554     int64_t defaultSize = getDefaultBufferSize(context);
555     int64_t tmpNumber = defaultSize;
556     if (napi_get_named_property(env, root, "bufferSize", &tempValue) != napi_ok) {
557         IMAGE_LOGI("No bufferSize, Using default");
558         return tmpNumber;
559     }
560     napi_get_value_int64(env, tempValue, &tmpNumber);
561     IMAGE_LOGD("BufferSize is %{public}" PRId64, tmpNumber);
562     if (tmpNumber < 0) {
563         return defaultSize;
564     }
565     return tmpNumber;
566 }
567 
handlePixelMapList(ImagePackerAsyncContext * context)568 static bool handlePixelMapList(ImagePackerAsyncContext* context)
569 {
570     if (context->frameCount == 0) {
571         IMAGE_LOGE("Parameter input error, invalid frameCount");
572         return false;
573     }
574     if (context->rPixelMaps == nullptr || context->rPixelMaps->empty()) {
575         IMAGE_LOGE("Parameter input error, pixelmaplist is empty");
576         return false;
577     }
578     uint32_t pixelMapListLength = context->rPixelMaps->size();
579     if (pixelMapListLength > context->frameCount) {
580         for (uint32_t i = pixelMapListLength; i > context->frameCount; i--) {
581             context->rPixelMaps->pop_back();
582         }
583     } else if (pixelMapListLength < context->frameCount) {
584         for (uint32_t i = pixelMapListLength; i < context->frameCount; i++) {
585             context->rPixelMaps->push_back((*context->rPixelMaps)[pixelMapListLength - 1]);
586         }
587     }
588     return true;
589 }
590 
parsePackOptionOfdelayTimes(napi_env env,napi_value root,ImagePackerAsyncContext * context)591 static bool parsePackOptionOfdelayTimes(napi_env env, napi_value root, ImagePackerAsyncContext* context)
592 {
593     napi_value tmpValue = nullptr;
594     if (!GET_NODE_BY_NAME(root, "delayTimeList", tmpValue)) {
595         IMAGE_LOGE("No delayTimeList in pack option");
596         return false;
597     }
598     bool isDelayTimesArray = false;
599     napi_is_array(env, tmpValue, &isDelayTimesArray);
600     if (isDelayTimesArray) {
601         int32_t num;
602         uint32_t len = 0;
603         if (napi_get_array_length(env, tmpValue, &len) != napi_ok || len == 0) {
604             IMAGE_LOGE("Parse pack napi_get_array_length failed");
605             return false;
606         }
607         for (size_t i = 0; i < len; i++) {
608             napi_value item;
609             napi_get_element(env, tmpValue, i, &item);
610             if (napi_get_value_int32(env, item, &num) != napi_ok) {
611                 IMAGE_LOGE("Parse delayTime in item failed %{public}zu", i);
612                 return false;
613             }
614             if (num <= 0 || num > MASK_16) {
615                 IMAGE_LOGE("Invalid delayTime, out of range");
616                 return false;
617             }
618             context->packOption.delayTimes.push_back(static_cast<uint16_t>(num) & static_cast<uint16_t>(MASK_16));
619         }
620         if (len < context->frameCount) {
621             for (uint32_t i = len; i < context->frameCount; i++) {
622                 context->packOption.delayTimes.push_back(static_cast<uint16_t>(num) & static_cast<uint16_t>(MASK_16));
623             }
624         }
625     }
626     return true;
627 }
628 
parsePackOptionOfFrameCout(napi_env env,napi_value root,ImagePackerAsyncContext * context)629 static bool parsePackOptionOfFrameCout(napi_env env, napi_value root, ImagePackerAsyncContext* context)
630 {
631     napi_value tmpValue = nullptr;
632     if (!GET_NODE_BY_NAME(root, "frameCount", tmpValue)) {
633         IMAGE_LOGE("No frameCount in pack option");
634         return false;
635     }
636     uint32_t count = 0;
637     napi_get_value_uint32(env, tmpValue, &count);
638     context->frameCount = count;
639     if (!handlePixelMapList(context)) {
640         return false;
641     }
642     return parsePackOptionOfdelayTimes(env, root, context);
643 }
644 
parsePackOptionOfdisposalTypes(napi_env env,napi_value root,PackOption * opts)645 static bool parsePackOptionOfdisposalTypes(napi_env env, napi_value root, PackOption* opts)
646 {
647     napi_value tmpValue = nullptr;
648     GET_NODE_BY_NAME(root, "disposalTypes", tmpValue);
649     bool isDisposalTypesArray = false;
650     napi_is_array(env, tmpValue, &isDisposalTypesArray);
651     if (isDisposalTypesArray) {
652         int32_t num;
653         uint32_t len = 0;
654         if (napi_get_array_length(env, tmpValue, &len) != napi_ok) {
655             IMAGE_LOGE("Parse pack napi_get_array_length failed");
656             return false;
657         }
658         for (size_t i = 0; i < len; i++) {
659             napi_value item;
660             napi_get_element(env, tmpValue, i, &item);
661             if (napi_get_value_int32(env, item, &num) != napi_ok) {
662                 IMAGE_LOGE("Parse disposalTypes in item failed %{public}zu", i);
663                 return false;
664             }
665             if (num < 0 || num > MASK_3) {
666                 IMAGE_LOGE("Invalid disposalTypes, out of range");
667                 return false;
668             }
669             opts->disposalTypes.push_back(static_cast<uint8_t>(num) & static_cast<uint8_t>(MASK_3));
670         }
671     }
672     return true;
673 }
674 
parsePackOptionOfLoop(napi_env env,napi_value root,ImagePackerAsyncContext * context)675 static bool parsePackOptionOfLoop(napi_env env, napi_value root, ImagePackerAsyncContext* context)
676 {
677     napi_value nullValue;
678     napi_get_null(env, &nullValue);
679     if (root == nullValue) {
680         IMAGE_LOGE("PackingOptionsForSequence is null");
681         return false;
682     }
683     context->packOption.format = "image/gif";
684     int32_t tmpNumber = 0;
685     if (!GET_INT32_BY_NAME(root, "loopCount", tmpNumber)) {
686         tmpNumber = 1;
687     }
688     if (tmpNumber < 0 || tmpNumber > MASK_16) {
689         IMAGE_LOGE("Invalid loopCount");
690         return false;
691     }
692     context->packOption.loop = static_cast<uint16_t>(tmpNumber) & static_cast<uint16_t>(MASK_16);
693     return parsePackOptionOfFrameCout(env, root, context);
694 }
695 
parsePackOptionOfQuality(napi_env env,napi_value root,PackOption * opts)696 static bool parsePackOptionOfQuality(napi_env env, napi_value root, PackOption* opts)
697 {
698     uint32_t tmpNumber = 0;
699     if (!GET_UINT32_BY_NAME(root, "quality", tmpNumber)) {
700         IMAGE_LOGE("No quality in pack option");
701         return false;
702     }
703     if (tmpNumber > SIZE) {
704         IMAGE_LOGE("Invalid quality");
705         opts->quality = BYTE_FULL;
706     } else {
707         opts->quality = static_cast<uint8_t>(tmpNumber & 0xff);
708     }
709     return true;
710 }
711 
parsePackOptions(napi_env env,napi_value root,PackOption * opts)712 static bool parsePackOptions(napi_env env, napi_value root, PackOption* opts)
713 {
714     napi_value tmpValue = nullptr;
715 
716     if (!GET_NODE_BY_NAME(root, "format", tmpValue)) {
717         IMAGE_LOGE("No format in pack option");
718         return false;
719     }
720 
721     bool isFormatArray = false;
722     napi_is_array(env, tmpValue, &isFormatArray);
723     auto formatType = ImageNapiUtils::getType(env, tmpValue);
724 
725     IMAGE_LOGD("parsePackOptions format type %{public}d, is array %{public}d",
726         formatType, isFormatArray);
727 
728     char buffer[SIZE] = {0};
729     size_t res = 0;
730     if (napi_string == formatType) {
731         if (napi_get_value_string_utf8(env, tmpValue, buffer, SIZE, &res) != napi_ok) {
732             IMAGE_LOGE("Parse pack option format failed");
733             return false;
734         }
735         opts->format = std::string(buffer);
736     } else if (isFormatArray) {
737         uint32_t len = 0;
738         if (napi_get_array_length(env, tmpValue, &len) != napi_ok) {
739             IMAGE_LOGE("Parse pack napi_get_array_length failed");
740             return false;
741         }
742         IMAGE_LOGD("Parse pack array_length=%{public}u", len);
743         for (size_t i = 0; i < len; i++) {
744             napi_value item;
745             napi_get_element(env, tmpValue, i, &item);
746             if (napi_get_value_string_utf8(env, item, buffer, SIZE, &res) != napi_ok) {
747                 IMAGE_LOGE("Parse format in item failed %{public}zu", i);
748                 continue;
749             }
750             opts->format = std::string(buffer);
751             IMAGE_LOGD("format is %{public}s.", opts->format.c_str());
752         }
753     } else {
754         IMAGE_LOGE("Invalid pack option format type");
755         return false;
756     }
757     opts->desiredDynamicRange = parseDynamicRange(env, root);
758     IMAGE_LOGI("parsePackOptions format:[%{public}s]", opts->format.c_str());
759     opts->needsPackProperties = parseNeedsPackProperties(env, root);
760     return parsePackOptionOfQuality(env, root, opts);
761 }
762 
ParserPackingArgumentType(napi_env env,napi_value argv)763 static int32_t ParserPackingArgumentType(napi_env env, napi_value argv)
764 {
765     napi_value constructor = nullptr;
766     napi_value global = nullptr;
767     bool isInstance = false;
768     napi_status ret = napi_invalid_arg;
769 
770     ret = napi_is_array(env, argv, &isInstance);
771     if (ret == napi_ok && isInstance) {
772         IMAGE_LOGD("This is Array type!");
773         return TYPE_ARRAY;
774     }
775     napi_get_global(env, &global);
776 
777     ret = napi_get_named_property(env, global, "ImageSource", &constructor);
778     if (ret != napi_ok) {
779         IMAGE_LOGE("Get ImageSourceNapi property failed!");
780     }
781 
782     ret = napi_instanceof(env, argv, constructor, &isInstance);
783     if (ret == napi_ok && isInstance) {
784         IMAGE_LOGD("This is ImageSourceNapi type!");
785         return TYPE_IMAGE_SOURCE;
786     }
787 
788     ret = napi_get_named_property(env, global, "PixelMap", &constructor);
789     if (ret != napi_ok) {
790         IMAGE_LOGE("Get PixelMapNapi property failed!");
791     }
792 
793     ret = napi_instanceof(env, argv, constructor, &isInstance);
794     if (ret == napi_ok && isInstance) {
795         IMAGE_LOGD("This is PixelMapNapi type!");
796         return TYPE_PIXEL_MAP;
797     }
798 
799 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
800     ret = napi_get_named_property(env, global, "Picture", &constructor);
801     if (ret != napi_ok) {
802         IMAGE_LOGE("Get PictureNapi property failed!");
803     }
804 
805     ret = napi_instanceof(env, argv, constructor, &isInstance);
806     if (ret == napi_ok && isInstance) {
807         IMAGE_LOGD("This is PictureNapi type!");
808         return TYPE_PICTURE;
809     }
810 #endif
811 
812     IMAGE_LOGE("Invalid type!");
813     return TYPE_IMAGE_SOURCE;
814 }
815 
GetImageSourceFromNapi(napi_env env,napi_value value)816 static std::shared_ptr<ImageSource> GetImageSourceFromNapi(napi_env env, napi_value value)
817 {
818     if (env == nullptr || value == nullptr) {
819         IMAGE_LOGE("GetImageSourceFromNapi input is null");
820         return nullptr;
821     }
822     std::unique_ptr<ImageSourceNapi> imageSourceNapi = std::make_unique<ImageSourceNapi>();
823     napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&imageSourceNapi));
824     if (!IMG_IS_OK(status)) {
825         IMAGE_LOGE("GetImageSourceFromNapi napi unwrap failed");
826         return nullptr;
827     }
828     if (imageSourceNapi == nullptr) {
829         IMAGE_LOGE("GetImageSourceFromNapi imageSourceNapi is nullptr");
830         return nullptr;
831     }
832     return imageSourceNapi.release()->nativeImgSrc;
833 }
834 
ParserPackingArguments(napi_env env,napi_value * argv,size_t argc,ImagePackerAsyncContext * context)835 static void ParserPackingArguments(napi_env env,
836     napi_value* argv, size_t argc, ImagePackerAsyncContext* context)
837 {
838     int32_t refCount = 1;
839     if (argc < PARAM1 || argc > PARAM3) {
840         BuildMsgOnError(context, false, "Arguments Count error", COMMON_ERR_INVALID_PARAMETER);
841     }
842     context->packType = ParserPackingArgumentType(env, argv[PARAM0]);
843     if (context->packType == TYPE_PICTURE || context->packType == TYPE_ARRAY) {
844         context->needReturnErrorCode = true;
845     }
846     if (context->packType == TYPE_IMAGE_SOURCE) {
847         context->rImageSource = GetImageSourceFromNapi(env, argv[PARAM0]);
848         BuildMsgOnError(context, context->rImageSource != nullptr, "ImageSource mismatch",
849             COMMON_ERR_INVALID_PARAMETER);
850     } else if (context->packType == TYPE_PIXEL_MAP) {
851         context->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[PARAM0]);
852         BuildMsgOnError(context, context->rPixelMap != nullptr, "Pixelmap is released",
853             COMMON_ERR_INVALID_PARAMETER);
854 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
855     } else if (context->packType == TYPE_PICTURE) {
856         context->rPicture = PictureNapi::GetPicture(env, argv[PARAM0]);
857         BuildMsgOnError(context, context->rPicture != nullptr, "Picture mismatch",
858             COMMON_ERR_INVALID_PARAMETER);
859 #endif
860     } else if (context->packType == TYPE_ARRAY) {
861         context->needReturnErrorCode = true;
862         context->rPixelMaps = PixelMapNapi::GetPixelMaps(env, argv[PARAM0]);
863         BuildMsgOnError(context, context->rPixelMaps != nullptr,
864             "PixelMap mismatch", COMMON_ERR_INVALID_PARAMETER);
865     }
866     if (argc > PARAM1 && ImageNapiUtils::getType(env, argv[PARAM1]) == napi_object) {
867         if (context->packType == TYPE_ARRAY) {
868             BuildMsgOnError(context,
869                 parsePackOptionOfLoop(env, argv[PARAM1], context),
870                 "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
871             context->resultBufferSize = parseBufferSize(env, argv[PARAM1]);
872             BuildMsgOnError(context,
873                 parsePackOptionOfdisposalTypes(env, argv[PARAM1], &(context->packOption)),
874                 "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
875         } else {
876             BuildMsgOnError(context, parsePackOptions(env, argv[PARAM1], &(context->packOption)),
877                 "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
878             context->resultBufferSize = parseBufferSize(env, argv[PARAM1], context);
879         }
880     }
881     if (argc > PARAM2 && ImageNapiUtils::getType(env, argv[PARAM2]) == napi_function) {
882         napi_create_reference(env, argv[PARAM2], refCount, &(context->callbackRef));
883     }
884 }
885 
Packing(napi_env env,napi_callback_info info,bool needReturnError)886 napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info, bool needReturnError)
887 {
888     ImageTrace imageTrace("ImagePackerNapi::Packing");
889     IMAGE_LOGI("PackingFromNapi IN");
890     napi_status status;
891     napi_value result = nullptr;
892     size_t argc = ARGS_THREE;
893     napi_value argv[ARGS_THREE] = {0};
894     napi_value thisVar = nullptr;
895 
896     napi_get_undefined(env, &result);
897 
898     IMG_JS_ARGS(env, info, status, argc, argv, thisVar);
899     NAPI_ASSERT(env, IMG_IS_OK(status), "fail to napi_get_cb_info");
900 
901     std::unique_ptr<ImagePackerAsyncContext> asyncContext = std::make_unique<ImagePackerAsyncContext>();
902     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
903     NAPI_ASSERT(env, IMG_IS_READY(status, asyncContext->constructor_), "fail to unwrap constructor_");
904     asyncContext->needReturnErrorCode = needReturnError;
905 
906     asyncContext->rImagePacker = asyncContext->constructor_->nativeImgPck;
907     ParserPackingArguments(env, argv, argc, asyncContext.get());
908     if (asyncContext->callbackRef == nullptr) {
909         napi_create_promise(env, &(asyncContext->deferred), &result);
910     }
911 
912     ImageNapiUtils::HicheckerReport();
913 
914     if (IsImagePackerErrorOccur(asyncContext.get())) {
915         if (PackingErrorSendEvent(env, asyncContext.get(), napi_eprio_high)) {
916             asyncContext.release();
917         }
918     } else {
919         IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "Packing",
920             PackingExec, PackingComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
921     }
922 
923     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
924         nullptr, IMAGE_LOGE("fail to create async work"));
925     return result;
926 }
927 
Packing(napi_env env,napi_callback_info info)928 napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info)
929 {
930     return Packing(env, info, false);
931 }
932 
PackToData(napi_env env,napi_callback_info info)933 napi_value ImagePackerNapi::PackToData(napi_env env, napi_callback_info info)
934 {
935     return Packing(env, info, true);
936 }
937 
GetSupportedFormats(napi_env env,napi_callback_info info)938 napi_value ImagePackerNapi::GetSupportedFormats(napi_env env, napi_callback_info info)
939 {
940     napi_value result = nullptr;
941     napi_get_undefined(env, &result);
942 
943     napi_status status;
944     napi_value thisVar = nullptr;
945     size_t argCount = 0;
946 
947     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
948 
949     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
950 
951     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
952     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
953 
954     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
955         nullptr, IMAGE_LOGE("fail to unwrap context"));
956     std::set<std::string> formats;
957     uint32_t ret = context->constructor_->nativeImgPck->GetSupportedFormats(formats);
958 
959     IMG_NAPI_CHECK_RET_D((ret == SUCCESS),
960         nullptr, IMAGE_LOGE("fail to get supported formats"));
961 
962     napi_create_array(env, &result);
963     size_t i = 0;
964     for (const std::string& formatStr: formats) {
965         napi_value format = nullptr;
966         napi_create_string_latin1(env, formatStr.c_str(), formatStr.length(), &format);
967         napi_set_element(env, result, i, format);
968         i++;
969     }
970     return result;
971 }
972 
ReleaseSendEvent(napi_env env,ImagePackerAsyncContext * context,napi_event_priority prio)973 static bool ReleaseSendEvent(napi_env env, ImagePackerAsyncContext* context,
974                              napi_event_priority prio)
975 {
976     auto task = [env, context]() {
977         napi_value result = nullptr;
978         napi_get_undefined(env, &result);
979 
980         if (context != nullptr && context->constructor_ != nullptr) {
981             delete context->constructor_;
982             context->constructor_ = nullptr;
983         }
984         CommonCallbackRoutine(env, const_cast<ImagePackerAsyncContext *&>(context), result);
985     };
986     if (napi_status::napi_ok != napi_send_event(env, task, prio)) {
987         IMAGE_LOGE("ReleaseSendEvent: failed to SendEvent!");
988         return false;
989     }
990     return true;
991 }
992 
Release(napi_env env,napi_callback_info info)993 napi_value ImagePackerNapi::Release(napi_env env, napi_callback_info info)
994 {
995     ImageTrace imageTrace("ImagePackerNapi::Release");
996     napi_value result = nullptr;
997     napi_get_undefined(env, &result);
998 
999     int32_t refCount = 1;
1000     napi_status status;
1001     napi_value thisVar = nullptr;
1002     napi_value argValue[NUM_1] = {0};
1003     size_t argCount = 1;
1004 
1005     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1006     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
1007     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
1008 
1009     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
1010     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1011 
1012     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_), result,
1013         IMAGE_LOGE("fail to unwrap context"));
1014     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
1015     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
1016         napi_create_reference(env, argValue[NUM_0], refCount, &context->callbackRef);
1017     }
1018 
1019     if (context->callbackRef == nullptr) {
1020         napi_create_promise(env, &(context->deferred), &result);
1021     }
1022 
1023     if (ReleaseSendEvent(env, context.get(), napi_eprio_high)) {
1024         context.release();
1025     }
1026     return result;
1027 }
1028 
ParserPackToFileArguments(napi_env env,napi_value * argv,size_t argc,ImagePackerAsyncContext * context)1029 static void ParserPackToFileArguments(napi_env env,
1030     napi_value* argv, size_t argc, ImagePackerAsyncContext* context)
1031 {
1032     int32_t refCount = 1;
1033     if (argc < PARAM1 || argc > PARAM4) {
1034         BuildMsgOnError(context, false, "Arguments Count error", ERR_IMAGE_INVALID_PARAMETER);
1035     }
1036     context->packType = ParserPackingArgumentType(env, argv[PARAM0]);
1037     if (context->packType == TYPE_IMAGE_SOURCE) {
1038         context->rImageSource = GetImageSourceFromNapi(env, argv[PARAM0]);
1039         BuildMsgOnError(context, context->rImageSource != nullptr,
1040             "ImageSource mismatch", ERR_IMAGE_INVALID_PARAMETER);
1041     } else if (context->packType == TYPE_PIXEL_MAP) {
1042         context->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[PARAM0]);
1043         BuildMsgOnError(context, context->rPixelMap != nullptr,
1044             "Pixelmap is released", ERR_IMAGE_INVALID_PARAMETER);
1045 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1046     } else if (context->packType == TYPE_PICTURE) {
1047         context->rPicture = PictureNapi::GetPicture(env, argv[PARAM0]);
1048         BuildMsgOnError(context, context->rPicture != nullptr,
1049             "Picture mismatch", COMMON_ERR_INVALID_PARAMETER);
1050 #endif
1051     } else if (context->packType == TYPE_ARRAY) {
1052         context->rPixelMaps = PixelMapNapi::GetPixelMaps(env, argv[PARAM0]);
1053         BuildMsgOnError(context, context->rPixelMaps != nullptr, "PixelMap mismatch", COMMON_ERR_INVALID_PARAMETER);
1054     }
1055     if (argc > PARAM1 && ImageNapiUtils::getType(env, argv[PARAM1]) == napi_number) {
1056         uint32_t errorCode = ((context->packType == TYPE_PICTURE ||
1057             context->packType == TYPE_ARRAY)) ? IMAGE_BAD_PARAMETER : ERR_IMAGE_INVALID_PARAMETER;
1058         BuildMsgOnError(context, (napi_get_value_int32(env, argv[PARAM1], &(context->fd)) == napi_ok &&
1059             context->fd > INVALID_FD), "fd mismatch", errorCode);
1060     }
1061     if (argc > PARAM2 && ImageNapiUtils::getType(env, argv[PARAM2]) == napi_object) {
1062         if (context->packType == TYPE_ARRAY) {
1063             BuildMsgOnError(context, parsePackOptionOfLoop(env, argv[PARAM2], context),
1064                 "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
1065             BuildMsgOnError(context, parsePackOptionOfdisposalTypes(env, argv[PARAM2], &(context->packOption)),
1066                 "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
1067         } else {
1068             BuildMsgOnError(context, parsePackOptions(env, argv[PARAM2], &(context->packOption)),
1069                 "PackOptions mismatch", ERR_IMAGE_INVALID_PARAMETER);
1070         }
1071     }
1072     if (argc > PARAM3 && ImageNapiUtils::getType(env, argv[PARAM3]) == napi_function) {
1073         napi_create_reference(env, argv[PARAM3], refCount, &(context->callbackRef));
1074     }
1075 }
1076 
FinalizePacking(ImagePackerAsyncContext * context)1077 static void FinalizePacking(ImagePackerAsyncContext* context)
1078 {
1079     int64_t packedSize = 0;
1080     auto packRes = context->rImagePacker->FinalizePacking(packedSize);
1081     IMAGE_LOGD("packRes=%{public}d packedSize=%{public}" PRId64, packRes, packedSize);
1082     if (packRes == SUCCESS && packedSize > 0) {
1083         context->packedSize = packedSize;
1084         context->status = SUCCESS;
1085     } else {
1086         context->status = ERROR;
1087         BuildMsgOnError(context, packRes == SUCCESS, "PackedSize outside size", packRes);
1088         IMAGE_LOGE("Packing failed, packedSize outside size.");
1089         if (context->packType == TYPE_PICTURE) {
1090             BuildMsgOnError(context, packRes == SUCCESS, "PackToFile picture failed",
1091                 packRes == ERR_IMAGE_INVALID_PARAMETER ? IMAGE_BAD_PARAMETER : IMAGE_ENCODE_FAILED);
1092         }
1093     }
1094 }
1095 
STATIC_EXEC_FUNC(PackToFile)1096 STATIC_EXEC_FUNC(PackToFile)
1097 {
1098     auto context = static_cast<ImagePackerAsyncContext*>(data);
1099     if (context->fd <= INVALID_FD) {
1100         uint32_t errorCode = ((context->packType == TYPE_PICTURE) ||
1101             (context->packType == TYPE_ARRAY)) ? IMAGE_BAD_PARAMETER : ERR_IMAGE_INVALID_PARAMETER;
1102         BuildMsgOnError(context, false, "ImagePacker invalid fd", errorCode);
1103         return;
1104     }
1105 
1106     auto startRes = context->rImagePacker->StartPacking(context->fd, context->packOption);
1107     if (startRes != SUCCESS) {
1108         context->status = ERROR;
1109         if (context->packType == TYPE_PICTURE) {
1110             BuildMsgOnError(context, startRes == SUCCESS, "PackToFile start packing failed",
1111                 startRes == ERR_IMAGE_INVALID_PARAMETER ? IMAGE_BAD_PARAMETER : IMAGE_ENCODE_FAILED);
1112             return;
1113         }
1114         BuildMsgOnError(context, startRes == SUCCESS, "Start packing failed", startRes);
1115         return;
1116     }
1117     if (context->packType == TYPE_IMAGE_SOURCE) {
1118         IMAGE_LOGD("ImagePacker set image source");
1119         if (!context->rImageSource) {
1120             BuildMsgOnError(context, !context->rImageSource, "ImageSource is nullptr", ERR_IMAGE_INVALID_PARAMETER);
1121             return;
1122         }
1123         context->rImagePacker->AddImage(*(context->rImageSource));
1124     } else if (context->packType == TYPE_PIXEL_MAP) {
1125         IMAGE_LOGD("ImagePacker set pixelmap");
1126         if (!context->rPixelMap) {
1127             BuildMsgOnError(context, !context->rImageSource, "Pixelmap is nullptr", ERR_IMAGE_INVALID_PARAMETER);
1128             return;
1129         }
1130         context->rImagePacker->AddImage(*(context->rPixelMap));
1131 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
1132     } else if (context->packType == TYPE_PICTURE) {
1133         if (!SetPicture(context)) {
1134             return;
1135         }
1136 #endif
1137     } else if (context->packType == TYPE_ARRAY) {
1138         if (!SetArrayPixel(context)) {
1139             return;
1140         }
1141     }
1142     FinalizePacking(context);
1143 }
1144 
STATIC_COMPLETE_FUNC(PackToFile)1145 STATIC_COMPLETE_FUNC(PackToFile)
1146 {
1147     napi_value result = nullptr;
1148     napi_get_undefined(env, &result);
1149     auto context = static_cast<ImagePackerAsyncContext*>(data);
1150     CommonCallbackRoutine(env, context, result);
1151 }
1152 
PackToFile(napi_env env,napi_callback_info info)1153 napi_value ImagePackerNapi::PackToFile(napi_env env, napi_callback_info info)
1154 {
1155     ImageTrace imageTrace("ImagePackerNapi::PackToFile");
1156     napi_status status;
1157     napi_value result = nullptr;
1158     size_t argc = ARGS_FOUR;
1159     napi_value argv[ARGS_FOUR] = {0};
1160     napi_value thisVar = nullptr;
1161 
1162     napi_get_undefined(env, &result);
1163 
1164     IMG_JS_ARGS(env, info, status, argc, argv, thisVar);
1165     NAPI_ASSERT(env, IMG_IS_OK(status), "fail to napi_get_cb_info");
1166 
1167     std::unique_ptr<ImagePackerAsyncContext> asyncContext = std::make_unique<ImagePackerAsyncContext>();
1168     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1169     NAPI_ASSERT(env, IMG_IS_READY(status, asyncContext->constructor_), "fail to unwrap constructor_");
1170 
1171     asyncContext->rImagePacker = asyncContext->constructor_->nativeImgPck;
1172     ParserPackToFileArguments(env, argv, argc, asyncContext.get());
1173     if (asyncContext->callbackRef == nullptr) {
1174         napi_create_promise(env, &(asyncContext->deferred), &result);
1175     }
1176 
1177     ImageNapiUtils::HicheckerReport();
1178 
1179     if (IsImagePackerErrorOccur(asyncContext.get())) {
1180         if (PackingErrorSendEvent(env, asyncContext.get(), napi_eprio_high)) {
1181             asyncContext.release();
1182         }
1183     } else {
1184         IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "PackToFile",
1185             PackToFileExec, PackToFileComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
1186     }
1187 
1188     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1189         nullptr, IMAGE_LOGE("fail to create async work"));
1190     return result;
1191 }
release()1192 void ImagePackerNapi::release()
1193 {
1194     if (!isRelease) {
1195         nativeImgPck = nullptr;
1196         isRelease = true;
1197     }
1198 }
GetNative(ImagePackerNapi * napi)1199 std::shared_ptr<ImagePacker> ImagePackerNapi::GetNative(ImagePackerNapi* napi)
1200 {
1201     if (napi != nullptr) {
1202         return napi->nativeImgPck;
1203     }
1204     return nullptr;
1205 }
1206 }  // namespace Media
1207 }  // namespace OHOS
1208