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_packer_ani.h"
22 #include "image_log.h"
23 #include "log_tags.h"
24 #include "media_errors.h"
25 #include "pixel_map_ani.h"
26 #include "securec.h"
27
28 #undef LOG_DOMAIN
29 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
30
31 #undef LOG_TAG
32 #define LOG_TAG "ImagePackerAni"
33
34 namespace OHOS {
35 namespace Media {
36 using namespace std;
37
CreateImagePackerAni(ani_env * env,ani_object obj)38 ani_object ImagePackerAni::CreateImagePackerAni([[maybe_unused]] ani_env* env, ani_object obj)
39 {
40 std::unique_ptr<ImagePackerAni> imagePackerAni = std::make_unique<ImagePackerAni>();
41 std::shared_ptr<ImagePacker> imagePacker = std::make_shared<ImagePacker>();
42 imagePackerAni->nativeImagePacker_ = imagePacker;
43
44 static const char* className = "L@ohos/multimedia/image/image/ImagePackerInner;";
45 ani_class cls;
46 if (ANI_OK != env->FindClass(className, &cls)) {
47 IMAGE_LOGE("Not found L@ohos/multimedia/image/image/ImagePacker;");
48 return nullptr;
49 }
50
51 ani_method ctor;
52 if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "J:V", &ctor)) {
53 IMAGE_LOGE("Not found Class_FindMethod");
54 return nullptr;
55 }
56
57 ani_object aniValue;
58 if (ANI_OK != env->Object_New(cls, ctor, &aniValue, reinterpret_cast<ani_long>(imagePackerAni.release()))) {
59 IMAGE_LOGE("New Context Fail");
60 }
61 return aniValue;
62 }
63
GetImagePackerFromAniEnv(ani_env * env,ani_object obj)64 ImagePacker* GetImagePackerFromAniEnv([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
65 {
66 ani_status ret;
67 ani_long nativeObj {};
68 if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
69 IMAGE_LOGE("[GetImagePackerFromAniEnv] Object_GetField_Long fetch field ");
70 return nullptr;
71 }
72 ImagePackerAni* imagePackerAni = reinterpret_cast<ImagePackerAni*>(nativeObj);
73 if (!imagePackerAni) {
74 IMAGE_LOGE("[GetImagePackerFromAniEnv] imagePackerAni field ");
75 return nullptr;
76 }
77 return (imagePackerAni->nativeImagePacker_).get();
78 }
79
ANIUtils_ANIStringToStdString(ani_env * env,ani_string ani_str)80 std::string ANIUtils_ANIStringToStdString(ani_env *env, ani_string ani_str)
81 {
82 ani_size strSize;
83 env->String_GetUTF8Size(ani_str, &strSize);
84
85 std::vector<char> buffer(strSize + 1); // +1 for null terminator
86 char* utfBuffer = buffer.data();
87
88 ani_size bytes_written = 0;
89 env->String_GetUTF8(ani_str, utfBuffer, strSize + 1, &bytes_written);
90
91 utfBuffer[bytes_written] = '\0';
92 std::string content = std::string(utfBuffer);
93 return content;
94 }
95
ParsePackingOptions(ani_env * env,ani_object para,PackOption & packOpts,uint32_t & outBufferSize)96 bool ParsePackingOptions([[maybe_unused]] ani_env* env, ani_object para, PackOption &packOpts, uint32_t &outBufferSize)
97 {
98 ani_ref tmptest;
99 if (ANI_OK != env->Object_CallMethodByName_Ref(para, "<get>format", ":Lstd/core/String;", &tmptest)) {
100 IMAGE_LOGE("Object_CallMethodByName_Ref <get>format failed");
101 return false;
102 }
103 std::string retStr = ANIUtils_ANIStringToStdString(env, static_cast<ani_string>(tmptest));
104 ani_status ret;
105 ani_int quality;
106 if ((ret = env->Object_CallMethodByName_Int(para, "<get>quality", ":I",
107 &quality)) != ANI_OK) {
108 IMAGE_LOGE("Object_CallMethodByName_Int Failed quality:%{public}d", ret);
109 }
110 ani_ref bufferSizeRef;
111 if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>bufferSize", ":Lstd/core/Int;",
112 &bufferSizeRef))) {
113 IMAGE_LOGE("Object_CallMethodByName_Int Failed bufferSizeRef:%{public}d", ret);
114 }
115 ani_int bufferSize;
116 if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(bufferSizeRef),
117 "unboxed", ":I", &bufferSize)) != ANI_OK || bufferSize <= 0) {
118 IMAGE_LOGE("Object_CallMethodByName_Int Failed bufferSize or invalid bufferSize:%{public}d", ret);
119 }
120 ani_ref desiredDynamicRangeRef;
121 if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>desiredDynamicRange",
122 ":Lstd/core/Int;", &desiredDynamicRangeRef))) {
123 IMAGE_LOGE("Object_CallMethodByName_Int Failed desiredDynamicRangeRef:%{public}d", ret);
124 }
125 ani_int desiredDynamicRange;
126 if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(desiredDynamicRangeRef),
127 "unboxed", ":I", &desiredDynamicRange)) != ANI_OK) {
128 IMAGE_LOGE("Object_CallMethodByName_Int Failed desiredDynamicRange:%{public}d", ret);
129 }
130 ani_ref needsPackPropertiesRef;
131 if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>needsPackProperties",
132 ":Lstd/core/Boolean;", &needsPackPropertiesRef))) {
133 IMAGE_LOGE("Object_CallMethodByName_Int Failed needsPackPropertiesRef:%{public}d", ret);
134 }
135 ani_boolean needsPackProperties;
136 if ((ret = env->Object_CallMethodByName_Boolean(reinterpret_cast<ani_object>(needsPackPropertiesRef),
137 "unboxed", ":Z", &needsPackProperties)) != ANI_OK) {
138 IMAGE_LOGE("Object_CallMethodByName_Int Failed needsPackProperties:%{public}d", ret);
139 }
140
141 packOpts.format = retStr;
142 packOpts.quality = static_cast<uint8_t>(quality);
143 outBufferSize = static_cast<uint32_t>(bufferSize);
144 return true;
145 }
146
nativePackingWithPixelMap(ani_env * env,ani_object obj,ani_object obj2,ani_object obj3)147 ani_arraybuffer nativePackingWithPixelMap([[maybe_unused]] ani_env* env,
148 [[maybe_unused]] ani_object obj, ani_object obj2, ani_object obj3)
149 {
150 ImagePacker* imgPacker = GetImagePackerFromAniEnv(env, obj);
151 if (!imgPacker) {
152 IMAGE_LOGE("nativePackingWithPixelMap isPacker null ");
153 return nullptr;
154 }
155 PixelMap* pixelmap = ImageAniUtils::GetPixelMapFromEnv(env, obj2);
156 if (!pixelmap) {
157 IMAGE_LOGE("nativePackingWithPixelMap pixelmap null ");
158 return nullptr;
159 }
160 ani_class optsClass;
161 env->FindClass("L@ohos/multimedia/image/image/PackingOption;", &optsClass);
162 ani_boolean isOpts;
163 env->Object_InstanceOf(obj3, optsClass, &isOpts);
164 if (!isOpts) {
165 IMAGE_LOGE("nativePackingWithPixelMap pixelmap null ");
166 return nullptr;
167 } else {
168 IMAGE_LOGE("nativePackingWithPixelMap opts sucess ");
169 }
170 PackOption packOpts;
171 uint32_t bufferSize = 0;
172 if (!ParsePackingOptions(env, obj3, packOpts, bufferSize)) {
173 IMAGE_LOGE("ParsePackingOptions failed ");
174 return nullptr;
175 }
176 std::unique_ptr<uint8_t[]> outBuffer = std::make_unique<uint8_t[]>(bufferSize);
177 uint8_t* data = outBuffer.get();
178 imgPacker->StartPacking(data, bufferSize, packOpts);
179 imgPacker->AddImage(*pixelmap);
180 int64_t packedSize = 0;
181 auto pacRes = imgPacker->FinalizePacking(packedSize);
182 if (pacRes) {
183 IMAGE_LOGE("FinalizePacking failed: %{public}d", pacRes);
184 return nullptr;
185 }
186 void* outData = static_cast<void*>(data);
187 ani_arraybuffer arrayBuffer;
188 env->CreateArrayBuffer(packedSize, &outData, &arrayBuffer);
189 return arrayBuffer;
190 }
191
Release(ani_env * env,ani_object obj)192 static void Release([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
193 {
194 ani_long nativeObj {};
195 bool ret;
196 if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
197 IMAGE_LOGE("[Release] Object_GetField_Long fetch field ret:%{public}d", ret);
198 return;
199 }
200 ImagePackerAni* imagePackerAni = reinterpret_cast<ImagePackerAni*>(nativeObj);
201 if (imagePackerAni == nullptr) {
202 IMAGE_LOGE("[Release] get ImagePackerAni failed");
203 return;
204 }
205 imagePackerAni->nativeImagePacker_ = nullptr;
206 }
207
Init(ani_env * env)208 ani_status ImagePackerAni::Init(ani_env* env)
209 {
210 static const char *className = "L@ohos/multimedia/image/image/ImagePackerInner;";
211 ani_class cls;
212 if (ANI_OK != env->FindClass(className, &cls)) {
213 IMAGE_LOGE("Not found L@ohos/multimedia/image/image/ImagePacker;");
214 return ANI_ERROR;
215 }
216 std::array methods = {
217 ani_native_function {"nativePackingWithPixelMap",
218 "L@ohos/multimedia/image/image/PixelMap;L@ohos/multimedia/image/image/PackingOption;"
219 ":Lescompat/ArrayBuffer;",
220 reinterpret_cast<void*>(OHOS::Media::nativePackingWithPixelMap)},
221 ani_native_function {"nativeRelease", ":V", reinterpret_cast<void*>(OHOS::Media::Release)},
222 };
223 ani_status ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
224 if (ANI_OK != ret) {
225 IMAGE_LOGE("[ImagePackerAni] Cannot bind native methods ret: %{public}d", ret);
226 return ANI_ERROR;
227 };
228 return ANI_OK;
229 }
230 } // Media
231 } // OHOS