1 /*
2  * Copyright (C) 2023 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_packer_mdk_kits.h"
17 
18 #include <map>
19 #include "image_log.h"
20 
21 #undef LOG_DOMAIN
22 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
23 
24 #undef LOG_TAG
25 #define LOG_TAG "ImagePackerMdk"
26 
27 namespace {
28     constexpr size_t SIZE_ZERO = 0;
29     constexpr int INVALID_FD = -1;
30 }
31 
32 namespace OHOS {
33 namespace Media {
34 using ImagePackerNativeFunc = int32_t (*)(struct ImagePackerArgs* args);
35 
36 enum class PackingSourceType : int32_t {
37     TYPE_INVALID = -1,
38     TYPE_IMAGE_SOURCE,
39     TYPE_PIXEL_MAP,
40 };
41 
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45 
IsInstanceOf(napi_env env,napi_value value,napi_value global,const char * type)46 static bool IsInstanceOf(napi_env env, napi_value value, napi_value global, const char* type)
47 {
48     napi_value constructor = nullptr;
49     if (napi_get_named_property(env, global, type, &constructor) != napi_ok) {
50         IMAGE_LOGE("Get constructor property failed!");
51         return false;
52     }
53 
54     bool isInstance = false;
55     if (napi_instanceof(env, value, constructor, &isInstance) == napi_ok && isInstance) {
56         return true;
57     }
58     return false;
59 }
60 
ParserPackingArgumentType(napi_env env,napi_value source)61 static PackingSourceType ParserPackingArgumentType(napi_env env, napi_value source)
62 {
63     napi_value global = nullptr;
64     if (napi_get_global(env, &global) != napi_ok) {
65         IMAGE_LOGE("Get global property failed!");
66         return PackingSourceType::TYPE_INVALID;
67     }
68 
69     if (IsInstanceOf(env, source, global, "ImageSource")) {
70         IMAGE_LOGD("This is ImageSource!");
71         return PackingSourceType::TYPE_IMAGE_SOURCE;
72     } else if (IsInstanceOf(env, source, global, "PixelMap")) {
73         IMAGE_LOGD("This is PixelMap!");
74         return PackingSourceType::TYPE_PIXEL_MAP;
75     }
76 
77     IMAGE_LOGE("Invalid type!");
78     return PackingSourceType::TYPE_INVALID;
79 }
80 
ImagePackerNapiCreate(struct ImagePackerArgs * args)81 static int32_t ImagePackerNapiCreate(struct ImagePackerArgs* args)
82 {
83     if (args == nullptr || args->inEnv == nullptr || args->outVal == nullptr) {
84         IMAGE_LOGE("ImagePackerNapiCreate bad parameter");
85         return IMAGE_RESULT_BAD_PARAMETER;
86     }
87     *(args->outVal) = ImagePackerNapi::CreateImagePacker(args->inEnv, nullptr);
88     if (*(args->outVal) == nullptr) {
89         IMAGE_LOGE("ImageSourceNapiCreate native create failed");
90         return IMAGE_RESULT_BAD_PARAMETER;
91     }
92     IMAGE_LOGD("ImagePackerNapiCreate success");
93     return IMAGE_RESULT_SUCCESS;
94 }
95 
GetNativeImageSouce(napi_env env,napi_value source)96 static std::shared_ptr<ImageSource> GetNativeImageSouce(napi_env env, napi_value source)
97 {
98     std::unique_ptr<ImageSourceNapi> napi = nullptr;
99     napi_status status = napi_unwrap(env, source, reinterpret_cast<void**>(&napi));
100     if ((status == napi_ok) && napi != nullptr) {
101         return napi.release()->nativeImgSrc;
102     }
103     return nullptr;
104 }
105 
DoStartPacking(std::shared_ptr<ImagePacker> & packer,struct ImagePackerArgs * args)106 static int32_t DoStartPacking(std::shared_ptr<ImagePacker> &packer, struct ImagePackerArgs* args)
107 {
108     if (args == nullptr || args->inOpts == nullptr) {
109         return IMAGE_RESULT_BAD_PARAMETER;
110     }
111 
112     PackOption option;
113     option.format = args->inOpts->format;
114     option.quality = args->inOpts->quality;
115     option.desiredDynamicRange = EncodeDynamicRange::SDR;
116     if (args->outData != nullptr && args->dataSize != nullptr && *(args->dataSize) != SIZE_ZERO) {
117         return packer->StartPacking(args->outData, *(args->dataSize), option);
118     } else if (args->inNum0 > INVALID_FD) {
119         return packer->StartPacking(args->inNum0, option);
120     }
121     IMAGE_LOGE("DoNativePacking StartPacking failed");
122     return IMAGE_RESULT_BAD_PARAMETER;
123 }
124 
DoAddImage(std::shared_ptr<ImagePacker> & packer,PackingSourceType type,struct ImagePackerArgs * args)125 static int32_t DoAddImage(std::shared_ptr<ImagePacker> &packer,
126     PackingSourceType type, struct ImagePackerArgs* args)
127 {
128     if (args == nullptr || args->inOpts == nullptr) {
129         return IMAGE_RESULT_BAD_PARAMETER;
130     }
131 
132     if (type == PackingSourceType::TYPE_IMAGE_SOURCE) {
133         auto image = GetNativeImageSouce(args->inEnv, args->inVal);
134         if (image != nullptr) {
135             return packer->AddImage(*image);
136         } else {
137             IMAGE_LOGE("DoNativePacking get image source native failed");
138             return IMAGE_RESULT_BAD_PARAMETER;
139         }
140     } else if (type == PackingSourceType::TYPE_PIXEL_MAP) {
141         auto pixel = PixelMapNapi::GetPixelMap(args->inEnv, args->inVal);
142         if (pixel != nullptr) {
143             return packer->AddImage(*pixel);
144         } else {
145             IMAGE_LOGE("DoNativePacking get pixelmap native failed");
146             return IMAGE_RESULT_BAD_PARAMETER;
147         }
148     }
149     IMAGE_LOGE("DoNativePacking unsupport packing source type %{public}d", type);
150     return IMAGE_RESULT_BAD_PARAMETER;
151 }
152 
DoNativePacking(struct ImagePackerArgs * args)153 static int32_t DoNativePacking(struct ImagePackerArgs* args)
154 {
155     if (args == nullptr || args->inOpts == nullptr || args->inVal == nullptr) {
156         return IMAGE_RESULT_BAD_PARAMETER;
157     }
158 
159     auto type = ParserPackingArgumentType(args->inEnv, args->inVal);
160     if (type == PackingSourceType::TYPE_INVALID) {
161         return IMAGE_RESULT_BAD_PARAMETER;
162     }
163     auto nativeImagePacker = ImagePackerNapi::GetNative(args->inNapi);
164     if (nativeImagePacker == nullptr) {
165         IMAGE_LOGE("DoNativePacking get native failed");
166         return IMAGE_RESULT_BAD_PARAMETER;
167     }
168     int32_t res = DoStartPacking(nativeImagePacker, args);
169     if (res != IMAGE_RESULT_SUCCESS) {
170         IMAGE_LOGE("DoNativePacking StartPacking failed");
171         return res;
172     }
173     res = DoAddImage(nativeImagePacker, type, args);
174     if (res != IMAGE_RESULT_SUCCESS) {
175         IMAGE_LOGE("DoNativePacking AddImage failed");
176         return res;
177     }
178     int64_t packedSize = SIZE_ZERO;
179     res = static_cast<int32_t>(nativeImagePacker->FinalizePacking(packedSize));
180     if (args->dataSize != nullptr) {
181         *args->dataSize = packedSize;
182     }
183     return res;
184 }
ImagePackerNapiPackToData(struct ImagePackerArgs * args)185 static int32_t ImagePackerNapiPackToData(struct ImagePackerArgs* args)
186 {
187     if (args == nullptr || args->inEnv == nullptr ||
188         args->inNapi == nullptr || args->inVal == nullptr ||
189         args->inOpts == nullptr || args->outData == nullptr ||
190         args->dataSize == nullptr || *(args->dataSize) == SIZE_ZERO) {
191         IMAGE_LOGE("ImagePackerNapiPackToData bad parameter");
192         return IMAGE_RESULT_BAD_PARAMETER;
193     }
194     return DoNativePacking(args);
195 }
196 
ImagePackerNapiPackToFile(struct ImagePackerArgs * args)197 static int32_t ImagePackerNapiPackToFile(struct ImagePackerArgs* args)
198 {
199     if (args == nullptr || args->inEnv == nullptr ||
200         args->inNapi == nullptr || args->inVal == nullptr ||
201         args->inOpts == nullptr || args->inNum0 <= INVALID_FD) {
202         IMAGE_LOGE("ImagePackerNapiPackToFile bad parameter");
203         return IMAGE_RESULT_BAD_PARAMETER;
204     }
205     return DoNativePacking(args);
206 }
207 
208 static const std::map<int32_t, ImagePackerNativeFunc> g_CtxFunctions = {
209     {ENV_FUNC_IMAGEPACKER_CREATE, ImagePackerNapiCreate},
210     {CTX_FUNC_IMAGEPACKER_PACKTODATA, ImagePackerNapiPackToData},
211     {CTX_FUNC_IMAGEPACKER_PACKTOFILE, ImagePackerNapiPackToFile},
212 };
213 
214 MIDK_EXPORT
ImagePackerNativeCall(int32_t mode,struct ImagePackerArgs * args)215 int32_t ImagePackerNativeCall(int32_t mode, struct ImagePackerArgs* args)
216 {
217     auto funcSearch = g_CtxFunctions.find(mode);
218     if (funcSearch == g_CtxFunctions.end()) {
219         return IMAGE_RESULT_BAD_PARAMETER;
220     }
221     return funcSearch->second(args);
222 }
223 
224 MIDK_EXPORT
ImagePackerNapi_Unwrap(napi_env env,napi_value value)225 ImagePackerNapi* ImagePackerNapi_Unwrap(napi_env env, napi_value value)
226 {
227     napi_valuetype valueType;
228     napi_typeof(env, value, &valueType);
229     if (valueType != napi_object) {
230         return nullptr;
231     }
232     std::unique_ptr<ImagePackerNapi> napi = nullptr;
233     napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&napi));
234     if ((status == napi_ok) && napi != nullptr) {
235         return napi.release();
236     }
237     return nullptr;
238 }
239 #ifdef __cplusplus
240 };
241 #endif
242 }  // namespace Media
243 }  // namespace OHOS
244