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