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