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