• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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_source_napi.h"
17 #include <fcntl.h>
18 #include "hilog/log.h"
19 #include "image_napi_utils.h"
20 #include "media_errors.h"
21 #include "string_ex.h"
22 #include "image_trace.h"
23 #include "hitrace_meter.h"
24 
25 using OHOS::HiviewDFX::HiLog;
26 namespace {
27     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN, "ImageSourceNapi"};
28     constexpr int INVALID_FD = -1;
29     constexpr uint32_t NUM_0 = 0;
30     constexpr uint32_t NUM_1 = 1;
31     constexpr uint32_t NUM_2 = 2;
32     constexpr uint32_t NUM_3 = 3;
33     constexpr uint32_t NUM_4 = 4;
34     constexpr uint32_t NUM_5 = 5;
35     constexpr uint32_t NUM_8 = 8;
36 }
37 
38 namespace OHOS {
39 namespace Media {
40 thread_local napi_ref ImageSourceNapi::sConstructor_ = nullptr;
41 std::shared_ptr<ImageSource> ImageSourceNapi::sImgSrc_ = nullptr;
42 std::shared_ptr<IncrementalPixelMap> ImageSourceNapi::sIncPixelMap_ = nullptr;
43 static const std::string CLASS_NAME = "ImageSource";
44 static const std::string FILE_URL_PREFIX = "file://";
45 std::string ImageSourceNapi::filePath_ = "";
46 int ImageSourceNapi::fileDescriptor_ = -1;
47 void* ImageSourceNapi::fileBuffer_ = nullptr;
48 size_t ImageSourceNapi::fileBufferSize_ = 0;
49 
50 napi_ref ImageSourceNapi::pixelMapFormatRef_ = nullptr;
51 napi_ref ImageSourceNapi::propertyKeyRef_ = nullptr;
52 napi_ref ImageSourceNapi::imageFormatRef_ = nullptr;
53 napi_ref ImageSourceNapi::alphaTypeRef_ = nullptr;
54 napi_ref ImageSourceNapi::scaleModeRef_ = nullptr;
55 napi_ref ImageSourceNapi::componentTypeRef_ = nullptr;
56 
57 struct ImageSourceAsyncContext {
58     napi_env env;
59     napi_async_work work;
60     napi_deferred deferred;
61     napi_ref callbackRef = nullptr;
62     ImageSourceNapi *constructor_;
63     uint32_t status;
64     std::string pathName = "";
65     int fdIndex = INVALID_FD;
66     void* sourceBuffer = nullptr;
67     size_t sourceBufferSize = NUM_0;
68     std::string keyStr;
69     std::string valueStr;
70     std::string defaultValueStr;
71     int32_t valueInt;
72     int32_t deufltValueInt;
73     void *updataBuffer;
74     size_t updataBufferSize;
75     uint32_t updataBufferOffset = 0;
76     uint32_t updataLength = 0;
77     bool isCompleted = false;
78     bool isSuccess = false;
79     size_t pathNameLength;
80     SourceOptions opts;
81     uint32_t index = 0;
82     ImageInfo imageInfo;
83     DecodeOptions decodeOpts;
84     std::shared_ptr<ImageSource> rImageSource;
85     std::shared_ptr<PixelMap> rPixelMap;
86     std::string errMsg;
87     std::unique_ptr<std::vector<std::unique_ptr<PixelMap>>> pixelMaps;
88     std::unique_ptr<std::vector<int32_t>> delayTimes;
89     uint32_t frameCount = 0;
90 };
91 
92 struct ImageEnum {
93     std::string name;
94     int32_t numVal;
95     std::string strVal;
96 };
97 
98 static std::vector<struct ImageEnum> sPixelMapFormatMap = {
99     {"UNKNOWN", 0, ""},
100     {"ARGB_8888", 1, ""},
101     {"RGB_565", 2, ""},
102     {"RGBA_8888", 3, ""},
103     {"BGRA_8888", 4, ""},
104     {"RGB_888", 5, ""},
105     {"ALPHA_8", 6, ""},
106     {"RGBA_F16", 7, ""},
107     {"NV21", 8, ""},
108     {"NV12", 9, ""},
109 };
110 static std::vector<struct ImageEnum> sPropertyKeyMap = {
111     {"BITS_PER_SAMPLE", 0, "BitsPerSample"},
112     {"ORIENTATION", 0, "Orientation"},
113     {"IMAGE_LENGTH", 0, "ImageLength"},
114     {"IMAGE_WIDTH", 0, "ImageWidth"},
115     {"GPS_LATITUDE", 0, "GPSLatitude"},
116     {"GPS_LONGITUDE", 0, "GPSLongitude"},
117     {"GPS_LATITUDE_REF", 0, "GPSLatitudeRef"},
118     {"GPS_LONGITUDE_REF", 0, "GPSLongitudeRef"},
119     {"DATE_TIME_ORIGINAL", 0, "DateTimeOriginal"},
120     {"EXPOSURE_TIME", 0, "ExposureTime"},
121     {"SCENE_TYPE", 0, "SceneType"},
122     {"ISO_SPEED_RATINGS", 0, "ISOSpeedRatings"},
123     {"F_NUMBER", 0, "FNumber"},
124     {"COMPRESSED_BITS_PER_PIXEL", 0, "CompressedBitsPerPixel"},
125     {"DATE_TIME", 0, "DateTime"},
126     {"GPS_TIME_STAMP", 0, "GPSTimeStamp"},
127     {"GPS_DATE_STAMP", 0, "GPSDateStamp"},
128     {"IMAGE_DESCRIPTION", 0, "ImageDescription"},
129     {"MAKE", 0, "Make"},
130     {"MODEL", 0, "Model"},
131     {"PHOTO_MODE", 0, "PhotoMode"},
132     {"SENSITIVITY_TYPE", 0, "SensitivityType"},
133     {"STANDARD_OUTPUT_SENSITIVITY", 0, "StandardOutputSensitivity"},
134     {"RECOMMENDED_EXPOSURE_INDEX", 0, "RecommendedExposureIndex"},
135     {"ISO_SPEED", 0, "ISOSpeedRatings"},
136     {"APERTURE_VALUE", 0, "ApertureValue"},
137     {"EXPOSURE_BIAS_VALUE", 0, "ExposureBiasValue"},
138     {"METERING_MODE", 0, "MeteringMode"},
139     {"LIGHT_SOURCE", 0, "LightSource"},
140     {"FLASH", 0, "Flash"},
141     {"FOCAL_LENGTH", 0, "FocalLength"},
142     {"USER_COMMENT", 0, "UserComment"},
143     {"PIXEL_X_DIMENSION", 0, "PixelXDimension"},
144     {"PIXEL_Y_DIMENSION", 0, "PixelYDimension"},
145     {"WHITE_BALANCE", 0, "WhiteBalance"},
146     {"FOCAL_LENGTH_IN_35_MM_FILM", 0, "FocalLengthIn35mmFilm"},
147     {"CAPTURE_MODE", 0, "HwMnoteCaptureMode"},
148     {"PHYSICAL_APERTURE", 0, "HwMnotePhysicalAperture"},
149 };
150 static std::vector<struct ImageEnum> sImageFormatMap = {
151     {"YCBCR_422_SP", 1000, ""},
152     {"JPEG", 2000, ""},
153 };
154 static std::vector<struct ImageEnum> sAlphaTypeMap = {
155     {"UNKNOWN", 0, ""},
156     {"OPAQUE", 1, ""},
157     {"PREMUL", 2, ""},
158     {"UNPREMUL", 3, ""},
159 };
160 static std::vector<struct ImageEnum> sScaleModeMap = {
161     {"FIT_TARGET_SIZE", 0, ""},
162     {"CENTER_CROP", 1, ""},
163 };
164 static std::vector<struct ImageEnum> sComponentTypeMap = {
165     {"YUV_Y", 1, ""},
166     {"YUV_U", 2, ""},
167     {"YUV_V", 3, ""},
168     {"JPEG", 4, ""},
169 };
170 
GetStringArgument(napi_env env,napi_value value)171 static std::string GetStringArgument(napi_env env, napi_value value)
172 {
173     std::string strValue = "";
174     size_t bufLength = 0;
175     napi_status status = napi_get_value_string_utf8(env, value, nullptr, NUM_0, &bufLength);
176     if (status == napi_ok && bufLength > NUM_0 && bufLength < PATH_MAX) {
177         char *buffer = reinterpret_cast<char *>(malloc((bufLength + NUM_1) * sizeof(char)));
178         if (buffer == nullptr) {
179             HiLog::Error(LABEL, "No memory");
180             return strValue;
181         }
182 
183         status = napi_get_value_string_utf8(env, value, buffer, bufLength + NUM_1, &bufLength);
184         if (status == napi_ok) {
185             HiLog::Debug(LABEL, "Get Success");
186             strValue.assign(buffer, 0, bufLength + NUM_1);
187         }
188         if (buffer != nullptr) {
189             free(buffer);
190             buffer = nullptr;
191         }
192     }
193     return strValue;
194 }
195 
ImageSourceCallbackRoutine(napi_env env,ImageSourceAsyncContext * & context,const napi_value & valueParam)196 static void ImageSourceCallbackRoutine(napi_env env, ImageSourceAsyncContext* &context, const napi_value &valueParam)
197 {
198     napi_value result[NUM_2] = {0};
199     napi_value retVal;
200     napi_value callback = nullptr;
201 
202     napi_get_undefined(env, &result[NUM_0]);
203     napi_get_undefined(env, &result[NUM_1]);
204 
205     if (context == nullptr) {
206         HiLog::Error(LABEL, "context is nullptr");
207         return;
208     }
209 
210     if (context->status == SUCCESS) {
211         result[NUM_1] = valueParam;
212     } else if (context->errMsg.size() > 0) {
213         napi_create_string_utf8(env, context->errMsg.c_str(), NAPI_AUTO_LENGTH, &result[NUM_0]);
214     } else {
215         HiLog::Debug(LABEL, "error status, no message");
216         napi_create_string_utf8(env, "error status, no message", NAPI_AUTO_LENGTH, &result[NUM_0]);
217     }
218 
219     if (context->deferred) {
220         if (context->status == SUCCESS) {
221             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
222         } else {
223             napi_reject_deferred(env, context->deferred, result[NUM_0]);
224         }
225     } else {
226         HiLog::Debug(LABEL, "call callback function");
227         napi_get_reference_value(env, context->callbackRef, &callback);
228         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
229         napi_delete_reference(env, context->callbackRef);
230     }
231 
232     napi_delete_async_work(env, context->work);
233 
234     delete context;
235     context = nullptr;
236 }
237 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct ImageEnum> imageEnumMap)238 static napi_value CreateEnumTypeObject(napi_env env,
239     napi_valuetype type, napi_ref* ref, std::vector<struct ImageEnum> imageEnumMap)
240 {
241     napi_value result = nullptr;
242     napi_status status;
243     int32_t refCount = 1;
244     std::string propName;
245     status = napi_create_object(env, &result);
246     if (status == napi_ok) {
247         for (auto imgEnum : imageEnumMap) {
248             napi_value enumNapiValue = nullptr;
249             if (type == napi_string) {
250                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(),
251                     NAPI_AUTO_LENGTH, &enumNapiValue);
252             } else if (type == napi_number) {
253                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
254             } else {
255                 HiLog::Error(LABEL, "Unsupported type %{public}d!", type);
256             }
257             if (status == napi_ok && enumNapiValue != nullptr) {
258                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
259             }
260             if (status != napi_ok) {
261                 HiLog::Error(LABEL, "Failed to add named prop!");
262                 break;
263             }
264         }
265 
266         if (status == napi_ok) {
267             status = napi_create_reference(env, result, refCount, ref);
268             if (status == napi_ok) {
269                 return result;
270             }
271         }
272     }
273     HiLog::Error(LABEL, "CreateEnumTypeObject is Failed!");
274     napi_get_undefined(env, &result);
275     return result;
276 }
277 
ImageSourceNapi()278 ImageSourceNapi::ImageSourceNapi():env_(nullptr)
279 {   }
280 
~ImageSourceNapi()281 ImageSourceNapi::~ImageSourceNapi()
282 {
283     release();
284 }
285 
286 struct ImageConstructorInfo {
287     std::string className;
288     napi_ref* classRef;
289     napi_callback constructor;
290     const napi_property_descriptor* property;
291     size_t propertyCount;
292     const napi_property_descriptor* staticProperty;
293     size_t staticPropertyCount;
294 };
295 
DoInit(napi_env env,napi_value exports,struct ImageConstructorInfo info)296 static napi_value DoInit(napi_env env, napi_value exports, struct ImageConstructorInfo info)
297 {
298     napi_value constructor = nullptr;
299     napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH,
300         info.constructor, nullptr, info.propertyCount, info.property, &constructor);
301     if (status != napi_ok) {
302         HiLog::Error(LABEL, "define class fail");
303         return nullptr;
304     }
305 
306     status = napi_create_reference(env, constructor, NUM_1, info.classRef);
307     if (status != napi_ok) {
308         HiLog::Error(LABEL, "create reference fail");
309         return nullptr;
310     }
311 
312     napi_value global = nullptr;
313     status = napi_get_global(env, &global);
314     if (status != napi_ok) {
315         HiLog::Error(LABEL, "Init:get global fail");
316         return nullptr;
317     }
318 
319     status = napi_set_named_property(env, global, info.className.c_str(), constructor);
320     if (status != napi_ok) {
321         HiLog::Error(LABEL, "Init:set global named property fail");
322         return nullptr;
323     }
324 
325     status = napi_set_named_property(env, exports, info.className.c_str(), constructor);
326     if (status != napi_ok) {
327         HiLog::Error(LABEL, "set named property fail");
328         return nullptr;
329     }
330 
331     status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty);
332     if (status != napi_ok) {
333         HiLog::Error(LABEL, "define properties fail");
334         return nullptr;
335     }
336     return exports;
337 }
338 
Init(napi_env env,napi_value exports)339 napi_value ImageSourceNapi::Init(napi_env env, napi_value exports)
340 {
341     napi_property_descriptor properties[] = {
342         DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo),
343         DECLARE_NAPI_FUNCTION("modifyImageProperty", ModifyImageProperty),
344         DECLARE_NAPI_FUNCTION("getImageProperty", GetImageProperty),
345         DECLARE_NAPI_FUNCTION("getDelayTimeList", GetDelayTime),
346         DECLARE_NAPI_FUNCTION("getFrameCount", GetFrameCount),
347         DECLARE_NAPI_FUNCTION("createPixelMapList", CreatePixelMapList),
348         DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap),
349         DECLARE_NAPI_FUNCTION("updateData", UpdateData),
350         DECLARE_NAPI_FUNCTION("release", Release),
351         DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats),
352     };
353 
354     napi_property_descriptor static_prop[] = {
355         DECLARE_NAPI_STATIC_FUNCTION("createImageSource", CreateImageSource),
356         DECLARE_NAPI_STATIC_FUNCTION("CreateIncrementalSource", CreateIncrementalSource),
357         DECLARE_NAPI_PROPERTY("PixelMapFormat",
358             CreateEnumTypeObject(env, napi_number, &pixelMapFormatRef_, sPixelMapFormatMap)),
359         DECLARE_NAPI_PROPERTY("PropertyKey",
360             CreateEnumTypeObject(env, napi_string, &propertyKeyRef_, sPropertyKeyMap)),
361         DECLARE_NAPI_PROPERTY("ImageFormat",
362             CreateEnumTypeObject(env, napi_number, &imageFormatRef_, sImageFormatMap)),
363         DECLARE_NAPI_PROPERTY("AlphaType",
364             CreateEnumTypeObject(env, napi_number, &alphaTypeRef_, sAlphaTypeMap)),
365         DECLARE_NAPI_PROPERTY("ScaleMode",
366             CreateEnumTypeObject(env, napi_number, &scaleModeRef_, sScaleModeMap)),
367         DECLARE_NAPI_PROPERTY("ComponentType",
368             CreateEnumTypeObject(env, napi_number, &componentTypeRef_, sComponentTypeMap)),
369     };
370 
371     struct ImageConstructorInfo info = {
372         .className = CLASS_NAME,
373         .classRef = &sConstructor_,
374         .constructor = Constructor,
375         .property = properties,
376         .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]),
377         .staticProperty = static_prop,
378         .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]),
379     };
380 
381     if (DoInit(env, exports, info)) {
382         return nullptr;
383     }
384 
385     HiLog::Debug(LABEL, "Init success");
386     return exports;
387 }
388 
Constructor(napi_env env,napi_callback_info info)389 napi_value ImageSourceNapi::Constructor(napi_env env, napi_callback_info info)
390 {
391     napi_value undefineValue = nullptr;
392     napi_get_undefined(env, &undefineValue);
393 
394     napi_status status;
395     napi_value thisVar = nullptr;
396     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
397     if (status == napi_ok && thisVar != nullptr) {
398         std::unique_ptr<ImageSourceNapi> pImgSrcNapi = std::make_unique<ImageSourceNapi>();
399         if (pImgSrcNapi != nullptr) {
400             pImgSrcNapi->env_ = env;
401             pImgSrcNapi->nativeImgSrc = sImgSrc_;
402             pImgSrcNapi->navIncPixelMap_ = sIncPixelMap_;
403             sIncPixelMap_ = nullptr;
404             sImgSrc_ = nullptr;
405             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgSrcNapi.get()),
406                                ImageSourceNapi::Destructor, nullptr, nullptr);
407             if (status == napi_ok) {
408                 pImgSrcNapi.release();
409                 return thisVar;
410             } else {
411                 HiLog::Error(LABEL, "Failure wrapping js to native napi");
412             }
413         }
414     }
415 
416     return undefineValue;
417 }
418 
Destructor(napi_env env,void * nativeObject,void * finalize)419 void ImageSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
420 {
421 }
422 
GetSupportedFormats(napi_env env,napi_callback_info info)423 napi_value ImageSourceNapi::GetSupportedFormats(napi_env env, napi_callback_info info)
424 {
425     napi_value result = nullptr;
426     napi_get_undefined(env, &result);
427 
428     napi_status status;
429     napi_value thisVar = nullptr;
430     size_t argCount = 0;
431     HiLog::Debug(LABEL, "GetSupportedFormats IN");
432 
433     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
434 
435     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
436 
437     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
438     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
439 
440     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
441         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
442     std::set<std::string> formats;
443     uint32_t ret = asyncContext->constructor_->nativeImgSrc->GetSupportedFormats(formats);
444 
445     IMG_NAPI_CHECK_RET_D((ret == SUCCESS),
446         nullptr, HiLog::Error(LABEL, "fail to get supported formats"));
447 
448     napi_create_array(env, &result);
449     size_t i = 0;
450     for (const std::string& formatStr: formats) {
451         napi_value format = nullptr;
452         napi_create_string_latin1(env, formatStr.c_str(), formatStr.length(), &format);
453         napi_set_element(env, result, i, format);
454         i++;
455     }
456     return result;
457 }
458 
STATIC_COMPLETE_FUNC(GetImageInfo)459 STATIC_COMPLETE_FUNC(GetImageInfo)
460 {
461     napi_value result = nullptr;
462     auto context = static_cast<ImageSourceAsyncContext*>(data);
463     if (context->status == SUCCESS) {
464         napi_create_object(env, &result);
465 
466         napi_value size = nullptr;
467         napi_create_object(env, &size);
468 
469         napi_value sizeWith = nullptr;
470         napi_create_int32(env, context->imageInfo.size.width, &sizeWith);
471         napi_set_named_property(env, size, "width", sizeWith);
472 
473         napi_value sizeHeight = nullptr;
474         napi_create_int32(env, context->imageInfo.size.height, &sizeHeight);
475         napi_set_named_property(env, size, "height", sizeHeight);
476 
477         napi_set_named_property(env, result, "size", size);
478 
479         napi_value pixelFormatValue = nullptr;
480         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.pixelFormat), &pixelFormatValue);
481         napi_set_named_property(env, result, "pixelFormat", pixelFormatValue);
482 
483         napi_value colorSpaceValue = nullptr;
484         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.colorSpace), &colorSpaceValue);
485         napi_set_named_property(env, result, "colorSpace", colorSpaceValue);
486 
487         napi_value alphaTypeValue = nullptr;
488         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.alphaType), &alphaTypeValue);
489         napi_set_named_property(env, result, "alphaType", alphaTypeValue);
490 
491         if (!IMG_IS_OK(status)) {
492             context->status = ERROR;
493             HiLog::Error(LABEL, "napi_create_int32 failed!");
494             napi_get_undefined(env, &result);
495         } else {
496             context->status = SUCCESS;
497         }
498     } else {
499         napi_get_undefined(env, &result);
500     }
501 
502     ImageSourceCallbackRoutine(env, context, result);
503 }
504 
ParseSize(napi_env env,napi_value root,Size * size)505 static bool ParseSize(napi_env env, napi_value root, Size* size)
506 {
507     if (size == nullptr) {
508         HiLog::Error(LABEL, "size is nullptr");
509         return false;
510     }
511     if (!GET_INT32_BY_NAME(root, "height", size->height)) {
512         return false;
513     }
514 
515     if (!GET_INT32_BY_NAME(root, "width", size->width)) {
516         return false;
517     }
518 
519     return true;
520 }
521 
ParseRegion(napi_env env,napi_value root,Rect * region)522 static bool ParseRegion(napi_env env, napi_value root, Rect* region)
523 {
524     napi_value tmpValue = nullptr;
525 
526     if (region == nullptr) {
527         HiLog::Error(LABEL, "region is nullptr");
528         return false;
529     }
530 
531     if (!GET_INT32_BY_NAME(root, "x", region->left)) {
532         return false;
533     }
534 
535     if (!GET_INT32_BY_NAME(root, "y", region->top)) {
536         return false;
537     }
538 
539     if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
540         return false;
541     }
542 
543     if (!GET_INT32_BY_NAME(tmpValue, "height", region->height)) {
544         return false;
545     }
546 
547     if (!GET_INT32_BY_NAME(tmpValue, "width", region->width)) {
548         return false;
549     }
550 
551     return true;
552 }
553 
IsSupportPixelFormat(int32_t val)554 static bool IsSupportPixelFormat(int32_t val)
555 {
556     if (val >= static_cast<int32_t>(PixelFormat::UNKNOWN) &&
557         val <= static_cast<int32_t>(PixelFormat::RGBA_F16)) {
558         return true;
559     }
560 
561     return false;
562 }
563 
ParsePixlForamt(int32_t val)564 static PixelFormat ParsePixlForamt(int32_t val)
565 {
566     if (val <= static_cast<int32_t>(PixelFormat::CMYK)) {
567         return PixelFormat(val);
568     }
569 
570     return PixelFormat::UNKNOWN;
571 }
572 
ParseDecodeOptions2(napi_env env,napi_value root,DecodeOptions * opts,std::string & error)573 static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, std::string &error)
574 {
575     uint32_t tmpNumber = 0;
576     if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) {
577         HiLog::Debug(LABEL, "no desiredPixelFormat");
578     } else {
579         if (IsSupportPixelFormat(tmpNumber)) {
580             opts->desiredPixelFormat = ParsePixlForamt(tmpNumber);
581         } else {
582             HiLog::Debug(LABEL, "Invalid desiredPixelFormat %{public}d", tmpNumber);
583             error = "DecodeOptions mismatch";
584             return false;
585         }
586     }
587 
588     if (!GET_INT32_BY_NAME(root, "fitDensity", opts->fitDensity)) {
589         HiLog::Debug(LABEL, "no fitDensity");
590     }
591 
592     if (GET_UINT32_BY_NAME(root, "fillColor", opts->SVGOpts.fillColor.color)) {
593         opts->SVGOpts.fillColor.isValidColor = true;
594         HiLog::Debug(LABEL, "fillColor %{public}x", opts->SVGOpts.fillColor.color);
595     } else {
596         HiLog::Debug(LABEL, "no fillColor");
597     }
598 
599     if (GET_UINT32_BY_NAME(root, "SVGResize", opts->SVGOpts.SVGResize.resizePercentage)) {
600         opts->SVGOpts.SVGResize.isValidPercentage = true;
601         HiLog::Debug(LABEL, "SVGResize percentage %{public}x", opts->SVGOpts.SVGResize.resizePercentage);
602     } else {
603         HiLog::Debug(LABEL, "no SVGResize percentage");
604     }
605     return true;
606 }
607 
ParseDecodeOptions(napi_env env,napi_value root,DecodeOptions * opts,uint32_t * pIndex,std::string & error)608 static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts,
609     uint32_t* pIndex, std::string &error)
610 {
611     napi_value tmpValue = nullptr;
612 
613     if (!ImageNapiUtils::GetUint32ByName(env, root, "index", pIndex)) {
614         HiLog::Debug(LABEL, "no index");
615     }
616 
617     if (opts == nullptr) {
618         HiLog::Error(LABEL, "opts is nullptr");
619         return false;
620     }
621 
622     if (!GET_UINT32_BY_NAME(root, "sampleSize", opts->sampleSize)) {
623         HiLog::Debug(LABEL, "no sampleSize");
624     }
625 
626     if (!GET_UINT32_BY_NAME(root, "rotate", opts->rotateNewDegrees)) {
627         HiLog::Debug(LABEL, "no rotate");
628     } else {
629         if (opts->rotateNewDegrees >= 0 &&
630             opts->rotateNewDegrees <= 360) { // 360 is the maximum rotation angle.
631             opts->rotateDegrees = static_cast<float>(opts->rotateNewDegrees);
632         } else {
633             HiLog::Debug(LABEL, "Invalid rotate %{public}d", opts->rotateNewDegrees);
634             error = "DecodeOptions mismatch";
635             return false;
636         }
637     }
638 
639     if (!GET_BOOL_BY_NAME(root, "editable", opts->editable)) {
640         HiLog::Debug(LABEL, "no editable");
641     }
642 
643     if (!GET_NODE_BY_NAME(root, "desiredSize", tmpValue)) {
644         HiLog::Debug(LABEL, "no desiredSize");
645     } else {
646         if (!ParseSize(env, tmpValue, &(opts->desiredSize))) {
647             HiLog::Debug(LABEL, "ParseSize error");
648         }
649     }
650 
651     if (!GET_NODE_BY_NAME(root, "desiredRegion", tmpValue)) {
652         HiLog::Debug(LABEL, "no desiredRegion");
653     } else {
654         if (!ParseRegion(env, tmpValue, &(opts->CropRect))) {
655             HiLog::Debug(LABEL, "ParseRegion error");
656         }
657     }
658     return ParseDecodeOptions2(env, root, opts, error);
659 }
660 
FileUrlToRawPath(const std::string & path)661 static std::string FileUrlToRawPath(const std::string &path)
662 {
663     if (path.size() > FILE_URL_PREFIX.size() &&
664         (path.compare(0, FILE_URL_PREFIX.size(), FILE_URL_PREFIX) == 0)) {
665         return path.substr(FILE_URL_PREFIX.size());
666     }
667     return path;
668 }
669 
parseSourceOptions(napi_env env,napi_value root,SourceOptions * opts)670 static void parseSourceOptions(napi_env env, napi_value root, SourceOptions* opts)
671 {
672     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourceDensity", &(opts->baseDensity))) {
673         HiLog::Debug(LABEL, "no sourceDensity");
674     }
675 
676     int32_t pixelFormat = 0;
677     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourcePixelFormat", &pixelFormat)) {
678         HiLog::Debug(LABEL, "no sourcePixelFormat");
679     } else {
680         opts->pixelFormat = static_cast<PixelFormat>(pixelFormat);
681         HiLog::Info(LABEL, "sourcePixelFormat:%{public}d", static_cast<int32_t>(opts->pixelFormat));
682     }
683 
684     napi_value tmpValue = nullptr;
685     if (!GET_NODE_BY_NAME(root, "sourceSize", tmpValue)) {
686         HiLog::Debug(LABEL, "no sourceSize");
687     } else {
688         if (!ParseSize(env, tmpValue, &(opts->size))) {
689             HiLog::Debug(LABEL, "ParseSize error");
690         }
691         HiLog::Info(LABEL, "sourceSize:(%{public}d, %{public}d)", opts->size.width, opts->size.height);
692     }
693 }
PrepareNapiEnv(napi_env env)694 static void PrepareNapiEnv(napi_env env)
695 {
696     napi_value globalValue;
697     napi_get_global(env, &globalValue);
698     napi_value func;
699     napi_get_named_property(env, globalValue, "requireNapi", &func);
700 
701     napi_value imageInfo;
702     napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &imageInfo);
703     napi_value funcArgv[1] = { imageInfo };
704     napi_value returnValue;
705     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
706 }
CreateNativeImageSource(napi_env env,napi_value argValue,SourceOptions & opts,ImageSourceAsyncContext * context)707 static std::unique_ptr<ImageSource> CreateNativeImageSource(napi_env env, napi_value argValue,
708     SourceOptions &opts, ImageSourceAsyncContext* context)
709 {
710     std::unique_ptr<ImageSource> imageSource = nullptr;
711     uint32_t errorCode = ERR_MEDIA_INVALID_VALUE;
712     napi_status status;
713 
714     auto inputType = ImageNapiUtils::getType(env, argValue);
715     if (napi_string == inputType) { // File Path
716         if (!ImageNapiUtils::GetUtf8String(env, argValue, context->pathName)) {
717             HiLog::Error(LABEL, "fail to get pathName");
718             return imageSource;
719         }
720         context->pathName = FileUrlToRawPath(context->pathName);
721         context->pathNameLength = context->pathName.size();
722         HiLog::Debug(LABEL, "pathName is [%{public}s]", context->pathName.c_str());
723         imageSource = ImageSource::CreateImageSource(context->pathName, opts, errorCode);
724     } else if (napi_number == inputType) { // Fd
725         napi_get_value_int32(env, argValue, &context->fdIndex);
726         HiLog::Debug(LABEL, "CreateImageSource fdIndex is [%{public}d]", context->fdIndex);
727         imageSource = ImageSource::CreateImageSource(context->fdIndex, opts, errorCode);
728     } else { // Input Buffer
729         uint32_t refCount = NUM_1;
730         napi_ref arrayRef = nullptr;
731         napi_create_reference(env, argValue, refCount, &arrayRef);
732         status = napi_get_arraybuffer_info(env, argValue, &(context->sourceBuffer), &(context->sourceBufferSize));
733         if (status != napi_ok) {
734             napi_delete_reference(env, arrayRef);
735             HiLog::Error(LABEL, "fail to get arraybufferinfo");
736             return nullptr;
737         }
738         imageSource = ImageSource::CreateImageSource(static_cast<uint8_t *>(context->sourceBuffer),
739             context->sourceBufferSize, opts, errorCode);
740         napi_delete_reference(env, arrayRef);
741     }
742     return imageSource;
743 }
744 
CreateImageSource(napi_env env,napi_callback_info info)745 napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info)
746 {
747     PrepareNapiEnv(env);
748     napi_value result = nullptr;
749     napi_get_undefined(env, &result);
750 
751     napi_status status;
752     napi_value thisVar = nullptr;
753     napi_value argValue[NUM_2] = {0};
754     size_t argCount = 2;
755     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
756     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
757     NAPI_ASSERT(env, argCount > 0, "No arg!");
758 
759     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
760     SourceOptions opts;
761     if (argCount > NUM_1) {
762         parseSourceOptions(env, argValue[NUM_1], &opts);
763     }
764     std::unique_ptr<ImageSource> imageSource = CreateNativeImageSource(env, argValue[NUM_0],
765         opts, asyncContext.get());
766     if (imageSource == nullptr) {
767         HiLog::Error(LABEL, "CreateImageSourceExec error");
768         napi_get_undefined(env, &result);
769         return result;
770     }
771     filePath_ = asyncContext->pathName;
772     fileDescriptor_ = asyncContext->fdIndex;
773     fileBuffer_ = asyncContext->sourceBuffer;
774     fileBufferSize_ = asyncContext->sourceBufferSize;
775 
776     napi_value constructor = nullptr;
777     status = napi_get_reference_value(env, sConstructor_, &constructor);
778     if (IMG_IS_OK(status)) {
779         sImgSrc_ = std::move(imageSource);
780         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
781     }
782     if (!IMG_IS_OK(status)) {
783         HiLog::Error(LABEL, "New instance could not be obtained");
784         napi_get_undefined(env, &result);
785     }
786     return result;
787 }
788 
CreateImageSourceComplete(napi_env env,napi_status status,void * data)789 napi_value ImageSourceNapi::CreateImageSourceComplete(napi_env env, napi_status status, void *data)
790 {
791     napi_value constructor = nullptr;
792     napi_value result = nullptr;
793 
794     HiLog::Debug(LABEL, "CreateImageSourceComplete IN");
795     auto context = static_cast<ImageSourceAsyncContext*>(data);
796     if (context == nullptr) {
797         return result;
798     }
799     status = napi_get_reference_value(env, sConstructor_, &constructor);
800     if (IMG_IS_OK(status)) {
801         sImgSrc_ = context->rImageSource;
802         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
803     }
804 
805     if (!IMG_IS_OK(status)) {
806         context->status = ERROR;
807         HiLog::Error(LABEL, "New instance could not be obtained");
808         napi_get_undefined(env, &result);
809     }
810     return result;
811 }
812 
CreateIncrementalSource(napi_env env,napi_callback_info info)813 napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_info info)
814 {
815     napi_value globalValue;
816     napi_get_global(env, &globalValue);
817     napi_value func;
818     napi_get_named_property(env, globalValue, "requireNapi", &func);
819 
820     napi_value imageInfo;
821     napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &imageInfo);
822     napi_value funcArgv[1] = { imageInfo };
823     napi_value returnValue;
824     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
825 
826     napi_value result = nullptr;
827     napi_get_undefined(env, &result);
828 
829     napi_status status;
830     HiLog::Debug(LABEL, "CreateIncrementalSource IN");
831 
832     napi_value thisVar = nullptr;
833     napi_value argValue[NUM_2] = {0};
834     size_t argCount = NUM_2;
835     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
836     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
837 
838     uint32_t errorCode = 0;
839     IncrementalSourceOptions incOpts;
840     if (argCount == NUM_2) {
841         parseSourceOptions(env, argValue[NUM_1], &(incOpts.sourceOptions));
842     }
843 
844     incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA;
845     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode);
846     DecodeOptions decodeOpts;
847     std::unique_ptr<IncrementalPixelMap> incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode);
848     HiLog::Debug(LABEL, "CreateIncrementalImageSource end");
849     if (errorCode != SUCCESS) {
850         HiLog::Error(LABEL, "CreateIncrementalImageSource error");
851         napi_get_undefined(env, &result);
852         return result;
853     }
854     napi_value constructor = nullptr;
855     status = napi_get_reference_value(env, sConstructor_, &constructor);
856     if (IMG_IS_OK(status)) {
857         sImgSrc_ = std::move(imageSource);
858         sIncPixelMap_ = std::move(incPixelMap);
859         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
860     }
861     if (!IMG_IS_OK(status)) {
862         HiLog::Error(LABEL, "New instance could not be obtained");
863         napi_get_undefined(env, &result);
864     }
865     return result;
866 }
867 
GetImageInfo(napi_env env,napi_callback_info info)868 napi_value ImageSourceNapi::GetImageInfo(napi_env env, napi_callback_info info)
869 {
870     StartTrace(HITRACE_TAG_ZIMAGE, "GetImageInfo");
871     napi_value result = nullptr;
872     napi_get_undefined(env, &result);
873 
874     int32_t refCount = 1;
875     napi_status status;
876     napi_value thisVar = nullptr;
877     napi_value argValue[NUM_2] = {0};
878     size_t argCount = 2;
879     HiLog::Debug(LABEL, "GetImageInfo IN");
880     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
881     HiLog::Debug(LABEL, "GetImageInfo argCount is [%{public}zu]", argCount);
882 
883     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
884 
885     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
886     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
887 
888     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
889         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
890 
891     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
892 
893     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
894         nullptr, HiLog::Error(LABEL, "empty native pixelmap"));
895     HiLog::Debug(LABEL, "GetImageInfo argCount is [%{public}zu]", argCount);
896     if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
897         HiLog::Debug(LABEL, "GetImageInfo arg0 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_0]));
898         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
899     } else if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number) {
900         napi_get_value_uint32(env, argValue[NUM_0], &asyncContext->index);
901     } else if (argCount == NUM_2 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number
902                 && ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_function) {
903         HiLog::Debug(LABEL, "GetImageInfo arg0 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_0]));
904         HiLog::Debug(LABEL, "GetImageInfo arg1 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_1]));
905         napi_get_value_uint32(env, argValue[NUM_0], &asyncContext->index);
906         napi_create_reference(env, argValue[NUM_1], refCount, &asyncContext->callbackRef);
907     }
908 
909     if (asyncContext->callbackRef == nullptr) {
910         napi_create_promise(env, &(asyncContext->deferred), &result);
911     } else {
912         napi_get_undefined(env, &result);
913     }
914 
915     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetImageInfo",
916         [](napi_env env, void *data) {
917             auto context = static_cast<ImageSourceAsyncContext*>(data);
918             int index = (context->index >= NUM_0) ? context->index : NUM_0;
919             context->status = context->rImageSource->GetImageInfo(index, context->imageInfo);
920         }, GetImageInfoComplete, asyncContext, asyncContext->work);
921 
922     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
923         nullptr, HiLog::Error(LABEL, "fail to create async work"));
924     FinishTrace(HITRACE_TAG_ZIMAGE);
925     return result;
926 }
927 
CreatePixelMapExecute(napi_env env,void * data)928 static void CreatePixelMapExecute(napi_env env, void *data)
929 {
930     HiLog::Debug(LABEL, "CreatePixelMapExecute IN");
931     if (data == nullptr) {
932         HiLog::Error(LABEL, "data is nullptr");
933         return;
934     }
935     uint32_t errorCode = 0;
936     auto context = static_cast<ImageSourceAsyncContext*>(data);
937     if (context == nullptr) {
938         HiLog::Error(LABEL, "empty context");
939         return;
940     }
941 
942     if (context->errMsg.size() > 0) {
943         HiLog::Error(LABEL, "mismatch args");
944         context->status = ERROR;
945         return;
946     }
947 
948     if (context->rImageSource == nullptr) {
949         HiLog::Error(LABEL, "empty context rImageSource");
950         return;
951     }
952 
953     if (context->constructor_ != nullptr) {
954         auto incPixelMap = context->constructor_->GetIncrementalPixelMap();
955         if (incPixelMap != nullptr) {
956             HiLog::Info(LABEL, "Get Incremental PixelMap!!!");
957             context->rPixelMap = incPixelMap;
958         }
959     } else {
960         HiLog::Info(LABEL, "Create PixelMap!!!");
961     }
962     if (context->rPixelMap == nullptr) {
963         int index = (context->index >= NUM_0) ? context->index : NUM_0;
964         context->rPixelMap = context->rImageSource->CreatePixelMapEx(index, context->decodeOpts, errorCode);
965     }
966 
967     if (IMG_NOT_NULL(context->rPixelMap)) {
968         context->status = SUCCESS;
969     } else {
970         context->status = ERROR;
971         context->errMsg = "Create PixelMap error";
972         HiLog::Error(LABEL, "Create PixelMap error");
973     }
974     HiLog::Debug(LABEL, "CreatePixelMapExecute OUT");
975 }
976 
CreatePixelMapComplete(napi_env env,napi_status status,void * data)977 static void CreatePixelMapComplete(napi_env env, napi_status status, void *data)
978 {
979     HiLog::Debug(LABEL, "CreatePixelMapComplete IN");
980     napi_value result = nullptr;
981     auto context = static_cast<ImageSourceAsyncContext*>(data);
982 
983     if (context->status == SUCCESS) {
984         result = PixelMapNapi::CreatePixelMap(env, context->rPixelMap);
985     } else {
986         napi_get_undefined(env, &result);
987     }
988     HiLog::Debug(LABEL, "CreatePixelMapComplete OUT");
989     ImageSourceCallbackRoutine(env, context, result);
990 }
991 
CreatePixelMap(napi_env env,napi_callback_info info)992 napi_value ImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info)
993 {
994     napi_value result = nullptr;
995     napi_get_undefined(env, &result);
996 
997     int32_t refCount = 1;
998     napi_status status;
999     napi_value thisVar = nullptr;
1000     napi_value argValue[NUM_2] = {0};
1001     size_t argCount = NUM_2;
1002     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1003     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, HiLog::Error(LABEL, "fail to get thisVar"));
1004     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1005 
1006     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
1007 
1008     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1009     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
1010         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1011     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_->nativeImgSrc),
1012         nullptr, HiLog::Error(LABEL, "fail to unwrap nativeImgSrc"));
1013     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
1014     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
1015         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1016 
1017     if (argCount == NUM_0) {
1018         HiLog::Debug(LABEL, "CreatePixelMap with no arg");
1019     } else if (argCount == NUM_1 || argCount == NUM_2) {
1020         if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
1021             if (!ParseDecodeOptions(env, argValue[NUM_0], &(asyncContext->decodeOpts),
1022                                     &(asyncContext->index), asyncContext->errMsg)) {
1023                 HiLog::Error(LABEL, "DecodeOptions mismatch");
1024             }
1025         }
1026         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1027             napi_create_reference(env, argValue[argCount - 1], refCount, &asyncContext->callbackRef);
1028         }
1029     } else {
1030         HiLog::Error(LABEL, "argCount mismatch");
1031         return result;
1032     }
1033     if (asyncContext->callbackRef == nullptr) {
1034         napi_create_promise(env, &(asyncContext->deferred), &result);
1035     } else {
1036         napi_get_undefined(env, &result);
1037     }
1038 
1039     ImageNapiUtils::HicheckerReport();
1040     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "CreatePixelMap", CreatePixelMapExecute,
1041         CreatePixelMapComplete, asyncContext, asyncContext->work);
1042 
1043     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1044         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1045     return result;
1046 }
1047 
ParsePropertyOptions(napi_env env,napi_value root,ImageSourceAsyncContext * context)1048 static bool ParsePropertyOptions(napi_env env, napi_value root, ImageSourceAsyncContext* context)
1049 {
1050     napi_value tmpValue = nullptr;
1051     if (!GET_UINT32_BY_NAME(root, "index", context->index)) {
1052         HiLog::Debug(LABEL, "no index");
1053         return false;
1054     }
1055     if (!GET_NODE_BY_NAME(root, "defaultValue", tmpValue)) {
1056         HiLog::Debug(LABEL, "no defaultValue");
1057     } else {
1058         if (tmpValue != nullptr) {
1059             context->defaultValueStr = GetStringArgument(env, tmpValue);
1060         }
1061     }
1062     return true;
1063 }
1064 
ModifyImagePropertyComplete(napi_env env,napi_status status,ImageSourceAsyncContext * context)1065 static void ModifyImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context)
1066 {
1067     if (context == nullptr) {
1068         HiLog::Error(LABEL, "context is nullptr");
1069         return;
1070     }
1071 
1072     napi_value result[NUM_2] = {0};
1073     napi_get_undefined(env, &result[NUM_0]);
1074     napi_get_undefined(env, &result[NUM_1]);
1075     napi_value retVal;
1076     napi_value callback = nullptr;
1077     if (context->status == ERR_MEDIA_WRITE_PARCEL_FAIL) {
1078         if (context->fdIndex != -1) {
1079             ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1080                 "Create Fd without write permission!");
1081         }
1082     } else if (context->status == ERR_MEDIA_OUT_OF_RANGE) {
1083         ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1084             "The given buffer size is too small to add new exif data!");
1085     } else if (context->status == ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
1086         ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1087             "The exif data format is not standard, so modify it failed!");
1088     } else if (context->status == ERR_MEDIA_VALUE_INVALID) {
1089         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, context->errMsg);
1090     }
1091 
1092     if (context->deferred) {
1093         if (context->status == SUCCESS) {
1094             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
1095         } else {
1096             napi_reject_deferred(env, context->deferred, result[NUM_0]);
1097         }
1098     } else {
1099         HiLog::Debug(LABEL, "call callback function");
1100         napi_get_reference_value(env, context->callbackRef, &callback);
1101         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
1102         napi_delete_reference(env, context->callbackRef);
1103     }
1104 
1105     napi_delete_async_work(env, context->work);
1106 
1107     delete context;
1108     context = nullptr;
1109 }
1110 
GetImagePropertyComplete(napi_env env,napi_status status,ImageSourceAsyncContext * context)1111 static void GetImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context)
1112 {
1113     if (context == nullptr) {
1114         HiLog::Error(LABEL, "context is nullptr");
1115         return;
1116     }
1117 
1118     napi_value result[NUM_2] = {0};
1119     napi_value retVal;
1120     napi_value callback = nullptr;
1121 
1122     napi_get_undefined(env, &result[NUM_0]);
1123     napi_get_undefined(env, &result[NUM_1]);
1124 
1125     if (context->status == SUCCESS) {
1126         napi_create_string_utf8(env, context->valueStr.c_str(), context->valueStr.length(), &result[NUM_1]);
1127     } else if (context->status == ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
1128         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, "Unsupport EXIF info key!");
1129     } else {
1130         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, "There is generic napi failure!");
1131     }
1132 
1133     if (context->deferred) {
1134         if (context->status == SUCCESS) {
1135             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
1136         } else {
1137             napi_reject_deferred(env, context->deferred, result[NUM_0]);
1138         }
1139     } else {
1140         HiLog::Debug(LABEL, "call callback function");
1141         napi_get_reference_value(env, context->callbackRef, &callback);
1142         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
1143         napi_delete_reference(env, context->callbackRef);
1144     }
1145 
1146     napi_delete_async_work(env, context->work);
1147     delete context;
1148     context = nullptr;
1149 }
1150 
UnwrapContext(napi_env env,napi_callback_info info)1151 static std::unique_ptr<ImageSourceAsyncContext> UnwrapContext(napi_env env, napi_callback_info info)
1152 {
1153     int32_t refCount = 1;
1154     napi_status status;
1155     napi_value thisVar = nullptr;
1156     napi_value argValue[NUM_3] = {0};
1157     size_t argCount = NUM_3;
1158     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1159     HiLog::Debug(LABEL, "GetImageProperty argCount is [%{public}zu]", argCount);
1160 
1161     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1162 
1163     std::unique_ptr<ImageSourceAsyncContext> context = std::make_unique<ImageSourceAsyncContext>();
1164     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1165 
1166     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
1167         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1168 
1169     context->rImageSource = context->constructor_->nativeImgSrc;
1170 
1171     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource),
1172         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1173 
1174     if (argCount < NUM_1 || argCount > NUM_3) {
1175         HiLog::Error(LABEL, "argCount missmatch");
1176         return nullptr;
1177     }
1178     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) {
1179         context->keyStr = GetStringArgument(env, argValue[NUM_0]);
1180     } else {
1181         HiLog::Error(LABEL, "arg 0 type missmatch");
1182         return nullptr;
1183     }
1184     if (argCount == NUM_2 || argCount == NUM_3) {
1185         if (ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_object) {
1186             IMG_NAPI_CHECK_RET_D(ParsePropertyOptions(env, argValue[NUM_1], context.get()),
1187                                  nullptr, HiLog::Error(LABEL, "PropertyOptions mismatch"));
1188         }
1189         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1190             napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef);
1191         }
1192     }
1193     return context;
1194 }
1195 
CheckExifDataValue(const std::string & key,const std::string & value,std::string & errorInfo)1196 static bool CheckExifDataValue(const std::string &key, const std::string &value, std::string &errorInfo)
1197 {
1198     if (IsSameTextStr(key, "BitsPerSample")) {
1199         std::vector<std::string> bitsVec;
1200         SplitStr(value, ",", bitsVec);
1201         if (bitsVec.size() > NUM_2) {
1202             errorInfo = "BitsPerSample has invalid exif value: ";
1203             errorInfo.append(value);
1204             return false;
1205         }
1206         for (size_t i = 0; i < bitsVec.size(); i++) {
1207             if (!IsNumericStr(bitsVec[i])) {
1208                 errorInfo = "BitsPerSample has invalid exif value: ";
1209                 errorInfo.append(bitsVec[i]);
1210                 return false;
1211             }
1212         }
1213     } else if (IsSameTextStr(key, "Orientation")) {
1214         if (!IsNumericStr(value) || atoi(value.c_str()) < 1 || static_cast<uint32_t>(atoi(value.c_str())) > NUM_8) {
1215             errorInfo = "Orientation has invalid exif value: ";
1216             errorInfo.append(value);
1217             return false;
1218         }
1219     } else if (IsSameTextStr(key, "ImageLength") || IsSameTextStr(key, "ImageWidth")) {
1220         if (!IsNumericStr(value)) {
1221             errorInfo = "ImageLength or ImageWidth has invalid exif value: ";
1222             errorInfo.append(value);
1223             return false;
1224         }
1225     } else if (IsSameTextStr(key, "GPSLatitude") || IsSameTextStr(key, "GPSLongitude")) {
1226         std::vector<std::string> gpsVec;
1227         SplitStr(value, ",", gpsVec);
1228         if (gpsVec.size() != NUM_2) {
1229             errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
1230             errorInfo.append(value);
1231             return false;
1232         }
1233 
1234         for (size_t i = 0; i < gpsVec.size(); i++) {
1235             if (!IsNumericStr(gpsVec[i])) {
1236                 errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
1237                 errorInfo.append(gpsVec[i]);
1238                 return false;
1239             }
1240         }
1241     } else if (IsSameTextStr(key, "GPSLatitudeRef")) {
1242         if (!IsSameTextStr(value, "N") && !IsSameTextStr(value, "S")) {
1243             errorInfo = "GPSLatitudeRef has invalid exif value: ";
1244             errorInfo.append(value);
1245             return false;
1246         }
1247     } else if (IsSameTextStr(key, "GPSLongitudeRef")) {
1248         if (!IsSameTextStr(value, "W") && !IsSameTextStr(value, "E")) {
1249             errorInfo = "GPSLongitudeRef has invalid exif value: ";
1250             errorInfo.append(value);
1251             return false;
1252         }
1253     }
1254     return true;
1255 }
1256 
UnwrapContextForModify(napi_env env,napi_callback_info info)1257 static std::unique_ptr<ImageSourceAsyncContext> UnwrapContextForModify(napi_env env,
1258     napi_callback_info info)
1259 {
1260     int32_t refCount = 1;
1261     napi_status status;
1262     napi_value thisVar = nullptr;
1263     napi_value argValue[NUM_4] = {0};
1264     size_t argCount = NUM_4;
1265     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1266     HiLog::Debug(LABEL, "UnwrapContextForModify argCount is [%{public}zu]", argCount);
1267 
1268     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1269 
1270     std::unique_ptr<ImageSourceAsyncContext> context = std::make_unique<ImageSourceAsyncContext>();
1271     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1272 
1273     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
1274         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1275 
1276     context->rImageSource = context->constructor_->nativeImgSrc;
1277 
1278     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource),
1279         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1280     if (argCount < NUM_1 || argCount > NUM_4) {
1281         HiLog::Error(LABEL, "argCount missmatch");
1282         return nullptr;
1283     }
1284     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) {
1285         context->keyStr = GetStringArgument(env, argValue[NUM_0]);
1286     } else {
1287         HiLog::Error(LABEL, "arg 0 type missmatch");
1288         return nullptr;
1289     }
1290     if (ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_string) {
1291         context->valueStr = GetStringArgument(env, argValue[NUM_1]);
1292     } else {
1293         HiLog::Error(LABEL, "arg 1 type missmatch");
1294         return nullptr;
1295     }
1296     if (argCount == NUM_3 || argCount == NUM_4) {
1297         if (ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_object) {
1298             IMG_NAPI_CHECK_RET_D(ParsePropertyOptions(env, argValue[NUM_2], context.get()),
1299                 nullptr, HiLog::Error(LABEL, "PropertyOptions mismatch"));
1300         }
1301         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1302             napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef);
1303         }
1304     }
1305     context->pathName = ImageSourceNapi::filePath_;
1306     context->fdIndex = ImageSourceNapi::fileDescriptor_;
1307     context->sourceBuffer = ImageSourceNapi::fileBuffer_;
1308     context->sourceBufferSize = ImageSourceNapi::fileBufferSize_;
1309     return context;
1310 }
1311 
ModifyImageProperty(napi_env env,napi_callback_info info)1312 napi_value ImageSourceNapi::ModifyImageProperty(napi_env env, napi_callback_info info)
1313 {
1314     napi_value result = nullptr;
1315     napi_get_undefined(env, &result);
1316 
1317     napi_status status;
1318     std::unique_ptr<ImageSourceAsyncContext> asyncContext = UnwrapContextForModify(env, info);
1319     if (asyncContext == nullptr) {
1320         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
1321             "async context unwrap failed");
1322     }
1323 
1324     if (asyncContext->callbackRef == nullptr) {
1325         napi_create_promise(env, &(asyncContext->deferred), &result);
1326     } else {
1327         napi_get_undefined(env, &result);
1328     }
1329 
1330     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ModifyImageProperty",
1331         [](napi_env env, void *data) {
1332             auto context = static_cast<ImageSourceAsyncContext*>(data);
1333 
1334             if (!CheckExifDataValue(context->keyStr, context->valueStr, context->errMsg)) {
1335                 HiLog::Error(LABEL, "There is invalid exif data parameter");
1336                 context->status = ERR_MEDIA_VALUE_INVALID;
1337                 return;
1338             }
1339             if (!IsSameTextStr(context->pathName, "")) {
1340                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1341                     context->keyStr, context->valueStr, context->pathName);
1342             } else if (context->fdIndex != -1) {
1343                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1344                     context->keyStr, context->valueStr, context->fdIndex);
1345             } else if (context->sourceBuffer != nullptr) {
1346                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1347                     context->keyStr, context->valueStr, static_cast<uint8_t *>(context->sourceBuffer),
1348                     context->sourceBufferSize);
1349             } else {
1350                 HiLog::Error(LABEL, "There is no image source!");
1351             }
1352         },
1353         reinterpret_cast<napi_async_complete_callback>(ModifyImagePropertyComplete),
1354         asyncContext,
1355         asyncContext->work);
1356 
1357     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1358         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1359     return result;
1360 }
1361 
GetImageProperty(napi_env env,napi_callback_info info)1362 napi_value ImageSourceNapi::GetImageProperty(napi_env env, napi_callback_info info)
1363 {
1364     StartTrace(HITRACE_TAG_ZIMAGE, "GetImageProperty");
1365     napi_value result = nullptr;
1366     napi_get_undefined(env, &result);
1367 
1368     napi_status status;
1369     std::unique_ptr<ImageSourceAsyncContext> asyncContext = UnwrapContext(env, info);
1370     if (asyncContext == nullptr) {
1371         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
1372             "async context unwrap failed");
1373     }
1374 
1375     if (asyncContext->callbackRef == nullptr) {
1376         napi_create_promise(env, &(asyncContext->deferred), &result);
1377     } else {
1378         napi_get_undefined(env, &result);
1379     }
1380 
1381     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetImageProperty",
1382         [](napi_env env, void *data) {
1383             auto context = static_cast<ImageSourceAsyncContext*>(data);
1384             context->status = context->rImageSource->GetImagePropertyString(context->index,
1385                                                                             context->keyStr,
1386                                                                             context->valueStr);
1387         },
1388         reinterpret_cast<napi_async_complete_callback>(GetImagePropertyComplete),
1389         asyncContext,
1390         asyncContext->work);
1391 
1392     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1393         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1394     FinishTrace(HITRACE_TAG_ZIMAGE);
1395     return result;
1396 }
1397 
UpdateDataExecute(napi_env env,void * data)1398 static void UpdateDataExecute(napi_env env, void *data)
1399 {
1400     auto context = static_cast<ImageSourceAsyncContext*>(data);
1401     uint8_t *buffer = static_cast<uint8_t*>(context->updataBuffer);
1402     if (context->updataBufferOffset < context->updataBufferSize) {
1403         buffer = buffer + context->updataBufferOffset;
1404     }
1405 
1406     uint32_t lastSize = context->updataBufferSize - context->updataBufferOffset;
1407     uint32_t size = context->updataLength < lastSize ? context->updataLength : lastSize;
1408 
1409     uint32_t res = context->rImageSource->UpdateData(buffer, size,
1410                                                      context->isCompleted);
1411     context->isSuccess = res == 0;
1412     if (context->isSuccess && context->constructor_ != nullptr) {
1413         auto incPixelMap = context->constructor_->GetIncrementalPixelMap();
1414         if (incPixelMap != nullptr) {
1415             uint8_t decodeProgress = 0;
1416             uint32_t err = incPixelMap->PromoteDecoding(decodeProgress);
1417             if (!(err == SUCCESS || (err == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && !context->isCompleted))) {
1418                 HiLog::Error(LABEL, "UpdateData PromoteDecoding error");
1419                 context->isSuccess = false;
1420             }
1421             if (context->isCompleted) {
1422                 incPixelMap->DetachFromDecoding();
1423             }
1424         }
1425     }
1426 }
1427 
UpdateDataComplete(napi_env env,napi_status status,void * data)1428 static void UpdateDataComplete(napi_env env, napi_status status, void *data)
1429 {
1430     napi_value result = nullptr;
1431     napi_create_object(env, &result);
1432 
1433     auto context = static_cast<ImageSourceAsyncContext*>(data);
1434 
1435     napi_get_boolean(env, context->isSuccess, &result);
1436     ImageSourceCallbackRoutine(env, context, result);
1437 }
1438 
isNapiTypedArray(napi_env env,napi_value val)1439 static bool isNapiTypedArray(napi_env env, napi_value val)
1440 {
1441     bool res = false;
1442     napi_is_typedarray(env, val, &res);
1443     HiLog::Debug(LABEL, "isNapiTypedArray %{public}d", res);
1444     return res;
1445 }
1446 
UpdateData(napi_env env,napi_callback_info info)1447 napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info)
1448 {
1449     napi_value result = nullptr;
1450     napi_get_undefined(env, &result);
1451 
1452     int32_t refCount = 1;
1453     napi_status status;
1454     napi_value thisVar = nullptr;
1455     napi_value argValue[NUM_5] = {0};
1456     size_t argCount = 5;
1457     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1458     HiLog::Debug(LABEL, "UpdateData argCount is [%{public}zu]", argCount);
1459 
1460     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1461 
1462     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
1463     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1464 
1465     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
1466         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1467 
1468     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
1469 
1470     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
1471         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1472     HiLog::Debug(LABEL, "UpdateData argCount %{public}zu", argCount);
1473     if (argCount > NUM_0 && isNapiTypedArray(env, argValue[NUM_0])) {
1474         HiLog::Error(LABEL, "UpdateData napi_get_arraybuffer_info ");
1475         napi_typedarray_type type;
1476         napi_value arraybuffer;
1477         size_t offset;
1478         status = napi_get_typedarray_info(env, argValue[NUM_0], &type,
1479             &(asyncContext->updataBufferSize), &(asyncContext->updataBuffer),
1480             &arraybuffer, &offset);
1481     }
1482 
1483     if (argCount >= NUM_2 && ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_boolean) {
1484         status = napi_get_value_bool(env, argValue[NUM_1], &(asyncContext->isCompleted));
1485     }
1486 
1487     if (argCount >= NUM_3 && ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_number) {
1488         asyncContext->updataBufferOffset = 0;
1489         status = napi_get_value_uint32(env, argValue[NUM_2], &(asyncContext->updataBufferOffset));
1490         HiLog::Debug(LABEL, "asyncContext->updataBufferOffset is [%{public}u]", asyncContext->updataBufferOffset);
1491     }
1492 
1493     if (argCount >= NUM_4 && ImageNapiUtils::getType(env, argValue[NUM_3]) == napi_number) {
1494         asyncContext->updataLength = 0;
1495         status = napi_get_value_uint32(env, argValue[NUM_3], &(asyncContext->updataLength));
1496         HiLog::Debug(LABEL, "asyncContext->updataLength is [%{public}u]", asyncContext->updataLength);
1497     }
1498 
1499     if (!IMG_IS_OK(status)) {
1500         HiLog::Error(LABEL, "fail to UpdateData");
1501         napi_get_undefined(env, &result);
1502         return result;
1503     }
1504 
1505     if (argCount == NUM_5 && ImageNapiUtils::getType(env, argValue[NUM_4]) == napi_function) {
1506         napi_create_reference(env, argValue[NUM_4], refCount, &asyncContext->callbackRef);
1507     }
1508 
1509     if (argCount == NUM_3 && ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_function) {
1510         napi_create_reference(env, argValue[NUM_2], refCount, &asyncContext->callbackRef);
1511     }
1512 
1513     if (asyncContext->callbackRef == nullptr) {
1514         napi_create_promise(env, &(asyncContext->deferred), &result);
1515     } else {
1516         napi_get_undefined(env, &result);
1517     }
1518 
1519     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "UpdateData",
1520         UpdateDataExecute, UpdateDataComplete, asyncContext, asyncContext->work);
1521 
1522     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1523         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1524     return result;
1525 }
1526 
ReleaseComplete(napi_env env,napi_status status,void * data)1527 static void ReleaseComplete(napi_env env, napi_status status, void *data)
1528 {
1529     napi_value result = nullptr;
1530     napi_get_undefined(env, &result);
1531 
1532     auto context = static_cast<ImageSourceAsyncContext*>(data);
1533     delete context->constructor_;
1534     context->constructor_ = nullptr;
1535     ImageSourceCallbackRoutine(env, context, result);
1536 }
1537 
Release(napi_env env,napi_callback_info info)1538 napi_value ImageSourceNapi::Release(napi_env env, napi_callback_info info)
1539 {
1540     HiLog::Debug(LABEL, "Release enter");
1541     napi_value result = nullptr;
1542     napi_get_undefined(env, &result);
1543 
1544     int32_t refCount = 1;
1545     napi_status status;
1546     napi_value thisVar = nullptr;
1547     napi_value argValue[NUM_1] = {0};
1548     size_t argCount = 1;
1549 
1550     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1551     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
1552     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1553 
1554     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
1555     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1556 
1557     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_), result,
1558         HiLog::Error(LABEL, "fail to unwrap context"));
1559 
1560     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
1561     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
1562         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
1563     }
1564 
1565     if (asyncContext->callbackRef == nullptr) {
1566         napi_create_promise(env, &(asyncContext->deferred), &result);
1567     }
1568 
1569     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Release",
1570         [](napi_env env, void *data) {}, ReleaseComplete, asyncContext, asyncContext->work);
1571     HiLog::Debug(LABEL, "Release exit");
1572     return result;
1573 }
1574 
release()1575 void ImageSourceNapi::release()
1576 {
1577     if (!isRelease) {
1578         if (nativeImgSrc != nullptr) {
1579             nativeImgSrc = nullptr;
1580         }
1581         isRelease = true;
1582     }
1583 }
1584 
UnwrapContextForList(napi_env env,napi_callback_info info)1585 static std::unique_ptr<ImageSourceAsyncContext> UnwrapContextForList(napi_env env, napi_callback_info info)
1586 {
1587     int32_t refCount = 1;
1588     napi_status status;
1589     napi_value thisVar = nullptr;
1590     napi_value argValue[NUM_3] = {0};
1591     size_t argCount = NUM_3;
1592 
1593     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1594     HiLog::Debug(LABEL, "UnwrapContextForList argCount is [%{public}zu]", argCount);
1595 
1596     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1597 
1598     std::unique_ptr<ImageSourceAsyncContext> context = std::make_unique<ImageSourceAsyncContext>();
1599     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1600 
1601     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
1602         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1603 
1604     context->rImageSource = context->constructor_->nativeImgSrc;
1605 
1606     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource),
1607         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1608 
1609     if (argCount > NUM_2) {
1610         HiLog::Error(LABEL, "argCount missmatch");
1611         return nullptr;
1612     }
1613 
1614     if (argCount > NUM_0) {
1615         if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
1616             HiLog::Debug(LABEL, "UnwrapContextForList object");
1617             if (!ParseDecodeOptions(env, argValue[NUM_0], &(context->decodeOpts),
1618                                     &(context->index), context->errMsg)) {
1619                 HiLog::Error(LABEL, "DecodeOptions mismatch");
1620             }
1621         }
1622 
1623         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1624             HiLog::Debug(LABEL, "UnwrapContextForList function");
1625             napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef);
1626         }
1627     }
1628 
1629     return context;
1630 }
1631 
CheckAsyncContext(ImageSourceAsyncContext * context,bool check)1632 static ImageSourceAsyncContext* CheckAsyncContext(ImageSourceAsyncContext* context, bool check)
1633 {
1634     if (context == nullptr) {
1635         HiLog::Error(LABEL, "context is nullptr");
1636         return nullptr;
1637     }
1638 
1639     if (check) {
1640         if (context->errMsg.size() > 0) {
1641             HiLog::Error(LABEL, "mismatch args");
1642             context->status = ERROR;
1643             return nullptr;
1644         }
1645 
1646         if (context->rImageSource == nullptr) {
1647             HiLog::Error(LABEL, "empty context rImageSource");
1648             return nullptr;
1649         }
1650     }
1651 
1652     return context;
1653 }
1654 
STATIC_EXEC_FUNC(CreatePixelMapList)1655 STATIC_EXEC_FUNC(CreatePixelMapList)
1656 {
1657     if (data == nullptr) {
1658         HiLog::Error(LABEL, "data is nullptr");
1659         return;
1660     }
1661 
1662     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), true);
1663     if (context == nullptr) {
1664         HiLog::Error(LABEL, "check async context fail");
1665         return;
1666     }
1667 
1668     context->pixelMaps = nullptr;
1669     uint32_t errorCode = 0;
1670     uint32_t frameCount = context->rImageSource->GetFrameCount(errorCode);
1671     if ((errorCode == SUCCESS) && (context->index >= NUM_0) && (context->index < frameCount)) {
1672         context->pixelMaps = context->rImageSource->CreatePixelMapList(context->decodeOpts, errorCode);
1673     }
1674     if ((errorCode == SUCCESS) && IMG_NOT_NULL(context->pixelMaps)) {
1675         context->status = SUCCESS;
1676     } else {
1677         HiLog::Error(LABEL, "Create PixelMap List error, error=%{public}u", errorCode);
1678         context->errMsg = "Create PixelMap List error";
1679         context->status = ERROR;
1680     }
1681 }
1682 
STATIC_COMPLETE_FUNC(CreatePixelMapList)1683 STATIC_COMPLETE_FUNC(CreatePixelMapList)
1684 {
1685     if (data == nullptr) {
1686         HiLog::Error(LABEL, "data is nullptr");
1687         return;
1688     }
1689 
1690     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), false);
1691     if (context == nullptr) {
1692         HiLog::Error(LABEL, "check async context fail");
1693         return;
1694     }
1695 
1696     napi_value result = nullptr;
1697     if ((context->status == SUCCESS) && IMG_NOT_NULL(context->pixelMaps)) {
1698         HiLog::Debug(LABEL, "CreatePixelMapListComplete array");
1699         napi_create_array(env, &result);
1700         size_t i = 0;
1701         for (auto &pixelMap : *context->pixelMaps.get()) {
1702             auto napiPixelMap = PixelMapNapi::CreatePixelMap(env, std::move(pixelMap));
1703             napi_set_element(env, result, i, napiPixelMap);
1704             i++;
1705         }
1706     } else {
1707         HiLog::Debug(LABEL, "CreatePixelMapListComplete undefined");
1708         napi_get_undefined(env, &result);
1709     }
1710 
1711     HiLog::Debug(LABEL, "CreatePixelMapListComplete set to nullptr");
1712     context->pixelMaps = nullptr;
1713 
1714     ImageSourceCallbackRoutine(env, context, result);
1715 }
1716 
CreatePixelMapList(napi_env env,napi_callback_info info)1717 napi_value ImageSourceNapi::CreatePixelMapList(napi_env env, napi_callback_info info)
1718 {
1719     StartTrace(HITRACE_TAG_ZIMAGE, "CreatePixelMapList");
1720 
1721     auto asyncContext = UnwrapContextForList(env, info);
1722     if (asyncContext == nullptr) {
1723         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
1724             "async context unwrap failed");
1725     }
1726 
1727     napi_value result = nullptr;
1728     napi_get_undefined(env, &result);
1729     if (asyncContext->callbackRef == nullptr) {
1730         napi_create_promise(env, &(asyncContext->deferred), &result);
1731     } else {
1732         napi_get_undefined(env, &result);
1733     }
1734 
1735     ImageNapiUtils::HicheckerReport();
1736 
1737     napi_status status;
1738     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "CreatePixelMapList", CreatePixelMapListExec,
1739         CreatePixelMapListComplete, asyncContext, asyncContext->work);
1740     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to create async work"));
1741 
1742     FinishTrace(HITRACE_TAG_ZIMAGE);
1743     return result;
1744 }
1745 
STATIC_EXEC_FUNC(GetDelayTime)1746 STATIC_EXEC_FUNC(GetDelayTime)
1747 {
1748     if (data == nullptr) {
1749         HiLog::Error(LABEL, "data is nullptr");
1750         return;
1751     }
1752 
1753     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), true);
1754     if (context == nullptr) {
1755         HiLog::Error(LABEL, "check async context fail");
1756         return;
1757     }
1758 
1759     uint32_t errorCode = 0;
1760     context->delayTimes = context->rImageSource->GetDelayTime(errorCode);
1761     if ((errorCode == SUCCESS) && IMG_NOT_NULL(context->delayTimes)) {
1762         context->status = SUCCESS;
1763     } else {
1764         HiLog::Error(LABEL, "Get DelayTime error, error=%{public}u", errorCode);
1765         context->errMsg = "Get DelayTime error";
1766         context->status = errorCode;
1767     }
1768 }
1769 
STATIC_COMPLETE_FUNC(GetDelayTime)1770 STATIC_COMPLETE_FUNC(GetDelayTime)
1771 {
1772     if (data == nullptr) {
1773         HiLog::Error(LABEL, "data is nullptr");
1774         return;
1775     }
1776 
1777     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), false);
1778     if (context == nullptr) {
1779         HiLog::Error(LABEL, "check async context fail");
1780         return;
1781     }
1782 
1783     napi_value result = nullptr;
1784     if (context->status == SUCCESS && IMG_NOT_NULL(context->delayTimes)) {
1785         HiLog::Debug(LABEL, "GetDelayTimeComplete array");
1786         napi_create_array(env, &result);
1787         size_t i = 0;
1788         for (auto delayTime : *context->delayTimes) {
1789             napi_value napiDelayTime = nullptr;
1790             napi_create_uint32(env, delayTime, &napiDelayTime);
1791             napi_set_element(env, result, i, napiDelayTime);
1792             i++;
1793         }
1794     } else {
1795         HiLog::Debug(LABEL, "GetDelayTimeComplete undefined");
1796         napi_get_undefined(env, &result);
1797     }
1798 
1799     HiLog::Debug(LABEL, "GetDelayTimeComplete set to nullptr");
1800     context->delayTimes = nullptr;
1801     ImageSourceCallbackRoutine(env, context, result);
1802 }
1803 
GetDelayTime(napi_env env,napi_callback_info info)1804 napi_value ImageSourceNapi::GetDelayTime(napi_env env, napi_callback_info info)
1805 {
1806     StartTrace(HITRACE_TAG_ZIMAGE, "GetDelayTime");
1807 
1808     auto asyncContext = UnwrapContextForList(env, info);
1809     if (asyncContext == nullptr) {
1810         return ImageNapiUtils::ThrowExceptionError(env, ERR_IMAGE_DATA_ABNORMAL,
1811             "async context unwrap failed");
1812     }
1813 
1814     napi_value result = nullptr;
1815     napi_get_undefined(env, &result);
1816     if (asyncContext->callbackRef == nullptr) {
1817         napi_create_promise(env, &(asyncContext->deferred), &result);
1818     } else {
1819         napi_get_undefined(env, &result);
1820     }
1821 
1822     napi_status status;
1823     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetDelayTime", GetDelayTimeExec,
1824         GetDelayTimeComplete, asyncContext, asyncContext->work);
1825     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to create async work"));
1826 
1827     FinishTrace(HITRACE_TAG_ZIMAGE);
1828     return result;
1829 }
1830 
STATIC_EXEC_FUNC(GetFrameCount)1831 STATIC_EXEC_FUNC(GetFrameCount)
1832 {
1833     if (data == nullptr) {
1834         HiLog::Error(LABEL, "data is nullptr");
1835         return;
1836     }
1837 
1838     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), true);
1839     if (context == nullptr) {
1840         HiLog::Error(LABEL, "check async context fail");
1841         return;
1842     }
1843 
1844     uint32_t errorCode = 0;
1845     context->frameCount = context->rImageSource->GetFrameCount(errorCode);
1846     HiLog::Debug(LABEL, "GetFrameCountExec count=%{public}u, error=%{public}u", context->frameCount, errorCode);
1847     if (errorCode == SUCCESS) {
1848         context->status = SUCCESS;
1849     } else {
1850         HiLog::Error(LABEL, "Get FrameCount error, error=%{public}u", errorCode);
1851         context->errMsg = "Get FrameCount error";
1852         context->status = errorCode;
1853     }
1854 }
1855 
STATIC_COMPLETE_FUNC(GetFrameCount)1856 STATIC_COMPLETE_FUNC(GetFrameCount)
1857 {
1858     if (data == nullptr) {
1859         HiLog::Error(LABEL, "data is nullptr");
1860         return;
1861     }
1862 
1863     auto context = CheckAsyncContext(static_cast<ImageSourceAsyncContext*>(data), false);
1864     if (context == nullptr) {
1865         HiLog::Error(LABEL, "check async context fail");
1866         return;
1867     }
1868 
1869     napi_value result = nullptr;
1870     if (context->status == SUCCESS) {
1871         HiLog::Debug(LABEL, "GetFrameCountComplete uint");
1872         napi_create_uint32(env, context->frameCount, &result);
1873     } else {
1874         HiLog::Debug(LABEL, "GetFrameCountComplete undefined");
1875         napi_get_undefined(env, &result);
1876     }
1877 
1878     context->frameCount = 0;
1879     ImageSourceCallbackRoutine(env, context, result);
1880 }
1881 
GetFrameCount(napi_env env,napi_callback_info info)1882 napi_value ImageSourceNapi::GetFrameCount(napi_env env, napi_callback_info info)
1883 {
1884     StartTrace(HITRACE_TAG_ZIMAGE, "GetFrameCount");
1885 
1886     auto asyncContext = UnwrapContextForList(env, info);
1887     if (asyncContext == nullptr) {
1888         return ImageNapiUtils::ThrowExceptionError(env, ERR_IMAGE_DATA_ABNORMAL,
1889             "async context unwrap failed");
1890     }
1891 
1892     napi_value result = nullptr;
1893     napi_get_undefined(env, &result);
1894     if (asyncContext->callbackRef == nullptr) {
1895         napi_create_promise(env, &(asyncContext->deferred), &result);
1896     } else {
1897         napi_get_undefined(env, &result);
1898     }
1899 
1900     napi_status status;
1901     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetFrameCount", GetFrameCountExec,
1902         GetFrameCountComplete, asyncContext, asyncContext->work);
1903     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to create async work"));
1904 
1905     FinishTrace(HITRACE_TAG_ZIMAGE);
1906     return result;
1907 }
1908 
CreateImageSourceNapi(napi_env env,napi_value * result)1909 int32_t ImageSourceNapi::CreateImageSourceNapi(napi_env env, napi_value* result)
1910 {
1911     napi_value constructor = nullptr;
1912     napi_status status = napi_ok;
1913     PrepareNapiEnv(env);
1914 
1915     status = napi_get_reference_value(env, sConstructor_, &constructor);
1916     if (status == napi_ok && constructor != nullptr) {
1917         status = napi_new_instance(env, constructor, NUM_0, nullptr, result);
1918     }
1919 
1920     if (status != napi_ok || result == nullptr) {
1921         HiLog::Error(LABEL, "CreateImageSourceNapi new instance failed");
1922         napi_get_undefined(env, result);
1923         return ERR_IMAGE_DATA_ABNORMAL;
1924     }
1925     return SUCCESS;
1926 }
1927 
SetIncrementalPixelMap(std::shared_ptr<IncrementalPixelMap> incrementalPixelMap)1928 void ImageSourceNapi::SetIncrementalPixelMap(std::shared_ptr<IncrementalPixelMap> incrementalPixelMap)
1929 {
1930     navIncPixelMap_ = incrementalPixelMap;
1931 }
1932 
SetNativeImageSource(std::shared_ptr<ImageSource> imageSource)1933 void ImageSourceNapi::SetNativeImageSource(std::shared_ptr<ImageSource> imageSource)
1934 {
1935     nativeImgSrc = imageSource;
1936 }
1937 
SetImageResource(ImageResource resource)1938 void ImageSourceNapi::SetImageResource(ImageResource resource)
1939 {
1940     resource_.type = resource.type;
1941     resource_.fd = resource.fd;
1942     resource_.path = resource.path;
1943     resource_.buffer = resource.buffer;
1944     resource_.bufferSize = resource.bufferSize;
1945 }
1946 
GetImageResource()1947 ImageResource ImageSourceNapi::GetImageResource()
1948 {
1949     return resource_;
1950 }
1951 }  // namespace Media
1952 }  // namespace OHOS
1953