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