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