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