1 /*
2 * Copyright (C) 2025 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 <ani.h>
17 #include <array>
18 #include <iostream>
19
20 #include "image_ani_utils.h"
21 #include "image_log.h"
22 #include "log_tags.h"
23 #include "media_errors.h"
24 #include "pixel_map_ani.h"
25
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
28
29 #undef LOG_TAG
30 #define LOG_TAG "PixelMapAni"
31
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35
parseEnumFromStruct(ani_env * env,ani_object & param,string propertyGet,string enumType)36 static ani_int parseEnumFromStruct(ani_env* env, ani_object ¶m, string propertyGet, string enumType)
37 {
38 ani_status ret;
39 ani_ref enumRef;
40 if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(param, propertyGet.c_str(), enumType.c_str(), &enumRef))) {
41 IMAGE_LOGE("Object_CallMethodByName_Int enumRef Failed: %{public}d", ret);
42 return 0;
43 }
44 ani_boolean undefined;
45 env->Reference_IsUndefined(enumRef, &undefined);
46 if (undefined) {
47 IMAGE_LOGI("Enum %{public}s is undefined", propertyGet.c_str());
48 return 0;
49 }
50
51 ani_int enumIndex;
52 if (ANI_OK != env->EnumItem_GetValue_Int(static_cast<ani_enum_item>(enumRef), &enumIndex)) {
53 IMAGE_LOGE("EnumItem_GetValue_Int enumIndex Failed: %{public}d", ret);
54 return 0;
55 }
56 return enumIndex;
57 }
58
ParseInitializationOptions(ani_env * env,ani_object param,InitializationOptions & opts)59 static bool ParseInitializationOptions([[maybe_unused]] ani_env* env, ani_object param, InitializationOptions &opts)
60 {
61 ani_boolean isUndefined;
62 env->Reference_IsUndefined(param, &isUndefined);
63 if (isUndefined) {
64 IMAGE_LOGE("ParseInitializationOptions isUndefined ");
65 return false;
66 }
67 ani_class dateCls;
68 const char *className = "L@ohos/multimedia/image/image/Size;";
69 if (ANI_OK != env->FindClass(className, &dateCls)) {
70 IMAGE_LOGE("Not found %{public}s", className);
71 return false;
72 }
73 ani_ref size;
74 if (ANI_OK != env->Object_CallMethodByName_Ref(param, "<get>size", ":L@ohos/multimedia/image/image/Size;", &size)) {
75 IMAGE_LOGE("Object_GetFieldByName_Ref Failed");
76 }
77 ani_status ret;
78 if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size),
79 "<get>width", ":I", &opts.size.width)) {
80 IMAGE_LOGE("Object_CallMethodByName_Int width Failed");
81 }
82 if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size),
83 "<get>height", ":I", &opts.size.height)) != ANI_OK) {
84 IMAGE_LOGE("Object_CallMethodByName_Int height Failed");
85 }
86 opts.srcPixelFormat = PixelFormat(parseEnumFromStruct(env, param, "<get>srcPixelFormat",
87 ":L@ohos/multimedia/image/image/PixelMapFormat;"));
88 opts.pixelFormat = PixelFormat(parseEnumFromStruct(env, param, "<get>pixelFormat",
89 ":L@ohos/multimedia/image/image/PixelMapFormat;"));
90 ani_ref editableRef;
91 if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(param,
92 "<get>editable", ":Lstd/core/Boolean;", &editableRef))) {
93 IMAGE_LOGE("Object_CallMethodByName_Int Failed editableRef:%{public}d", ret);
94 }
95 ani_boolean editable;
96 if ((ret = env->Object_CallMethodByName_Boolean(reinterpret_cast<ani_object>(editableRef),
97 "unboxed", ":Z", &editable)) != ANI_OK) {
98 IMAGE_LOGE("Object_CallMethodByName_Int Failed editable:%{public}d", ret);
99 }
100 opts.alphaType = AlphaType(parseEnumFromStruct(env, param, "<get>alphaType",
101 ":L@ohos/multimedia/image/image/AlphaType;"));
102 opts.scaleMode = ScaleMode(parseEnumFromStruct(env, param, "<get>scaleMode",
103 ":L@ohos/multimedia/image/image/ScaleMode;"));
104 return true;
105 }
106
ParseRegion(ani_env * env,ani_object region,Rect & rect)107 static bool ParseRegion([[maybe_unused]] ani_env* env, ani_object region, Rect& rect)
108 {
109 ani_boolean undefined;
110 env->Reference_IsUndefined(region, &undefined);
111 if (undefined) {
112 IMAGE_LOGE("ParseRegion argument undefined");
113 return false;
114 }
115
116 ani_ref size;
117 if (ANI_OK != env->Object_CallMethodByName_Ref(region, "<get>size", ":L@ohos/multimedia/image/image/Size;",
118 &size)) {
119 IMAGE_LOGE("Object_GetFieldByName_Ref Failed");
120 return false;
121 }
122 if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>width", ":I",
123 &rect.width)) {
124 IMAGE_LOGE("Object_CallMethodByName_Int width Failed");
125 return false;
126 }
127 if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>height", ":I",
128 &rect.height)) {
129 IMAGE_LOGE("Object_CallMethodByName_Int height Failed");
130 return false;
131 }
132
133 if (ANI_OK != env->Object_CallMethodByName_Int(region, "<get>x", ":I", &rect.left)) {
134 IMAGE_LOGE("Object_CallMethodByName_Int x Failed");
135 return false;
136 }
137 if (ANI_OK != env->Object_CallMethodByName_Int(region, "<get>y", ":I", &rect.top)) {
138 IMAGE_LOGE("Object_CallMethodByName_Int y Failed");
139 return false;
140 }
141
142 return true;
143 }
144
CreatePixelMap(ani_env * env,std::shared_ptr<PixelMap> pixelMap)145 ani_object PixelMapAni::CreatePixelMap([[maybe_unused]] ani_env* env, std::shared_ptr<PixelMap> pixelMap)
146 {
147 unique_ptr<PixelMapAni> pPixelMapAni = make_unique<PixelMapAni>();
148 pPixelMapAni->nativePixelMap_ = pixelMap;
149 static const char* className = "L@ohos/multimedia/image/image/PixelMapInner;";
150 ani_class cls;
151 if (ANI_OK != env->FindClass(className, &cls)) {
152 IMAGE_LOGE("Not found L@ohos/multimedia/image/image/PixelMapInner");
153 return nullptr;
154 }
155 ani_method ctor;
156 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
157 IMAGE_LOGE("Not found ani_method");
158 return nullptr;
159 }
160 ani_object aniValue;
161 if (ANI_OK != env->Object_New(cls, ctor, &aniValue, reinterpret_cast<ani_long>(pPixelMapAni.release()))) {
162 IMAGE_LOGE("New Context Fail");
163 }
164 return aniValue;
165 }
166
CreatePixelMapAni(ani_env * env,ani_object obj)167 ani_object PixelMapAni::CreatePixelMapAni([[maybe_unused]] ani_env* env, ani_object obj)
168 {
169 unique_ptr<PixelMapAni> pPixelMapAni = make_unique<PixelMapAni>();
170 InitializationOptions opts;
171 if (!ParseInitializationOptions(env, obj, opts)) {
172 IMAGE_LOGE("ParseInitializationOptions failed '");
173 return nullptr;
174 }
175
176 pPixelMapAni->nativePixelMap_ = PixelMap::Create(opts);
177 return ImageAniUtils::CreateAniPixelMap(env, pPixelMapAni);
178 }
179
CreateAlphaPixelmap(ani_env * env,ani_object obj)180 static ani_object CreateAlphaPixelmap([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
181 {
182 PixelMap* pixelMap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
183 if (pixelMap == nullptr) {
184 IMAGE_LOGE("[GetPixelMapFromEnv] pixelMap nullptr");
185 return nullptr;
186 }
187
188 std::unique_ptr<PixelMapAni> pPixelMapAni = std::make_unique<PixelMapAni>();
189 InitializationOptions opts;
190 opts.pixelFormat = PixelFormat::ALPHA_8;
191 pPixelMapAni->nativePixelMap_ = PixelMap::Create(*pixelMap, opts);
192 return ImageAniUtils::CreateAniPixelMap(env, pPixelMapAni);
193 }
194
GetImageInfo(ani_env * env,ani_object obj)195 static ani_object GetImageInfo([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
196 {
197 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
198 if (pixelmap == nullptr) {
199 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr ");
200 return nullptr;
201 }
202 ImageInfo imgInfo;
203 pixelmap->GetImageInfo(imgInfo);
204 return ImageAniUtils::CreateImageInfoValueFromNative(env, imgInfo, pixelmap);
205 }
206
GetBytesNumberPerRow(ani_env * env,ani_object obj)207 static ani_int GetBytesNumberPerRow([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
208 {
209 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
210 if (pixelmap == nullptr) {
211 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr");
212 return 0;
213 }
214 return pixelmap->GetRowBytes();
215 }
216
GetPixelBytesNumber(ani_env * env,ani_object obj)217 static ani_int GetPixelBytesNumber([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
218 {
219 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
220 if (pixelmap == nullptr) {
221 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr");
222 return 0;
223 }
224 return pixelmap->GetByteCount();
225 }
226
Release(ani_env * env,ani_object obj)227 static void Release([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
228 {
229 ani_status ret;
230 ani_long nativeObj {};
231 if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
232 IMAGE_LOGE("[Release] Object_GetField_Long fetch field");
233 return;
234 }
235 PixelMapAni* pixelmapAni = reinterpret_cast<PixelMapAni*>(nativeObj);
236 pixelmapAni->nativePixelMap_ = nullptr;
237 }
238
ReadPixelsToBuffer(ani_env * env,ani_object obj,ani_object param0)239 static void ReadPixelsToBuffer(ani_env* env, ani_object obj, ani_object param0)
240 {
241 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
242 if (pixelmap == nullptr) {
243 IMAGE_LOGE("[ReadPixelsToBuffer] pixelmap nullptr ");
244 return;
245 }
246 size_t bufferLength = 0;
247 void *dstbuffer = nullptr;
248 ani_arraybuffer arraybuffer = static_cast<ani_arraybuffer>(param0);
249 if (ANI_OK != env->ArrayBuffer_GetInfo(arraybuffer, &dstbuffer, &bufferLength)) {
250 IMAGE_LOGE("[ReadPixelsToBuffer] ArrayBuffer_GetInfo failed");
251 }
252 uint32_t ret = pixelmap->ReadPixels(bufferLength, static_cast<uint8_t*>(dstbuffer));
253 if (ret != 0) {
254 IMAGE_LOGE("[ReadPixelsToBuffer] failed");
255 }
256 }
257
Scale(ani_env * env,ani_object obj,ani_double x,ani_double y,ani_int level)258 static void Scale([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj, ani_double x, ani_double y,
259 ani_int level)
260 {
261 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
262 if (pixelmap == nullptr) {
263 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr");
264 return;
265 }
266
267 ani_int levelIntValue = 0;
268 ani_enum enumType;
269 if (ANI_OK != env->FindEnum("L@ohos/multimedia/image/image/AntiAliasingLevel;", &enumType)) {
270 IMAGE_LOGI("Find Enum AntiAliasingLevel Failed");
271 }
272 ani_enum_item enumItem;
273 if (ANI_OK != env->Enum_GetEnumItemByIndex(enumType, level, &enumItem)) {
274 IMAGE_LOGI("Enum_GetEnumItemByIndex AntiAliasingLevel Failed");
275 }
276 if (ANI_OK != env->EnumItem_GetValue_Int(enumItem, &levelIntValue)) {
277 IMAGE_LOGI("EnumItem_GetValue_Int AntiAliasingLevel Failed");
278 }
279
280 pixelmap->scale(static_cast<float>(x), static_cast<float>(y), AntiAliasingOption(levelIntValue));
281 }
282
Crop(ani_env * env,ani_object obj,ani_object region)283 static void Crop([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj, ani_object region)
284 {
285 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
286 if (pixelmap == nullptr) {
287 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr");
288 return;
289 }
290
291 Rect rect;
292 if (!ParseRegion(env, region, rect)) {
293 IMAGE_LOGE("ParseRegion failed");
294 return;
295 }
296
297 pixelmap->crop(rect);
298 }
299
Flip(ani_env * env,ani_object obj,ani_boolean horizontal,ani_boolean vertical)300 static void Flip([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj, ani_boolean horizontal,
301 ani_boolean vertical)
302 {
303 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj);
304 if (pixelmap == nullptr) {
305 IMAGE_LOGE("[GetPixelMapFromEnv] pixelmap nullptr");
306 return;
307 }
308
309 pixelmap->flip(static_cast<bool>(horizontal), static_cast<bool>(vertical));
310 }
311
Init(ani_env * env)312 ani_status PixelMapAni::Init(ani_env* env)
313 {
314 static const char *className = "L@ohos/multimedia/image/image/PixelMapInner;";
315 ani_class cls;
316 if (ANI_OK != env->FindClass(className, &cls)) {
317 IMAGE_LOGE("Not found L@ohos/multimedia/image/image/PixelMapInner;");
318 return ANI_ERROR;
319 }
320 std::array methods = {
321 ani_native_function {"nativeCreateAlphaPixelmap", ":L@ohos/multimedia/image/image/PixelMap;",
322 reinterpret_cast<void*>(OHOS::Media::CreateAlphaPixelmap)},
323 ani_native_function {"nativeGetImageInfo", ":L@ohos/multimedia/image/image/ImageInfo;",
324 reinterpret_cast<void*>(OHOS::Media::GetImageInfo)},
325 ani_native_function {"getBytesNumberPerRow", ":I", reinterpret_cast<void*>(OHOS::Media::GetBytesNumberPerRow)},
326 ani_native_function {"getPixelBytesNumber", ":I", reinterpret_cast<void*>(OHOS::Media::GetPixelBytesNumber)},
327 ani_native_function {"nativeRelease", ":V", reinterpret_cast<void*>(OHOS::Media::Release)},
328 ani_native_function {"nativeReadPixelsToBuffer", "Lescompat/ArrayBuffer;:V",
329 reinterpret_cast<void*>(OHOS::Media::ReadPixelsToBuffer)},
330 ani_native_function {"nativeScale", "DDL@ohos/multimedia/image/image/AntiAliasingLevel;:V",
331 reinterpret_cast<void*>(OHOS::Media::Scale)},
332 ani_native_function {"nativeCrop", "L@ohos/multimedia/image/image/Region;:V",
333 reinterpret_cast<void*>(OHOS::Media::Crop)},
334 ani_native_function {"nativeFlip", "ZZ:V", reinterpret_cast<void*>(OHOS::Media::Flip)},
335 };
336 ani_status ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
337 if (ANI_OK != ret) {
338 IMAGE_LOGE("[Init] Class_BindNativeMethods failed :%{public}d", ret);
339 return ANI_ERROR;
340 };
341 return ANI_OK;
342 }
343 } // Media
344 } // OHOS