• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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