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