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_napi.h"
17
18 #include "napi/native_node_api.h"
19 #include "image_log.h"
20 #include "media_errors.h"
21 #include "image_format.h"
22 #include "image_napi_utils.h"
23
24 #undef LOG_DOMAIN
25 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
26
27 #undef LOG_TAG
28 #define LOG_TAG "ImageNapi"
29
30 namespace {
31 constexpr int NUM0 = 0;
32 constexpr int NUM1 = 1;
33 constexpr int NUM2 = 2;
34 const std::string MY_NAME = "ImageNapi";
35 }
36
37 namespace OHOS {
38 namespace Media {
39 struct ImageAsyncContext {
40 napi_env env = nullptr;
41 napi_async_work work = nullptr;
42 napi_deferred deferred = nullptr;
43 napi_ref callbackRef = nullptr;
44 napi_ref thisRef = nullptr;
45 ImageNapi *napi = nullptr;
46 uint32_t status;
47 int32_t componentType;
48 NativeImage* image = nullptr;
49 NativeComponent* component = nullptr;
50 bool isTestContext = false;
51 };
52 ImageHolderManager<NativeImage> ImageNapi::sNativeImageHolder_;
53 thread_local napi_ref ImageNapi::sConstructor_ = nullptr;
54
ImageNapi()55 ImageNapi::ImageNapi()
56 {}
57
~ImageNapi()58 ImageNapi::~ImageNapi()
59 {
60 NativeRelease();
61 }
62
NativeRelease()63 void ImageNapi::NativeRelease()
64 {
65 if (native_ != nullptr) {
66 sNativeImageHolder_.release(native_->GetId());
67 native_->release();
68 native_ = nullptr;
69 }
70 }
71
Init(napi_env env, napi_value exports)72 napi_value ImageNapi::Init(napi_env env, napi_value exports)
73 {
74 IMAGE_FUNCTION_IN();
75 napi_property_descriptor props[] = {
76 DECLARE_NAPI_GETTER("clipRect", JSGetClipRect),
77 DECLARE_NAPI_GETTER("size", JsGetSize),
78 DECLARE_NAPI_GETTER("format", JsGetFormat),
79 DECLARE_NAPI_GETTER("timestamp", JsGetTimestamp),
80 DECLARE_NAPI_FUNCTION("getComponent", JsGetComponent),
81 DECLARE_NAPI_FUNCTION("release", JsRelease),
82 };
83 size_t size = IMG_ARRAY_SIZE(props);
84 napi_value thisVar = nullptr;
85 auto name = MY_NAME.c_str();
86 if (napi_define_class(env, name, SIZE_MAX, Constructor, nullptr, size, props, &thisVar) != napi_ok) {
87 IMAGE_ERR("Define class failed");
88 return exports;
89 }
90
91 sConstructor_ = nullptr;
92
93 if (napi_create_reference(env, thisVar, NUM1, &sConstructor_) != napi_ok) {
94 IMAGE_ERR("Create reference failed");
95 return exports;
96 }
97
98 if (napi_set_named_property(env, exports, name, thisVar) != napi_ok) {
99 IMAGE_ERR("Define class failed");
100 return exports;
101 }
102
103 IMAGE_DEBUG("Init success");
104 return exports;
105 }
106
107
GetNativeImage(napi_env env, napi_value image)108 std::shared_ptr<NativeImage> ImageNapi::GetNativeImage(napi_env env, napi_value image)
109 {
110 ImageNapi* napi = nullptr;
111
112 napi_status status = napi_unwrap(env, image, reinterpret_cast<void**>(&napi));
113 if (!IMG_IS_OK(status) || napi == nullptr) {
114 IMAGE_ERR("GetImage napi unwrap failed");
115 return nullptr;
116 }
117 return napi->native_;
118 }
119
Constructor(napi_env env, napi_callback_info info)120 napi_value ImageNapi::Constructor(napi_env env, napi_callback_info info)
121 {
122 napi_status status;
123 napi_value thisVar = nullptr;
124 napi_value undefineVar;
125 size_t argc = NUM1;
126 napi_value argv[NUM1];
127
128 IMAGE_FUNCTION_IN();
129 napi_get_undefined(env, &undefineVar);
130 status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
131 if (status != napi_ok || thisVar == nullptr || argc != NUM1) {
132 IMAGE_ERR("Constructor Failed to napi_get_cb_info");
133 return undefineVar;
134 }
135 std::string id;
136 if (!ImageNapiUtils::GetUtf8String(env, argv[NUM0], id) || (id.size() == NUM0)) {
137 IMAGE_ERR("Failed to parse native image id");
138 return undefineVar;
139 }
140 std::unique_ptr<ImageNapi> napi = std::make_unique<ImageNapi>();
141 napi->native_ = sNativeImageHolder_.get(id);
142 napi->isTestImage_ = false;
143 if (napi->native_ == nullptr) {
144 if (MY_NAME.compare(id.c_str()) == 0) {
145 napi->isTestImage_ = true;
146 } else {
147 IMAGE_ERR("Failed to get native image");
148 return undefineVar;
149 }
150 }
151 status = napi_wrap(env, thisVar,
152 reinterpret_cast<void *>(napi.get()), ImageNapi::Destructor, nullptr, nullptr);
153 if (status != napi_ok) {
154 IMAGE_ERR("Failure wrapping js to native napi");
155 return undefineVar;
156 }
157
158 napi.release();
159 IMAGE_FUNCTION_OUT();
160 return thisVar;
161 }
162
Destructor(napi_env env, void *nativeObject, void *finalize)163 void ImageNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
164 {
165 if (nativeObject != nullptr) {
166 delete reinterpret_cast<ImageNapi *>(nativeObject);
167 }
168 }
169
Create(napi_env env)170 napi_value ImageNapi::Create(napi_env env)
171 {
172 napi_value constructor = nullptr;
173 napi_value result = nullptr;
174 napi_value argv[NUM1];
175
176 IMAGE_FUNCTION_IN();
177 if (env == nullptr) {
178 IMAGE_ERR("Input args is invalid");
179 return nullptr;
180 }
181 if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
182 if (napi_create_string_utf8(env, MY_NAME.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
183 IMAGE_ERR("Create native image id Failed");
184 }
185 if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
186 IMAGE_ERR("New instance could not be obtained");
187 }
188 }
189 IMAGE_FUNCTION_OUT();
190 return result;
191 }
Create(napi_env env, std::shared_ptr<NativeImage> nativeImage)192 napi_value ImageNapi::Create(napi_env env, std::shared_ptr<NativeImage> nativeImage)
193 {
194 napi_value constructor = nullptr;
195 napi_value result = nullptr;
196 napi_value argv[NUM1];
197
198 IMAGE_FUNCTION_IN();
199 if (env == nullptr || nativeImage == nullptr) {
200 IMAGE_ERR("Input args is invalid %{public}p vs %{public}p", env, nativeImage.get());
201 return nullptr;
202 }
203 if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
204 auto id = sNativeImageHolder_.save(nativeImage);
205 nativeImage->SetId(id);
206 if (napi_create_string_utf8(env, id.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
207 IMAGE_ERR("Create native image id Failed");
208 }
209 if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
210 IMAGE_ERR("New instance could not be obtained");
211 }
212 }
213 IMAGE_FUNCTION_OUT();
214 return result;
215 }
JsCheckObjectType(napi_env env, napi_value value, napi_valuetype type)216 static inline bool JsCheckObjectType(napi_env env, napi_value value, napi_valuetype type)
217 {
218 return (ImageNapiUtils::getType(env, value) == type);
219 }
220
JsGetCallbackFunc(napi_env env, napi_value value, napi_ref *result)221 static inline bool JsGetCallbackFunc(napi_env env, napi_value value, napi_ref *result)
222 {
223 if (JsCheckObjectType(env, value, napi_function)) {
224 napi_create_reference(env, value, NUM1, result);
225 return true;
226 }
227 return false;
228 }
229
JsGetInt32Args(napi_env env, napi_value value, int *result)230 static inline bool JsGetInt32Args(napi_env env, napi_value value, int *result)
231 {
232 if (JsCheckObjectType(env, value, napi_number)) {
233 napi_get_value_int32(env, value, result);
234 return true;
235 }
236 return false;
237 }
238 using AsyncExecCallback = void (*)(napi_env env, ImageAsyncContext* ctx);
239 using AsyncCompleteCallback = void (*)(napi_env env, napi_status status, ImageAsyncContext* ctx);
JsCreateWork(napi_env env, const char* name, AsyncExecCallback exec, AsyncCompleteCallback complete, ImageAsyncContext* ctx)240 static bool JsCreateWork(napi_env env, const char* name, AsyncExecCallback exec,
241 AsyncCompleteCallback complete, ImageAsyncContext* ctx)
242 {
243 napi_value resource = nullptr;
244 napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resource);
245 napi_status status = napi_create_async_work(
246 env, nullptr, resource, reinterpret_cast<napi_async_execute_callback>(exec),
247 reinterpret_cast<napi_async_complete_callback>(complete), static_cast<void *>(ctx), &(ctx->work));
248 if (status != napi_ok) {
249 IMAGE_ERR("fail to create async work %{public}d", status);
250 return false;
251 }
252
253 if (napi_queue_async_work(env, ctx->work) != napi_ok) {
254 IMAGE_ERR("fail to queue async work");
255 return false;
256 }
257 return true;
258 }
259
GetNative()260 NativeImage* ImageNapi::GetNative()
261 {
262 if (native_ != nullptr) {
263 return native_.get();
264 }
265 return nullptr;
266 }
267
UnwrapContext(napi_env env, napi_callback_info info, size_t* argc = nullptr, napi_value* argv = nullptr, bool needCreateRef = false)268 static std::unique_ptr<ImageAsyncContext> UnwrapContext(napi_env env, napi_callback_info info,
269 size_t* argc = nullptr, napi_value* argv = nullptr, bool needCreateRef = false)
270 {
271 napi_value thisVar = nullptr;
272 size_t tmp = NUM0;
273
274 IMAGE_FUNCTION_IN();
275
276 if (napi_get_cb_info(env, info, (argc == nullptr)?&tmp:argc, argv, &thisVar, nullptr) != napi_ok) {
277 IMAGE_ERR("Fail to napi_get_cb_info");
278 return nullptr;
279 }
280
281 std::unique_ptr<ImageAsyncContext> ctx = std::make_unique<ImageAsyncContext>();
282 if (napi_unwrap(env, thisVar, reinterpret_cast<void**>(&ctx->napi)) != napi_ok || ctx->napi == nullptr) {
283 IMAGE_ERR("fail to unwrap constructor_");
284 return nullptr;
285 }
286 ctx->image = ctx->napi->GetNative();
287 if (needCreateRef) {
288 napi_create_reference(env, thisVar, NUM1, &(ctx->thisRef));
289 }
290 return ctx;
291 }
292
ProcessPromise(napi_env env, napi_deferred deferred, napi_value* result, bool resolved)293 static inline void ProcessPromise(napi_env env, napi_deferred deferred, napi_value* result, bool resolved)
294 {
295 napi_status status;
296 if (resolved) {
297 status = napi_resolve_deferred(env, deferred, result[NUM1]);
298 } else {
299 status = napi_reject_deferred(env, deferred, result[NUM0]);
300 }
301 if (status != napi_ok) {
302 IMAGE_ERR("ProcessPromise failed");
303 }
304 deferred = nullptr;
305 }
ProcessCallback(napi_env env, napi_ref ref, napi_value* result)306 static inline void ProcessCallback(napi_env env, napi_ref ref, napi_value* result)
307 {
308 napi_value retVal;
309 napi_value callback;
310 napi_get_reference_value(env, ref, &callback);
311 napi_call_function(env, nullptr, callback, NUM2, result, &retVal);
312 napi_delete_reference(env, ref);
313 }
CommonCallbackRoutine(napi_env env, ImageAsyncContext* &context, const napi_value &valueParam)314 static void CommonCallbackRoutine(napi_env env, ImageAsyncContext* &context, const napi_value &valueParam)
315 {
316 IMAGE_FUNCTION_IN();
317 napi_value result[2] = {0};
318
319 if (context == nullptr) {
320 IMAGE_ERR("context is nullptr");
321 return;
322 }
323
324 if (context->status == SUCCESS) {
325 napi_create_uint32(env, context->status, &result[0]);
326 result[1] = valueParam;
327 } else {
328 ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
329 "There is generic napi failure!");
330 napi_get_undefined(env, &result[1]);
331 }
332
333 if (context->deferred) {
334 ProcessPromise(env, context->deferred, result, context->status == SUCCESS);
335 } else {
336 ProcessCallback(env, context->callbackRef, result);
337 }
338
339 napi_delete_async_work(env, context->work);
340
341 delete context;
342 context = nullptr;
343 IMAGE_FUNCTION_OUT();
344 }
345
BuildIntProperty(napi_env env, const std::string &name, int32_t val, napi_value result)346 static void BuildIntProperty(napi_env env, const std::string &name,
347 int32_t val, napi_value result)
348 {
349 napi_value nVal;
350 napi_create_int32(env, val, &nVal);
351 napi_set_named_property(env, result, name.c_str(), nVal);
352 }
353
BuildJsSize(napi_env env, int32_t width, int32_t height)354 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
355 {
356 napi_value result = nullptr;
357
358 napi_create_object(env, &result);
359
360 BuildIntProperty(env, "width", width, result);
361 BuildIntProperty(env, "height", height, result);
362 return result;
363 }
364
BuildJsRegion(napi_env env, int32_t width, int32_t height, int32_t x, int32_t y)365 static napi_value BuildJsRegion(napi_env env, int32_t width,
366 int32_t height, int32_t x, int32_t y)
367 {
368 napi_value result = nullptr;
369
370 napi_create_object(env, &result);
371
372 napi_set_named_property(env, result, "size", BuildJsSize(env, width, height));
373
374 BuildIntProperty(env, "x", x, result);
375 BuildIntProperty(env, "y", y, result);
376 return result;
377 }
378
JSGetClipRect(napi_env env, napi_callback_info info)379 napi_value ImageNapi::JSGetClipRect(napi_env env, napi_callback_info info)
380 {
381 napi_value result = nullptr;
382
383 IMAGE_FUNCTION_IN();
384 napi_get_undefined(env, &result);
385 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
386 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
387 const int32_t WIDTH = 8192;
388 const int32_t HEIGHT = 8;
389 return BuildJsRegion(env, WIDTH, HEIGHT, NUM0, NUM0);
390 }
391 if (context == nullptr || context->image == nullptr) {
392 IMAGE_ERR("Image surface buffer is nullptr");
393 return result;
394 }
395
396 int32_t width = NUM0;
397 int32_t height = NUM0;
398 if (context->image->GetSize(width, height) != SUCCESS) {
399 IMAGE_ERR("Image native get size failed");
400 return result;
401 }
402 return BuildJsRegion(env, width, height, NUM0, NUM0);
403 }
404
JsGetSize(napi_env env, napi_callback_info info)405 napi_value ImageNapi::JsGetSize(napi_env env, napi_callback_info info)
406 {
407 napi_value result = nullptr;
408
409 IMAGE_FUNCTION_IN();
410 napi_get_undefined(env, &result);
411 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
412 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
413 const int32_t WIDTH = 8192;
414 const int32_t HEIGHT = 8;
415 return BuildJsSize(env, WIDTH, HEIGHT);
416 }
417 if (context == nullptr || context->image == nullptr) {
418 IMAGE_ERR("Image surface buffer is nullptr");
419 return result;
420 }
421
422 int32_t width = NUM0;
423 int32_t height = NUM0;
424 if (context->image->GetSize(width, height) != SUCCESS) {
425 IMAGE_ERR("Image native get size failed");
426 return result;
427 }
428 return BuildJsSize(env, width, height);
429 }
430
JsGetFormat(napi_env env, napi_callback_info info)431 napi_value ImageNapi::JsGetFormat(napi_env env, napi_callback_info info)
432 {
433 napi_value result = nullptr;
434
435 IMAGE_FUNCTION_IN();
436 napi_get_undefined(env, &result);
437 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
438 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
439 const int32_t FORMAT = 12;
440 napi_create_int32(env, FORMAT, &result);
441 return result;
442 }
443 if (context == nullptr || context->image == nullptr) {
444 IMAGE_ERR("Image surface buffer is nullptr");
445 return result;
446 }
447
448 int32_t format = NUM0;
449 if (context->image->GetFormat(format) != SUCCESS) {
450 IMAGE_ERR("Image native get format failed");
451 return result;
452 }
453
454 napi_create_int32(env, format, &result);
455 return result;
456 }
457
JsGetTimestamp(napi_env env, napi_callback_info info)458 napi_value ImageNapi::JsGetTimestamp(napi_env env, napi_callback_info info)
459 {
460 napi_value result = nullptr;
461
462 IMAGE_FUNCTION_IN();
463 napi_get_undefined(env, &result);
464 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
465 if (context == nullptr || context->image == nullptr) {
466 IMAGE_ERR("context is nullptr or Image native is nullptr");
467 return result;
468 }
469
470 int64_t timestamp = 0;
471 if (context->image->GetTimestamp(timestamp) != SUCCESS) {
472 IMAGE_ERR("Image native get timestamp failed");
473 return result;
474 }
475
476 napi_create_int64(env, timestamp, &result);
477 return result;
478 }
479
JSReleaseCallBack(napi_env env, napi_status status, ImageAsyncContext* context)480 static void JSReleaseCallBack(napi_env env, napi_status status,
481 ImageAsyncContext* context)
482 {
483 IMAGE_FUNCTION_IN();
484 napi_value result = nullptr;
485 napi_get_undefined(env, &result);
486
487 if (context == nullptr) {
488 IMAGE_ERR("context is nullptr");
489 return;
490 }
491
492 if (context->thisRef != nullptr) {
493 napi_value thisVar;
494 napi_get_reference_value(env, context->thisRef, &thisVar);
495 napi_delete_reference(env, context->thisRef);
496 if (thisVar != nullptr) {
497 ImageNapi *tmp = nullptr;
498 auto status_ = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&tmp));
499 if (status_ != napi_ok) {
500 IMAGE_ERR("NAPI remove wrap failed status %{public}d", status_);
501 }
502 }
503 }
504
505 context->status = SUCCESS;
506 IMAGE_FUNCTION_OUT();
507 CommonCallbackRoutine(env, context, result);
508 }
509
JsRelease(napi_env env, napi_callback_info info)510 napi_value ImageNapi::JsRelease(napi_env env, napi_callback_info info)
511 {
512 IMAGE_FUNCTION_IN();
513 napi_value result = nullptr;
514 size_t argc = NUM1;
515 napi_value argv[NUM1] = {0};
516
517 napi_get_undefined(env, &result);
518 auto context = UnwrapContext(env, info, &argc, argv, true);
519 if (context == nullptr) {
520 IMAGE_ERR("fail to unwrap constructor_");
521 return result;
522 }
523 if (argc == NUM1) {
524 if (!JsGetCallbackFunc(env, argv[NUM0], &(context->callbackRef))) {
525 IMAGE_ERR("Unsupport arg 0 type");
526 return result;
527 }
528 } else {
529 napi_create_promise(env, &(context->deferred), &result);
530 }
531
532 if (JsCreateWork(env, "JsRelease", [](napi_env env, ImageAsyncContext* data) {},
533 JSReleaseCallBack, context.get())) {
534 context.release();
535 }
536 IMAGE_FUNCTION_OUT();
537 return result;
538 }
539
CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)540 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
541 {
542 if (src == nullptr || srcLen == 0) {
543 return false;
544 }
545 auto status = napi_create_external_arraybuffer(env, src, srcLen,
546 [](napi_env env, void* data, void* hint) { }, nullptr, res);
547 if (status != napi_ok) {
548 return false;
549 }
550 return true;
551 }
552
IsEqual(const int32_t& check, ImageFormat format)553 static inline bool IsEqual(const int32_t& check, ImageFormat format)
554 {
555 return (check == int32_t(format));
556 }
IsEqual(const int32_t& check, ComponentType type)557 static inline bool IsEqual(const int32_t& check, ComponentType type)
558 {
559 return (check == int32_t(type));
560 }
IsYUVComponent(const int32_t& type)561 static inline bool IsYUVComponent(const int32_t& type)
562 {
563 return (IsEqual(type, ComponentType::YUV_Y) ||
564 IsEqual(type, ComponentType::YUV_U) ||
565 IsEqual(type, ComponentType::YUV_V));
566 }
IsYUV422SPImage(int32_t format)567 static inline bool IsYUV422SPImage(int32_t format)
568 {
569 return (IsEqual(format, ImageFormat::YCBCR_422_SP) ||
570 (format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)));
571 }
CheckComponentType(const int32_t& type, int32_t format)572 static inline bool CheckComponentType(const int32_t& type, int32_t format)
573 {
574 return ((IsYUV422SPImage(format) && IsYUVComponent(type)) ||
575 (!IsYUV422SPImage(format) && IsEqual(type, ComponentType::JPEG)));
576 }
577
BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer, NativeComponent* component, napi_value* result)578 static bool BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer,
579 NativeComponent* component, napi_value* result)
580 {
581 napi_value array;
582 if (!CreateArrayBuffer(env, buffer, component->size, &array)) {
583 return false;
584 }
585 napi_create_object(env, result);
586 napi_set_named_property(env, *result, "byteBuffer", array);
587 BuildIntProperty(env, "componentType", type, *result);
588 BuildIntProperty(env, "rowStride", component->rowStride, *result);
589 BuildIntProperty(env, "pixelStride", component->pixelStride, *result);
590 return true;
591 }
TestGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)592 static void TestGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)
593 {
594 if (context == nullptr) {
595 IMAGE_ERR("Invalid input context");
596 return;
597 }
598 napi_value result;
599 napi_value array;
600 void *nativePtr = nullptr;
601 if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
602 return;
603 }
604 napi_create_object(env, &result);
605 napi_set_named_property(env, result, "byteBuffer", array);
606 BuildIntProperty(env, "componentType", context->componentType, result);
607 BuildIntProperty(env, "rowStride", NUM0, result);
608 BuildIntProperty(env, "pixelStride", NUM0, result);
609 context->status = SUCCESS;
610 CommonCallbackRoutine(env, context, result);
611 }
612
JsGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)613 static void JsGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)
614 {
615 IMAGE_FUNCTION_IN();
616 napi_value result;
617 napi_get_undefined(env, &result);
618
619 if (context != nullptr && context->napi != nullptr && context->isTestContext) {
620 TestGetComponentCallBack(env, status, context);
621 return;
622 }
623
624 if (context == nullptr) {
625 IMAGE_ERR("Invalid input context");
626 return;
627 }
628 context->status = ERROR;
629 NativeComponent* component = context->component;
630 if (component == nullptr) {
631 IMAGE_ERR("Invalid component");
632 CommonCallbackRoutine(env, context, result);
633 return;
634 }
635
636 uint8_t *buffer = nullptr;
637 if (component->virAddr != nullptr) {
638 buffer = component->virAddr;
639 } else {
640 buffer = component->raw.data();
641 }
642
643 if (buffer == nullptr || component->size == NUM0) {
644 IMAGE_ERR("Invalid buffer");
645 CommonCallbackRoutine(env, context, result);
646 return;
647 }
648
649 if (BuildJsComponentObject(env, context->componentType, buffer, component, &result)) {
650 context->status = SUCCESS;
651 } else {
652 IMAGE_ERR("napi_create_arraybuffer failed!");
653 }
654
655 IMAGE_FUNCTION_OUT();
656 CommonCallbackRoutine(env, context, result);
657 }
JsGetComponentExec(napi_env env, ImageAsyncContext* context)658 static void JsGetComponentExec(napi_env env, ImageAsyncContext* context)
659 {
660 if (context == nullptr || context->napi == nullptr) {
661 IMAGE_ERR("Invalid input context");
662 return;
663 }
664
665 auto native = context->napi->GetNative();
666 if (native == nullptr) {
667 IMAGE_ERR("Empty native");
668 return;
669 }
670 context->component = native->GetComponent(context->componentType);
671 }
672
JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, ImageAsyncContext* context)673 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, ImageAsyncContext* context)
674 {
675 if (argv == nullptr || context == nullptr || argc < NUM1 || context->napi == nullptr) {
676 IMAGE_ERR("argv is nullptr");
677 return false;
678 }
679
680 if (!JsGetInt32Args(env, argv[NUM0], &(context->componentType))) {
681 IMAGE_ERR("Unsupport arg 0 type");
682 return false;
683 }
684
685 auto native = context->napi->GetNative();
686 if (native == nullptr && !context->isTestContext) {
687 IMAGE_ERR("native is nullptr");
688 return false;
689 }
690
691 int32_t format = NUM0;
692 if (context->isTestContext) {
693 const int32_t TEST_FORMAT = 12;
694 format = TEST_FORMAT;
695 } else {
696 native->GetFormat(format);
697 }
698
699 if (!CheckComponentType(context->componentType, format)) {
700 IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
701 return false;
702 }
703
704 if (argc == NUM2 && !JsGetCallbackFunc(env, argv[NUM1], &(context->callbackRef))) {
705 IMAGE_ERR("Unsupport arg 1 type");
706 return false;
707 }
708 return true;
709 }
710
JsGetComponent(napi_env env, napi_callback_info info)711 napi_value ImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
712 {
713 IMAGE_FUNCTION_IN();
714 napi_value result = nullptr;
715 size_t argc = NUM2;
716 napi_value argv[NUM2] = {0};
717
718 napi_get_undefined(env, &result);
719 auto context = UnwrapContext(env, info, &argc, argv);
720 if (context == nullptr) {
721 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
722 "fail to unwrap constructor_ ");
723 }
724 context->isTestContext = context->napi->isTestImage_;
725 if (!JsGetComponentArgs(env, argc, argv, context.get())) {
726 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
727 "Unsupport arg type!");
728 }
729
730 if (context->callbackRef == nullptr) {
731 napi_create_promise(env, &(context->deferred), &result);
732 }
733
734 if (JsCreateWork(env, "JsGetComponent", JsGetComponentExec, JsGetComponentCallBack, context.get())) {
735 context.release();
736 }
737
738 IMAGE_FUNCTION_OUT();
739 return result;
740 }
741 } // namespace Media
742 } // namespace OHOS
743