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