• 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 uint32_t NUM_0 = 0;
29     constexpr uint32_t NUM_1 = 1;
30     constexpr uint32_t NUM_2 = 2;
31     constexpr uint32_t NUM_3 = 3;
32     constexpr uint32_t NUM_4 = 4;
33     constexpr uint32_t NUM_5 = 5;
34     constexpr uint32_t NUM_8 = 8;
35 }
36 
37 namespace OHOS {
38 namespace Media {
39 thread_local napi_ref ImageSourceNapi::sConstructor_ = nullptr;
40 std::shared_ptr<ImageSource> ImageSourceNapi::sImgSrc_ = nullptr;
41 std::shared_ptr<IncrementalPixelMap> ImageSourceNapi::sIncPixelMap_ = nullptr;
42 static const std::string CLASS_NAME = "ImageSource";
43 static const std::string FILE_URL_PREFIX = "file://";
44 std::string ImageSourceNapi::filePath_ = "";
45 int ImageSourceNapi::fileDescriptor_ = -1;
46 void* ImageSourceNapi::fileBuffer_ = nullptr;
47 size_t ImageSourceNapi::fileBufferSize_ = 0;
48 
49 napi_ref ImageSourceNapi::pixelMapFormatRef_ = nullptr;
50 napi_ref ImageSourceNapi::propertyKeyRef_ = nullptr;
51 napi_ref ImageSourceNapi::imageFormatRef_ = nullptr;
52 napi_ref ImageSourceNapi::alphaTypeRef_ = nullptr;
53 napi_ref ImageSourceNapi::scaleModeRef_ = nullptr;
54 napi_ref ImageSourceNapi::componentTypeRef_ = nullptr;
55 
56 struct ImageSourceAsyncContext {
57     napi_env env;
58     napi_async_work work;
59     napi_deferred deferred;
60     napi_ref callbackRef = nullptr;
61     ImageSourceNapi *constructor_;
62     uint32_t status;
63     std::string pathName;
64     int fdIndex;
65     void* sourceBuffer;
66     size_t sourceBufferSize;
67     std::string keyStr;
68     std::string valueStr;
69     std::string defaultValueStr;
70     int32_t valueInt;
71     int32_t deufltValueInt;
72     void *updataBuffer;
73     size_t updataBufferSize;
74     uint32_t updataBufferOffset = 0;
75     uint32_t updataLength = 0;
76     bool isCompleted = false;
77     bool isSuccess = false;
78     size_t pathNameLength;
79     SourceOptions opts;
80     uint32_t index = 0;
81     ImageInfo imageInfo;
82     DecodeOptions decodeOpts;
83     std::shared_ptr<ImageSource> rImageSource;
84     std::shared_ptr<PixelMap> rPixelMap;
85     std::string errMsg;
86 };
87 
88 struct ImageEnum {
89     std::string name;
90     int32_t numVal;
91     std::string strVal;
92 };
93 
94 static std::vector<struct ImageEnum> sPixelMapFormatMap = {
95     {"UNKNOWN", 0, ""},
96     {"ARGB_8888", 1, ""},
97     {"RGB_565", 2, ""},
98     {"RGBA_8888", 3, ""},
99     {"BGRA_8888", 4, ""},
100     {"RGB_888", 5, ""},
101     {"ALPHA_8", 6, ""},
102     {"RGBA_F16", 7, ""},
103     {"NV21", 8, ""},
104     {"NV12", 9, ""},
105 };
106 static std::vector<struct ImageEnum> sPropertyKeyMap = {
107     {"BITS_PER_SAMPLE", 0, "BitsPerSample"},
108     {"ORIENTATION", 0, "Orientation"},
109     {"IMAGE_LENGTH", 0, "ImageLength"},
110     {"IMAGE_WIDTH", 0, "ImageWidth"},
111     {"GPS_LATITUDE", 0, "GPSLatitude"},
112     {"GPS_LONGITUDE", 0, "GPSLongitude"},
113     {"GPS_LATITUDE_REF", 0, "GPSLatitudeRef"},
114     {"GPS_LONGITUDE_REF", 0, "GPSLongitudeRef"},
115     {"DATE_TIME_ORIGINAL", 0, "DateTimeOriginal"},
116     {"EXPOSURE_TIME", 0, "ExposureTime"},
117     {"SCENE_TYPE", 0, "SceneType"},
118     {"ISO_SPEED_RATINGS", 0, "ISOSpeedRatings"},
119     {"F_NUMBER", 0, "FNumber"},
120     {"COMPRESSED_BITS_PER_PIXEL", 0, "CompressedBitsPerPixel"},
121 };
122 static std::vector<struct ImageEnum> sImageFormatMap = {
123     {"YCBCR_422_SP", 1000, ""},
124     {"JPEG", 2000, ""},
125 };
126 static std::vector<struct ImageEnum> sAlphaTypeMap = {
127     {"UNKNOWN", 0, ""},
128     {"OPAQUE", 1, ""},
129     {"PREMUL", 2, ""},
130     {"UNPREMUL", 3, ""},
131 };
132 static std::vector<struct ImageEnum> sScaleModeMap = {
133     {"FIT_TARGET_SIZE", 0, ""},
134     {"CENTER_CROP", 1, ""},
135 };
136 static std::vector<struct ImageEnum> sComponentTypeMap = {
137     {"YUV_Y", 1, ""},
138     {"YUV_U", 2, ""},
139     {"YUV_V", 3, ""},
140     {"JPEG", 4, ""},
141 };
142 
GetStringArgument(napi_env env,napi_value value)143 static std::string GetStringArgument(napi_env env, napi_value value)
144 {
145     std::string strValue = "";
146     size_t bufLength = 0;
147     napi_status status = napi_get_value_string_utf8(env, value, nullptr, NUM_0, &bufLength);
148     if (status == napi_ok && bufLength > NUM_0 && bufLength < PATH_MAX) {
149         char *buffer = reinterpret_cast<char *>(malloc((bufLength + NUM_1) * sizeof(char)));
150         if (buffer == nullptr) {
151             HiLog::Error(LABEL, "No memory");
152             return strValue;
153         }
154 
155         status = napi_get_value_string_utf8(env, value, buffer, bufLength + NUM_1, &bufLength);
156         if (status == napi_ok) {
157             HiLog::Debug(LABEL, "Get Success");
158             strValue = buffer;
159         } else {
160             free(buffer);
161             buffer = nullptr;
162         }
163     }
164     return strValue;
165 }
166 
ImageSourceCallbackRoutine(napi_env env,ImageSourceAsyncContext * & context,const napi_value & valueParam)167 static void ImageSourceCallbackRoutine(napi_env env, ImageSourceAsyncContext* &context, const napi_value &valueParam)
168 {
169     napi_value result[NUM_2] = {0};
170     napi_value retVal;
171     napi_value callback = nullptr;
172 
173     napi_get_undefined(env, &result[NUM_0]);
174     napi_get_undefined(env, &result[NUM_1]);
175 
176     if (context == nullptr) {
177         HiLog::Error(LABEL, "context is nullptr");
178         return;
179     }
180 
181     if (context->status == SUCCESS) {
182         result[NUM_1] = valueParam;
183     } else if (context->errMsg.size() > 0) {
184         napi_create_string_utf8(env, context->errMsg.c_str(), NAPI_AUTO_LENGTH, &result[NUM_0]);
185     } else {
186         HiLog::Debug(LABEL, "error status, no message");
187         napi_create_string_utf8(env, "error status, no message", NAPI_AUTO_LENGTH, &result[NUM_0]);
188     }
189 
190     if (context->deferred) {
191         if (context->status == SUCCESS) {
192             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
193         } else {
194             napi_reject_deferred(env, context->deferred, result[NUM_0]);
195         }
196     } else {
197         HiLog::Debug(LABEL, "call callback function");
198         napi_get_reference_value(env, context->callbackRef, &callback);
199         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
200         napi_delete_reference(env, context->callbackRef);
201     }
202 
203     napi_delete_async_work(env, context->work);
204 
205     delete context;
206     context = nullptr;
207 }
208 
CreateEnumTypeObject(napi_env env,napi_valuetype type,napi_ref * ref,std::vector<struct ImageEnum> imageEnumMap)209 static napi_value CreateEnumTypeObject(napi_env env,
210     napi_valuetype type, napi_ref* ref, std::vector<struct ImageEnum> imageEnumMap)
211 {
212     napi_value result = nullptr;
213     napi_status status;
214     int32_t refCount = 1;
215     std::string propName;
216     status = napi_create_object(env, &result);
217     if (status == napi_ok) {
218         for (auto imgEnum : imageEnumMap) {
219             napi_value enumNapiValue = nullptr;
220             if (type == napi_string) {
221                 status = napi_create_string_utf8(env, imgEnum.strVal.c_str(),
222                     NAPI_AUTO_LENGTH, &enumNapiValue);
223             } else if (type == napi_number) {
224                 status = napi_create_int32(env, imgEnum.numVal, &enumNapiValue);
225             } else {
226                 HiLog::Error(LABEL, "Unsupported type %{public}d!", type);
227             }
228             if (status == napi_ok && enumNapiValue != nullptr) {
229                 status = napi_set_named_property(env, result, imgEnum.name.c_str(), enumNapiValue);
230             }
231             if (status != napi_ok) {
232                 HiLog::Error(LABEL, "Failed to add named prop!");
233                 break;
234             }
235         }
236 
237         if (status == napi_ok) {
238             status = napi_create_reference(env, result, refCount, ref);
239             if (status == napi_ok) {
240                 return result;
241             }
242         }
243     }
244     HiLog::Error(LABEL, "CreateEnumTypeObject is Failed!");
245     napi_get_undefined(env, &result);
246     return result;
247 }
248 
ImageSourceNapi()249 ImageSourceNapi::ImageSourceNapi():env_(nullptr)
250 {   }
251 
~ImageSourceNapi()252 ImageSourceNapi::~ImageSourceNapi()
253 {
254     release();
255 }
256 
257 struct ImageConstructorInfo {
258     std::string className;
259     napi_ref* classRef;
260     napi_callback constructor;
261     const napi_property_descriptor* property;
262     size_t propertyCount;
263     const napi_property_descriptor* staticProperty;
264     size_t staticPropertyCount;
265 };
266 
DoInit(napi_env env,napi_value exports,struct ImageConstructorInfo info)267 static napi_value DoInit(napi_env env, napi_value exports, struct ImageConstructorInfo info)
268 {
269     napi_value constructor = nullptr;
270     napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH,
271         info.constructor, nullptr, info.propertyCount, info.property, &constructor);
272     if (status != napi_ok) {
273         HiLog::Error(LABEL, "define class fail");
274         return nullptr;
275     }
276 
277     status = napi_create_reference(env, constructor, NUM_1, info.classRef);
278     if (status != napi_ok) {
279         HiLog::Error(LABEL, "create reference fail");
280         return nullptr;
281     }
282 
283     napi_value global = nullptr;
284     status = napi_get_global(env, &global);
285     if (status != napi_ok) {
286         HiLog::Error(LABEL, "Init:get global fail");
287         return nullptr;
288     }
289 
290     status = napi_set_named_property(env, global, info.className.c_str(), constructor);
291     if (status != napi_ok) {
292         HiLog::Error(LABEL, "Init:set global named property fail");
293         return nullptr;
294     }
295 
296     status = napi_set_named_property(env, exports, info.className.c_str(), constructor);
297     if (status != napi_ok) {
298         HiLog::Error(LABEL, "set named property fail");
299         return nullptr;
300     }
301 
302     status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty);
303     if (status != napi_ok) {
304         HiLog::Error(LABEL, "define properties fail");
305         return nullptr;
306     }
307     return exports;
308 }
309 
Init(napi_env env,napi_value exports)310 napi_value ImageSourceNapi::Init(napi_env env, napi_value exports)
311 {
312     napi_property_descriptor properties[] = {
313         DECLARE_NAPI_FUNCTION("getImageInfo", GetImageInfo),
314         DECLARE_NAPI_FUNCTION("modifyImageProperty", ModifyImageProperty),
315         DECLARE_NAPI_FUNCTION("getImageProperty", GetImageProperty),
316         DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap),
317         DECLARE_NAPI_FUNCTION("updateData", UpdateData),
318         DECLARE_NAPI_FUNCTION("release", Release),
319         DECLARE_NAPI_GETTER("supportedFormats", GetSupportedFormats),
320     };
321 
322     napi_property_descriptor static_prop[] = {
323         DECLARE_NAPI_STATIC_FUNCTION("createImageSource", CreateImageSource),
324         DECLARE_NAPI_STATIC_FUNCTION("CreateIncrementalSource", CreateIncrementalSource),
325         DECLARE_NAPI_PROPERTY("PixelMapFormat",
326             CreateEnumTypeObject(env, napi_number, &pixelMapFormatRef_, sPixelMapFormatMap)),
327         DECLARE_NAPI_PROPERTY("PropertyKey",
328             CreateEnumTypeObject(env, napi_string, &propertyKeyRef_, sPropertyKeyMap)),
329         DECLARE_NAPI_PROPERTY("ImageFormat",
330             CreateEnumTypeObject(env, napi_number, &imageFormatRef_, sImageFormatMap)),
331         DECLARE_NAPI_PROPERTY("AlphaType",
332             CreateEnumTypeObject(env, napi_number, &alphaTypeRef_, sAlphaTypeMap)),
333         DECLARE_NAPI_PROPERTY("ScaleMode",
334             CreateEnumTypeObject(env, napi_number, &scaleModeRef_, sScaleModeMap)),
335         DECLARE_NAPI_PROPERTY("ComponentType",
336             CreateEnumTypeObject(env, napi_number, &componentTypeRef_, sComponentTypeMap)),
337     };
338 
339     struct ImageConstructorInfo info = {
340         .className = CLASS_NAME,
341         .classRef = &sConstructor_,
342         .constructor = Constructor,
343         .property = properties,
344         .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]),
345         .staticProperty = static_prop,
346         .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]),
347     };
348 
349     if (DoInit(env, exports, info)) {
350         return nullptr;
351     }
352 
353     HiLog::Debug(LABEL, "Init success");
354     return exports;
355 }
356 
Constructor(napi_env env,napi_callback_info info)357 napi_value ImageSourceNapi::Constructor(napi_env env, napi_callback_info info)
358 {
359     napi_value undefineValue = nullptr;
360     napi_get_undefined(env, &undefineValue);
361 
362     napi_status status;
363     napi_value thisVar = nullptr;
364     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
365     if (status == napi_ok && thisVar != nullptr) {
366         std::unique_ptr<ImageSourceNapi> pImgSrcNapi = std::make_unique<ImageSourceNapi>();
367         if (pImgSrcNapi != nullptr) {
368             pImgSrcNapi->env_ = env;
369             pImgSrcNapi->nativeImgSrc = sImgSrc_;
370             pImgSrcNapi->navIncPixelMap_ = sIncPixelMap_;
371             sIncPixelMap_ = nullptr;
372 
373             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgSrcNapi.get()),
374                                ImageSourceNapi::Destructor, nullptr, nullptr);
375             if (status == napi_ok) {
376                 pImgSrcNapi.release();
377                 return thisVar;
378             } else {
379                 HiLog::Error(LABEL, "Failure wrapping js to native napi");
380             }
381         }
382     }
383 
384     return undefineValue;
385 }
386 
Destructor(napi_env env,void * nativeObject,void * finalize)387 void ImageSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
388 {
389 }
390 
GetSupportedFormats(napi_env env,napi_callback_info info)391 napi_value ImageSourceNapi::GetSupportedFormats(napi_env env, napi_callback_info info)
392 {
393     napi_value result = nullptr;
394     napi_get_undefined(env, &result);
395 
396     napi_status status;
397     napi_value thisVar = nullptr;
398     size_t argCount = 0;
399     HiLog::Debug(LABEL, "GetSupportedFormats IN");
400 
401     IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
402 
403     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
404 
405     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
406     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
407 
408     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
409         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
410     std::set<std::string> formats;
411     uint32_t ret = asyncContext->constructor_->nativeImgSrc->GetSupportedFormats(formats);
412 
413     IMG_NAPI_CHECK_RET_D((ret == SUCCESS),
414         nullptr, HiLog::Error(LABEL, "fail to get supported formats"));
415 
416     napi_create_array(env, &result);
417     size_t i = 0;
418     for (const std::string& formatStr: formats) {
419         napi_value format = nullptr;
420         napi_create_string_latin1(env, formatStr.c_str(), formatStr.length(), &format);
421         napi_set_element(env, result, i, format);
422         i++;
423     }
424     return result;
425 }
426 
STATIC_COMPLETE_FUNC(GetImageInfo)427 STATIC_COMPLETE_FUNC(GetImageInfo)
428 {
429     HiLog::Debug(LABEL, "[ImageSource]GetImageInfoComplete IN");
430     napi_value result = nullptr;
431     auto context = static_cast<ImageSourceAsyncContext*>(data);
432     if (context->status == SUCCESS) {
433         napi_create_object(env, &result);
434 
435         napi_value size = nullptr;
436         napi_create_object(env, &size);
437 
438         napi_value sizeWith = nullptr;
439         napi_create_int32(env, context->imageInfo.size.width, &sizeWith);
440         napi_set_named_property(env, size, "width", sizeWith);
441 
442         napi_value sizeHeight = nullptr;
443         napi_create_int32(env, context->imageInfo.size.height, &sizeHeight);
444         napi_set_named_property(env, size, "height", sizeHeight);
445 
446         napi_set_named_property(env, result, "size", size);
447 
448         napi_value pixelFormatValue = nullptr;
449         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.pixelFormat), &pixelFormatValue);
450         napi_set_named_property(env, result, "pixelFormat", pixelFormatValue);
451 
452         napi_value colorSpaceValue = nullptr;
453         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.colorSpace), &colorSpaceValue);
454         napi_set_named_property(env, result, "colorSpace", colorSpaceValue);
455 
456         napi_value alphaTypeValue = nullptr;
457         napi_create_int32(env, static_cast<int32_t>(context->imageInfo.alphaType), &alphaTypeValue);
458         napi_set_named_property(env, result, "alphaType", alphaTypeValue);
459 
460         if (!IMG_IS_OK(status)) {
461             context->status = ERROR;
462             HiLog::Error(LABEL, "napi_create_int32 failed!");
463             napi_get_undefined(env, &result);
464         } else {
465             context->status = SUCCESS;
466         }
467     } else {
468         napi_get_undefined(env, &result);
469     }
470 
471     HiLog::Debug(LABEL, "[ImageSource]GetImageInfoComplete OUT");
472     ImageSourceCallbackRoutine(env, context, result);
473 }
474 
ParseSize(napi_env env,napi_value root,Size * size)475 static bool ParseSize(napi_env env, napi_value root, Size* size)
476 {
477     if (size == nullptr) {
478         HiLog::Error(LABEL, "size is nullptr");
479         return false;
480     }
481     if (!GET_INT32_BY_NAME(root, "height", size->height)) {
482         return false;
483     }
484 
485     if (!GET_INT32_BY_NAME(root, "width", size->width)) {
486         return false;
487     }
488 
489     return true;
490 }
491 
ParseRegion(napi_env env,napi_value root,Rect * region)492 static bool ParseRegion(napi_env env, napi_value root, Rect* region)
493 {
494     napi_value tmpValue = nullptr;
495 
496     if (region == nullptr) {
497         HiLog::Error(LABEL, "region is nullptr");
498         return false;
499     }
500 
501     if (!GET_INT32_BY_NAME(root, "x", region->left)) {
502         return false;
503     }
504 
505     if (!GET_INT32_BY_NAME(root, "y", region->top)) {
506         return false;
507     }
508 
509     if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
510         return false;
511     }
512 
513     if (!GET_INT32_BY_NAME(tmpValue, "height", region->height)) {
514         return false;
515     }
516 
517     if (!GET_INT32_BY_NAME(tmpValue, "width", region->width)) {
518         return false;
519     }
520 
521     return true;
522 }
523 
IsSupportPixelFormat(int32_t val)524 static bool IsSupportPixelFormat(int32_t val)
525 {
526     if (val >= static_cast<int32_t>(PixelFormat::UNKNOWN) &&
527         val <= static_cast<int32_t>(PixelFormat::RGBA_F16)) {
528         return true;
529     }
530 
531     return false;
532 }
533 
ParsePixlForamt(int32_t val)534 static PixelFormat ParsePixlForamt(int32_t val)
535 {
536     if (val <= static_cast<int32_t>(PixelFormat::CMYK)) {
537         return PixelFormat(val);
538     }
539 
540     return PixelFormat::UNKNOWN;
541 }
542 
ParseDecodeOptions2(napi_env env,napi_value root,DecodeOptions * opts,std::string & error)543 static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, std::string &error)
544 {
545     uint32_t tmpNumber = 0;
546     if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) {
547         HiLog::Debug(LABEL, "no desiredPixelFormat");
548     } else {
549         if (IsSupportPixelFormat(tmpNumber)) {
550             opts->desiredPixelFormat = ParsePixlForamt(tmpNumber);
551         } else {
552             HiLog::Debug(LABEL, "Invalid desiredPixelFormat %{public}d", tmpNumber);
553             error = "DecodeOptions mismatch";
554             return false;
555         }
556     }
557 
558     if (opts == nullptr) {
559         HiLog::Error(LABEL, "opts is nullptr");
560         return false;
561     }
562 
563     if (!GET_INT32_BY_NAME(root, "fitDensity", opts->fitDensity)) {
564         HiLog::Debug(LABEL, "no fitDensity");
565     }
566     return true;
567 }
568 
ParseDecodeOptions(napi_env env,napi_value root,DecodeOptions * opts,uint32_t * pIndex,std::string & error)569 static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts,
570     uint32_t* pIndex, std::string &error)
571 {
572     napi_value tmpValue = nullptr;
573 
574     if (!ImageNapiUtils::GetUint32ByName(env, root, "index", pIndex)) {
575         HiLog::Debug(LABEL, "no index");
576     }
577 
578     if (opts == nullptr) {
579         HiLog::Error(LABEL, "opts is nullptr");
580         return false;
581     }
582 
583     if (!GET_UINT32_BY_NAME(root, "sampleSize", opts->sampleSize)) {
584         HiLog::Debug(LABEL, "no sampleSize");
585     }
586 
587     if (!GET_UINT32_BY_NAME(root, "rotate", opts->rotateNewDegrees)) {
588         HiLog::Debug(LABEL, "no rotate");
589     } else {
590         if (opts->rotateNewDegrees >= 0 &&
591             opts->rotateNewDegrees <= 360) { // 360 is the maximum rotation angle.
592             opts->rotateDegrees = (float)opts->rotateNewDegrees;
593         } else {
594             HiLog::Debug(LABEL, "Invalid rotate %{public}d", opts->rotateNewDegrees);
595             error = "DecodeOptions mismatch";
596             return false;
597         }
598     }
599 
600     if (!GET_BOOL_BY_NAME(root, "editable", opts->editable)) {
601         HiLog::Debug(LABEL, "no editable");
602     }
603 
604     if (!GET_NODE_BY_NAME(root, "desiredSize", tmpValue)) {
605         HiLog::Debug(LABEL, "no desiredSize");
606     } else {
607         if (!ParseSize(env, tmpValue, &(opts->desiredSize))) {
608             HiLog::Debug(LABEL, "ParseSize error");
609         }
610     }
611 
612     if (!GET_NODE_BY_NAME(root, "desiredRegion", tmpValue)) {
613         HiLog::Debug(LABEL, "no desiredRegion");
614     } else {
615         if (!ParseRegion(env, tmpValue, &(opts->CropRect))) {
616             HiLog::Debug(LABEL, "ParseRegion error");
617         }
618     }
619     return ParseDecodeOptions2(env, root, opts, error);
620 }
621 
FileUrlToRawPath(const std::string & path)622 static std::string FileUrlToRawPath(const std::string &path)
623 {
624     if (path.size() > FILE_URL_PREFIX.size() &&
625         (path.compare(0, FILE_URL_PREFIX.size(), FILE_URL_PREFIX) == 0)) {
626         return path.substr(FILE_URL_PREFIX.size());
627     }
628     return path;
629 }
630 
parseSourceOptions(napi_env env,napi_value root,SourceOptions * opts)631 static void parseSourceOptions(napi_env env, napi_value root, SourceOptions* opts)
632 {
633     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourceDensity", &(opts->baseDensity))) {
634         HiLog::Debug(LABEL, "no sourceDensity");
635     }
636 
637     int32_t pixelFormat = 0;
638     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourcePixelFormat", &pixelFormat)) {
639         HiLog::Debug(LABEL, "no sourcePixelFormat");
640     } else {
641         opts->pixelFormat = static_cast<PixelFormat>(pixelFormat);
642         HiLog::Info(LABEL, "sourcePixelFormat:%{public}d", static_cast<int32_t>(opts->pixelFormat));
643     }
644 
645     napi_value tmpValue = nullptr;
646     if (!GET_NODE_BY_NAME(root, "sourceSize", tmpValue)) {
647         HiLog::Debug(LABEL, "no sourceSize");
648     } else {
649         if (!ParseSize(env, tmpValue, &(opts->size))) {
650             HiLog::Debug(LABEL, "ParseSize error");
651         }
652         HiLog::Info(LABEL, "sourceSize:(%{public}d, %{public}d)", opts->size.width, opts->size.height);
653     }
654 }
655 
CreateImageSource(napi_env env,napi_callback_info info)656 napi_value ImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info)
657 {
658     napi_value globalValue;
659     napi_get_global(env, &globalValue);
660     napi_value func;
661     napi_get_named_property(env, globalValue, "requireNapi", &func);
662 
663     napi_value imageInfo;
664     napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &imageInfo);
665     napi_value funcArgv[1] = { imageInfo };
666     napi_value returnValue;
667     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
668 
669     napi_value result = nullptr;
670     napi_get_undefined(env, &result);
671 
672     napi_status status;
673     napi_value thisVar = nullptr;
674     napi_value argValue[NUM_2] = {0};
675     size_t argCount = 2;
676     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
677     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
678 
679     filePath_ = "";
680     fileDescriptor_ = -1;
681     fileBuffer_ = nullptr;
682     fileBufferSize_ = 0;
683 
684     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
685     uint32_t errorCode = ERR_MEDIA_INVALID_VALUE;
686     SourceOptions opts;
687     std::unique_ptr<ImageSource> imageSource = nullptr;
688 
689     NAPI_ASSERT(env, argCount > 0, "No arg!");
690 
691     if (argCount > NUM_1) {
692         parseSourceOptions(env, argValue[NUM_1], &opts);
693     }
694 
695     auto inputType = ImageNapiUtils::getType(env, argValue[NUM_0]);
696     if (napi_string == inputType) { // File Path
697         if (!ImageNapiUtils::GetUtf8String(env, argValue[NUM_0], asyncContext->pathName)) {
698             HiLog::Error(LABEL, "fail to get pathName");
699             napi_get_undefined(env, &result);
700             return result;
701         }
702         asyncContext->pathName = FileUrlToRawPath(asyncContext->pathName);
703         asyncContext->pathNameLength = asyncContext->pathName.size();
704         HiLog::Debug(LABEL, "pathName is [%{public}s]", asyncContext->pathName.c_str());
705         filePath_ = asyncContext->pathName;
706         imageSource = ImageSource::CreateImageSource(asyncContext->pathName, opts, errorCode);
707     } else if (napi_number == inputType) { // Fd
708         napi_get_value_int32(env, argValue[NUM_0], &asyncContext->fdIndex);
709         HiLog::Debug(LABEL, "CreateImageSource fdIndex is [%{public}d]", asyncContext->fdIndex);
710         fileDescriptor_ = asyncContext->fdIndex;
711         imageSource = ImageSource::CreateImageSource(asyncContext->fdIndex, opts, errorCode);
712     } else { // Input Buffer
713         napi_get_arraybuffer_info(env, argValue[NUM_0], &(fileBuffer_), &(fileBufferSize_));
714         asyncContext->sourceBuffer = fileBuffer_;
715         asyncContext->sourceBufferSize = fileBufferSize_;
716         imageSource = ImageSource::CreateImageSource(static_cast<uint8_t *>(fileBuffer_),
717             fileBufferSize_, opts, errorCode);
718     }
719 
720     if (errorCode != SUCCESS || imageSource == nullptr) {
721         HiLog::Error(LABEL, "CreateImageSourceExec error");
722         napi_get_undefined(env, &result);
723         return result;
724     }
725     napi_value constructor = nullptr;
726     status = napi_get_reference_value(env, sConstructor_, &constructor);
727     if (IMG_IS_OK(status)) {
728         sImgSrc_ = std::move(imageSource);
729         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
730     }
731     if (!IMG_IS_OK(status)) {
732         HiLog::Error(LABEL, "New instance could not be obtained");
733         napi_get_undefined(env, &result);
734     }
735     return result;
736 }
737 
CreateImageSourceComplete(napi_env env,napi_status status,void * data)738 napi_value ImageSourceNapi::CreateImageSourceComplete(napi_env env, napi_status status, void *data)
739 {
740     napi_value constructor = nullptr;
741     napi_value result = nullptr;
742 
743     HiLog::Debug(LABEL, "CreateImageSourceComplete IN");
744     auto context = static_cast<ImageSourceAsyncContext*>(data);
745     if (context == nullptr) {
746         return result;
747     }
748     status = napi_get_reference_value(env, sConstructor_, &constructor);
749     if (IMG_IS_OK(status)) {
750         sImgSrc_ = context->rImageSource;
751         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
752     }
753 
754     if (!IMG_IS_OK(status)) {
755         context->status = ERROR;
756         HiLog::Error(LABEL, "New instance could not be obtained");
757         napi_get_undefined(env, &result);
758     }
759     return result;
760 }
761 
CreateIncrementalSource(napi_env env,napi_callback_info info)762 napi_value ImageSourceNapi::CreateIncrementalSource(napi_env env, napi_callback_info info)
763 {
764     napi_value globalValue;
765     napi_get_global(env, &globalValue);
766     napi_value func;
767     napi_get_named_property(env, globalValue, "requireNapi", &func);
768 
769     napi_value imageInfo;
770     napi_create_string_utf8(env, "multimedia.image", NAPI_AUTO_LENGTH, &imageInfo);
771     napi_value funcArgv[1] = { imageInfo };
772     napi_value returnValue;
773     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
774 
775     napi_value result = nullptr;
776     napi_get_undefined(env, &result);
777 
778     napi_status status;
779     HiLog::Debug(LABEL, "CreateIncrementalSource IN");
780 
781     napi_value thisVar = nullptr;
782     napi_value argValue[NUM_2] = {0};
783     size_t argCount = NUM_2;
784     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
785     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
786 
787     uint32_t errorCode = 0;
788     IncrementalSourceOptions incOpts;
789     if (argCount == NUM_2) {
790         parseSourceOptions(env, argValue[NUM_1], &(incOpts.sourceOptions));
791     }
792 
793     incOpts.incrementalMode = IncrementalMode::INCREMENTAL_DATA;
794     std::unique_ptr<ImageSource> imageSource = ImageSource::CreateIncrementalImageSource(incOpts, errorCode);
795     DecodeOptions decodeOpts;
796     std::unique_ptr<IncrementalPixelMap> incPixelMap = imageSource->CreateIncrementalPixelMap(0, decodeOpts, errorCode);
797     HiLog::Debug(LABEL, "CreateIncrementalImageSource end");
798     if (errorCode != SUCCESS || imageSource == nullptr) {
799         HiLog::Error(LABEL, "CreateIncrementalImageSource error");
800         napi_get_undefined(env, &result);
801         return result;
802     }
803     napi_value constructor = nullptr;
804     status = napi_get_reference_value(env, sConstructor_, &constructor);
805     if (IMG_IS_OK(status)) {
806         sImgSrc_ = std::move(imageSource);
807         sIncPixelMap_ = std::move(incPixelMap);
808         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
809     }
810     if (!IMG_IS_OK(status)) {
811         HiLog::Error(LABEL, "New instance could not be obtained");
812         napi_get_undefined(env, &result);
813     }
814     return result;
815 }
816 
GetImageInfo(napi_env env,napi_callback_info info)817 napi_value ImageSourceNapi::GetImageInfo(napi_env env, napi_callback_info info)
818 {
819     StartTrace(HITRACE_TAG_ZIMAGE, "GetImageInfo");
820     napi_value result = nullptr;
821     napi_get_undefined(env, &result);
822 
823     int32_t refCount = 1;
824     napi_status status;
825     napi_value thisVar = nullptr;
826     napi_value argValue[NUM_2] = {0};
827     size_t argCount = 2;
828     HiLog::Debug(LABEL, "GetImageInfo IN");
829     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
830     HiLog::Debug(LABEL, "GetImageInfo argCount is [%{public}zu]", argCount);
831 
832     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
833 
834     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
835     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
836 
837     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
838         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
839 
840     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
841 
842     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
843         nullptr, HiLog::Error(LABEL, "empty native pixelmap"));
844     HiLog::Debug(LABEL, "GetImageInfo argCount is [%{public}zu]", argCount);
845     if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
846         HiLog::Debug(LABEL, "GetImageInfo arg0 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_0]));
847         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
848     } else if (argCount == NUM_1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number) {
849         napi_get_value_uint32(env, argValue[NUM_0], &asyncContext->index);
850     } else if (argCount == NUM_2 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_number
851                 && ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_function) {
852         HiLog::Debug(LABEL, "GetImageInfo arg0 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_0]));
853         HiLog::Debug(LABEL, "GetImageInfo arg1 getType is [%{public}u]", ImageNapiUtils::getType(env, argValue[NUM_1]));
854         napi_get_value_uint32(env, argValue[NUM_0], &asyncContext->index);
855         napi_create_reference(env, argValue[NUM_1], refCount, &asyncContext->callbackRef);
856     }
857 
858     if (asyncContext->callbackRef == nullptr) {
859         napi_create_promise(env, &(asyncContext->deferred), &result);
860     } else {
861         napi_get_undefined(env, &result);
862     }
863 
864     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetImageInfo",
865         [](napi_env env, void *data) {
866             auto context = static_cast<ImageSourceAsyncContext*>(data);
867             int index = (context->index >= NUM_0) ? context->index : NUM_0;
868             context->status = context->rImageSource->GetImageInfo(index, context->imageInfo);
869         }, GetImageInfoComplete, asyncContext, asyncContext->work);
870 
871     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
872         nullptr, HiLog::Error(LABEL, "fail to create async work"));
873     FinishTrace(HITRACE_TAG_ZIMAGE);
874     return result;
875 }
876 
CreatePixelMapExecute(napi_env env,void * data)877 static void CreatePixelMapExecute(napi_env env, void *data)
878 {
879     HiLog::Debug(LABEL, "CreatePixelMapExecute IN");
880     if (data == nullptr) {
881         HiLog::Error(LABEL, "data is nullptr");
882         return;
883     }
884     uint32_t errorCode = 0;
885     auto context = static_cast<ImageSourceAsyncContext*>(data);
886     if (context == nullptr) {
887         HiLog::Error(LABEL, "empty context");
888         return;
889     }
890 
891     if (context->errMsg.size() > 0) {
892         HiLog::Error(LABEL, "mismatch args");
893         context->status = ERROR;
894         return;
895     }
896 
897     if (context->rImageSource == nullptr) {
898         HiLog::Error(LABEL, "empty context rImageSource");
899         return;
900     }
901 
902     if (context->constructor_ != nullptr) {
903         auto incPixelMap = context->constructor_->GetIncrementalPixelMap();
904         if (incPixelMap != nullptr) {
905             HiLog::Info(LABEL, "Get Incremental PixelMap!!!");
906             context->rPixelMap = incPixelMap;
907         }
908     } else {
909         HiLog::Info(LABEL, "Create PixelMap!!!");
910     }
911     if (context->rPixelMap == nullptr) {
912         int index = (context->index >= NUM_0) ? context->index : NUM_0;
913         context->rPixelMap = context->rImageSource->CreatePixelMapEx(index, context->decodeOpts, errorCode);
914     }
915 
916     if (IMG_NOT_NULL(context->rPixelMap)) {
917         context->status = SUCCESS;
918     } else {
919         context->status = ERROR;
920         context->errMsg = "Create PixelMap error";
921         HiLog::Error(LABEL, "Create PixelMap error");
922     }
923     HiLog::Debug(LABEL, "CreatePixelMapExecute OUT");
924 }
925 
CreatePixelMapComplete(napi_env env,napi_status status,void * data)926 static void CreatePixelMapComplete(napi_env env, napi_status status, void *data)
927 {
928     HiLog::Debug(LABEL, "CreatePixelMapComplete IN");
929     napi_value result = nullptr;
930     auto context = static_cast<ImageSourceAsyncContext*>(data);
931 
932     if (context->status == SUCCESS) {
933         result = PixelMapNapi::CreatePixelMap(env, context->rPixelMap);
934     } else {
935         napi_get_undefined(env, &result);
936     }
937     HiLog::Debug(LABEL, "CreatePixelMapComplete OUT");
938     ImageSourceCallbackRoutine(env, context, result);
939 }
940 
CreatePixelMap(napi_env env,napi_callback_info info)941 napi_value ImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info)
942 {
943     napi_value result = nullptr;
944     napi_get_undefined(env, &result);
945 
946     int32_t refCount = 1;
947     napi_status status;
948     napi_value thisVar = nullptr;
949     napi_value argValue[NUM_2] = {0};
950     size_t argCount = NUM_2;
951     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
952     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, HiLog::Error(LABEL, "fail to get thisVar"));
953     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
954 
955     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
956 
957     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
958     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
959         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
960     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_->nativeImgSrc),
961         nullptr, HiLog::Error(LABEL, "fail to unwrap nativeImgSrc"));
962     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
963     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
964         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
965 
966     if (argCount == NUM_0) {
967         HiLog::Debug(LABEL, "CreatePixelMap with no arg");
968     } else if (argCount == NUM_1 || argCount == NUM_2) {
969         if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
970             if (!ParseDecodeOptions(env, argValue[NUM_0], &(asyncContext->decodeOpts),
971                                     &(asyncContext->index), asyncContext->errMsg)) {
972                 HiLog::Error(LABEL, "DecodeOptions mismatch");
973             }
974         }
975         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
976             napi_create_reference(env, argValue[argCount - 1], refCount, &asyncContext->callbackRef);
977         }
978     } else {
979         HiLog::Error(LABEL, "argCount mismatch");
980         return result;
981     }
982     if (asyncContext->callbackRef == nullptr) {
983         napi_create_promise(env, &(asyncContext->deferred), &result);
984     } else {
985         napi_get_undefined(env, &result);
986     }
987 
988     ImageNapiUtils::HicheckerReport();
989     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "CreatePixelMap", CreatePixelMapExecute,
990         CreatePixelMapComplete, asyncContext, asyncContext->work);
991 
992     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
993         nullptr, HiLog::Error(LABEL, "fail to create async work"));
994     return result;
995 }
996 
ParsePropertyOptions(napi_env env,napi_value root,ImageSourceAsyncContext * context)997 static bool ParsePropertyOptions(napi_env env, napi_value root, ImageSourceAsyncContext* context)
998 {
999     napi_value tmpValue = nullptr;
1000     if (!GET_UINT32_BY_NAME(root, "index", context->index)) {
1001         HiLog::Debug(LABEL, "no index");
1002         return false;
1003     }
1004     if (!GET_NODE_BY_NAME(root, "defaultValue", tmpValue)) {
1005         HiLog::Debug(LABEL, "no defaultValue");
1006     } else {
1007         if (tmpValue != nullptr) {
1008             context->defaultValueStr = GetStringArgument(env, tmpValue);
1009         }
1010     }
1011     return true;
1012 }
1013 
ModifyImagePropertyComplete(napi_env env,napi_status status,ImageSourceAsyncContext * context)1014 static void ModifyImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context)
1015 {
1016     HiLog::Debug(LABEL, "ModifyPropertyComplete IN");
1017 
1018     if (context == nullptr) {
1019         HiLog::Error(LABEL, "context is nullptr");
1020         return;
1021     }
1022 
1023     napi_value result[NUM_2] = {0};
1024     napi_get_undefined(env, &result[NUM_0]);
1025     napi_get_undefined(env, &result[NUM_1]);
1026     napi_value retVal;
1027     napi_value callback = nullptr;
1028     if (context->status == ERR_MEDIA_WRITE_PARCEL_FAIL) {
1029         if (context->fdIndex != -1) {
1030             ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1031                 "Create Fd without write permission!");
1032         }
1033     } else if (context->status == ERR_MEDIA_OUT_OF_RANGE) {
1034         ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1035             "The given buffer size is too small to add new exif data!");
1036     } else if (context->status == ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
1037         ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
1038             "The exif data format is not standard, so modify it failed!");
1039     } else if (context->status == ERR_MEDIA_VALUE_INVALID) {
1040         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, context->errMsg);
1041     }
1042 
1043     if (context->deferred) {
1044         if (context->status == SUCCESS) {
1045             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
1046         } else {
1047             napi_reject_deferred(env, context->deferred, result[NUM_0]);
1048         }
1049     } else {
1050         HiLog::Debug(LABEL, "call callback function");
1051         napi_get_reference_value(env, context->callbackRef, &callback);
1052         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
1053         napi_delete_reference(env, context->callbackRef);
1054     }
1055 
1056     napi_delete_async_work(env, context->work);
1057 
1058     delete context;
1059     context = nullptr;
1060     HiLog::Debug(LABEL, "ModifyPropertyComplete OUT");
1061 }
1062 
GetImagePropertyComplete(napi_env env,napi_status status,ImageSourceAsyncContext * context)1063 static void GetImagePropertyComplete(napi_env env, napi_status status, ImageSourceAsyncContext *context)
1064 {
1065     HiLog::Debug(LABEL, "GetImagePropertyComplete IN");
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_value retVal;
1074     napi_value callback = nullptr;
1075 
1076     napi_get_undefined(env, &result[NUM_0]);
1077     napi_get_undefined(env, &result[NUM_1]);
1078 
1079     if (context->status == SUCCESS) {
1080         napi_create_string_utf8(env, context->valueStr.c_str(), context->valueStr.length(), &result[NUM_1]);
1081     } else if (context->status == ERR_IMAGE_DECODE_EXIF_UNSUPPORT) {
1082         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, "Unsupport EXIF info key!");
1083     } else {
1084         ImageNapiUtils::CreateErrorObj(env, result[0], context->status, "There is generic napi failure!");
1085     }
1086 
1087     if (context->deferred) {
1088         if (context->status == SUCCESS) {
1089             napi_resolve_deferred(env, context->deferred, result[NUM_1]);
1090         } else {
1091             napi_reject_deferred(env, context->deferred, result[NUM_0]);
1092         }
1093     } else {
1094         HiLog::Debug(LABEL, "call callback function");
1095         napi_get_reference_value(env, context->callbackRef, &callback);
1096         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
1097         napi_delete_reference(env, context->callbackRef);
1098     }
1099 
1100     napi_delete_async_work(env, context->work);
1101     delete context;
1102     context = nullptr;
1103     HiLog::Debug(LABEL, "GetImagePropertyComplete OUT");
1104 }
1105 
UnwrapContext(napi_env env,napi_callback_info info)1106 static std::unique_ptr<ImageSourceAsyncContext> UnwrapContext(napi_env env, napi_callback_info info)
1107 {
1108     int32_t refCount = 1;
1109     napi_status status;
1110     napi_value thisVar = nullptr;
1111     napi_value argValue[NUM_3] = {0};
1112     size_t argCount = NUM_3;
1113     HiLog::Debug(LABEL, "GetImageProperty UnwrapContext");
1114     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1115     HiLog::Debug(LABEL, "GetImageProperty argCount is [%{public}zu]", argCount);
1116 
1117     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1118 
1119     std::unique_ptr<ImageSourceAsyncContext> context = std::make_unique<ImageSourceAsyncContext>();
1120     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1121 
1122     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
1123         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1124 
1125     context->rImageSource = context->constructor_->nativeImgSrc;
1126 
1127     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource),
1128         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1129 
1130     if (argCount < NUM_1 || argCount > NUM_3) {
1131         HiLog::Error(LABEL, "argCount missmatch");
1132         return nullptr;
1133     }
1134     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) {
1135         context->keyStr = GetStringArgument(env, argValue[NUM_0]);
1136     } else {
1137         HiLog::Error(LABEL, "arg 0 type missmatch");
1138         return nullptr;
1139     }
1140     if (argCount == NUM_2 || argCount == NUM_3) {
1141         if (ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_object) {
1142             IMG_NAPI_CHECK_RET_D(ParsePropertyOptions(env, argValue[NUM_1], context.get()),
1143                                  nullptr, HiLog::Error(LABEL, "PropertyOptions mismatch"));
1144         }
1145         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1146             napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef);
1147         }
1148     }
1149     return context;
1150 }
1151 
CheckExifDataValue(const std::string & key,const std::string & value,std::string & errorInfo)1152 static bool CheckExifDataValue(const std::string &key, const std::string &value, std::string &errorInfo)
1153 {
1154     if (IsSameTextStr(key, "BitsPerSample")) {
1155         std::vector<std::string> bitsVec;
1156         SplitStr(value, ",", bitsVec);
1157         if (bitsVec.size() > NUM_2) {
1158             errorInfo = "BitsPerSample has invalid exif value: ";
1159             errorInfo.append(value);
1160             return false;
1161         }
1162         for (size_t i = 0; i < bitsVec.size(); i++) {
1163             if (!IsNumericStr(bitsVec[i])) {
1164                 errorInfo = "BitsPerSample has invalid exif value: ";
1165                 errorInfo.append(bitsVec[i]);
1166                 return false;
1167             }
1168         }
1169     } else if (IsSameTextStr(key, "Orientation")) {
1170         if (!IsNumericStr(value) || atoi(value.c_str()) < 1 || static_cast<uint32_t>(atoi(value.c_str())) > NUM_8) {
1171             errorInfo = "Orientation has invalid exif value: ";
1172             errorInfo.append(value);
1173             return false;
1174         }
1175     } else if (IsSameTextStr(key, "ImageLength") || IsSameTextStr(key, "ImageWidth")) {
1176         if (!IsNumericStr(value)) {
1177             errorInfo = "ImageLength or ImageWidth has invalid exif value: ";
1178             errorInfo.append(value);
1179             return false;
1180         }
1181     } else if (IsSameTextStr(key, "GPSLatitude") || IsSameTextStr(key, "GPSLongitude")) {
1182         std::vector<std::string> gpsVec;
1183         SplitStr(value, ",", gpsVec);
1184         if (gpsVec.size() != NUM_2) {
1185             errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
1186             errorInfo.append(value);
1187             return false;
1188         }
1189 
1190         for (size_t i = 0; i < gpsVec.size(); i++) {
1191             if (!IsNumericStr(gpsVec[i])) {
1192                 errorInfo = "GPSLatitude or GPSLongitude has invalid exif value: ";
1193                 errorInfo.append(gpsVec[i]);
1194                 return false;
1195             }
1196         }
1197     } else if (IsSameTextStr(key, "GPSLatitudeRef")) {
1198         if (!IsSameTextStr(value, "N") && !IsSameTextStr(value, "S")) {
1199             errorInfo = "GPSLatitudeRef has invalid exif value: ";
1200             errorInfo.append(value);
1201             return false;
1202         }
1203     } else if (IsSameTextStr(key, "GPSLongitudeRef")) {
1204         if (!IsSameTextStr(value, "W") && !IsSameTextStr(value, "E")) {
1205             errorInfo = "GPSLongitudeRef has invalid exif value: ";
1206             errorInfo.append(value);
1207             return false;
1208         }
1209     }
1210     return true;
1211 }
1212 
UnwrapContextForModify(napi_env env,napi_callback_info info)1213 static std::unique_ptr<ImageSourceAsyncContext> UnwrapContextForModify(napi_env env,
1214     napi_callback_info info)
1215 {
1216     int32_t refCount = 1;
1217     napi_status status;
1218     napi_value thisVar = nullptr;
1219     napi_value argValue[NUM_4] = {0};
1220     size_t argCount = NUM_4;
1221     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1222     HiLog::Debug(LABEL, "UnwrapContextForModify argCount is [%{public}zu]", argCount);
1223 
1224     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1225 
1226     std::unique_ptr<ImageSourceAsyncContext> context = std::make_unique<ImageSourceAsyncContext>();
1227     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&context->constructor_));
1228 
1229     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->constructor_),
1230         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1231 
1232     context->rImageSource = context->constructor_->nativeImgSrc;
1233 
1234     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, context->rImageSource),
1235         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1236     if (argCount < NUM_1 || argCount > NUM_4) {
1237         HiLog::Error(LABEL, "argCount missmatch");
1238         return nullptr;
1239     }
1240     if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_string) {
1241         context->keyStr = GetStringArgument(env, argValue[NUM_0]);
1242     } else {
1243         HiLog::Error(LABEL, "arg 0 type missmatch");
1244         return nullptr;
1245     }
1246     if (ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_string) {
1247         context->valueStr = GetStringArgument(env, argValue[NUM_1]);
1248     } else {
1249         HiLog::Error(LABEL, "arg 1 type missmatch");
1250         return nullptr;
1251     }
1252     if (argCount == NUM_3 || argCount == NUM_4) {
1253         if (ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_object) {
1254             IMG_NAPI_CHECK_RET_D(ParsePropertyOptions(env, argValue[NUM_2], context.get()),
1255                 nullptr, HiLog::Error(LABEL, "PropertyOptions mismatch"));
1256         }
1257         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
1258             napi_create_reference(env, argValue[argCount - 1], refCount, &context->callbackRef);
1259         }
1260     }
1261     context->pathName = ImageSourceNapi::filePath_;
1262     context->fdIndex = ImageSourceNapi::fileDescriptor_;
1263     context->sourceBuffer = ImageSourceNapi::fileBuffer_;
1264     context->sourceBufferSize = ImageSourceNapi::fileBufferSize_;
1265     return context;
1266 }
1267 
ModifyImageProperty(napi_env env,napi_callback_info info)1268 napi_value ImageSourceNapi::ModifyImageProperty(napi_env env, napi_callback_info info)
1269 {
1270     napi_value result = nullptr;
1271     napi_get_undefined(env, &result);
1272 
1273     napi_status status;
1274     HiLog::Debug(LABEL, "ModifyImageProperty IN");
1275     std::unique_ptr<ImageSourceAsyncContext> asyncContext = UnwrapContextForModify(env, info);
1276     if (asyncContext == nullptr) {
1277         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
1278             "async context unwrap failed");
1279     }
1280 
1281     if (asyncContext->callbackRef == nullptr) {
1282         napi_create_promise(env, &(asyncContext->deferred), &result);
1283     } else {
1284         napi_get_undefined(env, &result);
1285     }
1286 
1287     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ModifyImageProperty",
1288         [](napi_env env, void *data) {
1289             auto context = static_cast<ImageSourceAsyncContext*>(data);
1290 
1291             if (!CheckExifDataValue(context->keyStr, context->valueStr, context->errMsg)) {
1292                 HiLog::Error(LABEL, "There is invalid exif data parameter");
1293                 context->status = ERR_MEDIA_VALUE_INVALID;
1294                 return;
1295             }
1296             if (!IsSameTextStr(context->pathName, "")) {
1297                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1298                     context->keyStr, context->valueStr, context->pathName);
1299             } else if (context->fdIndex != -1) {
1300                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1301                     context->keyStr, context->valueStr, context->fdIndex);
1302             } else if (context->sourceBuffer != nullptr) {
1303                 context->status = context->rImageSource->ModifyImageProperty(context->index,
1304                     context->keyStr, context->valueStr, static_cast<uint8_t *>(context->sourceBuffer),
1305                     context->sourceBufferSize);
1306             } else {
1307                 HiLog::Error(LABEL, "There is no image source!");
1308             }
1309         },
1310         reinterpret_cast<napi_async_complete_callback>(ModifyImagePropertyComplete),
1311         asyncContext,
1312         asyncContext->work);
1313 
1314     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1315         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1316     return result;
1317 }
1318 
GetImageProperty(napi_env env,napi_callback_info info)1319 napi_value ImageSourceNapi::GetImageProperty(napi_env env, napi_callback_info info)
1320 {
1321     StartTrace(HITRACE_TAG_ZIMAGE, "GetImageProperty");
1322     napi_value result = nullptr;
1323     napi_get_undefined(env, &result);
1324 
1325     napi_status status;
1326     HiLog::Debug(LABEL, "GetImageProperty IN");
1327     std::unique_ptr<ImageSourceAsyncContext> asyncContext = UnwrapContext(env, info);
1328     if (asyncContext == nullptr) {
1329         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
1330             "async context unwrap failed");
1331     }
1332 
1333     if (asyncContext->callbackRef == nullptr) {
1334         napi_create_promise(env, &(asyncContext->deferred), &result);
1335     } else {
1336         napi_get_undefined(env, &result);
1337     }
1338 
1339     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetImageProperty",
1340         [](napi_env env, void *data) {
1341             auto context = static_cast<ImageSourceAsyncContext*>(data);
1342             context->status = context->rImageSource->GetImagePropertyString(context->index,
1343                                                                             context->keyStr,
1344                                                                             context->valueStr);
1345         },
1346         reinterpret_cast<napi_async_complete_callback>(GetImagePropertyComplete),
1347         asyncContext,
1348         asyncContext->work);
1349 
1350     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1351         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1352     FinishTrace(HITRACE_TAG_ZIMAGE);
1353     return result;
1354 }
1355 
UpdateDataExecute(napi_env env,void * data)1356 static void UpdateDataExecute(napi_env env, void *data)
1357 {
1358     auto context = static_cast<ImageSourceAsyncContext*>(data);
1359     uint8_t *buffer = static_cast<uint8_t*>(context->updataBuffer);
1360     if (context->updataBufferOffset < context->updataBufferSize) {
1361         buffer = buffer + context->updataBufferOffset;
1362     }
1363 
1364     uint32_t lastSize = context->updataBufferSize - context->updataBufferOffset;
1365     uint32_t size = context->updataLength < lastSize ? context->updataLength : lastSize;
1366 
1367     uint32_t res = context->rImageSource->UpdateData(buffer, size,
1368                                                      context->isCompleted);
1369     context->isSuccess = res == 0;
1370     if (context->isSuccess && context->constructor_ != nullptr) {
1371         auto incPixelMap = context->constructor_->GetIncrementalPixelMap();
1372         if (incPixelMap != nullptr) {
1373             uint8_t decodeProgress = 0;
1374             uint32_t err = incPixelMap->PromoteDecoding(decodeProgress);
1375             if (!(err == SUCCESS || (err == ERR_IMAGE_SOURCE_DATA_INCOMPLETE && !context->isCompleted))) {
1376                 HiLog::Error(LABEL, "UpdateData PromoteDecoding error");
1377                 context->isSuccess = false;
1378             }
1379             if (context->isCompleted) {
1380                 incPixelMap->DetachFromDecoding();
1381             }
1382         }
1383     }
1384 }
1385 
UpdateDataComplete(napi_env env,napi_status status,void * data)1386 static void UpdateDataComplete(napi_env env, napi_status status, void *data)
1387 {
1388     HiLog::Debug(LABEL, "UpdateDataComplete IN");
1389     napi_value result = nullptr;
1390     napi_create_object(env, &result);
1391 
1392     auto context = static_cast<ImageSourceAsyncContext*>(data);
1393 
1394     napi_get_boolean(env, context->isSuccess, &result);
1395     HiLog::Debug(LABEL, "UpdateDataComplete OUT");
1396     ImageSourceCallbackRoutine(env, context, result);
1397 }
1398 
isNapiTypedArray(napi_env env,napi_value val)1399 static bool isNapiTypedArray(napi_env env, napi_value val)
1400 {
1401     bool res = false;
1402     napi_is_typedarray(env, val, &res);
1403     HiLog::Debug(LABEL, "isNapiTypedArray %{public}d", res);
1404     return res;
1405 }
1406 
UpdateData(napi_env env,napi_callback_info info)1407 napi_value ImageSourceNapi::UpdateData(napi_env env, napi_callback_info info)
1408 {
1409     napi_value result = nullptr;
1410     napi_get_undefined(env, &result);
1411 
1412     int32_t refCount = 1;
1413     napi_status status;
1414     napi_value thisVar = nullptr;
1415     napi_value argValue[NUM_5] = {0};
1416     size_t argCount = 5;
1417     HiLog::Debug(LABEL, "UpdateData IN");
1418     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1419     HiLog::Debug(LABEL, "UpdateData argCount is [%{public}zu]", argCount);
1420 
1421     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1422 
1423     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
1424     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1425 
1426     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
1427         nullptr, HiLog::Error(LABEL, "fail to unwrap context"));
1428 
1429     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
1430 
1431     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
1432         nullptr, HiLog::Error(LABEL, "empty native rImageSource"));
1433     HiLog::Debug(LABEL, "UpdateData argCount %{public}zu", argCount);
1434     if (argCount > NUM_0 && isNapiTypedArray(env, argValue[NUM_0])) {
1435         HiLog::Error(LABEL, "UpdateData napi_get_arraybuffer_info ");
1436         napi_typedarray_type type;
1437         napi_value arraybuffer;
1438         size_t offset;
1439         status = napi_get_typedarray_info(env, argValue[NUM_0], &type,
1440             &(asyncContext->updataBufferSize), &(asyncContext->updataBuffer),
1441             &arraybuffer, &offset);
1442     }
1443 
1444     if (argCount >= NUM_2 && ImageNapiUtils::getType(env, argValue[NUM_1]) == napi_boolean) {
1445         status = napi_get_value_bool(env, argValue[NUM_1], &(asyncContext->isCompleted));
1446     }
1447 
1448     if (argCount >= NUM_3 && ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_number) {
1449         asyncContext->updataBufferOffset = 0;
1450         status = napi_get_value_uint32(env, argValue[NUM_2], &(asyncContext->updataBufferOffset));
1451         HiLog::Debug(LABEL, "asyncContext->updataBufferOffset is [%{public}u]", asyncContext->updataBufferOffset);
1452     }
1453 
1454     if (argCount >= NUM_4 && ImageNapiUtils::getType(env, argValue[NUM_3]) == napi_number) {
1455         asyncContext->updataLength = 0;
1456         status = napi_get_value_uint32(env, argValue[NUM_3], &(asyncContext->updataLength));
1457         HiLog::Debug(LABEL, "asyncContext->updataLength is [%{public}u]", asyncContext->updataLength);
1458     }
1459 
1460     if (!IMG_IS_OK(status)) {
1461         HiLog::Error(LABEL, "fail to UpdateData");
1462         napi_get_undefined(env, &result);
1463         return result;
1464     }
1465 
1466     if (argCount == NUM_5 && ImageNapiUtils::getType(env, argValue[NUM_4]) == napi_function) {
1467         napi_create_reference(env, argValue[NUM_4], refCount, &asyncContext->callbackRef);
1468     }
1469 
1470     if (argCount == NUM_3 && ImageNapiUtils::getType(env, argValue[NUM_2]) == napi_function) {
1471         napi_create_reference(env, argValue[NUM_2], refCount, &asyncContext->callbackRef);
1472     }
1473 
1474     if (asyncContext->callbackRef == nullptr) {
1475         napi_create_promise(env, &(asyncContext->deferred), &result);
1476     } else {
1477         napi_get_undefined(env, &result);
1478     }
1479 
1480     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "UpdateData",
1481         UpdateDataExecute, UpdateDataComplete, asyncContext, asyncContext->work);
1482 
1483     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
1484         nullptr, HiLog::Error(LABEL, "fail to create async work"));
1485     return result;
1486 }
1487 
ReleaseComplete(napi_env env,napi_status status,void * data)1488 static void ReleaseComplete(napi_env env, napi_status status, void *data)
1489 {
1490     HiLog::Debug(LABEL, "ReleaseComplete IN");
1491     napi_value result = nullptr;
1492     napi_get_undefined(env, &result);
1493 
1494     auto context = static_cast<ImageSourceAsyncContext*>(data);
1495     delete context->constructor_;
1496     context->constructor_ = nullptr;
1497     HiLog::Debug(LABEL, "ReleaseComplete OUT");
1498     ImageSourceCallbackRoutine(env, context, result);
1499 }
1500 
Release(napi_env env,napi_callback_info info)1501 napi_value ImageSourceNapi::Release(napi_env env, napi_callback_info info)
1502 {
1503     HiLog::Debug(LABEL, "Release enter");
1504     napi_value result = nullptr;
1505     napi_get_undefined(env, &result);
1506 
1507     int32_t refCount = 1;
1508     napi_status status;
1509     napi_value thisVar = nullptr;
1510     napi_value argValue[NUM_1] = {0};
1511     size_t argCount = 1;
1512 
1513     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
1514     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
1515     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, HiLog::Error(LABEL, "fail to napi_get_cb_info"));
1516 
1517     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
1518     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
1519 
1520     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_), result,
1521         HiLog::Error(LABEL, "fail to unwrap context"));
1522 
1523     HiLog::Debug(LABEL, "Release argCount is [%{public}zu]", argCount);
1524     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
1525         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
1526     }
1527 
1528     if (asyncContext->callbackRef == nullptr) {
1529         napi_create_promise(env, &(asyncContext->deferred), &result);
1530     }
1531 
1532     IMG_CREATE_CREATE_ASYNC_WORK(env, status, "Release",
1533         [](napi_env env, void *data) {}, ReleaseComplete, asyncContext, asyncContext->work);
1534     HiLog::Debug(LABEL, "Release exit");
1535     return result;
1536 }
1537 
release()1538 void ImageSourceNapi::release()
1539 {
1540     if (!isRelease) {
1541         if (nativeImgSrc != nullptr) {
1542             nativeImgSrc = nullptr;
1543         }
1544         isRelease = true;
1545     }
1546 }
1547 }  // namespace Media
1548 }  // namespace OHOS
1549