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");
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 if (napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resource) != napi_ok) {
245 IMAGE_ERR("napi_create_string_utf8 failed");
246 return false;
247 }
248 napi_status status = napi_create_async_work(
249 env, nullptr, resource, reinterpret_cast<napi_async_execute_callback>(exec),
250 reinterpret_cast<napi_async_complete_callback>(complete), static_cast<void *>(ctx), &(ctx->work));
251 if (status != napi_ok) {
252 IMAGE_ERR("fail to create async work %{public}d", status);
253 return false;
254 }
255
256 if (napi_queue_async_work(env, ctx->work) != napi_ok) {
257 IMAGE_ERR("fail to queue async work");
258 return false;
259 }
260 return true;
261 }
262
GetNative()263 NativeImage* ImageNapi::GetNative()
264 {
265 if (native_ != nullptr) {
266 return native_.get();
267 }
268 return nullptr;
269 }
270
UnwrapContext(napi_env env,napi_callback_info info,size_t * argc=nullptr,napi_value * argv=nullptr,bool needCreateRef=false)271 static std::unique_ptr<ImageAsyncContext> UnwrapContext(napi_env env, napi_callback_info info,
272 size_t* argc = nullptr, napi_value* argv = nullptr, bool needCreateRef = false)
273 {
274 napi_value thisVar = nullptr;
275 size_t tmp = NUM0;
276
277 IMAGE_FUNCTION_IN();
278
279 if (napi_get_cb_info(env, info, (argc == nullptr)?&tmp:argc, argv, &thisVar, nullptr) != napi_ok) {
280 IMAGE_ERR("Fail to napi_get_cb_info");
281 return nullptr;
282 }
283
284 std::unique_ptr<ImageAsyncContext> ctx = std::make_unique<ImageAsyncContext>();
285 if (napi_unwrap(env, thisVar, reinterpret_cast<void**>(&ctx->napi)) != napi_ok || ctx->napi == nullptr) {
286 IMAGE_ERR("fail to unwrap constructor_");
287 return nullptr;
288 }
289 ctx->image = ctx->napi->GetNative();
290 if (needCreateRef) {
291 napi_create_reference(env, thisVar, NUM1, &(ctx->thisRef));
292 }
293 return ctx;
294 }
295
ProcessPromise(napi_env env,napi_deferred deferred,napi_value * result,bool resolved)296 static inline void ProcessPromise(napi_env env, napi_deferred deferred, napi_value* result, bool resolved)
297 {
298 napi_status status;
299 if (resolved) {
300 status = napi_resolve_deferred(env, deferred, result[NUM1]);
301 } else {
302 status = napi_reject_deferred(env, deferred, result[NUM0]);
303 }
304 if (status != napi_ok) {
305 IMAGE_ERR("ProcessPromise failed");
306 }
307 deferred = nullptr;
308 }
ProcessCallback(napi_env env,napi_ref ref,napi_value * result)309 static inline void ProcessCallback(napi_env env, napi_ref ref, napi_value* result)
310 {
311 napi_value retVal;
312 napi_value callback;
313 napi_get_reference_value(env, ref, &callback);
314 if (callback != nullptr) {
315 napi_call_function(env, nullptr, callback, NUM2, result, &retVal);
316 }
317 napi_delete_reference(env, ref);
318 }
CommonCallbackRoutine(napi_env env,ImageAsyncContext * & context,const napi_value & valueParam)319 static void CommonCallbackRoutine(napi_env env, ImageAsyncContext* &context, const napi_value &valueParam)
320 {
321 IMAGE_FUNCTION_IN();
322 napi_value result[2] = {0};
323
324 if (context == nullptr) {
325 IMAGE_ERR("context is nullptr");
326 return;
327 }
328
329 if (context->status == SUCCESS) {
330 napi_create_uint32(env, context->status, &result[0]);
331 result[1] = valueParam;
332 } else {
333 ImageNapiUtils::CreateErrorObj(env, result[0], context->status,
334 "There is generic napi failure!");
335 napi_get_undefined(env, &result[1]);
336 }
337
338 if (context->deferred) {
339 ProcessPromise(env, context->deferred, result, context->status == SUCCESS);
340 } else {
341 ProcessCallback(env, context->callbackRef, result);
342 }
343
344 napi_delete_async_work(env, context->work);
345
346 delete context;
347 context = nullptr;
348 IMAGE_FUNCTION_OUT();
349 }
350
BuildIntProperty(napi_env env,const std::string & name,int32_t val,napi_value result)351 static void BuildIntProperty(napi_env env, const std::string &name,
352 int32_t val, napi_value result)
353 {
354 napi_value nVal;
355 napi_create_int32(env, val, &nVal);
356 napi_set_named_property(env, result, name.c_str(), nVal);
357 }
358
BuildJsSize(napi_env env,int32_t width,int32_t height)359 static napi_value BuildJsSize(napi_env env, int32_t width, int32_t height)
360 {
361 napi_value result = nullptr;
362
363 napi_create_object(env, &result);
364
365 BuildIntProperty(env, "width", width, result);
366 BuildIntProperty(env, "height", height, result);
367 return result;
368 }
369
BuildJsRegion(napi_env env,int32_t width,int32_t height,int32_t x,int32_t y)370 static napi_value BuildJsRegion(napi_env env, int32_t width,
371 int32_t height, int32_t x, int32_t y)
372 {
373 napi_value result = nullptr;
374
375 napi_create_object(env, &result);
376
377 napi_set_named_property(env, result, "size", BuildJsSize(env, width, height));
378
379 BuildIntProperty(env, "x", x, result);
380 BuildIntProperty(env, "y", y, result);
381 return result;
382 }
383
JSGetClipRect(napi_env env,napi_callback_info info)384 napi_value ImageNapi::JSGetClipRect(napi_env env, napi_callback_info info)
385 {
386 napi_value result = nullptr;
387
388 IMAGE_FUNCTION_IN();
389 napi_get_undefined(env, &result);
390 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
391 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
392 const int32_t WIDTH = 8192;
393 const int32_t HEIGHT = 8;
394 return BuildJsRegion(env, WIDTH, HEIGHT, NUM0, NUM0);
395 }
396 if (context == nullptr || context->image == nullptr) {
397 IMAGE_ERR("Image surface buffer is nullptr");
398 return result;
399 }
400
401 int32_t width = NUM0;
402 int32_t height = NUM0;
403 if (context->image->GetSize(width, height) != SUCCESS) {
404 IMAGE_ERR("Image native get size failed");
405 return result;
406 }
407 return BuildJsRegion(env, width, height, NUM0, NUM0);
408 }
409
JsGetSize(napi_env env,napi_callback_info info)410 napi_value ImageNapi::JsGetSize(napi_env env, napi_callback_info info)
411 {
412 napi_value result = nullptr;
413
414 IMAGE_FUNCTION_IN();
415 napi_get_undefined(env, &result);
416 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
417 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
418 const int32_t WIDTH = 8192;
419 const int32_t HEIGHT = 8;
420 return BuildJsSize(env, WIDTH, HEIGHT);
421 }
422 if (context == nullptr || context->image == nullptr) {
423 IMAGE_ERR("Image surface buffer is nullptr");
424 return result;
425 }
426
427 int32_t width = NUM0;
428 int32_t height = NUM0;
429 if (context->image->GetSize(width, height) != SUCCESS) {
430 IMAGE_ERR("Image native get size failed");
431 return result;
432 }
433 return BuildJsSize(env, width, height);
434 }
435
JsGetFormat(napi_env env,napi_callback_info info)436 napi_value ImageNapi::JsGetFormat(napi_env env, napi_callback_info info)
437 {
438 napi_value result = nullptr;
439
440 IMAGE_FUNCTION_IN();
441 napi_get_undefined(env, &result);
442 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
443 if (context != nullptr && context->napi != nullptr && context->napi->isTestImage_) {
444 const int32_t FORMAT = 12;
445 napi_create_int32(env, FORMAT, &result);
446 return result;
447 }
448 if (context == nullptr || context->image == nullptr) {
449 IMAGE_ERR("Image surface buffer is nullptr");
450 return result;
451 }
452
453 int32_t format = NUM0;
454 if (context->image->GetFormat(format) != SUCCESS) {
455 IMAGE_ERR("Image native get format failed");
456 return result;
457 }
458
459 napi_create_int32(env, format, &result);
460 return result;
461 }
462
JsGetTimestamp(napi_env env,napi_callback_info info)463 napi_value ImageNapi::JsGetTimestamp(napi_env env, napi_callback_info info)
464 {
465 napi_value result = nullptr;
466
467 IMAGE_FUNCTION_IN();
468 napi_get_undefined(env, &result);
469 std::unique_ptr<ImageAsyncContext> context = UnwrapContext(env, info);
470 if (context == nullptr || context->image == nullptr) {
471 IMAGE_ERR("context is nullptr or Image native is nullptr");
472 return result;
473 }
474
475 int64_t timestamp = 0;
476 if (context->image->GetTimestamp(timestamp) != SUCCESS) {
477 IMAGE_ERR("Image native get timestamp failed");
478 return result;
479 }
480
481 napi_create_int64(env, timestamp, &result);
482 return result;
483 }
484
JSReleaseCallBack(napi_env env,napi_status status,ImageAsyncContext * context)485 static void JSReleaseCallBack(napi_env env, napi_status status,
486 ImageAsyncContext* context)
487 {
488 IMAGE_FUNCTION_IN();
489 napi_value result = nullptr;
490 napi_get_undefined(env, &result);
491
492 if (context == nullptr) {
493 IMAGE_ERR("context is nullptr");
494 return;
495 }
496
497 if (context->thisRef != nullptr) {
498 napi_value thisVar;
499 napi_get_reference_value(env, context->thisRef, &thisVar);
500 napi_delete_reference(env, context->thisRef);
501 if (thisVar != nullptr) {
502 ImageNapi *tmp = nullptr;
503 auto status_ = napi_remove_wrap(env, thisVar, reinterpret_cast<void**>(&tmp));
504 if (status_ != napi_ok) {
505 IMAGE_ERR("NAPI remove wrap failed status %{public}d", status_);
506 }
507 }
508 }
509
510 context->status = SUCCESS;
511 IMAGE_FUNCTION_OUT();
512 CommonCallbackRoutine(env, context, result);
513 }
514
JsRelease(napi_env env,napi_callback_info info)515 napi_value ImageNapi::JsRelease(napi_env env, napi_callback_info info)
516 {
517 IMAGE_FUNCTION_IN();
518 napi_value result = nullptr;
519 size_t argc = NUM1;
520 napi_value argv[NUM1] = {0};
521
522 napi_get_undefined(env, &result);
523 auto context = UnwrapContext(env, info, &argc, argv, true);
524 if (context == nullptr) {
525 IMAGE_ERR("fail to unwrap constructor_");
526 return result;
527 }
528 if (argc == NUM1) {
529 if (!JsGetCallbackFunc(env, argv[NUM0], &(context->callbackRef))) {
530 IMAGE_ERR("Unsupport arg 0 type");
531 return result;
532 }
533 } else {
534 napi_create_promise(env, &(context->deferred), &result);
535 }
536
537 if (JsCreateWork(env, "JsRelease", [](napi_env env, ImageAsyncContext* data) {},
538 JSReleaseCallBack, context.get())) {
539 context.release();
540 }
541 IMAGE_FUNCTION_OUT();
542 return result;
543 }
544
CreateArrayBuffer(napi_env env,uint8_t * src,size_t srcLen,napi_value * res)545 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
546 {
547 if (src == nullptr || srcLen == 0) {
548 return false;
549 }
550 auto status = napi_create_external_arraybuffer(env, src, srcLen,
551 [](napi_env env, void* data, void* hint) { }, nullptr, res);
552 if (status != napi_ok) {
553 return false;
554 }
555 return true;
556 }
557
IsEqual(const int32_t & check,ImageFormat format)558 static inline bool IsEqual(const int32_t& check, ImageFormat format)
559 {
560 return (check == int32_t(format));
561 }
IsEqual(const int32_t & check,ComponentType type)562 static inline bool IsEqual(const int32_t& check, ComponentType type)
563 {
564 return (check == int32_t(type));
565 }
IsYUVComponent(const int32_t & type)566 static inline bool IsYUVComponent(const int32_t& type)
567 {
568 return (IsEqual(type, ComponentType::YUV_Y) ||
569 IsEqual(type, ComponentType::YUV_U) ||
570 IsEqual(type, ComponentType::YUV_V));
571 }
IsYUV422SPImage(int32_t format)572 static inline bool IsYUV422SPImage(int32_t format)
573 {
574 return (IsEqual(format, ImageFormat::YCBCR_422_SP) ||
575 (format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)));
576 }
CheckComponentType(const int32_t & type,int32_t format)577 static inline bool CheckComponentType(const int32_t& type, int32_t format)
578 {
579 return ((IsYUV422SPImage(format) && IsYUVComponent(type)) ||
580 (!IsYUV422SPImage(format) && IsEqual(type, ComponentType::JPEG)));
581 }
582
BuildJsComponentObject(napi_env env,int32_t type,uint8_t * buffer,NativeComponent * component,napi_value * result)583 static bool BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer,
584 NativeComponent* component, napi_value* result)
585 {
586 napi_value array;
587 if (!CreateArrayBuffer(env, buffer, component->size, &array)) {
588 return false;
589 }
590 napi_create_object(env, result);
591 napi_set_named_property(env, *result, "byteBuffer", array);
592 BuildIntProperty(env, "componentType", type, *result);
593 BuildIntProperty(env, "rowStride", component->rowStride, *result);
594 BuildIntProperty(env, "pixelStride", component->pixelStride, *result);
595 return true;
596 }
TestGetComponentCallBack(napi_env env,napi_status status,ImageAsyncContext * context)597 static void TestGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)
598 {
599 if (context == nullptr) {
600 IMAGE_ERR("Invalid input context");
601 return;
602 }
603 napi_value result;
604 napi_value array;
605 void *nativePtr = nullptr;
606 if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
607 return;
608 }
609 napi_create_object(env, &result);
610 napi_set_named_property(env, result, "byteBuffer", array);
611 BuildIntProperty(env, "componentType", context->componentType, result);
612 BuildIntProperty(env, "rowStride", NUM0, result);
613 BuildIntProperty(env, "pixelStride", NUM0, result);
614 context->status = SUCCESS;
615 CommonCallbackRoutine(env, context, result);
616 }
617
JsGetComponentCallBack(napi_env env,napi_status status,ImageAsyncContext * context)618 static void JsGetComponentCallBack(napi_env env, napi_status status, ImageAsyncContext* context)
619 {
620 IMAGE_FUNCTION_IN();
621 napi_value result;
622 napi_get_undefined(env, &result);
623
624 if (context != nullptr && context->napi != nullptr && context->isTestContext) {
625 TestGetComponentCallBack(env, status, context);
626 return;
627 }
628
629 if (context == nullptr) {
630 IMAGE_ERR("Invalid input context");
631 return;
632 }
633 context->status = ERROR;
634 NativeComponent* component = context->component;
635 if (component == nullptr) {
636 IMAGE_ERR("Invalid component");
637 CommonCallbackRoutine(env, context, result);
638 return;
639 }
640
641 uint8_t *buffer = nullptr;
642 if (component->virAddr != nullptr) {
643 buffer = component->virAddr;
644 } else {
645 buffer = component->raw.data();
646 }
647
648 if (buffer == nullptr || component->size == NUM0) {
649 IMAGE_ERR("Invalid buffer");
650 CommonCallbackRoutine(env, context, result);
651 return;
652 }
653
654 if (BuildJsComponentObject(env, context->componentType, buffer, component, &result)) {
655 context->status = SUCCESS;
656 } else {
657 IMAGE_ERR("napi_create_arraybuffer failed!");
658 }
659
660 IMAGE_FUNCTION_OUT();
661 CommonCallbackRoutine(env, context, result);
662 }
JsGetComponentExec(napi_env env,ImageAsyncContext * context)663 static void JsGetComponentExec(napi_env env, ImageAsyncContext* context)
664 {
665 if (context == nullptr || context->napi == nullptr) {
666 IMAGE_ERR("Invalid input context");
667 return;
668 }
669
670 auto native = context->napi->GetNative();
671 if (native == nullptr) {
672 IMAGE_ERR("Empty native");
673 return;
674 }
675 context->component = native->GetComponent(context->componentType);
676 }
677
JsGetComponentArgs(napi_env env,size_t argc,napi_value * argv,ImageAsyncContext * context)678 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, ImageAsyncContext* context)
679 {
680 if (argv == nullptr || context == nullptr || argc < NUM1 || context->napi == nullptr) {
681 IMAGE_ERR("argv is nullptr");
682 return false;
683 }
684
685 if (!JsGetInt32Args(env, argv[NUM0], &(context->componentType))) {
686 IMAGE_ERR("Unsupport arg 0 type");
687 return false;
688 }
689
690 auto native = context->napi->GetNative();
691 if (native == nullptr && !context->isTestContext) {
692 IMAGE_ERR("native is nullptr");
693 return false;
694 }
695
696 int32_t format = NUM0;
697 if (context->isTestContext) {
698 const int32_t TEST_FORMAT = 12;
699 format = TEST_FORMAT;
700 } else {
701 native->GetFormat(format);
702 }
703
704 if (!CheckComponentType(context->componentType, format)) {
705 IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
706 return false;
707 }
708
709 if (argc == NUM2 && !JsGetCallbackFunc(env, argv[NUM1], &(context->callbackRef))) {
710 IMAGE_ERR("Unsupport arg 1 type");
711 return false;
712 }
713 return true;
714 }
715
JsGetComponent(napi_env env,napi_callback_info info)716 napi_value ImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
717 {
718 IMAGE_FUNCTION_IN();
719 napi_value result = nullptr;
720 size_t argc = NUM2;
721 napi_value argv[NUM2] = {0};
722
723 napi_get_undefined(env, &result);
724 auto context = UnwrapContext(env, info, &argc, argv);
725 if (context == nullptr) {
726 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
727 "fail to unwrap constructor_ ");
728 }
729 context->isTestContext = context->napi->isTestImage_;
730 if (!JsGetComponentArgs(env, argc, argv, context.get())) {
731 return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
732 "Unsupport arg type!");
733 }
734
735 if (context->callbackRef == nullptr) {
736 napi_create_promise(env, &(context->deferred), &result);
737 }
738
739 if (JsCreateWork(env, "JsGetComponent", JsGetComponentExec, JsGetComponentCallBack, context.get())) {
740 context.release();
741 }
742
743 IMAGE_FUNCTION_OUT();
744 return result;
745 }
746 } // namespace Media
747 } // namespace OHOS
748