• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 "sendable_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 "SendableImageNapi"
29 
30 namespace {
31     constexpr int NUM0 = 0;
32     constexpr int NUM1 = 1;
33     constexpr int NUM2 = 2;
34     const std::string MY_NAME = "SendableImageNapi";
35 }
36 
37 namespace OHOS {
38 namespace Media {
39 struct SendableImageAsyncContext {
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     SendableImageNapi *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> SendableImageNapi::sNativeImageHolder_;
53 thread_local napi_ref SendableImageNapi::sConstructor_ = nullptr;
54 
SendableImageNapi()55 SendableImageNapi::SendableImageNapi()
56 {}
57 
~SendableImageNapi()58 SendableImageNapi::~SendableImageNapi()
59 {
60     NativeRelease();
61 }
62 
NativeRelease()63 void SendableImageNapi::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 SendableImageNapi::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_GETTER("timestamp", JsGetTimestamp),
79         DECLARE_NAPI_FUNCTION("getComponent", JsGetComponent),
80         DECLARE_NAPI_FUNCTION("release", JsRelease),
81     };
82     size_t size = IMG_ARRAY_SIZE(props);
83     napi_value thisVar = nullptr;
84     auto name = MY_NAME.c_str();
85     if (napi_define_sendable_class(env, name, SIZE_MAX, Constructor, nullptr, size, props, nullptr, &thisVar) != napi_ok) {
86         IMAGE_ERR("Define class failed");
87         return exports;
88     }
89 
90     sConstructor_ = nullptr;
91 
92     if (napi_create_reference(env, thisVar, NUM1, &sConstructor_) != napi_ok) {
93         IMAGE_ERR("Create reference failed");
94         return exports;
95     }
96 
97     if (napi_set_named_property(env, exports, name, thisVar) != napi_ok) {
98         IMAGE_ERR("Define class failed");
99         return exports;
100     }
101 
102     IMAGE_DEBUG("Init success");
103     return exports;
104 }
105 
106 
GetNativeImage(napi_env env,napi_value image)107 std::shared_ptr<NativeImage> SendableImageNapi::GetNativeImage(napi_env env, napi_value image)
108 {
109     SendableImageNapi* napi = nullptr;
110 
111     napi_status status = napi_unwrap_sendable(env, image, reinterpret_cast<void**>(&napi));
112     if (!IMG_IS_OK(status) || napi == nullptr) {
113         IMAGE_ERR("GetImage napi unwrap failed");
114         return nullptr;
115     }
116     return napi->native_;
117 }
118 
Constructor(napi_env env,napi_callback_info info)119 napi_value SendableImageNapi::Constructor(napi_env env, napi_callback_info info)
120 {
121     napi_status status;
122     napi_value thisVar = nullptr;
123     napi_value undefineVar;
124     size_t argc = NUM1;
125     napi_value argv[NUM1];
126 
127     IMAGE_FUNCTION_IN();
128     napi_get_undefined(env, &undefineVar);
129     status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
130     if (status != napi_ok || thisVar == nullptr || argc != NUM1) {
131         IMAGE_ERR("Constructor Failed to napi_get_cb_info");
132         return undefineVar;
133     }
134     std::string id;
135     if (!ImageNapiUtils::GetUtf8String(env, argv[NUM0], id) || (id.size() == NUM0)) {
136         IMAGE_ERR("Failed to parse native image id");
137         return undefineVar;
138     }
139     std::unique_ptr<SendableImageNapi> napi = std::make_unique<SendableImageNapi>();
140     napi->native_ = sNativeImageHolder_.get(id);
141     napi->isTestImage_ = false;
142     if (napi->native_ == nullptr) {
143         if (MY_NAME.compare(id.c_str()) == 0) {
144             napi->isTestImage_ = true;
145         } else {
146             IMAGE_ERR("Failed to get native image");
147             return undefineVar;
148         }
149     }
150     status = napi_wrap_sendable(env, thisVar,
151         reinterpret_cast<void *>(napi.get()), SendableImageNapi::Destructor, nullptr);
152     if (status != napi_ok) {
153         IMAGE_ERR("Failure wrapping js to native napi");
154         return undefineVar;
155     }
156 
157     napi.release();
158     IMAGE_FUNCTION_OUT();
159     return thisVar;
160 }
161 
Destructor(napi_env env,void * nativeObject,void * finalize)162 void SendableImageNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
163 {
164     if (nativeObject != nullptr) {
165         delete reinterpret_cast<SendableImageNapi *>(nativeObject);
166     }
167 }
168 
Create(napi_env env)169 napi_value SendableImageNapi::Create(napi_env env)
170 {
171     napi_value constructor = nullptr;
172     napi_value result = nullptr;
173     napi_value argv[NUM1];
174 
175     IMAGE_FUNCTION_IN();
176     if (env == nullptr) {
177         IMAGE_ERR("Input args is invalid");
178         return nullptr;
179     }
180     if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
181         if (napi_create_string_utf8(env, MY_NAME.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
182             IMAGE_ERR("Create native image id Failed");
183         }
184         if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
185             IMAGE_ERR("New instance could not be obtained");
186         }
187     }
188     IMAGE_FUNCTION_OUT();
189     return result;
190 }
Create(napi_env env,std::shared_ptr<NativeImage> nativeImage)191 napi_value SendableImageNapi::Create(napi_env env, std::shared_ptr<NativeImage> nativeImage)
192 {
193     napi_value constructor = nullptr;
194     napi_value result = nullptr;
195     napi_value argv[NUM1];
196 
197     IMAGE_FUNCTION_IN();
198     if (env == nullptr || nativeImage == nullptr) {
199         IMAGE_ERR("Input args is invalid");
200         return nullptr;
201     }
202     if (napi_get_reference_value(env, sConstructor_, &constructor) == napi_ok && constructor != nullptr) {
203         auto id = sNativeImageHolder_.save(nativeImage);
204         if (napi_create_string_utf8(env, id.c_str(), NAPI_AUTO_LENGTH, &(argv[NUM0])) != napi_ok) {
205             IMAGE_ERR("Create native image id Failed");
206         }
207         if (napi_new_instance(env, constructor, NUM1, argv, &result) != napi_ok) {
208             IMAGE_ERR("New instance could not be obtained");
209         }
210     }
211     IMAGE_FUNCTION_OUT();
212     return result;
213 }
JsCheckObjectType(napi_env env,napi_value value,napi_valuetype type)214 static inline bool JsCheckObjectType(napi_env env, napi_value value, napi_valuetype type)
215 {
216     return (ImageNapiUtils::getType(env, value) == type);
217 }
218 
JsGetCallbackFunc(napi_env env,napi_value value,napi_ref * result)219 static inline bool JsGetCallbackFunc(napi_env env, napi_value value, napi_ref *result)
220 {
221     if (JsCheckObjectType(env, value, napi_function)) {
222         napi_create_reference(env, value, NUM1, result);
223         return true;
224     }
225     return false;
226 }
227 
JsGetInt32Args(napi_env env,napi_value value,int * result)228 static inline bool JsGetInt32Args(napi_env env, napi_value value, int *result)
229 {
230     if (JsCheckObjectType(env, value, napi_number)) {
231         napi_get_value_int32(env, value, result);
232         return true;
233     }
234     return false;
235 }
236 using AsyncExecCallback = void (*)(napi_env env, SendableImageAsyncContext* ctx);
237 using AsyncCompleteCallback = void (*)(napi_env env, napi_status status, SendableImageAsyncContext* ctx);
JsCreateWork(napi_env env,const char * name,AsyncExecCallback exec,AsyncCompleteCallback complete,SendableImageAsyncContext * ctx)238 static bool JsCreateWork(napi_env env, const char* name, AsyncExecCallback exec,
239     AsyncCompleteCallback complete, SendableImageAsyncContext* ctx)
240 {
241     napi_value resource = nullptr;
242     napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resource);
243     napi_status status = napi_create_async_work(
244         env, nullptr, resource, reinterpret_cast<napi_async_execute_callback>(exec),
245         reinterpret_cast<napi_async_complete_callback>(complete), static_cast<void *>(ctx), &(ctx->work));
246     if (status != napi_ok) {
247         IMAGE_ERR("fail to create async work %{public}d", status);
248         return false;
249     }
250 
251     if (napi_queue_async_work(env, ctx->work) != napi_ok) {
252         IMAGE_ERR("fail to queue async work");
253         return false;
254     }
255     return true;
256 }
257 
GetNative()258 NativeImage* SendableImageNapi::GetNative()
259 {
260     if (native_ != nullptr) {
261         return native_.get();
262     }
263     return nullptr;
264 }
265 
UnwrapContext(napi_env env,napi_callback_info info,size_t * argc=nullptr,napi_value * argv=nullptr,bool needCreateRef=false)266 static std::unique_ptr<SendableImageAsyncContext> UnwrapContext(napi_env env, napi_callback_info info,
267     size_t* argc = nullptr, napi_value* argv = nullptr, bool needCreateRef = false)
268 {
269     napi_value thisVar = nullptr;
270     size_t tmp = NUM0;
271 
272     IMAGE_FUNCTION_IN();
273 
274     if (napi_get_cb_info(env, info, (argc == nullptr)?&tmp:argc, argv, &thisVar, nullptr) != napi_ok) {
275         IMAGE_ERR("Fail to napi_get_cb_info");
276         return nullptr;
277     }
278 
279     std::unique_ptr<SendableImageAsyncContext> ctx = std::make_unique<SendableImageAsyncContext>();
280     if (napi_unwrap_sendable(env, thisVar, reinterpret_cast<void**>(&ctx->napi)) != napi_ok || ctx->napi == nullptr) {
281         IMAGE_ERR("fail to unwrap ets image object, image maybe released");
282         return nullptr;
283     }
284     ctx->image = ctx->napi->GetNative();
285     if (needCreateRef) {
286         napi_create_reference(env, thisVar, NUM1, &(ctx->thisRef));
287     }
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,SendableImageAsyncContext * & context,const napi_value & valueParam)307 static void CommonCallbackRoutine(napi_env env, SendableImageAsyncContext* &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 SendableImageNapi::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<SendableImageAsyncContext> 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 surfacebuffer 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 SendableImageNapi::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<SendableImageAsyncContext> 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 surfacebuffer 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 SendableImageNapi::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<SendableImageAsyncContext> 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 surfacebuffer 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 
JsGetTimestamp(napi_env env,napi_callback_info info)451 napi_value SendableImageNapi::JsGetTimestamp(napi_env env, napi_callback_info info)
452 {
453     napi_value result = nullptr;
454 
455     IMAGE_FUNCTION_IN();
456     napi_get_undefined(env, &result);
457     std::unique_ptr<SendableImageAsyncContext> context = UnwrapContext(env, info);
458     if (context == nullptr || context->image == nullptr) {
459         IMAGE_ERR("context is nullptr or Image native is nullptr");
460         return result;
461     }
462 
463     int64_t timestamp = 0;
464     if (context->image->GetTimestamp(timestamp) != SUCCESS) {
465         IMAGE_ERR("Image native get timestamp failed");
466         return result;
467     }
468 
469     napi_create_int64(env, timestamp, &result);
470     return result;
471 }
472 
JSReleaseCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)473 static void JSReleaseCallBack(napi_env env, napi_status status,
474                               SendableImageAsyncContext* context)
475 {
476     IMAGE_FUNCTION_IN();
477     napi_value result = nullptr;
478     napi_get_undefined(env, &result);
479 
480     if (context == nullptr) {
481         IMAGE_ERR("context is nullptr");
482         return;
483     }
484 
485     if (context->thisRef != nullptr) {
486         napi_value thisVar;
487         napi_get_reference_value(env, context->thisRef, &thisVar);
488         napi_delete_reference(env, context->thisRef);
489         if (thisVar != nullptr) {
490             SendableImageNapi *tmp = nullptr;
491             auto status_ = napi_remove_wrap_sendable(env, thisVar, reinterpret_cast<void**>(&tmp));
492             if (status_ != napi_ok) {
493                 IMAGE_ERR("NAPI remove wrap failed status %{public}d", status_);
494             }
495         }
496     }
497 
498     context->status = SUCCESS;
499     IMAGE_FUNCTION_OUT();
500     CommonCallbackRoutine(env, context, result);
501 }
502 
JsRelease(napi_env env,napi_callback_info info)503 napi_value SendableImageNapi::JsRelease(napi_env env, napi_callback_info info)
504 {
505     IMAGE_FUNCTION_IN();
506     napi_value result = nullptr;
507     size_t argc = NUM1;
508     napi_value argv[NUM1] = {0};
509 
510     napi_get_undefined(env, &result);
511     auto context = UnwrapContext(env, info, &argc, argv, true);
512     if (context == nullptr) {
513         IMAGE_ERR("fail to unwrap ets image object, image maybe released");
514         return result;
515     }
516     if (argc == NUM1) {
517         if (!JsGetCallbackFunc(env, argv[NUM0], &(context->callbackRef))) {
518             IMAGE_ERR("Unsupport arg 0 type");
519             return result;
520         }
521     } else {
522         napi_create_promise(env, &(context->deferred), &result);
523     }
524 
525     if (JsCreateWork(env, "JsRelease", [](napi_env env, SendableImageAsyncContext* data) {},
526         JSReleaseCallBack, context.get())) {
527         context.release();
528     }
529     IMAGE_FUNCTION_OUT();
530     return result;
531 }
532 
CreateArrayBuffer(napi_env env,uint8_t * src,size_t srcLen,napi_value * res)533 static bool CreateArrayBuffer(napi_env env, uint8_t* src, size_t srcLen, napi_value *res)
534 {
535     if (src == nullptr || srcLen == 0) {
536         return false;
537     }
538     auto status = napi_create_external_arraybuffer(env, src, srcLen,
539         [](napi_env env, void* data, void* hint) { }, nullptr, res);
540     if (status != napi_ok) {
541         return false;
542     }
543     return true;
544 }
545 
IsEqual(const int32_t & check,ImageFormat format)546 static inline bool IsEqual(const int32_t& check,  ImageFormat format)
547 {
548     return (check == int32_t(format));
549 }
IsEqual(const int32_t & check,ComponentType type)550 static inline bool IsEqual(const int32_t& check,  ComponentType type)
551 {
552     return (check == int32_t(type));
553 }
IsYUVComponent(const int32_t & type)554 static inline bool IsYUVComponent(const int32_t& type)
555 {
556     return (IsEqual(type, ComponentType::YUV_Y) ||
557         IsEqual(type, ComponentType::YUV_U) ||
558         IsEqual(type, ComponentType::YUV_V));
559 }
IsYUV422SPImage(int32_t format)560 static inline bool IsYUV422SPImage(int32_t format)
561 {
562     return (IsEqual(format, ImageFormat::YCBCR_422_SP) ||
563         (format == int32_t(GRAPHIC_PIXEL_FMT_YCBCR_422_SP)));
564 }
CheckComponentType(const int32_t & type,int32_t format)565 static inline bool CheckComponentType(const int32_t& type, int32_t format)
566 {
567     return ((IsYUV422SPImage(format) && IsYUVComponent(type)) ||
568         (!IsYUV422SPImage(format) && IsEqual(type, ComponentType::JPEG)));
569 }
570 
BuildJsComponentObject(napi_env env,int32_t type,uint8_t * buffer,NativeComponent * component,napi_value * result)571 static bool BuildJsComponentObject(napi_env env, int32_t type, uint8_t* buffer,
572     NativeComponent* component, napi_value* result)
573 {
574     napi_value array;
575     if (!CreateArrayBuffer(env, buffer, component->size, &array)) {
576         return false;
577     }
578     napi_create_object(env, result);
579     napi_set_named_property(env, *result, "byteBuffer", array);
580     BuildIntProperty(env, "componentType", type, *result);
581     BuildIntProperty(env, "rowStride", component->rowStride, *result);
582     BuildIntProperty(env, "pixelStride", component->pixelStride, *result);
583     return true;
584 }
TestGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)585 static void TestGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
586 {
587     if (context == nullptr) {
588         IMAGE_ERR("Invalid input context");
589         return;
590     }
591     napi_value result;
592     napi_value array;
593     void *nativePtr = nullptr;
594     if (napi_create_arraybuffer(env, NUM1, &nativePtr, &array) != napi_ok || nativePtr == nullptr) {
595         return;
596     }
597     napi_create_object(env, &result);
598     napi_set_named_property(env, result, "byteBuffer", array);
599     BuildIntProperty(env, "componentType", context->componentType, result);
600     BuildIntProperty(env, "rowStride", NUM0, result);
601     BuildIntProperty(env, "pixelStride", NUM0, result);
602     context->status = SUCCESS;
603     CommonCallbackRoutine(env, context, result);
604 }
605 
JsGetComponentCallBack(napi_env env,napi_status status,SendableImageAsyncContext * context)606 static void JsGetComponentCallBack(napi_env env, napi_status status, SendableImageAsyncContext* context)
607 {
608     IMAGE_FUNCTION_IN();
609     napi_value result;
610     napi_get_undefined(env, &result);
611 
612     if (context != nullptr && context->napi != nullptr && context->isTestContext) {
613         TestGetComponentCallBack(env, status, context);
614         return;
615     }
616 
617     if (context == nullptr) {
618         IMAGE_ERR("Invalid input context");
619         return;
620     }
621     context->status = ERROR;
622     NativeComponent* component = context->component;
623     if (component == nullptr) {
624         IMAGE_ERR("Invalid component");
625         CommonCallbackRoutine(env, context, result);
626         return;
627     }
628 
629     uint8_t *buffer = nullptr;
630     if (component->virAddr != nullptr) {
631         buffer = component->virAddr;
632     } else {
633         buffer = component->raw.data();
634     }
635 
636     if (buffer == nullptr || component->size == NUM0) {
637         IMAGE_ERR("Invalid buffer");
638         CommonCallbackRoutine(env, context, result);
639         return;
640     }
641 
642     if (BuildJsComponentObject(env, context->componentType, buffer, component, &result)) {
643         context->status = SUCCESS;
644     } else {
645         IMAGE_ERR("napi_create_arraybuffer failed!");
646     }
647 
648     IMAGE_FUNCTION_OUT();
649     CommonCallbackRoutine(env, context, result);
650 }
JsGetComponentExec(napi_env env,SendableImageAsyncContext * context)651 static void JsGetComponentExec(napi_env env, SendableImageAsyncContext* context)
652 {
653     if (context == nullptr || context->napi == nullptr) {
654         IMAGE_ERR("Invalid input context");
655         return;
656     }
657 
658     auto native = context->napi->GetNative();
659     if (native == nullptr) {
660         IMAGE_ERR("Empty native");
661         return;
662     }
663     context->component = native->GetComponent(context->componentType);
664 }
665 
JsGetComponentArgs(napi_env env,size_t argc,napi_value * argv,SendableImageAsyncContext * context)666 static bool JsGetComponentArgs(napi_env env, size_t argc, napi_value* argv, SendableImageAsyncContext* context)
667 {
668     if (argv == nullptr || context == nullptr || argc < NUM1 || context->napi == nullptr) {
669         IMAGE_ERR("argv is nullptr");
670         return false;
671     }
672 
673     if (!JsGetInt32Args(env, argv[NUM0], &(context->componentType))) {
674         IMAGE_ERR("Unsupport arg 0 type");
675         return false;
676     }
677 
678     auto native = context->napi->GetNative();
679     int32_t format = NUM0;
680     if (context->isTestContext) {
681         const int32_t TEST_FORMAT = 12;
682         format = TEST_FORMAT;
683     } else if (native != nullptr) {
684         native->GetFormat(format);
685     } else {
686         IMAGE_ERR("GetFormat: native is nullptr");
687         return false;
688     }
689 
690     if (!CheckComponentType(context->componentType, format)) {
691         IMAGE_ERR("Unsupport component type 0 value: %{public}d", context->componentType);
692         return false;
693     }
694 
695     if (argc == NUM2 && !JsGetCallbackFunc(env, argv[NUM1], &(context->callbackRef))) {
696         IMAGE_ERR("Unsupport arg 1 type");
697         return false;
698     }
699     return true;
700 }
701 
JsGetComponent(napi_env env,napi_callback_info info)702 napi_value SendableImageNapi::JsGetComponent(napi_env env, napi_callback_info info)
703 {
704     IMAGE_FUNCTION_IN();
705     napi_value result = nullptr;
706     size_t argc = NUM2;
707     napi_value argv[NUM2] = {0};
708 
709     napi_get_undefined(env, &result);
710     auto context = UnwrapContext(env, info, &argc, argv);
711     if (context == nullptr) {
712         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
713             "fail to unwrap ets image object, image maybe released");
714     }
715     context->isTestContext = context->napi->isTestImage_;
716     if (!JsGetComponentArgs(env, argc, argv, context.get())) {
717         return ImageNapiUtils::ThrowExceptionError(env, static_cast<int32_t>(napi_invalid_arg),
718             "Unsupport arg type!");
719     }
720 
721     if (context->callbackRef == nullptr) {
722         napi_create_promise(env, &(context->deferred), &result);
723     }
724 
725     if (JsCreateWork(env, "JsGetComponent", JsGetComponentExec, JsGetComponentCallBack, context.get())) {
726         context.release();
727     }
728 
729     IMAGE_FUNCTION_OUT();
730     return result;
731 }
732 }  // namespace Media
733 }  // namespace OHOS
734