• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 #include "sendable_image_source_napi.h"
16 #include <fcntl.h>
17 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
18 #include "color_space_object_convertor.h"
19 #endif
20 
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23 
24 #undef LOG_TAG
25 #define LOG_TAG "SendableImageSourceNapi"
26 
27 namespace {
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 }
33 
34 namespace OHOS {
35 namespace Media {
36 thread_local napi_ref SendableImageSourceNapi::sConstructor_ = nullptr;
37 thread_local std::shared_ptr<ImageSource> SendableImageSourceNapi::sImgSrc_ = nullptr;
38 std::shared_ptr<IncrementalPixelMap> SendableImageSourceNapi::sIncPixelMap_ = nullptr;
39 static const std::string CLASS_NAME = "ImageSourceSendable";
40 static const std::string FILE_URL_PREFIX = "file://";
41 thread_local std::string SendableImageSourceNapi::filePath_ = "";
42 thread_local int SendableImageSourceNapi::fileDescriptor_ = -1;
43 thread_local void* SendableImageSourceNapi::fileBuffer_ = nullptr;
44 thread_local size_t SendableImageSourceNapi::fileBufferSize_ = 0;
45 napi_ref SendableImageSourceNapi::pixelMapFormatRef_ = nullptr;
46 napi_ref SendableImageSourceNapi::propertyKeyRef_ = nullptr;
47 napi_ref SendableImageSourceNapi::imageFormatRef_ = nullptr;
48 napi_ref SendableImageSourceNapi::alphaTypeRef_ = nullptr;
49 napi_ref SendableImageSourceNapi::scaleModeRef_ = nullptr;
50 napi_ref SendableImageSourceNapi::componentTypeRef_ = nullptr;
51 napi_ref SendableImageSourceNapi::decodingDynamicRangeRef_ = nullptr;
52 napi_ref SendableImageSourceNapi::decodingResolutionQualityRef_ = nullptr;
53 
54 static std::mutex imageSourceCrossThreadMutex_;
55 
56 struct RawFileDescriptorInfo {
57     int32_t fd = INVALID_FD;
58     int32_t offset;
59     int32_t length;
60 };
61 
62 struct ImageSourceAsyncContext {
63     napi_env env;
64     napi_async_work work;
65     napi_deferred deferred;
66     napi_ref callbackRef = nullptr;
67     SendableImageSourceNapi *constructor_;
68     uint32_t status;
69     std::string pathName = "";
70     int fdIndex = INVALID_FD;
71     void* sourceBuffer = nullptr;
72     size_t sourceBufferSize = NUM_0;
73     std::string keyStr;
74     std::string valueStr;
75     std::vector<std::string> keyStrArray;
76     std::vector<std::pair<std::string, std::string>> kVStrArray;
77     std::string defaultValueStr;
78     int32_t valueInt;
79     int32_t deufltValueInt;
80     void *updataBuffer;
81     size_t updataBufferSize;
82     uint32_t updataBufferOffset = 0;
83     uint32_t updataLength = 0;
84     bool isCompleted = false;
85     bool isSuccess = false;
86     bool isBatch = false;
87     size_t pathNameLength;
88     SourceOptions opts;
89     uint32_t index = 0;
90     ImageInfo imageInfo;
91     DecodeOptions decodeOpts;
92     std::shared_ptr<ImageSource> rImageSource;
93     std::shared_ptr<PixelMap> rPixelMap;
94     std::string errMsg;
95     std::multimap<std::int32_t, std::string> errMsgArray;
96     std::unique_ptr<std::vector<std::unique_ptr<PixelMap>>> pixelMaps;
97     std::unique_ptr<std::vector<int32_t>> delayTimes;
98     std::unique_ptr<std::vector<int32_t>> disposalType;
99     uint32_t frameCount = 0;
100     struct RawFileDescriptorInfo rawFileInfo;
101 };
102 
103 struct ImageEnum {
104     std::string name;
105     int32_t numVal;
106     std::string strVal;
107 };
108 
109 static std::vector<struct ImageEnum> sPixelMapFormatMap = {
110     {"UNKNOWN", 0, ""},
111     {"ARGB_8888", 1, ""},
112     {"RGB_565", 2, ""},
113     {"RGBA_8888", 3, ""},
114     {"BGRA_8888", 4, ""},
115     {"RGB_888", 5, ""},
116     {"ALPHA_8", 6, ""},
117     {"RGBA_F16", 7, ""},
118     {"NV21", 8, ""},
119     {"NV12", 9, ""},
120 };
121 
122 static std::vector<struct ImageEnum> sPropertyKeyMap = {
123     {"BITS_PER_SAMPLE", 0, "BitsPerSample"},
124     {"ORIENTATION", 0, "Orientation"},
125     {"IMAGE_LENGTH", 0, "ImageLength"},
126     {"IMAGE_WIDTH", 0, "ImageWidth"},
127     {"GPS_LATITUDE", 0, "GPSLatitude"},
128     {"GPS_LONGITUDE", 0, "GPSLongitude"},
129     {"GPS_LATITUDE_REF", 0, "GPSLatitudeRef"},
130     {"GPS_LONGITUDE_REF", 0, "GPSLongitudeRef"},
131     {"DATE_TIME_ORIGINAL", 0, "DateTimeOriginal"},
132     {"EXPOSURE_TIME", 0, "ExposureTime"},
133     {"SCENE_TYPE", 0, "SceneType"},
134     {"ISO_SPEED_RATINGS", 0, "ISOSpeedRatings"},
135     {"F_NUMBER", 0, "FNumber"},
136     {"COMPRESSED_BITS_PER_PIXEL", 0, "CompressedBitsPerPixel"},
137     {"DATE_TIME", 0, "DateTime"},
138     {"GPS_TIME_STAMP", 0, "GPSTimeStamp"},
139     {"GPS_DATE_STAMP", 0, "GPSDateStamp"},
140     {"IMAGE_DESCRIPTION", 0, "ImageDescription"},
141     {"MAKE", 0, "Make"},
142     {"MODEL", 0, "Model"},
143     {"PHOTO_MODE", 0, "PhotoMode"},
144     {"SENSITIVITY_TYPE", 0, "SensitivityType"},
145     {"STANDARD_OUTPUT_SENSITIVITY", 0, "StandardOutputSensitivity"},
146     {"RECOMMENDED_EXPOSURE_INDEX", 0, "RecommendedExposureIndex"},
147     {"ISO_SPEED", 0, "ISOSpeedRatings"},
148     {"APERTURE_VALUE", 0, "ApertureValue"},
149     {"EXPOSURE_BIAS_VALUE", 0, "ExposureBiasValue"},
150     {"METERING_MODE", 0, "MeteringMode"},
151     {"LIGHT_SOURCE", 0, "LightSource"},
152     {"FLASH", 0, "Flash"},
153     {"FOCAL_LENGTH", 0, "FocalLength"},
154     {"USER_COMMENT", 0, "UserComment"},
155     {"PIXEL_X_DIMENSION", 0, "PixelXDimension"},
156     {"PIXEL_Y_DIMENSION", 0, "PixelYDimension"},
157     {"WHITE_BALANCE", 0, "WhiteBalance"},
158     {"FOCAL_LENGTH_IN_35_MM_FILM", 0, "FocalLengthIn35mmFilm"},
159     {"CAPTURE_MODE", 0, "HwMnoteCaptureMode"},
160     {"PHYSICAL_APERTURE", 0, "HwMnotePhysicalAperture"},
161     {"ROLL_ANGLE", 0, "HwMnoteRollAngle"},
162     {"PITCH_ANGLE", 0, "HwMnotePitchAngle"},
163     {"SCENE_FOOD_CONF", 0, "HwMnoteSceneFoodConf"},
164     {"SCENE_STAGE_CONF", 0, "HwMnoteSceneStageConf"},
165     {"SCENE_BLUE_SKY_CONF", 0, "HwMnoteSceneBlueSkyConf"},
166     {"SCENE_GREEN_PLANT_CONF", 0, "HwMnoteSceneGreenPlantConf"},
167     {"SCENE_BEACH_CONF", 0, "HwMnoteSceneBeachConf"},
168     {"SCENE_SNOW_CONF", 0, "HwMnoteSceneSnowConf"},
169     {"SCENE_SUNSET_CONF", 0, "HwMnoteSceneSunsetConf"},
170     {"SCENE_FLOWERS_CONF", 0, "HwMnoteSceneFlowersConf"},
171     {"SCENE_NIGHT_CONF", 0, "HwMnoteSceneNightConf"},
172     {"SCENE_TEXT_CONF", 0, "HwMnoteSceneTextConf"},
173     {"FACE_COUNT", 0, "HwMnoteFaceCount"},
174     {"FOCUS_MODE", 0, "HwMnoteFocusMode"},
175 };
176 static std::vector<struct ImageEnum> sImageFormatMap = {
177     {"YCBCR_422_SP", 1000, ""},
178     {"JPEG", 2000, ""},
179 };
180 static std::vector<struct ImageEnum> sAlphaTypeMap = {
181     {"UNKNOWN", 0, ""},
182     {"OPAQUE", 1, ""},
183     {"PREMUL", 2, ""},
184     {"UNPREMUL", 3, ""},
185 };
186 static std::vector<struct ImageEnum> sScaleModeMap = {
187     {"FIT_TARGET_SIZE", 0, ""},
188     {"CENTER_CROP", 1, ""},
189 };
190 static std::vector<struct ImageEnum> sComponentTypeMap = {
191     {"YUV_Y", 1, ""},
192     {"YUV_U", 2, ""},
193     {"YUV_V", 3, ""},
194     {"JPEG", 4, ""},
195 };
196 static std::vector<struct ImageEnum> sDecodingDynamicRangeMap = {
197     {"AUTO", 0, ""},
198     {"SDR", 1, ""},
199     {"HDR", 2, ""},
200 };
201 static std::vector<struct ImageEnum> sDecodingResolutionQualityMap = {
202     {"LOW", 1, ""},
203     {"MEDIUM", 2, ""},
204     {"HIGH", 3, ""},
205 };
206 
ParseSize(napi_env env,napi_value root,Size * size)207 static bool ParseSize(napi_env env, napi_value root, Size* size)
208 {
209     if (size == nullptr) {
210         IMAGE_LOGE("size is nullptr");
211         return false;
212     }
213     if (!GET_INT32_BY_NAME(root, "height", size->height)) {
214         return false;
215     }
216 
217     if (!GET_INT32_BY_NAME(root, "width", size->width)) {
218         return false;
219     }
220 
221     return true;
222 }
223 
parseSourceOptions(napi_env env,napi_value root,SourceOptions * opts)224 static void parseSourceOptions(napi_env env, napi_value root, SourceOptions* opts)
225 {
226     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourceDensity", &(opts->baseDensity))) {
227         IMAGE_LOGD("no sourceDensity");
228     }
229 
230     int32_t pixelFormat = 0;
231     if (!ImageNapiUtils::GetInt32ByName(env, root, "sourcePixelFormat", &pixelFormat)) {
232         IMAGE_LOGD("no sourcePixelFormat");
233     } else {
234         opts->pixelFormat = static_cast<PixelFormat>(pixelFormat);
235         IMAGE_LOGI("sourcePixelFormat:%{public}d", static_cast<int32_t>(opts->pixelFormat));
236     }
237 
238     napi_value tmpValue = nullptr;
239     if (!GET_NODE_BY_NAME(root, "sourceSize", tmpValue)) {
240         IMAGE_LOGD("no sourceSize");
241     } else {
242         if (!ParseSize(env, tmpValue, &(opts->size))) {
243             IMAGE_LOGD("ParseSize error");
244         }
245         IMAGE_LOGI("sourceSize:(%{public}d, %{public}d)", opts->size.width, opts->size.height);
246     }
247 }
248 
PrepareNapiEnv(napi_env env)249 static void PrepareNapiEnv(napi_env env)
250 {
251     napi_value globalValue;
252     napi_get_global(env, &globalValue);
253     napi_value func;
254     napi_get_named_property(env, globalValue, "requireNapi", &func);
255 
256     napi_value imageInfo;
257     napi_create_string_utf8(env, "multimedia.sendableimage", NAPI_AUTO_LENGTH, &imageInfo);
258     napi_value funcArgv[1] = { imageInfo };
259     napi_value returnValue;
260     napi_call_function(env, globalValue, func, 1, funcArgv, &returnValue);
261 }
262 
hasNamedProperty(napi_env env,napi_value object,const std::string & name)263 static bool hasNamedProperty(napi_env env, napi_value object, const std::string& name)
264 {
265     bool res = false;
266     return (napi_has_named_property(env, object, name.c_str(), &res) == napi_ok) && res;
267 }
268 
parseRawFileItem(napi_env env,napi_value argValue,const std::string & item,int32_t * value)269 static bool parseRawFileItem(napi_env env, napi_value argValue, const std::string& item, int32_t* value)
270 {
271     napi_value nItem;
272     if (napi_get_named_property(env, argValue, item.c_str(), &nItem) != napi_ok) {
273         IMAGE_LOGE("Failed to parse RawFileDescriptor item %{public}s", item.c_str());
274         return false;
275     }
276     if (napi_get_value_int32(env, nItem, value) != napi_ok) {
277         IMAGE_LOGE("Failed to get RawFileDescriptor item %{public}s value", item.c_str());
278         return false;
279     }
280     return true;
281 }
282 
isRawFileDescriptor(napi_env env,napi_value argValue,ImageSourceAsyncContext * context)283 static bool isRawFileDescriptor(napi_env env, napi_value argValue, ImageSourceAsyncContext* context)
284 {
285     if (env == nullptr || argValue == nullptr || context == nullptr) {
286         IMAGE_LOGE("isRawFileDescriptor invalid input");
287         return false;
288     }
289     if (!hasNamedProperty(env, argValue, "fd") ||
290         !hasNamedProperty(env, argValue, "offset") ||
291         !hasNamedProperty(env, argValue, "length")) {
292         IMAGE_LOGD("RawFileDescriptor mismatch");
293         return false;
294     }
295     if (parseRawFileItem(env, argValue, "fd", &(context->rawFileInfo.fd)) &&
296         parseRawFileItem(env, argValue, "offset", &(context->rawFileInfo.offset)) &&
297         parseRawFileItem(env, argValue, "length", &(context->rawFileInfo.length))) {
298         return true;
299     }
300 
301     IMAGE_LOGE("Failed to parse RawFileDescriptor item");
302     return false;
303 }
304 
FileUrlToRawPath(const std::string & path)305 static std::string FileUrlToRawPath(const std::string &path)
306 {
307     if (path.size() > FILE_URL_PREFIX.size() &&
308         (path.compare(0, FILE_URL_PREFIX.size(), FILE_URL_PREFIX) == 0)) {
309         return path.substr(FILE_URL_PREFIX.size());
310     }
311     return path;
312 }
313 
ParseRegion(napi_env env,napi_value root,Rect * region)314 static bool ParseRegion(napi_env env, napi_value root, Rect* region)
315 {
316     napi_value tmpValue = nullptr;
317 
318     if (region == nullptr) {
319         IMAGE_LOGE("region is nullptr");
320         return false;
321     }
322 
323     if (!GET_INT32_BY_NAME(root, "x", region->left)) {
324         return false;
325     }
326 
327     if (!GET_INT32_BY_NAME(root, "y", region->top)) {
328         return false;
329     }
330 
331     if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
332         return false;
333     }
334 
335     if (!GET_INT32_BY_NAME(tmpValue, "height", region->height)) {
336         return false;
337     }
338 
339     if (!GET_INT32_BY_NAME(tmpValue, "width", region->width)) {
340         return false;
341     }
342 
343     return true;
344 }
345 
IsSupportPixelFormat(int32_t val)346 static bool IsSupportPixelFormat(int32_t val)
347 {
348     if (val >= static_cast<int32_t>(PixelFormat::UNKNOWN) &&
349         val <= static_cast<int32_t>(PixelFormat::NV12)) {
350         return true;
351     }
352 
353     return false;
354 }
355 
ParsePixlForamt(int32_t val)356 static PixelFormat ParsePixlForamt(int32_t val)
357 {
358     if (val <= static_cast<int32_t>(PixelFormat::CMYK)) {
359         return PixelFormat(val);
360     }
361 
362     return PixelFormat::UNKNOWN;
363 }
364 
ParseResolutionQuality(napi_env env,napi_value root)365 static ResolutionQuality ParseResolutionQuality(napi_env env, napi_value root)
366 {
367     uint32_t resolutionQuality = NUM_0;
368     if (!GET_UINT32_BY_NAME(root, "resolutionQuality", resolutionQuality)) {
369         IMAGE_LOGD("no resolutionQuality");
370         return ResolutionQuality::LOW;
371     }
372     if (resolutionQuality <= static_cast<uint32_t>(ResolutionQuality::HIGH)) {
373         return ResolutionQuality(resolutionQuality);
374     }
375     return ResolutionQuality::LOW;
376 }
377 
ParseDynamicRange(napi_env env,napi_value root)378 static DecodeDynamicRange ParseDynamicRange(napi_env env, napi_value root)
379 {
380     uint32_t tmpNumber = 0;
381     if (!GET_UINT32_BY_NAME(root, "desiredDynamicRange", tmpNumber)) {
382         IMAGE_LOGD("no desiredDynamicRange");
383         return DecodeDynamicRange::SDR;
384     }
385     if (tmpNumber <= static_cast<uint32_t>(DecodeDynamicRange::HDR)) {
386         return DecodeDynamicRange(tmpNumber);
387     }
388     return DecodeDynamicRange::SDR;
389 }
390 
ParseDecodeOptions2(napi_env env,napi_value root,DecodeOptions * opts,std::string & error)391 static bool ParseDecodeOptions2(napi_env env, napi_value root, DecodeOptions* opts, std::string &error)
392 {
393     uint32_t tmpNumber = 0;
394     if (!GET_UINT32_BY_NAME(root, "desiredPixelFormat", tmpNumber)) {
395         IMAGE_LOGD("no desiredPixelFormat");
396     } else {
397         if (IsSupportPixelFormat(tmpNumber)) {
398             opts->desiredPixelFormat = ParsePixlForamt(tmpNumber);
399         } else {
400             IMAGE_LOGD("Invalid desiredPixelFormat %{public}d", tmpNumber);
401             error = "DecodeOptions mismatch";
402             return false;
403         }
404     }
405 
406     if (!GET_INT32_BY_NAME(root, "fitDensity", opts->fitDensity)) {
407         IMAGE_LOGD("no fitDensity");
408     }
409 
410     if (GET_UINT32_BY_NAME(root, "fillColor", opts->SVGOpts.fillColor.color)) {
411         opts->SVGOpts.fillColor.isValidColor = true;
412         IMAGE_LOGD("fillColor %{public}x", opts->SVGOpts.fillColor.color);
413     } else {
414         IMAGE_LOGD("no fillColor");
415     }
416 
417     if (GET_UINT32_BY_NAME(root, "SVGResize", opts->SVGOpts.SVGResize.resizePercentage)) {
418         opts->SVGOpts.SVGResize.isValidPercentage = true;
419         IMAGE_LOGD("SVGResize percentage %{public}x", opts->SVGOpts.SVGResize.resizePercentage);
420     } else {
421         IMAGE_LOGD("no SVGResize percentage");
422     }
423     napi_value nDesiredColorSpace = nullptr;
424     if (napi_get_named_property(env, root, "desiredColorSpace", &nDesiredColorSpace) == napi_ok) {
425         opts->desiredColorSpaceInfo = OHOS::ColorManager::GetColorSpaceByJSObject(env, nDesiredColorSpace);
426         IMAGE_LOGD("desiredColorSpace parse finished");
427     }
428     if (opts->desiredColorSpaceInfo == nullptr) {
429         IMAGE_LOGD("no desiredColorSpace");
430     }
431     opts->desiredDynamicRange = ParseDynamicRange(env, root);
432     opts->resolutionQuality = ParseResolutionQuality(env, root);
433     return true;
434 }
435 
ParseDecodeOptions(napi_env env,napi_value root,DecodeOptions * opts,uint32_t * pIndex,std::string & error)436 static bool ParseDecodeOptions(napi_env env, napi_value root, DecodeOptions* opts,
437     uint32_t* pIndex, std::string &error)
438 {
439     napi_value tmpValue = nullptr;
440 
441     if (!ImageNapiUtils::GetUint32ByName(env, root, "index", pIndex)) {
442         IMAGE_LOGD("no index");
443     }
444 
445     if (opts == nullptr) {
446         IMAGE_LOGE("opts is nullptr");
447         return false;
448     }
449 
450     if (!GET_UINT32_BY_NAME(root, "sampleSize", opts->sampleSize)) {
451         IMAGE_LOGD("no sampleSize");
452     }
453 
454     if (!GET_UINT32_BY_NAME(root, "rotate", opts->rotateNewDegrees)) {
455         IMAGE_LOGD("no rotate");
456     } else {
457         if (opts->rotateNewDegrees >= 0 &&
458             opts->rotateNewDegrees <= 360) { // 360 is the maximum rotation angle.
459             opts->rotateDegrees = static_cast<float>(opts->rotateNewDegrees);
460         } else {
461             IMAGE_LOGD("Invalid rotate %{public}d", opts->rotateNewDegrees);
462             error = "DecodeOptions mismatch";
463             return false;
464         }
465     }
466 
467     if (!GET_BOOL_BY_NAME(root, "editable", opts->editable)) {
468         IMAGE_LOGD("no editable");
469     }
470 
471     if (!GET_NODE_BY_NAME(root, "desiredSize", tmpValue)) {
472         IMAGE_LOGD("no desiredSize");
473     } else {
474         if (!ParseSize(env, tmpValue, &(opts->desiredSize))) {
475             IMAGE_LOGD("ParseSize error");
476         }
477     }
478 
479     if (!GET_NODE_BY_NAME(root, "desiredRegion", tmpValue)) {
480         IMAGE_LOGD("no desiredRegion");
481     } else {
482         if (!ParseRegion(env, tmpValue, &(opts->CropRect))) {
483             IMAGE_LOGD("ParseRegion error");
484         }
485     }
486     return ParseDecodeOptions2(env, root, opts, error);
487 }
488 
ImageSourceCallbackRoutine(napi_env env,ImageSourceAsyncContext * & context,const napi_value & valueParam)489 static void ImageSourceCallbackRoutine(napi_env env, ImageSourceAsyncContext* &context, const napi_value &valueParam)
490 {
491     napi_value result[NUM_2] = {0};
492     napi_value retVal;
493     napi_value callback = nullptr;
494 
495     napi_get_undefined(env, &result[NUM_0]);
496     napi_get_undefined(env, &result[NUM_1]);
497 
498     if (context == nullptr) {
499         IMAGE_LOGE("context is nullptr");
500         return;
501     }
502 
503     if (context->status == SUCCESS) {
504         result[NUM_1] = valueParam;
505     } else if (context->errMsg.size() > 0) {
506         napi_create_string_utf8(env, context->errMsg.c_str(), NAPI_AUTO_LENGTH, &result[NUM_0]);
507     } else {
508         IMAGE_LOGD("error status, no message");
509         napi_create_string_utf8(env, "error status, no message", NAPI_AUTO_LENGTH, &result[NUM_0]);
510     }
511 
512     if (context->deferred) {
513         if (context->status == SUCCESS) {
514             napi_status status = napi_resolve_deferred(env, context->deferred, result[NUM_1]);
515             uint64_t imageId = 0;
516             if (context->rImageSource != nullptr) {
517                 imageId = context->rImageSource->GetImageId();
518             }
519             if (status != napi_ok) {
520                 IMAGE_LOGE("napi resolve failed, imageId:%{public}lu, status:%{public}d",
521                     static_cast<unsigned long>(imageId), status);
522             } else {
523                 IMAGE_LOGD("napi resolve success, imageId:%{public}lu",
524                     static_cast<unsigned long>(imageId));
525             }
526         } else {
527             napi_reject_deferred(env, context->deferred, result[NUM_0]);
528         }
529     } else {
530         IMAGE_LOGD("call callback function");
531         napi_get_reference_value(env, context->callbackRef, &callback);
532         napi_call_function(env, nullptr, callback, NUM_2, result, &retVal);
533         napi_delete_reference(env, context->callbackRef);
534     }
535 
536     napi_delete_async_work(env, context->work);
537 
538     delete context;
539     context = nullptr;
540 }
541 
CreatePixelMapInner(SendableImageSourceNapi * thisPtr,std::shared_ptr<ImageSource> imageSource,uint32_t index,DecodeOptions decodeOpts,uint32_t & status)542 static std::shared_ptr<PixelMap> CreatePixelMapInner(SendableImageSourceNapi *thisPtr,
543     std::shared_ptr<ImageSource> imageSource, uint32_t index, DecodeOptions decodeOpts, uint32_t &status)
544 {
545     if (thisPtr == nullptr || imageSource == nullptr) {
546         IMAGE_LOGE("Invailed args");
547         status = ERROR;
548         return nullptr;
549     }
550 
551     std::shared_ptr<PixelMap> pixelMap;
552     auto incPixelMap = thisPtr->GetIncrementalPixelMap();
553     if (incPixelMap != nullptr) {
554         IMAGE_LOGD("Get Incremental PixelMap!!!");
555         pixelMap = incPixelMap;
556     } else {
557         decodeOpts.invokeType = JS_INTERFACE;
558         pixelMap = imageSource->CreatePixelMapEx(index, decodeOpts, status);
559     }
560 
561     if (status != SUCCESS || !IMG_NOT_NULL(pixelMap)) {
562         IMAGE_LOGE("Create PixelMap error");
563     }
564 
565     return pixelMap;
566 }
567 
CreatePixelMapExecute(napi_env env,void * data)568 static void CreatePixelMapExecute(napi_env env, void *data)
569 {
570     IMAGE_LOGD("CreatePixelMapExecute IN");
571     if (data == nullptr) {
572         IMAGE_LOGE("data is nullptr");
573         return;
574     }
575     auto context = static_cast<ImageSourceAsyncContext*>(data);
576     if (context == nullptr) {
577         IMAGE_LOGE("empty context");
578         return;
579     }
580 
581     if (context->errMsg.size() > 0) {
582         IMAGE_LOGE("mismatch args");
583         context->status = ERROR;
584         return;
585     }
586 
587     context->rPixelMap = CreatePixelMapInner(context->constructor_, context->rImageSource,
588         context->index, context->decodeOpts, context->status);
589 
590     if (context->status != SUCCESS) {
591         context->errMsg = "Create PixelMap error";
592         IMAGE_LOGE("Create PixelMap error");
593     }
594     IMAGE_LOGD("CreatePixelMapExecute OUT");
595 }
596 
CreatePixelMapComplete(napi_env env,napi_status status,void * data)597 static void CreatePixelMapComplete(napi_env env, napi_status status, void *data)
598 {
599     napi_value result = nullptr;
600     auto context = static_cast<ImageSourceAsyncContext*>(data);
601     uint64_t imageId = 0;
602     if (context->rImageSource != nullptr) {
603         imageId = context->rImageSource->GetImageId();
604     }
605     IMAGE_LOGD("CreatePixelMapComplete IN imageId:%{public}lu", static_cast<unsigned long>(imageId));
606 
607     if (context->status == SUCCESS) {
608         result = SendablePixelMapNapi::CreateSendablePixelMap(env, context->rPixelMap);
609     } else {
610         napi_get_undefined(env, &result);
611     }
612     IMAGE_LOGD("CreatePixelMapComplete OUT imageId:%{public}lu", static_cast<unsigned long>(imageId));
613     ImageSourceCallbackRoutine(env, context, result);
614 }
615 
CreateNativeImageSource(napi_env env,napi_value argValue,SourceOptions & opts,ImageSourceAsyncContext * context)616 static std::unique_ptr<ImageSource> CreateNativeImageSource(napi_env env, napi_value argValue,
617     SourceOptions &opts, ImageSourceAsyncContext* context)
618 {
619     std::unique_ptr<ImageSource> imageSource = nullptr;
620     uint32_t errorCode = ERR_MEDIA_INVALID_VALUE;
621     napi_status status;
622 
623     auto inputType = ImageNapiUtils::getType(env, argValue);
624     if (napi_string == inputType) { // File Path
625         if (!ImageNapiUtils::GetUtf8String(env, argValue, context->pathName)) {
626             IMAGE_LOGE("fail to get pathName");
627             return imageSource;
628         }
629         context->pathName = FileUrlToRawPath(context->pathName);
630         context->pathNameLength = context->pathName.size();
631         imageSource = ImageSource::CreateImageSource(context->pathName, opts, errorCode);
632     } else if (napi_number == inputType) { // Fd
633         napi_get_value_int32(env, argValue, &context->fdIndex);
634         IMAGE_LOGD("CreateImageSource fdIndex is [%{public}d]", context->fdIndex);
635         imageSource = ImageSource::CreateImageSource(context->fdIndex, opts, errorCode);
636     } else if (isRawFileDescriptor(env, argValue, context)) {
637         IMAGE_LOGE(
638             "CreateImageSource RawFileDescriptor fd: %{public}d, offset: %{public}d, length: %{public}d",
639             context->rawFileInfo.fd, context->rawFileInfo.offset, context->rawFileInfo.length);
640         int32_t fileSize = context->rawFileInfo.offset + context->rawFileInfo.length;
641         imageSource = ImageSource::CreateImageSource(context->rawFileInfo.fd,
642             context->rawFileInfo.offset, fileSize, opts, errorCode);
643     } else { // Input Buffer
644         uint32_t refCount = NUM_1;
645         napi_ref arrayRef = nullptr;
646         napi_create_reference(env, argValue, refCount, &arrayRef);
647         status = napi_get_arraybuffer_info(env, argValue, &(context->sourceBuffer), &(context->sourceBufferSize));
648         if (status != napi_ok) {
649             napi_delete_reference(env, arrayRef);
650             IMAGE_LOGE("fail to get arraybufferinfo");
651             return nullptr;
652         }
653         imageSource = ImageSource::CreateImageSource(static_cast<uint8_t *>(context->sourceBuffer),
654             context->sourceBufferSize, opts, errorCode);
655         napi_delete_reference(env, arrayRef);
656     }
657     return imageSource;
658 }
659 
CreatePixelMap(napi_env env,napi_callback_info info)660 napi_value SendableImageSourceNapi::CreatePixelMap(napi_env env, napi_callback_info info)
661 {
662     napi_value result = nullptr;
663     napi_get_undefined(env, &result);
664 
665     int32_t refCount = 1;
666     napi_status status;
667     napi_value thisVar = nullptr;
668     napi_value argValue[NUM_2] = {0};
669     size_t argCount = NUM_2;
670     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
671     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, thisVar), nullptr, IMAGE_LOGE("fail to get thisVar"));
672     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info"));
673 
674     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
675 
676     status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
677     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_),
678         nullptr, IMAGE_LOGE("fail to unwrap context"));
679     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_->nativeImgSrc),
680         nullptr, IMAGE_LOGE("fail to unwrap nativeImgSrc"));
681     asyncContext->rImageSource = asyncContext->constructor_->nativeImgSrc;
682     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rImageSource),
683         nullptr, IMAGE_LOGE("empty native rImageSource"));
684 
685     if (argCount == NUM_0) {
686         IMAGE_LOGD("CreatePixelMap with no arg");
687     } else if (argCount == NUM_1 || argCount == NUM_2) {
688         if (ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_object) {
689             if (!ParseDecodeOptions(env, argValue[NUM_0], &(asyncContext->decodeOpts),
690                                     &(asyncContext->index), asyncContext->errMsg)) {
691                 IMAGE_LOGE("DecodeOptions mismatch");
692             }
693         }
694         if (ImageNapiUtils::getType(env, argValue[argCount - 1]) == napi_function) {
695             napi_create_reference(env, argValue[argCount - 1], refCount, &asyncContext->callbackRef);
696         }
697     } else {
698         IMAGE_LOGE("argCount mismatch");
699         return result;
700     }
701     if (asyncContext->callbackRef == nullptr) {
702         napi_create_promise(env, &(asyncContext->deferred), &result);
703     } else {
704         napi_get_undefined(env, &result);
705     }
706 
707     ImageNapiUtils::HicheckerReport();
708     IMG_CREATE_CREATE_ASYNC_WORK_WITH_QOS(env, status, "CreatePixelMap", CreatePixelMapExecute,
709         CreatePixelMapComplete, asyncContext, asyncContext->work, napi_qos_user_initiated);
710 
711     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
712         nullptr, IMAGE_LOGE("fail to create async work"));
713     return result;
714 }
715 
CreateImageSource(napi_env env,napi_callback_info info)716 napi_value SendableImageSourceNapi::CreateImageSource(napi_env env, napi_callback_info info)
717 {
718     PrepareNapiEnv(env);
719     napi_value result = nullptr;
720     napi_get_undefined(env, &result);
721 
722     napi_status status;
723     napi_value thisVar = nullptr;
724     napi_value argValue[NUM_2] = {0};
725     size_t argCount = 2;
726     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
727     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("fail to napi_get_cb_info"));
728     NAPI_ASSERT(env, argCount > 0, "No arg!");
729 
730     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
731     SourceOptions opts;
732     if (argCount > NUM_1) {
733         parseSourceOptions(env, argValue[NUM_1], &opts);
734     }
735     std::unique_ptr<ImageSource> imageSource = CreateNativeImageSource(env, argValue[NUM_0],
736         opts, asyncContext.get());
737     if (imageSource == nullptr) {
738         IMAGE_LOGE("CreateImageSourceExec error");
739         napi_get_undefined(env, &result);
740         return result;
741     }
742 
743     {
744         std::lock_guard<std::mutex> lock(imageSourceCrossThreadMutex_);
745         filePath_ = asyncContext->pathName;
746         fileDescriptor_ = asyncContext->fdIndex;
747         fileBuffer_ = asyncContext->sourceBuffer;
748         fileBufferSize_ = asyncContext->sourceBufferSize;
749     }
750 
751     napi_value constructor = nullptr;
752     status = napi_get_reference_value(env, sConstructor_, &constructor);
753     if (IMG_IS_OK(status)) {
754         sImgSrc_ = std::move(imageSource);
755         status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
756     }
757     if (!IMG_IS_OK(status)) {
758         IMAGE_LOGE("New instance could not be obtained");
759         napi_get_undefined(env, &result);
760     }
761     return result;
762 }
763 
764 struct ImageConstructorInfo {
765     std::string className;
766     napi_ref* classRef;
767     napi_callback constructor;
768     const napi_property_descriptor* property;
769     size_t propertyCount;
770     const napi_property_descriptor* staticProperty;
771     size_t staticPropertyCount;
772 };
773 
SendableImageSourceNapi()774 SendableImageSourceNapi::SendableImageSourceNapi():env_(nullptr)
775 {   }
776 
~SendableImageSourceNapi()777 SendableImageSourceNapi::~SendableImageSourceNapi()
778 {
779     release();
780 }
781 
DoInit(napi_env env,napi_value exports,struct ImageConstructorInfo info)782 static napi_value DoInit(napi_env env, napi_value exports, struct ImageConstructorInfo info)
783 {
784     napi_value constructor = nullptr;
785     napi_status status = napi_define_class(env, info.className.c_str(), NAPI_AUTO_LENGTH,
786         info.constructor, nullptr, info.propertyCount, info.property, &constructor);
787     if (status != napi_ok) {
788         IMAGE_LOGE("define class fail");
789         return nullptr;
790     }
791 
792     status = napi_create_reference(env, constructor, NUM_1, info.classRef);
793     if (status != napi_ok) {
794         IMAGE_LOGE("create reference fail");
795         return nullptr;
796     }
797 
798     napi_value global = nullptr;
799     status = napi_get_global(env, &global);
800     if (status != napi_ok) {
801         IMAGE_LOGE("Init:get global fail");
802         return nullptr;
803     }
804 
805     status = napi_set_named_property(env, global, info.className.c_str(), constructor);
806     if (status != napi_ok) {
807         IMAGE_LOGE("Init:set global named property fail");
808         return nullptr;
809     }
810 
811     status = napi_define_properties(env, exports, info.staticPropertyCount, info.staticProperty);
812     if (status != napi_ok) {
813         IMAGE_LOGE("define properties fail");
814         return nullptr;
815     }
816     return exports;
817 }
818 
Init(napi_env env,napi_value exports)819 napi_value SendableImageSourceNapi::Init(napi_env env, napi_value exports)
820 {
821     napi_property_descriptor properties[] = {
822         DECLARE_NAPI_FUNCTION("createPixelMap", CreatePixelMap),
823         DECLARE_NAPI_FUNCTION("release", Release),
824     };
825 
826     napi_property_descriptor static_prop[] = {
827         DECLARE_NAPI_STATIC_FUNCTION("createImageSource", CreateImageSource),
828     };
829 
830     struct ImageConstructorInfo info = {
831         .className = CLASS_NAME,
832         .classRef = &sConstructor_,
833         .constructor = Constructor,
834         .property = properties,
835         .propertyCount = sizeof(properties) / sizeof(properties[NUM_0]),
836         .staticProperty = static_prop,
837         .staticPropertyCount = sizeof(static_prop) / sizeof(static_prop[NUM_0]),
838     };
839 
840     if (DoInit(env, exports, info)) {
841         return nullptr;
842     }
843     return exports;
844 }
845 
Constructor(napi_env env,napi_callback_info info)846 napi_value SendableImageSourceNapi::Constructor(napi_env env, napi_callback_info info)
847 {
848     napi_value undefineValue = nullptr;
849     napi_get_undefined(env, &undefineValue);
850 
851     napi_status status;
852     napi_value thisVar = nullptr;
853     status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
854     if (status == napi_ok && thisVar != nullptr) {
855         std::unique_ptr<SendableImageSourceNapi> pImgSrcNapi = std::make_unique<SendableImageSourceNapi>();
856         if (pImgSrcNapi != nullptr) {
857             pImgSrcNapi->env_ = env;
858             pImgSrcNapi->nativeImgSrc = sImgSrc_;
859             if (pImgSrcNapi->nativeImgSrc == nullptr) {
860                 IMAGE_LOGE("Failed to set nativeImageSource with null. Maybe a reentrancy error");
861             }
862             pImgSrcNapi->navIncPixelMap_ = sIncPixelMap_;
863             sIncPixelMap_ = nullptr;
864             sImgSrc_ = nullptr;
865             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pImgSrcNapi.get()),
866                                SendableImageSourceNapi::Destructor, nullptr, nullptr);
867             if (status == napi_ok) {
868                 pImgSrcNapi.release();
869                 return thisVar;
870             } else {
871                 IMAGE_LOGE("Failure wrapping js to native napi");
872             }
873         }
874     }
875 
876     return undefineValue;
877 }
878 
Destructor(napi_env env,void * nativeObject,void * finalize)879 void SendableImageSourceNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
880 {
881     reinterpret_cast<SendableImageSourceNapi *>(nativeObject)->nativeImgSrc = nullptr;
882     IMAGE_LOGD("ImageSourceNapi::Destructor");
883 }
884 
ReleaseSendEvent(napi_env env,ImageSourceAsyncContext * context,napi_event_priority prio)885 static bool ReleaseSendEvent(napi_env env, ImageSourceAsyncContext* context,
886                              napi_event_priority prio)
887 {
888     auto task = [env, context]() {
889         napi_value result = nullptr;
890         napi_get_undefined(env, &result);
891 
892         delete context->constructor_;
893         context->constructor_ = nullptr;
894         ImageSourceCallbackRoutine(env, const_cast<ImageSourceAsyncContext *&>(context), result);
895     };
896     if (napi_status::napi_ok != napi_send_event(env, task, prio)) {
897         IMAGE_LOGE("ReleaseSendEvent: failed to SendEvent!");
898         return false;
899     }
900     return true;
901 }
902 
Release(napi_env env,napi_callback_info info)903 napi_value SendableImageSourceNapi::Release(napi_env env, napi_callback_info info)
904 {
905     IMAGE_LOGD("Release enter");
906     napi_value result = nullptr;
907     napi_get_undefined(env, &result);
908 
909     int32_t refCount = 1;
910     napi_status status;
911     napi_value thisVar = nullptr;
912     napi_value argValue[NUM_1] = {0};
913     size_t argCount = 1;
914 
915     IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
916     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
917     IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("fail to napi_get_cb_info"));
918 
919     std::unique_ptr<ImageSourceAsyncContext> asyncContext = std::make_unique<ImageSourceAsyncContext>();
920     status = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->constructor_));
921 
922     IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->constructor_), result,
923         IMAGE_LOGE("fail to unwrap context"));
924 
925     IMAGE_LOGD("Release argCount is [%{public}zu]", argCount);
926     if (argCount == 1 && ImageNapiUtils::getType(env, argValue[NUM_0]) == napi_function) {
927         napi_create_reference(env, argValue[NUM_0], refCount, &asyncContext->callbackRef);
928     }
929 
930     if (asyncContext->callbackRef == nullptr) {
931         napi_create_promise(env, &(asyncContext->deferred), &result);
932     }
933 
934     if (ReleaseSendEvent(env, asyncContext.get(), napi_eprio_high)) {
935         asyncContext.release();
936     }
937     IMAGE_LOGD("Release exit");
938     return result;
939 }
940 
release()941 void SendableImageSourceNapi::release()
942 {
943     if (!isRelease) {
944         nativeImgSrc = nullptr;
945         isRelease = true;
946     }
947 }
948 
949 }
950 }