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 }