• 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 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
78 const int32_t TYPE_PICTURE = 3;
79 const int32_t TYPE_ARRAY = 4;
80 #endif
81 const int64_t DEFAULT_BUFFER_SIZE = 25 * 1024 * 1024; // 25M is the maximum default packedSize
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 };
112 
113 struct PackingOption {
114     std::string format;
115     uint8_t quality = 100;
116 };
117 
ImagePackerNapi()118 ImagePackerNapi::ImagePackerNapi():env_(nullptr)
119 {}
120 
~ImagePackerNapi()121 ImagePackerNapi::~ImagePackerNapi()
122 {
123     release();
124 }
125 
IsImagePackerErrorOccur(ImagePackerAsyncContext * ctx)126 static bool IsImagePackerErrorOccur(ImagePackerAsyncContext *ctx)
127 {
128     if (ctx == nullptr) {
129         return true;
130     }
131     if (ctx->error.hasErrorCode) {
132         return ctx->error.errorCode != SUCCESS;
133     }
134     return !ctx->error.msg.empty();
135 }
136 
ImagePackerErrorToNapiError(napi_env env,ImagePackerAsyncContext * ctx,napi_value & out)137 static void ImagePackerErrorToNapiError(napi_env env, ImagePackerAsyncContext *ctx, napi_value &out)
138 {
139     if (ctx == nullptr || ctx->status == SUCCESS) {
140         napi_get_undefined(env, &out);
141         return;
142     }
143 
144     auto msg = (ctx->error.msg.empty()) ? "Internal error" : ctx->error.msg;
145     if (!ctx->error.hasErrorCode) {
146         if (napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &out) != napi_ok) {
147             IMAGE_LOGE("Create error msg only error");
148         }
149         return;
150     }
151 
152     auto errorCode = (ctx->error.errorCode != SUCCESS) ? ctx->error.errorCode : ctx->status;
153     napi_value message;
154     napi_value code;
155     if (napi_create_object(env, &out) != napi_ok) {
156         IMAGE_LOGE("Create error object error");
157         return;
158     }
159     if (napi_create_int32(env, errorCode, &code) != napi_ok ||
160         napi_set_named_property(env, out, "code", code) != napi_ok) {
161         IMAGE_LOGE("Create error code error");
162         return;
163     }
164     if (napi_create_string_utf8(env, msg.c_str(), NAPI_AUTO_LENGTH, &message) != napi_ok ||
165         napi_set_named_property(env, out, "message", message) != napi_ok) {
166         IMAGE_LOGE("Create error msg error");
167         return;
168     }
169 }
170 
CommonCallbackRoutine(napi_env env,ImagePackerAsyncContext * & connect,const napi_value & valueParam)171 static void CommonCallbackRoutine(napi_env env, ImagePackerAsyncContext* &connect, const napi_value &valueParam)
172 {
173     if (connect == nullptr) {
174         return;
175     }
176     napi_value result[NUM_2] = {0};
177     napi_value retVal;
178     napi_value callback = nullptr;
179 
180     napi_get_undefined(env, &result[NUM_0]);
181     napi_get_undefined(env, &result[NUM_1]);
182 
183     if (connect->status == SUCCESS) {
184         result[NUM_1] = valueParam;
185     } else {
186         ImagePackerErrorToNapiError(env, connect, result[NUM_0]);
187     }
188 
189     if (connect->deferred) {
190         if (connect->status == SUCCESS) {
191             napi_resolve_deferred(env, connect->deferred, result[NUM_1]);
192         } else {
193             napi_reject_deferred(env, connect->deferred, result[NUM_0]);
194         }
195     } else {
196         napi_get_reference_value(env, connect->callbackRef, &callback);
197         napi_call_function(env, nullptr, callback, PARAM2, result, &retVal);
198         napi_delete_reference(env, connect->callbackRef);
199     }
200 
201     napi_delete_async_work(env, connect->work);
202 
203     delete connect;
204     connect = nullptr;
205 }
206 
BuildMsgOnError(ImagePackerAsyncContext * ctx,bool assertion,const std::string msg,int32_t errorCode)207 static void BuildMsgOnError(ImagePackerAsyncContext* ctx, bool assertion,
208     const std::string msg, int32_t errorCode)
209 {
210     if (ctx == nullptr || assertion) {
211         return;
212     }
213     IMAGE_LOGE("%{public}s", msg.c_str());
214     ctx->error.hasErrorCode = ctx->needReturnErrorCode;
215     ctx->error.errorCode = errorCode;
216     ctx->error.msg = msg;
217 }
218 
getDefaultBufferSize(int32_t width,int32_t height)219 static int64_t getDefaultBufferSize(int32_t width, int32_t height)
220 {
221     if (width <= SIZE_256 && height <= SIZE_256) {
222         return FILE_SIZE_300K;
223     }
224     if (width <= SIZE_512 && height <= SIZE_512) {
225         return FILE_SIZE_1M;
226     }
227     if (width <= SIZE_1024 && height <= SIZE_1024) {
228         return FILE_SIZE_4M;
229     }
230     if (width <= SIZE_1440 && height <= SIZE_1920) {
231         return FILE_SIZE_10M;
232     }
233     return DEFAULT_BUFFER_SIZE;
234 }
235 
getDefaultBufferSize(ImagePackerAsyncContext * context)236 static int64_t getDefaultBufferSize(ImagePackerAsyncContext *context)
237 {
238     if (context == nullptr) {
239         return DEFAULT_BUFFER_SIZE;
240     }
241     ImageInfo imageInfo {};
242     if (context->packType == TYPE_IMAGE_SOURCE) {
243         if (context->rImageSource == nullptr) {
244             return DEFAULT_BUFFER_SIZE;
245         }
246         context->rImageSource->GetImageInfo(imageInfo);
247     } else if (context->packType == TYPE_PIXEL_MAP) {
248         if (context->rPixelMap == nullptr) {
249             return DEFAULT_BUFFER_SIZE;
250         }
251         context->rPixelMap->GetImageInfo(imageInfo);
252     }
253     if (imageInfo.size.width <= 0 || imageInfo.size.height <= 0) {
254         return DEFAULT_BUFFER_SIZE;
255     }
256     return getDefaultBufferSize(imageInfo.size.width, imageInfo.size.height);
257 }
258 
STATIC_EXEC_FUNC(Packing)259 STATIC_EXEC_FUNC(Packing)
260 {
261     int64_t packedSize = 0;
262     auto context = static_cast<ImagePackerAsyncContext*>(data);
263     IMAGE_LOGD("ImagePacker BufferSize %{public}" PRId64, context->resultBufferSize);
264     context->resultBuffer = std::make_unique<uint8_t[]>(
265         (context->resultBufferSize <= 0) ? getDefaultBufferSize(context) : context->resultBufferSize);
266     int32_t innerEncodeErrorCode = static_cast<int32_t>(
267         context->packType == TYPE_PICTURE ? IMAGE_ENCODE_FAILED : ERR_IMAGE_ENCODE_FAILED);
268     if (context->resultBuffer == nullptr) {
269         BuildMsgOnError(context, false, "ImagePacker buffer alloc error", innerEncodeErrorCode);
270         return;
271     }
272     auto startRes = context->rImagePacker->StartPacking(context->resultBuffer.get(),
273         context->resultBufferSize, context->packOption);
274     if (startRes != SUCCESS) {
275         context->status = ERROR;
276         BuildMsgOnError(context, false, "Packing start packing failed",
277             startRes == ERR_IMAGE_INVALID_PARAMETER ? COMMON_ERR_INVALID_PARAMETER : innerEncodeErrorCode);
278         return;
279     }
280     if (context->packType == TYPE_IMAGE_SOURCE) {
281         IMAGE_LOGI("ImagePacker set image source");
282         if (context->rImageSource == nullptr) {
283             BuildMsgOnError(context, false, "ImageSource is nullptr", COMMON_ERR_INVALID_PARAMETER);
284             return;
285         }
286         context->rImagePacker->AddImage(*(context->rImageSource));
287     } else if (context->packType == TYPE_PIXEL_MAP) {
288         IMAGE_LOGD("ImagePacker set pixelmap");
289         if (context->rPixelMap == nullptr) {
290             BuildMsgOnError(context, false, "Pixelmap is nullptr", COMMON_ERR_INVALID_PARAMETER);
291             return;
292         }
293         context->rImagePacker->AddImage(*(context->rPixelMap));
294 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
295     } else if (context->packType == TYPE_PICTURE) {
296         IMAGE_LOGI("ImagePacker set picture");
297         if (context->rPicture == nullptr) {
298             BuildMsgOnError(context, context->rPicture == nullptr, "Picture is nullptr",
299                 COMMON_ERR_INVALID_PARAMETER);
300             return;
301         }
302         context->rImagePacker->AddPicture(*(context->rPicture));
303 #endif
304     }
305     auto packRes = context->rImagePacker->FinalizePacking(packedSize);
306     IMAGE_LOGD("packedSize=%{public}" PRId64, packedSize);
307     if (packRes == SUCCESS) {
308         context->packedSize = packedSize;
309         context->status = SUCCESS;
310     } else if (packedSize == context->resultBufferSize) {
311         context->status = ERROR;
312         if (context->packType == TYPE_PICTURE) {
313             BuildMsgOnError(context, false, "output buffer is not enough", IMAGE_ENCODE_FAILED);
314         } else {
315             BuildMsgOnError(context, false, "output buffer is not enough", ERR_IMAGE_TOO_LARGE);
316         }
317         IMAGE_LOGE("output buffer is not enough.");
318     } else {
319         context->status = ERROR;
320         IMAGE_LOGE("Packing failed, packedSize outside size.");
321         BuildMsgOnError(context, false, "Packing failed",
322             packRes == ERR_IMAGE_INVALID_PARAMETER ? COMMON_ERR_INVALID_PARAMETER : innerEncodeErrorCode);
323     }
324 }
325 
STATIC_COMPLETE_FUNC(PackingError)326 STATIC_COMPLETE_FUNC(PackingError)
327 {
328     napi_value result = nullptr;
329     napi_get_undefined(env, &result);
330     auto context = static_cast<ImagePackerAsyncContext*>(data);
331     context->status = ERROR;
332     CommonCallbackRoutine(env, context, result);
333 }
334 
STATIC_COMPLETE_FUNC(Packing)335 STATIC_COMPLETE_FUNC(Packing)
336 {
337     napi_value result = nullptr;
338     napi_get_undefined(env, &result);
339     auto context = static_cast<ImagePackerAsyncContext*>(data);
340 
341     if (!ImageNapiUtils::CreateArrayBuffer(env, context->resultBuffer.get(),
342                                            context->packedSize, &result)) {
343         context->status = ERROR;
344         IMAGE_LOGE("napi_create_arraybuffer failed!");
345         napi_get_undefined(env, &result);
346     } else {
347         context->status = SUCCESS;
348     }
349     context->resultBuffer = nullptr;
350     context->resultBufferSize = 0;
351     CommonCallbackRoutine(env, context, result);
352 }
353 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct ImageEnum> imageEnumMap)354 static napi_value CreateEnumTypeObject(napi_env env,
355     napi_valuetype type, napi_ref* ref, std::vector<struct ImageEnum> imageEnumMap)
356 {
357     napi_value result = nullptr;
358     napi_status status;
359     int32_t refCount = 1;
360     std::string propName;
361     status = napi_create_object(env, &result);
362     if (status == napi_ok) {
363         for (auto imgEnum : imageEnumMap) {
364             napi_value enumNapiValue = nullptr;
365             if (type == napi_string) {
366                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(),
367                     NAPI_AUTO_LENGTH, &enumNapiValue);
368             } else if (type == napi_number) {
369                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
370             } else {
371                 IMAGE_LOGE("Unsupported type %{public}d!", type);
372             }
373             if (status == napi_ok && enumNapiValue != nullptr) {
374                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
375             }
376             if (status != napi_ok) {
377                 IMAGE_LOGE("Failed to add named prop!");
378                 break;
379             }
380         }
381 
382         if (status == napi_ok) {
383             status = napi_create_reference(env, result, refCount, ref);
384             if (status == napi_ok) {
385                 return result;
386             }
387         }
388     }
389     IMAGE_LOGE("CreateEnumTypeObject is Failed!");
390     napi_get_undefined(env, &result);
391     return result;
392 }
393 
Init(napi_env env,napi_value exports)394 napi_value ImagePackerNapi::Init(napi_env env, napi_value exports)
395 {
396     napi_property_descriptor props[] = {
397         DECLARE_NAPI_FUNCTION("packing", Packing),
398         DECLARE_NAPI_FUNCTION("packToData", PackToData),
399         DECLARE_NAPI_FUNCTION("packToFile", PackToFile),
400         DECLARE_NAPI_FUNCTION("packingFromPixelMap", Packing),
401         DECLARE_NAPI_FUNCTION("release", Release),
402         DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats),
403     };
404     napi_property_descriptor static_prop[] = {
405         DECLARE_NAPI_STATIC_FUNCTION("createImagePacker", CreateImagePacker),
406         DECLARE_NAPI_PROPERTY("PackingDynamicRange",
407             CreateEnumTypeObject(env, napi_number, &packingDynamicRangeRef_, sPackingDynamicRangeMap)),
408     };
409 
410     napi_value constructor = nullptr;
411 
412     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
413         napi_define_class(env, CLASS_NAME_IMAGEPACKER.c_str(), NAPI_AUTO_LENGTH, Constructor,
414         nullptr, IMG_ARRAY_SIZE(props), props, &constructor)), nullptr,
415         IMAGE_LOGE("define class fail")
416     );
417 
418     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
419         napi_create_reference(env, constructor, 1, &sConstructor_)),
420         nullptr,
421         IMAGE_LOGE("create reference fail")
422     );
423 
424     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
425         napi_set_named_property(env, exports, CLASS_NAME_IMAGEPACKER.c_str(), constructor)),
426         nullptr,
427         IMAGE_LOGE("set named property fail")
428     );
429     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
430         napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
431         nullptr,
432         IMAGE_LOGE("define properties fail")
433     );
434 
435     IMAGE_LOGD("Init success");
436     return exports;
437 }
438 
Constructor(napi_env env,napi_callback_info info)439 napi_value ImagePackerNapi::Constructor(napi_env env, napi_callback_info info)
440 {
441     napi_value undefineVar = nullptr;
442     napi_get_undefined(env, &undefineVar);
443 
444     napi_status status;
445     napi_value thisVar = nullptr;
446 
447     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
448     if (status == napi_ok && thisVar != nullptr) {
449         std::unique_ptr<ImagePackerNapi> pImgPackerNapi = std::make_unique<ImagePackerNapi>();
450         if (pImgPackerNapi != nullptr) {
451             pImgPackerNapi->env_ = env;
452             pImgPackerNapi->nativeImgPck = sImgPck_;
453             sImgPck_ = nullptr;
454             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgPackerNapi.get()),
455                                ImagePackerNapi::Destructor, nullptr, nullptr);
456             if (status == napi_ok) {
457                 pImgPackerNapi.release();
458                 return thisVar;
459             } else {
460                 IMAGE_LOGE("Failure wrapping js to native napi");
461             }
462         }
463     }
464 
465     return undefineVar;
466 }
467 
CreateImagePacker(napi_env env,napi_callback_info info)468 napi_value ImagePackerNapi::CreateImagePacker(napi_env env, napi_callback_info info)
469 {
470     ImageTrace imageTrace("ImagePackerNapi::CreateImagePacker");
471     napi_value constructor = nullptr;
472     napi_value result = nullptr;
473     napi_status status;
474 
475     std::shared_ptr<ImagePacker> imagePacker = std::make_shared<ImagePacker>();
476     status = napi_get_reference_value(env, sConstructor_, &constructor);
477     if (IMG_IS_OK(status)) {
478         sImgPck_ = imagePacker;
479         status = napi_new_instance(env, constructor, 0, nullptr, &result);
480         if (status == napi_ok) {
481             return result;
482         } else {
483             IMAGE_LOGE("New instance could not be obtained");
484         }
485     }
486     return result;
487 }
488 
Destructor(napi_env env,void * nativeObject,void * finalize)489 void ImagePackerNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
490 {
491 }
492 
parseDynamicRange(napi_env env,napi_value root)493 static EncodeDynamicRange parseDynamicRange(napi_env env, napi_value root)
494 {
495     uint32_t tmpNumber = 0;
496     if (!GET_UINT32_BY_NAME(root, "desiredDynamicRange", tmpNumber)) {
497         return EncodeDynamicRange::SDR;
498     }
499     if (tmpNumber <= static_cast<uint32_t>(EncodeDynamicRange::SDR)) {
500         return EncodeDynamicRange(tmpNumber);
501     }
502     return EncodeDynamicRange::SDR;
503 }
504 
parseNeedsPackProperties(napi_env env,napi_value root)505 static bool parseNeedsPackProperties(napi_env env, napi_value root)
506 {
507     bool tmpNeedsPackProperties = false;
508     if (!GET_BOOL_BY_NAME(root, "needsPackProperties", tmpNeedsPackProperties)) {
509         IMAGE_LOGD("No needsPackProperties in pack option");
510     }
511     return tmpNeedsPackProperties;
512 }
513 
parseBufferSize(napi_env env,napi_value root,ImagePackerAsyncContext * context=nullptr)514 static int64_t parseBufferSize(napi_env env, napi_value root, ImagePackerAsyncContext *context = nullptr)
515 {
516     napi_value tempValue = nullptr;
517     int64_t defaultSize = getDefaultBufferSize(context);
518     int64_t tmpNumber = defaultSize;
519     if (napi_get_named_property(env, root, "bufferSize", &tempValue) != napi_ok) {
520         IMAGE_LOGI("No bufferSize, Using default");
521         return tmpNumber;
522     }
523     napi_get_value_int64(env, tempValue, &tmpNumber);
524     IMAGE_LOGD("BufferSize is %{public}" PRId64, tmpNumber);
525     if (tmpNumber < 0) {
526         return defaultSize;
527     }
528     return tmpNumber;
529 }
530 
parsePackOptionOfQuality(napi_env env,napi_value root,PackOption * opts)531 static bool parsePackOptionOfQuality(napi_env env, napi_value root, PackOption* opts)
532 {
533     uint32_t tmpNumber = 0;
534     if (!GET_UINT32_BY_NAME(root, "quality", tmpNumber)) {
535         IMAGE_LOGE("No quality in pack option");
536         return false;
537     }
538     if (tmpNumber > SIZE) {
539         IMAGE_LOGE("Invalid quality");
540         opts->quality = BYTE_FULL;
541     } else {
542         opts->quality = static_cast<uint8_t>(tmpNumber & 0xff);
543     }
544     return true;
545 }
546 
parsePackOptions(napi_env env,napi_value root,PackOption * opts)547 static bool parsePackOptions(napi_env env, napi_value root, PackOption* opts)
548 {
549     napi_value tmpValue = nullptr;
550 
551     if (!GET_NODE_BY_NAME(root, "format", tmpValue)) {
552         IMAGE_LOGE("No format in pack option");
553         return false;
554     }
555 
556     bool isFormatArray = false;
557     napi_is_array(env, tmpValue, &isFormatArray);
558     auto formatType = ImageNapiUtils::getType(env, tmpValue);
559 
560     IMAGE_LOGD("parsePackOptions format type %{public}d, is array %{public}d",
561         formatType, isFormatArray);
562 
563     char buffer[SIZE] = {0};
564     size_t res = 0;
565     if (napi_string == formatType) {
566         if (napi_get_value_string_utf8(env, tmpValue, buffer, SIZE, &res) != napi_ok) {
567             IMAGE_LOGE("Parse pack option format failed");
568             return false;
569         }
570         opts->format = std::string(buffer);
571     } else if (isFormatArray) {
572         uint32_t len = 0;
573         if (napi_get_array_length(env, tmpValue, &len) != napi_ok) {
574             IMAGE_LOGE("Parse pack napi_get_array_length failed");
575             return false;
576         }
577         IMAGE_LOGD("Parse pack array_length=%{public}u", len);
578         for (size_t i = 0; i < len; i++) {
579             napi_value item;
580             napi_get_element(env, tmpValue, i, &item);
581             if (napi_get_value_string_utf8(env, item, buffer, SIZE, &res) != napi_ok) {
582                 IMAGE_LOGE("Parse format in item failed %{public}zu", i);
583                 continue;
584             }
585             opts->format = std::string(buffer);
586             IMAGE_LOGD("format is %{public}s.", opts->format.c_str());
587         }
588     } else {
589         IMAGE_LOGE("Invalid pack option format type");
590         return false;
591     }
592     opts->desiredDynamicRange = parseDynamicRange(env, root);
593     IMAGE_LOGD("parsePackOptions format:[%{public}s]", opts->format.c_str());
594     opts->needsPackProperties = parseNeedsPackProperties(env, root);
595     return parsePackOptionOfQuality(env, root, opts);
596 }
597 
ParserPackingArgumentType(napi_env env,napi_value argv)598 static int32_t ParserPackingArgumentType(napi_env env, napi_value argv)
599 {
600     napi_value constructor = nullptr;
601     napi_value global = nullptr;
602     bool isInstance = false;
603     napi_status ret = napi_invalid_arg;
604 
605     napi_get_global(env, &global);
606 
607     ret = napi_get_named_property(env, global, "ImageSource", &constructor);
608     if (ret != napi_ok) {
609         IMAGE_LOGE("Get ImageSourceNapi property failed!");
610     }
611 
612     ret = napi_instanceof(env, argv, constructor, &isInstance);
613     if (ret == napi_ok && isInstance) {
614         IMAGE_LOGD("This is ImageSourceNapi type!");
615         return TYPE_IMAGE_SOURCE;
616     }
617 
618     ret = napi_get_named_property(env, global, "PixelMap", &constructor);
619     if (ret != napi_ok) {
620         IMAGE_LOGE("Get PixelMapNapi property failed!");
621     }
622 
623     ret = napi_instanceof(env, argv, constructor, &isInstance);
624     if (ret == napi_ok && isInstance) {
625         IMAGE_LOGD("This is PixelMapNapi type!");
626         return TYPE_PIXEL_MAP;
627     }
628 
629 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
630     ret = napi_get_named_property(env, global, "Picture", &constructor);
631     if (ret != napi_ok) {
632         IMAGE_LOGE("Get PictureNapi property failed!");
633     }
634 
635     ret = napi_instanceof(env, argv, constructor, &isInstance);
636     if (ret == napi_ok && isInstance) {
637         IMAGE_LOGD("This is PictureNapi type!");
638         return TYPE_PICTURE;
639     }
640 #endif
641 
642     IMAGE_LOGE("Invalid type!");
643     return TYPE_IMAGE_SOURCE;
644 }
645 
GetImageSourceFromNapi(napi_env env,napi_value value)646 static std::shared_ptr<ImageSource> GetImageSourceFromNapi(napi_env env, napi_value value)
647 {
648     if (env == nullptr || value == nullptr) {
649         IMAGE_LOGE("GetImageSourceFromNapi input is null");
650         return nullptr;
651     }
652     std::unique_ptr<ImageSourceNapi> imageSourceNapi = std::make_unique<ImageSourceNapi>();
653     napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&imageSourceNapi));
654     if (!IMG_IS_OK(status)) {
655         IMAGE_LOGE("GetImageSourceFromNapi napi unwrap failed");
656         return nullptr;
657     }
658     if (imageSourceNapi == nullptr) {
659         IMAGE_LOGE("GetImageSourceFromNapi imageSourceNapi is nullptr");
660         return nullptr;
661     }
662     return imageSourceNapi.release()->nativeImgSrc;
663 }
664 
ParserPackingArguments(napi_env env,napi_value * argv,size_t argc,ImagePackerAsyncContext * context)665 static void ParserPackingArguments(napi_env env,
666     napi_value* argv, size_t argc, ImagePackerAsyncContext* context)
667 {
668     int32_t refCount = 1;
669     if (argc < PARAM1 || argc > PARAM3) {
670         BuildMsgOnError(context, false, "Arguments Count error", COMMON_ERR_INVALID_PARAMETER);
671     }
672     context->packType = ParserPackingArgumentType(env, argv[PARAM0]);
673     if (context->packType == TYPE_PICTURE || context->packType == TYPE_ARRAY) {
674         context->needReturnErrorCode = true;
675     }
676     if (context->packType == TYPE_IMAGE_SOURCE) {
677         context->rImageSource = GetImageSourceFromNapi(env, argv[PARAM0]);
678         BuildMsgOnError(context, context->rImageSource != nullptr, "ImageSource mismatch",
679             COMMON_ERR_INVALID_PARAMETER);
680     } else if (context->packType == TYPE_PIXEL_MAP) {
681         context->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[PARAM0]);
682         BuildMsgOnError(context, context->rPixelMap != nullptr, "PixelMap mismatch",
683             COMMON_ERR_INVALID_PARAMETER);
684 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
685     } else if (context->packType == TYPE_PICTURE) {
686         context->rPicture = PictureNapi::GetPicture(env, argv[PARAM0]);
687         BuildMsgOnError(context, context->rPicture != nullptr, "Picture mismatch",
688             COMMON_ERR_INVALID_PARAMETER);
689 #endif
690     }
691     if (argc > PARAM1 && ImageNapiUtils::getType(env, argv[PARAM1]) == napi_object) {
692         BuildMsgOnError(context, parsePackOptions(env, argv[PARAM1], &(context->packOption)),
693             "PackOptions mismatch", COMMON_ERR_INVALID_PARAMETER);
694         context->resultBufferSize = parseBufferSize(env, argv[PARAM1], context);
695     }
696     if (argc > PARAM2 && ImageNapiUtils::getType(env, argv[PARAM2]) == napi_function) {
697         napi_create_reference(env, argv[PARAM2], refCount, &(context->callbackRef));
698     }
699 }
700 
Packing(napi_env env,napi_callback_info info,bool needReturnError)701 napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info, bool needReturnError)
702 {
703     ImageTrace imageTrace("ImagePackerNapi::Packing");
704     napi_status status;
705     napi_value result = nullptr;
706     size_t argc = ARGS_THREE;
707     napi_value argv[ARGS_THREE] = {0};
708     napi_value thisVar = nullptr;
709 
710     napi_get_undefined(env, &result);
711 
712     IMG_JS_ARGS(env, info, status, argc, argv, thisVar);
713     NAPI_ASSERT(env, IMG_IS_OK(status), "fail to napi_get_cb_info");
714 
715     std::unique_ptr<ImagePackerAsyncContext> asyncContext = std::make_unique<ImagePackerAsyncContext>();
716     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
717     NAPI_ASSERT(env, IMG_IS_READY(status, asyncContext->constructor_), "fail to unwrap constructor_");
718     asyncContext->needReturnErrorCode = needReturnError;
719 
720     asyncContext->rImagePacker = asyncContext->constructor_->nativeImgPck;
721     ParserPackingArguments(env, argv, argc, asyncContext.get());
722     if (asyncContext->callbackRef == nullptr) {
723         napi_create_promise(env, &(asyncContext->deferred), &result);
724     }
725 
726     ImageNapiUtils::HicheckerReport();
727 
728     if (IsImagePackerErrorOccur(asyncContext.get())) {
729         IMG_CREATE_CREATE_ASYNC_WORK(env, status, "PackingError",
730             [](napi_env env, void *data) {}, PackingErrorComplete, asyncContext, asyncContext->work);
731     } else {
732         IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "Packing",
733             PackingExec, PackingComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
734     }
735 
736     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
737         nullptr, IMAGE_LOGE("fail to create async work"));
738     return result;
739 }
740 
Packing(napi_env env,napi_callback_info info)741 napi_value ImagePackerNapi::Packing(napi_env env, napi_callback_info info)
742 {
743     return Packing(env, info, false);
744 }
745 
PackToData(napi_env env,napi_callback_info info)746 napi_value ImagePackerNapi::PackToData(napi_env env, napi_callback_info info)
747 {
748     return Packing(env, info, true);
749 }
750 
GetSupportedFormats(napi_env env,napi_callback_info info)751 napi_value ImagePackerNapi::GetSupportedFormats(napi_env env, napi_callback_info info)
752 {
753     napi_value result = nullptr;
754     napi_get_undefined(env, &result);
755 
756     napi_status status;
757     napi_value thisVar = nullptr;
758     size_t argCount = 0;
759 
760     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
761 
762     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
763 
764     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
765     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
766 
767     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
768         nullptr, IMAGE_LOGE("fail to unwrap context"));
769     std::set<std::string> formats;
770     uint32_t ret = context->constructor_->nativeImgPck->GetSupportedFormats(formats);
771 
772     IMG_NAPI_CHECK_RET_D((ret == SUCCESS),
773         nullptr, IMAGE_LOGE("fail to get supported formats"));
774 
775     napi_create_array(env, &result);
776     size_t i = 0;
777     for (const std::string& formatStr: formats) {
778         napi_value format = nullptr;
779         napi_create_string_latin1(env, formatStr.c_str(), formatStr.length(), &format);
780         napi_set_element(env, result, i, format);
781         i++;
782     }
783     return result;
784 }
785 
ReleaseComplete(napi_env env,napi_status status,void * data)786 static void ReleaseComplete(napi_env env, napi_status status, void *data)
787 {
788     napi_value result = nullptr;
789     napi_get_undefined(env, &result);
790 
791     auto context = static_cast<ImagePackerAsyncContext*>(data);
792     if (context != nullptr && context->constructor_ != nullptr) {
793         delete context->constructor_;
794         context->constructor_ = nullptr;
795     }
796     CommonCallbackRoutine(env, context, result);
797 }
798 
Release(napi_env env,napi_callback_info info)799 napi_value ImagePackerNapi::Release(napi_env env, napi_callback_info info)
800 {
801     ImageTrace imageTrace("ImagePackerNapi::Release");
802     napi_value result = nullptr;
803     napi_get_undefined(env, &result);
804 
805     int32_t refCount = 1;
806     napi_status status;
807     napi_value thisVar = nullptr;
808     napi_value argValue[NUM_1] = {0};
809     size_t argCount = 1;
810 
811     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
812     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
813     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
814 
815     std::unique_ptr<ImagePackerAsyncContext> context = std::make_unique<ImagePackerAsyncContext>();
816     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
817 
818     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_), result,
819         IMAGE_LOGE("fail to unwrap context"));
820     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
821     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
822         napi_create_reference(env, argValue[NUM_0], refCount, &context->callbackRef);
823     }
824 
825     if (context->callbackRef == nullptr) {
826         napi_create_promise(env, &(context->deferred), &result);
827     }
828 
829     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Release",
830         [](napi_env env, void *data) {}, ReleaseComplete, context, context->work);
831     return result;
832 }
833 
ParserPackToFileArguments(napi_env env,napi_value * argv,size_t argc,ImagePackerAsyncContext * context)834 static void ParserPackToFileArguments(napi_env env,
835     napi_value* argv, size_t argc, ImagePackerAsyncContext* context)
836 {
837     int32_t refCount = 1;
838     if (argc < PARAM1 || argc > PARAM4) {
839         BuildMsgOnError(context, (argc < PARAM1 || argc > PARAM4),
840             "Arguments Count error", ERR_IMAGE_INVALID_PARAMETER);
841     }
842     context->packType = ParserPackingArgumentType(env, argv[PARAM0]);
843     if (context->packType == TYPE_IMAGE_SOURCE) {
844         context->rImageSource = GetImageSourceFromNapi(env, argv[PARAM0]);
845         BuildMsgOnError(context, context->rImageSource != nullptr,
846             "ImageSource mismatch", ERR_IMAGE_INVALID_PARAMETER);
847     } else if (context->packType == TYPE_PIXEL_MAP) {
848         context->rPixelMap = PixelMapNapi::GetPixelMap(env, argv[PARAM0]);
849         BuildMsgOnError(context, context->rPixelMap != nullptr,
850             "PixelMap mismatch", ERR_IMAGE_INVALID_PARAMETER);
851 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
852     } else if (context->packType == TYPE_PICTURE) {
853         context->rPicture = PictureNapi::GetPicture(env, argv[PARAM0]);
854         BuildMsgOnError(context, context->rPicture != nullptr,
855             "Picture mismatch", ERR_IMAGE_INVALID_PARAMETER);
856 #endif
857     }
858     if (argc > PARAM1 && ImageNapiUtils::getType(env, argv[PARAM1]) == napi_number) {
859         BuildMsgOnError(context, (napi_get_value_int32(env, argv[PARAM1], &(context->fd)) == napi_ok &&
860             context->fd > INVALID_FD), "fd mismatch", ERR_IMAGE_INVALID_PARAMETER);
861     }
862     if (argc > PARAM2 && ImageNapiUtils::getType(env, argv[PARAM2]) == napi_object) {
863         BuildMsgOnError(context,
864             parsePackOptions(env, argv[PARAM2], &(context->packOption)),
865             "PackOptions mismatch", ERR_IMAGE_INVALID_PARAMETER);
866     }
867     if (argc > PARAM3 && ImageNapiUtils::getType(env, argv[PARAM3]) == napi_function) {
868         napi_create_reference(env, argv[PARAM3], refCount, &(context->callbackRef));
869     }
870 }
871 
872 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
SetPicture(ImagePackerAsyncContext * context)873 bool SetPicture(ImagePackerAsyncContext *context)
874 {
875     IMAGE_LOGD("ImagePacker set picture");
876     if (context->rPicture == nullptr) {
877         BuildMsgOnError(context, context->rImageSource == nullptr,
878             "Picture is nullptr", IMAGE_BAD_PARAMETER);
879         return false;
880     }
881     context->rImagePacker->AddPicture(*(context->rPicture));
882     return true;
883 }
884 #endif
885 
FinalizePacking(ImagePackerAsyncContext * context)886 static void FinalizePacking(ImagePackerAsyncContext* context)
887 {
888     int64_t packedSize = 0;
889     auto packRes = context->rImagePacker->FinalizePacking(packedSize);
890     IMAGE_LOGD("packRes=%{public}d packedSize=%{public}" PRId64, packRes, packedSize);
891     if (packRes == SUCCESS && packedSize > 0) {
892         context->packedSize = packedSize;
893         context->status = SUCCESS;
894     } else {
895         context->status = ERROR;
896         BuildMsgOnError(context, packRes == SUCCESS, "PackedSize outside size", packRes);
897         IMAGE_LOGE("Packing failed, packedSize outside size.");
898         if (context->packType == TYPE_PICTURE) {
899             BuildMsgOnError(context, packRes == SUCCESS, "PackToFile picture failed",
900                 packRes == ERR_IMAGE_INVALID_PARAMETER ? IMAGE_BAD_PARAMETER : IMAGE_ENCODE_FAILED);
901         }
902     }
903 }
904 
STATIC_EXEC_FUNC(PackToFile)905 STATIC_EXEC_FUNC(PackToFile)
906 {
907     auto context = static_cast<ImagePackerAsyncContext*>(data);
908     if (context->fd <= INVALID_FD) {
909         BuildMsgOnError(context, context->fd <= INVALID_FD, "ImagePacker invalid fd", ERR_IMAGE_INVALID_PARAMETER);
910         return;
911     }
912 
913     auto startRes = context->rImagePacker->StartPacking(context->fd, context->packOption);
914     if (startRes != SUCCESS) {
915         context->status = ERROR;
916         BuildMsgOnError(context, startRes == SUCCESS, "Start packing failed", startRes);
917         return;
918     }
919     if (context->packType == TYPE_IMAGE_SOURCE) {
920         IMAGE_LOGD("ImagePacker set image source");
921         if (context->rImageSource == nullptr) {
922             BuildMsgOnError(context, context->rImageSource == nullptr,
923                 "ImageSource is nullptr", ERR_IMAGE_INVALID_PARAMETER);
924             return;
925         }
926         context->rImagePacker->AddImage(*(context->rImageSource));
927     } else if (context->packType == TYPE_PIXEL_MAP) {
928         IMAGE_LOGD("ImagePacker set pixelmap");
929         if (context->rPixelMap == nullptr) {
930             BuildMsgOnError(context, context->rImageSource == nullptr,
931                 "Pixelmap is nullptr", ERR_IMAGE_INVALID_PARAMETER);
932             return;
933         }
934         context->rImagePacker->AddImage(*(context->rPixelMap));
935 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
936     } else if (context->packType == TYPE_PICTURE) {
937         if (!SetPicture(context)) {
938             return;
939         }
940 #endif
941     }
942     FinalizePacking(context);
943 }
944 
STATIC_COMPLETE_FUNC(PackToFile)945 STATIC_COMPLETE_FUNC(PackToFile)
946 {
947     napi_value result = nullptr;
948     napi_get_undefined(env, &result);
949     auto context = static_cast<ImagePackerAsyncContext*>(data);
950     CommonCallbackRoutine(env, context, result);
951 }
952 
PackToFile(napi_env env,napi_callback_info info)953 napi_value ImagePackerNapi::PackToFile(napi_env env, napi_callback_info info)
954 {
955     ImageTrace imageTrace("ImagePackerNapi::PackToFile");
956     napi_status status;
957     napi_value result = nullptr;
958     size_t argc = ARGS_FOUR;
959     napi_value argv[ARGS_FOUR] = {0};
960     napi_value thisVar = nullptr;
961 
962     napi_get_undefined(env, &result);
963 
964     IMG_JS_ARGS(env, info, status, argc, argv, thisVar);
965     NAPI_ASSERT(env, IMG_IS_OK(status), "fail to napi_get_cb_info");
966 
967     std::unique_ptr<ImagePackerAsyncContext> asyncContext = std::make_unique<ImagePackerAsyncContext>();
968     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
969     NAPI_ASSERT(env, IMG_IS_READY(status, asyncContext->constructor_), "fail to unwrap constructor_");
970 
971     asyncContext->rImagePacker = asyncContext->constructor_->nativeImgPck;
972     ParserPackToFileArguments(env, argv, argc, asyncContext.get());
973     if (asyncContext->callbackRef == nullptr) {
974         napi_create_promise(env, &(asyncContext->deferred), &result);
975     }
976 
977     ImageNapiUtils::HicheckerReport();
978 
979     if (IsImagePackerErrorOccur(asyncContext.get())) {
980         IMG_CREATE_CREATE_ASYNC_WORK(env, status, "PackingError",
981             [](napi_env env, void *data) {}, PackingErrorComplete, asyncContext, asyncContext->work);
982     } else {
983         IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "PackToFile",
984             PackToFileExec, PackToFileComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
985     }
986 
987     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
988         nullptr, IMAGE_LOGE("fail to create async work"));
989     return result;
990 }
release()991 void ImagePackerNapi::release()
992 {
993     if (!isRelease) {
994         nativeImgPck = nullptr;
995         isRelease = true;
996     }
997 }
GetNative(ImagePackerNapi * napi)998 std::shared_ptr<ImagePacker> ImagePackerNapi::GetNative(ImagePackerNapi* napi)
999 {
1000     if (napi != nullptr) {
1001         return napi->nativeImgPck;
1002     }
1003     return nullptr;
1004 }
1005 }  // namespace Media
1006 }  // namespace OHOS
1007