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