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 <memory.h>
17 #include "auxiliary_picture_napi.h"
18 #include "media_errors.h"
19 #include "image_log.h"
20 #include "image_napi.h"
21 #include "image_napi_utils.h"
22 #include "pixel_map_napi.h"
23 #include "pixel_map.h"
24 #include "metadata_napi.h"
25 #include "color_space_object_convertor.h"
26 #include "image_utils.h"
27 #include "image_common.h"
28
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
31
32 #undef LOG_TAG
33 #define LOG_TAG "AuxiliaryPictureNapi"
34
35 namespace {
36 constexpr uint32_t NUM_0 = 0;
37 constexpr uint32_t NUM_1 = 1;
38 constexpr uint32_t NUM_2 = 2;
39 constexpr uint32_t NUM_3 = 3;
40 }
41
42 namespace OHOS {
43 namespace Media {
44 static const std::string CLASS_NAME = "AuxiliaryPicture";
45 thread_local napi_ref AuxiliaryPictureNapi::sConstructor_ = nullptr;
46 thread_local std::shared_ptr<AuxiliaryPicture> AuxiliaryPictureNapi::sAuxiliaryPic_ = nullptr;
47 #if !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
48 #endif
49
50 struct AuxiliaryPictureNapiAsyncContext {
51 napi_env env;
52 napi_async_work work;
53 napi_deferred deferred;
54 napi_ref callbackRef;
55 napi_ref error = nullptr;
56 uint32_t status;
57 AuxiliaryPictureNapi *nConstructor;
58 std::shared_ptr<PixelMap> rPixelmap;
59 std::shared_ptr<Picture> rPicture;
60 std::shared_ptr<AuxiliaryPicture> auxPicture;
61 void *arrayBuffer;
62 size_t arrayBufferSize;
63 Size size;
64 AuxiliaryPictureType type;
65 MetadataNapi *metadataNapi;
66 std::shared_ptr<AuxiliaryPicture> rAuxiliaryPicture;
67 std::shared_ptr<ImageMetadata> imageMetadata;
68 MetadataType metadataType = MetadataType::EXIF;
69 AuxiliaryPictureNapi *auxiliaryPictureNapi;
70 AuxiliaryPictureInfo auxiliaryPictureInfo;
71 std::shared_ptr<OHOS::ColorManager::ColorSpace> AuxColorSpace = nullptr;
72 };
73
74 using AuxiliaryPictureNapiAsyncContextPtr = std::unique_ptr<AuxiliaryPictureNapiAsyncContext>;
75
76 struct NapiValues {
77 napi_status status;
78 napi_value thisVar = nullptr;
79 napi_value result = nullptr;
80 napi_value* argv = nullptr;
81 size_t argc;
82 int32_t refCount = 1;
83 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> context;
84 };
85
AuxiliaryPictureNapi()86 AuxiliaryPictureNapi::AuxiliaryPictureNapi():env_(nullptr)
87 {
88 static std::atomic<uint32_t> currentId = 0;
89 uniqueId_ = currentId.fetch_add(1, std::memory_order_relaxed);
90 }
91
~AuxiliaryPictureNapi()92 AuxiliaryPictureNapi::~AuxiliaryPictureNapi()
93 {
94 release();
95 }
96
Init(napi_env env,napi_value exports)97 napi_value AuxiliaryPictureNapi::Init(napi_env env, napi_value exports)
98 {
99 napi_property_descriptor props[] = {
100 DECLARE_NAPI_FUNCTION("readPixelsToBuffer", ReadPixelsToBuffer),
101 DECLARE_NAPI_FUNCTION("writePixelsFromBuffer", WritePixelsFromBuffer),
102 DECLARE_NAPI_FUNCTION("getType", GetType),
103 DECLARE_NAPI_FUNCTION("getMetadata", GetMetadata),
104 DECLARE_NAPI_FUNCTION("setMetadata", SetMetadata),
105 DECLARE_NAPI_FUNCTION("getAuxiliaryPictureInfo", GetAuxiliaryPictureInfo),
106 DECLARE_NAPI_FUNCTION("setAuxiliaryPictureInfo", SetAuxiliaryPictureInfo),
107 DECLARE_NAPI_FUNCTION("release", Release),
108 };
109 napi_property_descriptor static_prop[] = {
110 DECLARE_NAPI_STATIC_FUNCTION("createAuxiliaryPicture", CreateAuxiliaryPicture),
111 };
112
113 napi_value constructor = nullptr;
114
115 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
116 napi_define_class(env, CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
117 Constructor, nullptr, IMG_ARRAY_SIZE(props),
118 props, &constructor)),
119 nullptr, IMAGE_LOGE("define class fail")
120 );
121
122 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
123 napi_create_reference(env, constructor, 1, &sConstructor_)),
124 nullptr, IMAGE_LOGE("create reference fail")
125 );
126
127 napi_value global = nullptr;
128 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
129 napi_get_global(env, &global)),
130 nullptr, IMAGE_LOGE("Init:get global fail")
131 );
132
133 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
134 napi_set_named_property(env, global, CLASS_NAME.c_str(), constructor)),
135 nullptr, IMAGE_LOGE("Init:set global named property fail")
136 );
137
138 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
139 napi_set_named_property(env, exports, CLASS_NAME.c_str(), constructor)),
140 nullptr, IMAGE_LOGE("set named property fail")
141 );
142
143 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(
144 napi_define_properties(env, exports, IMG_ARRAY_SIZE(static_prop), static_prop)),
145 nullptr, IMAGE_LOGE("define properties fail")
146 );
147
148 IMAGE_LOGD("Init success");
149 return exports;
150 }
151
Constructor(napi_env env,napi_callback_info info)152 napi_value AuxiliaryPictureNapi::Constructor(napi_env env, napi_callback_info info)
153 {
154 napi_value undefineVar = nullptr;
155 napi_get_undefined(env, &undefineVar);
156
157 napi_status status;
158 napi_value thisVar = nullptr;
159 napi_get_undefined(env, &thisVar);
160 IMAGE_LOGD("Constructor IN");
161 status = napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
162 IMG_NAPI_CHECK_RET(IMG_IS_READY(status, thisVar), undefineVar);
163 std::unique_ptr<AuxiliaryPictureNapi> pAuxiliaryPictureNapi = std::make_unique<AuxiliaryPictureNapi>();
164 if (pAuxiliaryPictureNapi != nullptr) {
165 pAuxiliaryPictureNapi->env_ = env;
166 pAuxiliaryPictureNapi->nativeAuxiliaryPicture_ = sAuxiliaryPic_;
167 if (pAuxiliaryPictureNapi->nativeAuxiliaryPicture_ == nullptr) {
168 IMAGE_LOGE("Failed to set nativeAuxiliaryPicture_ with null. Maybe a reentrancy error");
169 }
170 status = napi_wrap(env, thisVar, reinterpret_cast<void *>(pAuxiliaryPictureNapi.release()),
171 AuxiliaryPictureNapi::Destructor, nullptr, nullptr);
172 if (status != napi_ok) {
173 IMAGE_LOGE("Failure wrapping js to native napi");
174 return undefineVar;
175 }
176 }
177 return thisVar;
178 }
179
Destructor(napi_env env,void * nativeObject,void * finalize)180 void AuxiliaryPictureNapi::Destructor(napi_env env, void *nativeObject, void *finalize)
181 {
182 if (nativeObject != nullptr) {
183 IMAGE_LOGD("Destructor PictureNapi");
184 delete reinterpret_cast<AuxiliaryPictureNapi*>(nativeObject);
185 nativeObject = nullptr;
186 }
187 }
188
CreateAuxiliaryPicture(napi_env env,std::shared_ptr<AuxiliaryPicture> auxiliaryPic)189 napi_value AuxiliaryPictureNapi::CreateAuxiliaryPicture(napi_env env, std::shared_ptr<AuxiliaryPicture> auxiliaryPic)
190 {
191 if (AuxiliaryPictureNapi::GetConstructor() == nullptr) {
192 napi_value exports = nullptr;
193 napi_create_object(env, &exports);
194 AuxiliaryPictureNapi::Init(env, exports);
195 }
196
197 napi_value constructor = nullptr;
198 napi_value result = nullptr;
199 napi_status status;
200 IMAGE_LOGD("CreateAuxiliaryPicture IN");
201 status = napi_get_reference_value(env, sConstructor_, &constructor);
202 if (IMG_IS_OK(status)) {
203 sAuxiliaryPic_ = auxiliaryPic;
204 status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
205 }
206 if (!IMG_IS_OK(status)) {
207 IMAGE_LOGE("CreateAuxiliaryPicture | New instance could not be obtained");
208 napi_get_undefined(env, &result);
209 }
210
211 return result;
212 }
213
STATIC_EXEC_FUNC(CreateAuxiliaryPicture)214 STATIC_EXEC_FUNC(CreateAuxiliaryPicture)
215 {
216 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
217 InitializationOptions opts;
218 opts.size = context->size;
219 opts.editable = true;
220 opts.useDMA = true;
221 auto colors = static_cast<uint32_t*>(context->arrayBuffer);
222 if (colors == nullptr) {
223 return;
224 }
225 auto tmpPixelmap = PixelMap::Create(colors, context->arrayBufferSize, opts);
226 std::shared_ptr<PixelMap> pixelmap = std::move(tmpPixelmap);
227 auto picture = AuxiliaryPicture::Create(pixelmap, context->type, context->size);
228 context->auxPicture = std::move(picture);
229 if (IMG_NOT_NULL(context->auxPicture)) {
230 context->status = SUCCESS;
231 } else {
232 context->status = ERROR;
233 }
234 }
235
ParseSize(napi_env env,napi_value root,int32_t & width,int32_t & height)236 static bool ParseSize(napi_env env, napi_value root, int32_t& width, int32_t& height)
237 {
238 if (!GET_INT32_BY_NAME(root, "width", width) || !GET_INT32_BY_NAME(root, "height", height)) {
239 return false;
240 }
241 if (width <= 0 || height <= 0) {
242 return false;
243 }
244 return true;
245 }
246
ParseBuffer(napi_env env,napi_value argValue,std::unique_ptr<AuxiliaryPictureNapiAsyncContext> & context)247 static bool ParseBuffer(napi_env env, napi_value argValue,
248 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> &context)
249 {
250 napi_status status;
251 if (context == nullptr) {
252 return false;
253 }
254 status = napi_get_arraybuffer_info(env, argValue, &(context->arrayBuffer),
255 &(context->arrayBufferSize));
256 if (!IMG_IS_OK(status)) {
257 return false;
258 }
259 if (context->arrayBuffer == nullptr || context->arrayBufferSize < NUM_0) {
260 return false;
261 }
262 return true;
263 }
264
ParseAuxiliaryPictureType(int32_t val)265 static AuxiliaryPictureType ParseAuxiliaryPictureType(int32_t val)
266 {
267 if (val >= static_cast<int32_t>(AuxiliaryPictureType::GAINMAP)
268 && val <= static_cast<int32_t>(AuxiliaryPictureType::FRAGMENT_MAP)) {
269 return AuxiliaryPictureType(val);
270 }
271 return AuxiliaryPictureType::NONE;
272 }
273
CreateAuxiliaryPicture(napi_env env,napi_callback_info info)274 napi_value AuxiliaryPictureNapi::CreateAuxiliaryPicture(napi_env env, napi_callback_info info)
275 {
276 if (AuxiliaryPictureNapi::GetConstructor() == nullptr) {
277 napi_value exports = nullptr;
278 napi_create_object(env, &exports);
279 AuxiliaryPictureNapi::Init(env, exports);
280 }
281
282 napi_value result = nullptr;
283 napi_get_undefined(env, &result);
284
285 napi_value constructor = nullptr;
286 napi_status status;
287 napi_value thisVar = nullptr;
288 size_t argCount = NUM_3;
289 napi_value argValue[NUM_3] = {0};
290 uint32_t auxiType = 0;
291 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
292 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
293 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
294 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
295 "Invalid args"), IMAGE_LOGE("Call napi_get_cb_info failed"));
296
297 IMG_NAPI_CHECK_RET_D(argCount == NUM_3, ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
298 "Invalid args count"), IMAGE_LOGE("Invalid args count %{public}zu", argCount));
299
300 if (!ParseBuffer(env, argValue[NUM_0], asyncContext)) {
301 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Fail to get arrayBuffer.");
302 }
303
304 if (!ParseSize(env, argValue[NUM_1], asyncContext->size.width, asyncContext->size.height)) {
305 IMAGE_LOGE("Fail to get auxiliary picture size");
306 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args.");
307 }
308 status = napi_get_value_uint32(env, argValue[NUM_2], &auxiType);
309 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get auxiliary picture Type"));
310 if (auxiType < static_cast<uint32_t>(AuxiliaryPictureType::GAINMAP)
311 || auxiType > static_cast<uint32_t>(AuxiliaryPictureType::FRAGMENT_MAP)) {
312 IMAGE_LOGE("AuxiliaryFigureType is invalid");
313 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args.");
314 }
315 asyncContext->type = ParseAuxiliaryPictureType(auxiType);
316 if (asyncContext->type == AuxiliaryPictureType::NONE) {
317 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid auxiliary picture Type.");
318 }
319 CreateAuxiliaryPictureExec(env, static_cast<void*>((asyncContext).get()));
320 status = napi_get_reference_value(env, sConstructor_, &constructor);
321 if (IMG_IS_OK(status)) {
322 sAuxiliaryPic_ = std::move(asyncContext->auxPicture);
323 status = napi_new_instance(env, constructor, NUM_0, nullptr, &result);
324 }
325 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to create picture sync"));
326 return result;
327 }
328
GetType(napi_env env,napi_callback_info info)329 napi_value AuxiliaryPictureNapi::GetType(napi_env env, napi_callback_info info)
330 {
331 NapiValues nVal;
332 napi_get_undefined(env, &nVal.result);
333 nVal.argc = NUM_0;
334 IMAGE_LOGD("Call GetType");
335 IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
336 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to call napi_get_cb_info"));
337
338 AuxiliaryPictureNapi* auxPictureNapi = nullptr;
339 nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxPictureNapi));
340 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxPictureNapi), nVal.result, IMAGE_LOGE("Fail to unwrap context"));
341 if (auxPictureNapi->nativeAuxiliaryPicture_ != nullptr) {
342 auto auxType = auxPictureNapi->nativeAuxiliaryPicture_->GetType();
343 IMAGE_LOGD("AuxiliaryPictureNapi::GetType %{public}d", auxType);
344 if (static_cast<int32_t>(auxType) >= NUM_0 && auxType <= AuxiliaryPictureType::FRAGMENT_MAP) {
345 napi_create_int32(env, static_cast<int32_t>(auxType), &nVal.result);
346 }
347 } else {
348 IMAGE_LOGE("Native picture is nullptr!");
349 }
350 return nVal.result;
351 }
352
Release(napi_env env,napi_callback_info info)353 napi_value AuxiliaryPictureNapi::Release(napi_env env, napi_callback_info info)
354 {
355 NapiValues nVal;
356 nVal.result = nullptr;
357 napi_get_undefined(env, &nVal.result);
358 nVal.argc = NUM_0;
359 IMAGE_LOGD("Call Release");
360 AuxiliaryPictureNapi *auxiliaryPicture = nullptr;
361
362 IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
363 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nVal.result, IMAGE_LOGE("Fail to call napi_get_cb_info"));
364 nVal.status = napi_remove_wrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxiliaryPicture));
365
366 return nVal.result;
367 }
368
CommonCallbackRoutine(napi_env env,AuxiliaryPictureNapiAsyncContext * & connect,const napi_value & valueParam)369 static void CommonCallbackRoutine(napi_env env, AuxiliaryPictureNapiAsyncContext* &connect,
370 const napi_value &valueParam)
371 {
372 napi_value result[NUM_2] = {0};
373
374 napi_get_undefined(env, &result[NUM_0]);
375 napi_get_undefined(env, &result[NUM_1]);
376
377 if (connect->status == SUCCESS) {
378 result[NUM_1] = valueParam;
379 } else {
380 ImageNapiUtils::CreateErrorObj(env, result[0], connect->status,
381 "There is generic napi failure!");
382 napi_get_undefined(env, &result[1]);
383 }
384
385 if (connect->deferred) {
386 if (connect->status == SUCCESS) {
387 napi_resolve_deferred(env, connect->deferred, result[NUM_1]);
388 } else {
389 napi_reject_deferred(env, connect->deferred, result[NUM_0]);
390 }
391 }
392
393 napi_delete_async_work(env, connect->work);
394
395 delete connect;
396 connect = nullptr;
397 }
398
CheckMetadataType(const AuxiliaryPictureNapiAsyncContext * context)399 static bool CheckMetadataType(const AuxiliaryPictureNapiAsyncContext* context)
400 {
401 if (context == nullptr || context->rAuxiliaryPicture == nullptr) {
402 IMAGE_LOGE("Auxiliary picture is null");
403 return false;
404 }
405 return !(context->rAuxiliaryPicture->GetType() != AuxiliaryPictureType::FRAGMENT_MAP &&
406 context->metadataType == MetadataType::FRAGMENT);
407 }
408
GetMetadataComplete(napi_env env,napi_status status,void * data)409 static void GetMetadataComplete(napi_env env, napi_status status, void *data)
410 {
411 IMAGE_LOGD("[AuxiliaryPicture]GetMetadata IN");
412 napi_value result = nullptr;
413 napi_get_undefined(env, &result);
414 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
415 if (context->imageMetadata != nullptr) {
416 result = MetadataNapi::CreateMetadata(env, context->imageMetadata);
417 }
418
419 if (!IMG_IS_OK(status)) {
420 context->status = ERROR;
421 IMAGE_LOGE("Get Metadata failed!");
422 } else {
423 context->status = SUCCESS;
424 }
425 IMAGE_LOGD("[AuxiliaryPicture]GetMetadata OUT");
426 CommonCallbackRoutine(env, context, result);
427 }
428
GetMetadata(napi_env env,napi_callback_info info)429 napi_value AuxiliaryPictureNapi::GetMetadata(napi_env env, napi_callback_info info)
430 {
431 napi_value result = nullptr;
432 napi_get_undefined(env, &result);
433 napi_status status;
434 napi_value thisVar = nullptr;
435 size_t argCount = NUM_1;
436 napi_value argValue[NUM_1] = {0};
437 uint32_t metadataType = 0;
438
439 IMAGE_LOGD("GetMetadata IN");
440 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
441 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argment from info"));
442 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
443 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
444 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
445 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
446 nullptr, IMAGE_LOGE("Fail to unwrap context"));
447 asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
448 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
449 nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
450 status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
451 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env,
452 IMAGE_BAD_PARAMETER, "Invalid args metadata type."), IMAGE_LOGE("Fail to get metadata type"));
453 if (metadataType >= static_cast<uint32_t>(MetadataType::EXIF)
454 && metadataType <= static_cast<uint32_t>(MetadataType::FRAGMENT)) {
455 asyncContext->metadataType = MetadataType(metadataType);
456 } else {
457 return ImageNapiUtils::ThrowExceptionError(
458 env, IMAGE_BAD_PARAMETER, "Invalid args metadata type");
459 }
460
461 if (!CheckMetadataType(asyncContext.get()) || asyncContext->metadataType == MetadataType::EXIF) {
462 return ImageNapiUtils::ThrowExceptionError(
463 env, IMAGE_UNSUPPORTED_METADATA, "Unsupported metadata");
464 }
465 napi_create_promise(env, &(asyncContext->deferred), &result);
466 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "GetMetadata",
467 [](napi_env env, void* data) {
468 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
469 context->imageMetadata = context->rAuxiliaryPicture->GetMetadata(context->metadataType);
470 }, GetMetadataComplete, asyncContext, asyncContext->work);
471 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
472 nullptr, IMAGE_LOGE("Fail to create async work"));
473 return result;
474 }
475
SetMetadataComplete(napi_env env,napi_status status,void * data)476 static void SetMetadataComplete(napi_env env, napi_status status, void *data)
477 {
478 IMAGE_LOGD("[AuxiliaryPicture]GetMetadata IN");
479 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
480 napi_value result = nullptr;
481 napi_get_undefined(env, &result);
482
483 if (!IMG_IS_OK(status)) {
484 context->status = ERROR;
485 IMAGE_LOGE("Set Metadata failed!");
486 } else {
487 context->status = SUCCESS;
488 }
489 IMAGE_LOGD("[AuxiliaryPicture]GetMetadata OUT");
490 CommonCallbackRoutine(env, context, result);
491 }
492
SetMetadata(napi_env env,napi_callback_info info)493 napi_value AuxiliaryPictureNapi::SetMetadata(napi_env env, napi_callback_info info)
494 {
495 napi_value result = nullptr;
496 napi_get_undefined(env, &result);
497 napi_status status;
498 napi_value thisVar = nullptr;
499 size_t argCount = NUM_2;
500 napi_value argValue[NUM_2] = {0};
501 uint32_t metadataType = 0;
502
503 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
504 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), result, IMAGE_LOGE("Fail to get argments from info"));
505 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
506 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
507 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
508 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
509 nullptr, IMAGE_LOGE("Fail to unwrap context"));
510 asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
511 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
512 nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
513
514 status = napi_get_value_uint32(env, argValue[NUM_0], &metadataType);
515 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(env,
516 IMAGE_BAD_PARAMETER, "Fail to get metadata type."), IMAGE_LOGE("Fail to get metadata type."));
517 if (metadataType >= static_cast<uint32_t>(MetadataType::EXIF)
518 && metadataType <= static_cast<uint32_t>(MetadataType::FRAGMENT)) {
519 asyncContext->metadataType = MetadataType(metadataType);
520 } else {
521 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Invalid args metadata type.");
522 }
523
524 if (!CheckMetadataType(asyncContext.get())) {
525 return ImageNapiUtils::ThrowExceptionError(env, IMAGE_UNSUPPORTED_METADATA, "Unsupported metadata");
526 }
527 status = napi_unwrap(env, argValue[NUM_1], reinterpret_cast<void**>(&asyncContext->metadataNapi));
528 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->metadataNapi), ImageNapiUtils::ThrowExceptionError(env,
529 IMAGE_BAD_PARAMETER, "Fail to unwrap MetadataNapi."), IMAGE_LOGE("Fail to unwrap MetadataNapi"));
530 asyncContext->imageMetadata = asyncContext->metadataNapi->GetNativeMetadata();
531 if (asyncContext->imageMetadata == nullptr) {
532 IMAGE_LOGE("Empty native metadata");
533 }
534
535 napi_create_promise(env, &(asyncContext->deferred), &result);
536 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "SetMetadata",
537 [](napi_env env, void* data) {
538 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
539 context->rAuxiliaryPicture->SetMetadata(context->metadataType, context->imageMetadata);
540 context->status = SUCCESS;
541 }, SetMetadataComplete, asyncContext, asyncContext->work);
542 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to create async work"));
543 return result;
544 }
545
GetAuxiliaryPictureInfoNapiValue(napi_env env,void * data,std::shared_ptr<AuxiliaryPicture> picture)546 static napi_value GetAuxiliaryPictureInfoNapiValue(napi_env env, void* data, std::shared_ptr<AuxiliaryPicture> picture)
547 {
548 napi_value result = nullptr;
549 auto auxiliaryPictureInfo = static_cast<AuxiliaryPictureInfo*>(data);
550 napi_create_object(env, &result);
551 napi_value auxiliaryPictureTypeValue = nullptr;
552 napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->auxiliaryPictureType),
553 &auxiliaryPictureTypeValue);
554 napi_set_named_property(env, result, "auxiliaryPictureType", auxiliaryPictureTypeValue);
555
556 napi_value size = nullptr;
557 napi_create_object(env, &size);
558
559 napi_value sizeWidth = nullptr;
560 napi_create_int32(env, auxiliaryPictureInfo->size.width, &sizeWidth);
561 napi_set_named_property(env, size, "width", sizeWidth);
562
563 napi_value sizeHeight = nullptr;
564 napi_create_int32(env, auxiliaryPictureInfo->size.height, &sizeHeight);
565 napi_set_named_property(env, size, "height", sizeHeight);
566
567 napi_set_named_property(env, result, "size", size);
568
569 napi_value rowStrideValue = nullptr;
570 napi_create_int32(env, auxiliaryPictureInfo->rowStride, &rowStrideValue);
571 napi_set_named_property(env, result, "rowStride", rowStrideValue);
572
573 napi_value pixelFormatValue = nullptr;
574 napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->pixelFormat), &pixelFormatValue);
575 napi_set_named_property(env, result, "pixelFormat", pixelFormatValue);
576 std::shared_ptr<PixelMap> rPixelmap = nullptr;
577
578 if (picture->GetContentPixel() == nullptr) {
579 return ImageNapiUtils::ThrowExceptionError(
580 env, ERR_IMAGE_DATA_ABNORMAL, "Invalid pixelmap");
581 }
582 auto grCS = picture->GetContentPixel()->InnerGetGrColorSpacePtr();
583 if (grCS == nullptr) {
584 return ImageNapiUtils::ThrowExceptionError(
585 env, ERR_IMAGE_DATA_UNSUPPORT, "No colorspace in pixelmap");
586 }
587 auto resultValue = ColorManager::CreateJsColorSpaceObject(env, grCS);
588 napi_value colorSpaceValue = reinterpret_cast<napi_value>(resultValue);
589 napi_create_int32(env, static_cast<int32_t>(auxiliaryPictureInfo->colorSpace), &colorSpaceValue);
590 napi_set_named_property(env, result, "colorSpace", colorSpaceValue);
591 return result;
592 }
593
GetAuxiliaryPictureInfo(napi_env env,napi_callback_info info)594 napi_value AuxiliaryPictureNapi::GetAuxiliaryPictureInfo(napi_env env, napi_callback_info info)
595 {
596 NapiValues nVal;
597 napi_get_undefined(env, &nVal.result);
598 nVal.argc = NUM_0;
599 IMAGE_LOGD("Call GetAuxiliaryPictureInfo");
600 IMG_JS_ARGS(env, info, nVal.status, nVal.argc, nullptr, nVal.thisVar);
601 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(nVal.status), nullptr, IMAGE_LOGE("Call napi_get_cb_info failed"));
602 AuxiliaryPictureNapi *auxiliaryPictureNapi = nullptr;
603 nVal.status = napi_unwrap(env, nVal.thisVar, reinterpret_cast<void**>(&auxiliaryPictureNapi));
604 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxiliaryPictureNapi),
605 nullptr, IMAGE_LOGE("Fail to unwrap context"));
606 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(nVal.status, auxiliaryPictureNapi->nativeAuxiliaryPicture_),
607 nullptr, IMAGE_LOGE("Empty native auxiliarypicture"));
608 if (auxiliaryPictureNapi->nativeAuxiliaryPicture_ != nullptr) {
609 AuxiliaryPictureInfo auxiliaryPictureInfo =
610 auxiliaryPictureNapi->nativeAuxiliaryPicture_->GetAuxiliaryPictureInfo();
611 nVal.result = GetAuxiliaryPictureInfoNapiValue(env, &auxiliaryPictureInfo,
612 auxiliaryPictureNapi->nativeAuxiliaryPicture_);
613 } else {
614 IMAGE_LOGE("Native auxiliarypicture is nullptr!");
615 }
616 return nVal.result;
617 }
618
ParsePixelFormat(int32_t val)619 static PixelFormat ParsePixelFormat(int32_t val)
620 {
621 if (val >= static_cast<int32_t>(PixelFormat::ARGB_8888) && val <= static_cast<int32_t>(PixelFormat::CMYK)) {
622 return PixelFormat(val);
623 }
624 return PixelFormat::UNKNOWN;
625 }
626
ParseColorSpace(napi_env env,napi_value val,AuxiliaryPictureNapiAsyncContext * context)627 static void ParseColorSpace(napi_env env, napi_value val, AuxiliaryPictureNapiAsyncContext* context)
628 {
629 #ifdef IMAGE_COLORSPACE_FLAG
630 context->AuxColorSpace = ColorManager::GetColorSpaceByJSObject(env, val);
631 if (context->AuxColorSpace == nullptr) {
632 ImageNapiUtils::ThrowExceptionError(
633 env, ERR_IMAGE_INVALID_PARAMETER, "ColorSpace mismatch");
634 return;
635 }
636 context->rPixelmap->InnerSetColorSpace(*(context->AuxColorSpace));
637 #else
638 ImageNapiUtils::ThrowExceptionError(
639 env, ERR_INVALID_OPERATION, "Unsupported operation");
640 #endif
641 }
642
ParseAuxiliaryPictureInfo(napi_env env,napi_value result,napi_value root,AuxiliaryPictureNapiAsyncContext * auxiliaryPictureNapiAsyncContext)643 static bool ParseAuxiliaryPictureInfo(napi_env env, napi_value result, napi_value root,
644 AuxiliaryPictureNapiAsyncContext* auxiliaryPictureNapiAsyncContext)
645 {
646 uint32_t tmpNumber = 0;
647 int32_t tmpInt32 = 0;
648 napi_value tmpValue = nullptr;
649 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(auxiliaryPictureNapiAsyncContext);
650
651 if (!GET_UINT32_BY_NAME(root, "auxiliaryPictureType", tmpNumber)) {
652 IMAGE_LOGI("No auxiliaryPictureType in auxiliaryPictureInfo");
653 return false;
654 }
655 context->auxiliaryPictureInfo.auxiliaryPictureType = ParseAuxiliaryPictureType(tmpNumber);
656
657 if (!GET_NODE_BY_NAME(root, "size", tmpValue)) {
658 return false;
659 }
660 if (!ParseSize(env, tmpValue, context->auxiliaryPictureInfo.size.width,
661 context->auxiliaryPictureInfo.size.height)) {
662 return false;
663 }
664
665 if (!GET_INT32_BY_NAME(root, "rowStride", tmpInt32) || tmpInt32 < 0) {
666 IMAGE_LOGI("Invalid rowStride in auxiliaryPictureInfo");
667 return false;
668 }
669 context->auxiliaryPictureInfo.rowStride = static_cast<uint32_t>(tmpInt32);
670
671 tmpNumber = 0;
672 if (!GET_UINT32_BY_NAME(root, "pixelFormat", tmpNumber)) {
673 IMAGE_LOGI("No pixelFormat in auxiliaryPictureInfo");
674 return false;
675 }
676 context->auxiliaryPictureInfo.pixelFormat = ParsePixelFormat(tmpNumber);
677
678 context->rPixelmap = context->auxPicture->GetContentPixel();
679 napi_value auxColorSpace = nullptr;
680 if (!GET_NODE_BY_NAME(root, "colorSpace", auxColorSpace)) {
681 IMAGE_LOGI("No colorSpace in auxiliaryPictureInfo");
682 return false;
683 }
684 ParseColorSpace(env, auxColorSpace, context);
685 return true;
686 }
687
SetAuxiliaryPictureInfo(napi_env env,napi_callback_info info)688 napi_value AuxiliaryPictureNapi::SetAuxiliaryPictureInfo(napi_env env, napi_callback_info info)
689 {
690 napi_value result = nullptr;
691 napi_get_undefined(env, &result);
692 napi_status status;
693 napi_value thisVar = nullptr;
694 size_t argCount = NUM_2;
695 napi_value argValue[NUM_2] = {0};
696
697 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
698
699 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), ImageNapiUtils::ThrowExceptionError(
700 env, IMAGE_BAD_PARAMETER, "Parameter error."), IMAGE_LOGE("Call napi_get_cb_info failed."));
701 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
702 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
703 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
704 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
705 nullptr, IMAGE_LOGE("Fail to unwrap context"));
706 asyncContext->auxPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
707 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->auxPicture),
708 nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
709 IMG_NAPI_CHECK_RET_D(ParseAuxiliaryPictureInfo(env, result, argValue[NUM_0], asyncContext.get()),
710 ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Parameter error."),
711 IMAGE_LOGE("AuxiliaryPictureInfo mismatch"));
712
713 if (status == napi_ok) {
714 uint32_t res = asyncContext->auxPicture->SetAuxiliaryPictureInfo(asyncContext->auxiliaryPictureInfo);
715 if (res != SUCCESS) {
716 ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER, "Parameter error.");
717 }
718 } else {
719 IMAGE_LOGE("Failed to call napi_unwrap for auxilianypictureinfo");
720 }
721 return result;
722 }
723
ReadPixelsToBufferComplete(napi_env env,napi_status status,void * data)724 static void ReadPixelsToBufferComplete(napi_env env, napi_status status, void *data)
725 {
726 napi_value result = nullptr;
727 napi_get_undefined(env, &result);
728 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
729
730 if (context->status == SUCCESS &&
731 !ImageNapiUtils::CreateArrayBuffer(env, context->arrayBuffer, context->arrayBufferSize, &result)) {
732 context->status = ERROR;
733 IMAGE_LOGE("Fail to create napi arraybuffer!");
734 napi_get_undefined(env, &result);
735 }
736
737 delete[] static_cast<uint8_t*>(context->arrayBuffer);
738 context->arrayBuffer = nullptr;
739 context->arrayBufferSize = 0;
740 CommonCallbackRoutine(env, context, result);
741 }
742
ReadPixelsToBuffer(napi_env env,napi_callback_info info)743 napi_value AuxiliaryPictureNapi::ReadPixelsToBuffer(napi_env env, napi_callback_info info)
744 {
745 napi_value result = nullptr;
746 napi_get_undefined(env, &result);
747 napi_status status;
748 napi_value thisVar = nullptr;
749 size_t argCount = NUM_0;
750
751 IMG_JS_ARGS(env, info, status, argCount, nullptr, thisVar);
752 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to get argments from info"));
753
754 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
755 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
756 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
757 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
758 nullptr, IMAGE_LOGE("Fail to unwrap context"));
759 asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
760 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
761 nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
762
763 napi_create_promise(env, &(asyncContext->deferred), &result);
764 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "ReadPixelsToBuffer",
765 [](napi_env env, void *data) {
766 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
767 AuxiliaryPictureInfo info = context->rAuxiliaryPicture->GetAuxiliaryPictureInfo();
768 context->arrayBufferSize = info.size.width * info.size.height * ImageUtils::GetPixelBytes(info.pixelFormat);
769 context->arrayBuffer = new uint8_t[context->arrayBufferSize];
770 if (context->arrayBuffer != nullptr) {
771 context->status = context->rAuxiliaryPicture->ReadPixels(
772 context->arrayBufferSize, static_cast<uint8_t*>(context->arrayBuffer));
773 } else {
774 context->status = ERR_MEDIA_MALLOC_FAILED;
775 ImageNapiUtils::ThrowExceptionError(env, IMAGE_ALLOC_FAILED, "Memory alloc failed.");
776 }
777 }, ReadPixelsToBufferComplete, asyncContext, asyncContext->work);
778
779 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
780 nullptr, IMAGE_LOGE("Fail to create async work"));
781 return result;
782 }
783
EmptyResultComplete(napi_env env,napi_status status,void * data)784 static void EmptyResultComplete(napi_env env, napi_status status, void *data)
785 {
786 napi_value result = nullptr;
787 napi_get_undefined(env, &result);
788 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
789 CommonCallbackRoutine(env, context, result);
790 }
791
WritePixelsFromBuffer(napi_env env,napi_callback_info info)792 napi_value AuxiliaryPictureNapi::WritePixelsFromBuffer(napi_env env, napi_callback_info info)
793 {
794 napi_value result = nullptr;
795 napi_get_undefined(env, &result);
796 napi_status status;
797 napi_value thisVar = nullptr;
798 size_t argCount = NUM_1;
799 napi_value argValue[NUM_1] = {0};
800
801 IMG_JS_ARGS(env, info, status, argCount, argValue, thisVar);
802 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status), nullptr, IMAGE_LOGE("Fail to get argments from info"));
803
804 std::unique_ptr<AuxiliaryPictureNapiAsyncContext> asyncContext =
805 std::make_unique<AuxiliaryPictureNapiAsyncContext>();
806 status = napi_unwrap(env, thisVar, reinterpret_cast<void**>(&asyncContext->nConstructor));
807 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->nConstructor),
808 nullptr, IMAGE_LOGE("Fail to unwrap context"));
809 asyncContext->rAuxiliaryPicture = asyncContext->nConstructor->nativeAuxiliaryPicture_;
810 IMG_NAPI_CHECK_RET_D(IMG_IS_READY(status, asyncContext->rAuxiliaryPicture),
811 nullptr, IMAGE_LOGE("Empty native auxiliary picture"));
812 status = napi_get_arraybuffer_info(env, argValue[NUM_0],
813 &(asyncContext->arrayBuffer), &(asyncContext->arrayBufferSize));
814 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
815 ImageNapiUtils::ThrowExceptionError(env, IMAGE_BAD_PARAMETER,
816 "Invalid args."), IMAGE_LOGE("Fail to get buffer info"));
817
818 napi_create_promise(env, &(asyncContext->deferred), &result);
819 IMG_CREATE_CREATE_ASYNC_WORK(env, status, "WritePixelsFromBuffer",
820 [](napi_env env, void *data) {
821 auto context = static_cast<AuxiliaryPictureNapiAsyncContext*>(data);
822 context->status = context->rAuxiliaryPicture->WritePixels(
823 static_cast<uint8_t*>(context->arrayBuffer), context->arrayBufferSize);
824 }, EmptyResultComplete, asyncContext, asyncContext->work);
825
826 IMG_NAPI_CHECK_RET_D(IMG_IS_OK(status),
827 nullptr, IMAGE_LOGE("Fail to create async work"));
828 return result;
829 }
830
release()831 void AuxiliaryPictureNapi::release()
832 {
833 if (!isRelease) {
834 if (nativeAuxiliaryPicture_ != nullptr) {
835 nativeAuxiliaryPicture_ = nullptr;
836 }
837 isRelease = true;
838 }
839 }
840 } // namespace Media
841 } // namespace OHOS
842