• 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 #include "image_source_ani.h"
20 #include "pixel_map_ani.h"
21 #include "image_ani_utils.h"
22 #include "log_tags.h"
23 #include "media_errors.h"
24 #include "image_log.h"
25 #include "string_ex.h"
26 
27 #undef LOG_DOMAIN
28 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
29 
30 #undef LOG_TAG
31 #define LOG_TAG "ImageSourceAni"
32 
33 namespace OHOS {
34 namespace Media {
35 using namespace std;
36 
37 static const string FILE_URL_PREFIX = "file://";
38 
ANIUtils_ANIStringToStdString2(ani_env * env,ani_string ani_str)39 std::string ANIUtils_ANIStringToStdString2(ani_env *env, ani_string ani_str)
40 {
41     ani_size strSize;
42     env->String_GetUTF8Size(ani_str, &strSize);
43 
44     std::vector<char> buffer(strSize + 1); // +1 for null terminator
45     char* utfBuffer = buffer.data();
46 
47     ani_size bytes_written = 0;
48     if (ANI_OK != env->String_GetUTF8(ani_str, utfBuffer, strSize + 1, &bytes_written)) {
49         IMAGE_LOGE("ANIUtils_ANIStringToStdString fail");
50         return "";
51     }
52 
53     utfBuffer[bytes_written] = '\0';
54     std::string content = std::string(utfBuffer);
55     return content;
56 }
57 
FileUrlToRawPath(const string & path)58 static string FileUrlToRawPath(const string &path)
59 {
60     if (path.size() > FILE_URL_PREFIX.size() &&
61         (path.compare(0, FILE_URL_PREFIX.size(), FILE_URL_PREFIX) == 0)) {
62         return path.substr(FILE_URL_PREFIX.size());
63     }
64     return path;
65 }
66 
CreateImageSourceAni(ani_env * env,ani_object obj)67 ani_object ImageSourceAni::CreateImageSourceAni([[maybe_unused]] ani_env* env, ani_object obj)
68 {
69     std::unique_ptr<ImageSourceAni> pImageSourceAni = std::make_unique<ImageSourceAni>();
70     ani_class stringClass;
71     env->FindClass("Lstd/core/String;", &stringClass);
72     ani_boolean isString;
73     env->Object_InstanceOf(obj, stringClass, &isString);
74     if (isString) {
75         string fileUrl = ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(obj));
76         IMAGE_LOGI("Image source URI: %{public}s", fileUrl.c_str());
77         pImageSourceAni->filePath_ = FileUrlToRawPath(fileUrl);
78         SourceOptions opts;
79         uint32_t errorCode;
80         pImageSourceAni->nativeImageSource_ =
81             ImageSource::CreateImageSource(pImageSourceAni->filePath_, opts, errorCode);
82         if (pImageSourceAni->nativeImageSource_ == nullptr) {
83             IMAGE_LOGE("CreateImageSource failed'");
84         }
85     }
86 
87     ani_class arrayBufferClass;
88     env->FindClass("Lescompat/ArrayBuffer;", &arrayBufferClass);
89     ani_boolean isArrayBuffer;
90     env->Object_InstanceOf(obj, arrayBufferClass, &isArrayBuffer);
91     if (isArrayBuffer) {
92         ani_int length;
93         env->Object_CallMethodByName_Int(obj, "getByteLength", nullptr, &length);
94         IMAGE_LOGI("Object is ArraryBuffer Length: %{public}d", length);
95     }
96 
97     ani_class intClass;
98     env->FindClass("Lstd/core/Int;", &intClass);
99     ani_boolean isInt;
100     env->Object_InstanceOf(obj, intClass, &isInt);
101     if (isInt) {
102         ani_int fd;
103         env->Object_CallMethodByName_Int(obj, "unboxed", ":I", &fd);
104         IMAGE_LOGI("Image source fd: %{public}d", fd);
105         SourceOptions opts;
106         uint32_t errorCode;
107         pImageSourceAni->nativeImageSource_ = ImageSource::CreateImageSource(fd, opts, errorCode);
108     }
109 
110     if (pImageSourceAni->nativeImageSource_ == nullptr) {
111         IMAGE_LOGE("CreateImageSource failed'");
112     }
113 
114     return ImageAniUtils::CreateAniImageSource(env, pImageSourceAni);
115 }
116 
GetImageInfo(ani_env * env,ani_object obj,ani_int indexObj)117 static ani_object GetImageInfo([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj, ani_int indexObj)
118 {
119     ani_status ret;
120     IMAGE_LOGE("[GetImageInfo] Object_GetField_Long in");
121     ani_long nativeObj {};
122     if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
123         IMAGE_LOGE("[GetImageInfo] Object_GetField_Long fetch field");
124         return nullptr;
125     }
126     IMAGE_LOGE("[GetImageInfo] Object_GetField_Long sucess ");
127     ImageSourceAni* imageSourceAni = reinterpret_cast<ImageSourceAni*>(nativeObj);
128     int index = reinterpret_cast<int>(indexObj);
129     IMAGE_LOGE("[GetImageInfo] index: %{public}d", index);
130     ImageInfo imgInfo;
131     if (imageSourceAni != nullptr) {
132         IMAGE_LOGI("[GetImageInfo] get imageSourceAni success ");
133     } else {
134         IMAGE_LOGE("[GetImageInfo] imageSourceAni is nullptr ");
135         return nullptr;
136     }
137     return ImageAniUtils::CreateImageInfoValueFromNative(env, imgInfo, nullptr);
138 }
139 
parseEnumFromStruct(ani_env * env,ani_object & param,string propertyGet,string enumType)140 static ani_int parseEnumFromStruct(ani_env* env, ani_object &param, string propertyGet, string enumType)
141 {
142     ani_status ret;
143     ani_ref enumRef;
144     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(param, propertyGet.c_str(), enumType.c_str(), &enumRef))) {
145         IMAGE_LOGE("Object_CallMethodByName_Int enumRef Failed: %{public}d", ret);
146         return 0;
147     }
148     ani_boolean undefined;
149     env->Reference_IsUndefined(enumRef, &undefined);
150     if (undefined) {
151         IMAGE_LOGI("Enum %{public}s is undefined", propertyGet.c_str());
152         return 0;
153     }
154 
155     ani_int enumIndex;
156     if (ANI_OK != env->EnumItem_GetValue_Int(static_cast<ani_enum_item>(enumRef), &enumIndex)) {
157         IMAGE_LOGE("EnumItem_GetValue_Int enumIndex Failed: %{public}d", ret);
158         return 0;
159     }
160     return enumIndex;
161 }
162 
ParseRegion(ani_env * env,ani_object region,Rect & rect)163 static bool ParseRegion([[maybe_unused]] ani_env* env, ani_object region, Rect& rect)
164 {
165     ani_boolean undefined;
166     env->Reference_IsUndefined(region, &undefined);
167     if (undefined) {
168         IMAGE_LOGE("ParseRegion argument undefined");
169         return false;
170     }
171 
172     ani_ref size;
173     if (ANI_OK != env->Object_CallMethodByName_Ref(region, "<get>size", ":L@ohos/multimedia/image/image/Size;",
174         &size)) {
175         IMAGE_LOGE("Object_GetFieldByName_Ref Failed");
176         return false;
177     }
178     if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>width", ":I",
179         &rect.width)) {
180         IMAGE_LOGE("Object_CallMethodByName_Int width Failed");
181         return false;
182     }
183     if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>height", ":I",
184         &rect.height)) {
185         IMAGE_LOGE("Object_CallMethodByName_Int height Failed");
186         return false;
187     }
188 
189     if (ANI_OK != env->Object_CallMethodByName_Int(region, "<get>x", ":I", &rect.left)) {
190         IMAGE_LOGE("Object_CallMethodByName_Int x Failed");
191         return false;
192     }
193     if (ANI_OK != env->Object_CallMethodByName_Int(region, "<get>y", ":I", &rect.top)) {
194         IMAGE_LOGE("Object_CallMethodByName_Int y Failed");
195         return false;
196     }
197 
198     return true;
199 }
200 
ParseDecodingOptions2(ani_env * env,ani_object & param,DecodeOptions & opts)201 static bool ParseDecodingOptions2([[maybe_unused]] ani_env* env, ani_object &param, DecodeOptions &opts)
202 {
203     ani_status ret;
204     ani_ref size;
205     if (ANI_OK != env->Object_CallMethodByName_Ref(param, "<get>desiredSize",
206         ":L@ohos/multimedia/image/image/Size;", &size)) {
207         IMAGE_LOGE("Object_CallMethodByName_Ref size Faild");
208     }
209     if (ANI_OK != env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>width", ":I",
210         &opts.desiredSize.width)) {
211         IMAGE_LOGE("Object_CallMethodByName_Int width Faild");
212     }
213     if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(size), "<get>height", ":I",
214         &opts.desiredSize.height)) != ANI_OK) {
215         IMAGE_LOGE("Object_CallMethodByName_Int height Faild :%{public}d", ret);
216     }
217 
218     ani_ref regionRef;
219     if (ANI_OK != env->Object_CallMethodByName_Ref(param, "<get>desiredRegion",
220         ":L@ohos/multimedia/image/image/Region;", &regionRef)) {
221         IMAGE_LOGE("Object_CallMethodByName_Ref desiredRegion Faild");
222     }
223     if (!ParseRegion(env, static_cast<ani_object>(regionRef), opts.desiredRegion)) {
224         IMAGE_LOGE("Parse desiredRegion Faild");
225     }
226     opts.desiredPixelFormat = PixelFormat(parseEnumFromStruct(env, param, "<get>desiredPixelFormat",
227         ":L@ohos/multimedia/image/image/PixelMapFormat;"));
228     ani_ref fitDensityRef;
229     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(param,
230         "<get>fitDensity", ":Lstd/core/Int;", &fitDensityRef))) {
231         IMAGE_LOGE("Object_CallMethodByName_Ref Faild fitDensityRef:%{public}d", ret);
232     }
233     ani_int fitDensity;
234     if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(fitDensityRef),
235         "unboxed", ":I", &fitDensity)) != ANI_OK) {
236         IMAGE_LOGE("Object_CallMethodByName_Int Faild fitDensity:%{public}d", ret);
237     }
238     return true;
239 }
240 
ParseDecodingOptions(ani_env * env,ani_object para,DecodeOptions & opts)241 static bool ParseDecodingOptions([[maybe_unused]] ani_env* env, ani_object para, DecodeOptions &opts)
242 {
243     ani_boolean isUndefined;
244     ani_status ret;
245     ani_ref indexRef;
246     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>index", ":Lstd/core/Int;", &indexRef))) {
247         IMAGE_LOGE("Object_CallMethodByName_Ref Faild indexRef:%{public}d", ret);
248     }
249     env->Reference_IsUndefined(indexRef, &isUndefined);
250     if (!isUndefined) {
251         ani_int index;
252         if (env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(indexRef),
253             "unboxed", ":I", &index) != ANI_OK) {
254             IMAGE_LOGE("Object_CallMethodByName_Int Faild");
255         }
256     }
257 
258     ani_ref sampleRef;
259     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>sampleSize", ":Lstd/core/Int;", &sampleRef))) {
260         IMAGE_LOGE("Object_CallMethodByName_Ref Faild sampleRef:%{public}d", ret);
261     }
262     ani_int sample;
263     if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(sampleRef),
264         "unboxed", ":I", &sample)) != ANI_OK) {
265         IMAGE_LOGE("Object_CallMethodByName_Int Faild sample:%{public}d", ret);
266     }
267 
268     ani_ref rotateRef;
269     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>rotate", ":Lstd/core/Int;", &rotateRef))) {
270         IMAGE_LOGE("Object_CallMethodByName_Ref Faild rotateRef:%{public}d", ret);
271     }
272     ani_int rotate;
273     if ((ret = env->Object_CallMethodByName_Int(reinterpret_cast<ani_object>(rotateRef),
274         "unboxed", ":I", &rotate)) != ANI_OK) {
275         IMAGE_LOGE("Object_CallMethodByName_Int Faild rotate:%{public}d", ret);
276     }
277 
278     ani_ref editableRef;
279     if (ANI_OK != (ret = env->Object_CallMethodByName_Ref(para, "<get>editable", ":Lstd/core/Boolean;",
280         &editableRef))) {
281         IMAGE_LOGE("Object_CallMethodByName_Ref Faild editableRef:%{public}d", ret);
282     }
283     ani_boolean editable;
284     if ((ret = env->Object_CallMethodByName_Boolean(reinterpret_cast<ani_object>(editableRef),
285         "unboxed", ":Z", &editable)) != ANI_OK) {
286         IMAGE_LOGE("Object_CallMethodByName_Int Faild editable:%{public}d", ret);
287     }
288     opts.editable = static_cast<bool>(editable);
289 
290     if (!ParseDecodingOptions2(env, para, opts)) {
291         return false;
292     }
293 
294     return true;
295 }
296 
CreatePixelMap(ani_env * env,ani_object obj,ani_object para)297 static ani_object CreatePixelMap([[maybe_unused]] ani_env* env,
298     [[maybe_unused]] ani_object obj, [[maybe_unused]]ani_object para)
299 {
300     ani_status ret;
301     ani_long nativeObj {};
302     if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
303         IMAGE_LOGE("[CreatePixelMap] Object_GetField_Long fetch field ");
304         return nullptr;
305     }
306     ImageSourceAni* imageSourceAni = reinterpret_cast<ImageSourceAni*>(nativeObj);
307     ImageInfo imgInfo;
308     imgInfo.encodedFormat = "abcdefg";
309     if (imageSourceAni != nullptr) {
310     } else {
311         IMAGE_LOGE("[CreatePixelMap] imageSourceAni is nullptr");
312     }
313 
314     DecodeOptions opts;
315     ParseDecodingOptions(env, para, opts);
316 
317     return PixelMapAni::CreatePixelMap(env, std::make_shared<PixelMap>());
318 }
319 
ModifyImageProperty(ani_env * env,ani_object obj,ani_long longObj,ani_object key,ani_object value)320 static void ModifyImageProperty([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj,
321     ani_long longObj, ani_object key, ani_object value)
322 {
323     IMAGE_LOGE("ModifyImageProperty in ");
324     ani_status ret;
325     ani_long nativeObj {};
326     if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
327         IMAGE_LOGE("[ModifyImageProperty] Object_GetField_Long fetch field ");
328         return;
329     }
330     ImageSourceAni* imageSourceAni = reinterpret_cast<ImageSourceAni*>(nativeObj);
331     if (imageSourceAni == nullptr) {
332         IMAGE_LOGE("[ModifyImageProperty] get imageSourceAni failed");
333     }
334     IMAGE_LOGE("[ModifyImageProperty] get imageSourceAni success");
335 
336     ani_class stringClass;
337     env->FindClass("Lstd/core/String;", &stringClass);
338     ani_boolean isString;
339     env->Object_InstanceOf(key, stringClass, &isString);
340     std::string keyS = "";
341     if (isString) {
342         keyS = ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(key));
343     }
344     std::string valueS = ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(value));
345     IMAGE_LOGI("ModifyImageProperty get key:%{public}s value:%{public}s", keyS.c_str(), valueS.c_str());
346 }
347 
348 
349 template <typename F>
forEachMapEntry(ani_env * env,ani_object map_object,F && callback)350 static bool forEachMapEntry(ani_env *env, ani_object map_object, F &&callback)
351 {
352     ani_ref keys;
353     if (ANI_OK != env->Object_CallMethodByName_Ref(map_object, "keys", ":Lescompat/IterableIterator;", &keys)) {
354         IMAGE_LOGE("Failed to get keys iterator");
355         return false;
356     }
357 
358     bool success = true;
359     while (success) {
360         ani_ref next;
361         ani_boolean done;
362 
363         if (ANI_OK != env->Object_CallMethodByName_Ref(static_cast<ani_object>(keys), "next", nullptr, &next)) {
364             IMAGE_LOGE("Failed to get next key");
365             success = false;
366             break;
367         }
368 
369         if (ANI_OK != env->Object_GetFieldByName_Boolean(static_cast<ani_object>(next), "done", &done)) {
370             IMAGE_LOGE("Failed to check iterator done");
371             success = false;
372             break;
373         }
374         if (done) {
375             IMAGE_LOGE("[forEachMapEntry] done break");
376             break;
377         }
378 
379         ani_ref key_value;
380         if (ANI_OK != env->Object_GetFieldByName_Ref(static_cast<ani_object>(next), "value", &key_value)) {
381             IMAGE_LOGE("Failed to get key value");
382             success = false;
383             break;
384         }
385 
386         ani_ref value_obj;
387         if (ANI_OK != env->Object_CallMethodByName_Ref(map_object, "$_get", nullptr, &value_obj, key_value)) {
388             IMAGE_LOGE("Failed to get value for key");
389             success = false;
390             break;
391         }
392 
393         callback(key_value, value_obj);
394     }
395     return success;
396 }
397 
398 
399 class ANIIntanceHelper {
400 public:
401     ANIIntanceHelper() = default;
ANIIntanceHelper(ani_env * aniEnv)402     explicit ANIIntanceHelper(ani_env *aniEnv) { env = aniEnv; };
Init()403     bool Init()
404     {
405         if (ANI_OK != env->FindClass("Lstd/core/String;", &stringType)) {
406             IMAGE_LOGE("FindClass std/core/String failed");
407             return false;
408         }
409         if (ANI_OK != env->FindClass("Lescompat/Record;", &recordType)) {
410             IMAGE_LOGE("FindClass Lescompat/Record; failed");
411             return false;
412         }
413         if (ANI_OK != env->FindClass("Lstd/core/Numeric;", &numberType)) {
414             IMAGE_LOGE("Lstd/core/Numeric; failed");
415             return false;
416         }
417         inited = true;
418         return true;
419     }
isString(ani_object obj)420     bool isString(ani_object obj)
421     {
422         if (!inited) {
423             return false;
424         }
425         ani_boolean is_string;
426         if (ANI_OK != env->Object_InstanceOf(static_cast<ani_object>(obj),
427             static_cast<ani_type>(stringType), &is_string)) {
428             IMAGE_LOGE("Call Object_InstanceOf failed");
429             return false;
430         }
431         return (bool)is_string;
432     }
isRecord(ani_object obj)433     bool isRecord(ani_object obj)
434     {
435         if (!inited) {
436             return false;
437         }
438         ani_boolean is_record;
439         if (ANI_OK != env->Object_InstanceOf(static_cast<ani_object>(obj),
440             static_cast<ani_type>(recordType), &is_record)) {
441             IMAGE_LOGE("Call Object_InstanceOf failed");
442             return false;
443         }
444         return (bool)is_record;
445     }
isNumber(ani_object obj)446     bool isNumber(ani_object obj)
447     {
448         if (!inited) {
449             return false;
450         }
451         ani_boolean is_number;
452         if (ANI_OK != env->Object_InstanceOf(static_cast<ani_object>(obj),
453             static_cast<ani_type>(numberType), &is_number)) {
454             IMAGE_LOGE("Call Object_InstanceOf Fail");
455             return false;
456         }
457         return (bool)is_number;
458     }
isArray(ani_object obj)459     bool isArray(ani_object obj)
460     {
461         if (!inited) {
462             return false;
463         }
464         ani_size arrayLength;
465         if (ANI_OK !=
466             env->Array_GetLength(static_cast<ani_array>(obj), &arrayLength)) {
467             return false;
468         }
469         return true;
470     }
471 private:
472     ani_class stringType = nullptr;
473     ani_class recordType = nullptr;
474     ani_class numberType = nullptr;
475     ani_env *env;
476     bool inited = false;
477 };
478 
ProcMapEntry(ani_env * env,ani_ref key,ani_ref value,ImageSourceAni * imageSourceAni,ANIIntanceHelper & ih)479 bool ProcMapEntry(ani_env* env, ani_ref key, ani_ref value, ImageSourceAni* imageSourceAni, ANIIntanceHelper &ih)
480 {
481     auto imageSource = imageSourceAni->nativeImageSource_;
482     if (imageSource == nullptr) {
483         IMAGE_LOGE("[ProcMapEntry] imageSource nullptr");
484         return false;
485     }
486     if (!ih.isString(static_cast<ani_object>(key))) {
487         IMAGE_LOGE("[ProcMapEntry] key is not string");
488         return false;
489     }
490     auto keyStr = ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(key));
491     auto valueStr = ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(value));
492     IMAGE_LOGI("[ProcMapEntry] ProcMapEntry key:%{public}s value:%{public}s", keyStr.c_str(), valueStr.c_str());
493 
494     if (!IsSameTextStr(imageSourceAni->filePath_, "")) {
495         imageSource->ModifyImageProperty(0, keyStr, valueStr, imageSourceAni->filePath_);
496     } else if (imageSourceAni->fileDescriptor_ != -1) {
497         imageSource->ModifyImageProperty(0, keyStr, valueStr, imageSourceAni->fileDescriptor_);
498     } else {
499         IMAGE_LOGE("There is no image source!");
500         return false;
501     }
502     return true;
503 }
504 
ModifyImageProperties(ani_env * env,ani_object obj,ani_object recordsObj)505 static void ModifyImageProperties([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj, ani_object recordsObj)
506 {
507     ImageSourceAni* imageSourceAni = ImageAniUtils::GetImageSourceAniFromEnv(env, obj);
508     if (imageSourceAni == nullptr) {
509         IMAGE_LOGE("[GetImageSourceFromEnv] imageSource nullptr");
510         return;
511     }
512 
513     ANIIntanceHelper ih(env);
514     if (!ih.Init()) {
515         IMAGE_LOGE("[ModifyImageProperties] ih init fail");
516         return;
517     }
518 
519     forEachMapEntry(env, recordsObj,
520         [env, &imageSourceAni, &ih](ani_ref key, ani_ref value) -> bool {
521             return ProcMapEntry(env, key, value, imageSourceAni, ih);
522         });
523 }
524 
ParseArrayString(ani_env * env,ani_object arrayObj,std::vector<std::string> & strings)525 bool ParseArrayString([[maybe_unused]] ani_env* env, ani_object arrayObj, std::vector<std::string> &strings)
526 {
527     ani_double length;
528     if (ANI_OK != env->Object_GetPropertyByName_Double(arrayObj, "length", &length)) {
529         IMAGE_LOGE("Object_GetPropecortyByName_Double length Failed");
530         return false;
531     }
532     for (int i = 0; i < int(length); i++) {
533         ani_ref stringEntryRef;
534         if (ANI_OK != env->Object_CallMethodByName_Ref(arrayObj, "$_get",
535             "I:Lstd/core/Object;", &stringEntryRef, (ani_int)i)) {
536             IMAGE_LOGE("Object_GetPropertyByName_Double length Failed");
537             return false;
538         }
539         strings.emplace_back(ANIUtils_ANIStringToStdString2(env, static_cast<ani_string>(stringEntryRef)));
540     }
541     return true;
542 }
543 
GetImageProperties(ani_env * env,ani_object obj,ani_object arrayObj)544 static ani_object GetImageProperties([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj,
545     ani_object arrayObj)
546 {
547     auto imageSource = ImageAniUtils::GetImageSourceFromEnv(env, obj);
548     if (imageSource == nullptr) {
549         IMAGE_LOGE("[GetImageProperties] imageSource nullptr");
550         return nullptr;
551     }
552 
553     vector<string> keyStrArray;
554     ParseArrayString(env, arrayObj, keyStrArray);
555 
556     vector<pair<string, string>> kVStrArray;
557     uint32_t errCode = SUCCESS;
558     for (auto keyStrIt = keyStrArray.begin(); keyStrIt != keyStrArray.end(); ++keyStrIt) {
559         string valueStr = "";
560         errCode = imageSource->GetImagePropertyString(0, *keyStrIt, valueStr);
561         if (errCode == SUCCESS) {
562             kVStrArray.emplace_back(make_pair(*keyStrIt, valueStr));
563         } else {
564             kVStrArray.emplace_back(make_pair(*keyStrIt, ""));
565             IMAGE_LOGE("errCode: %{public}u , exif key: %{public}s", errCode, keyStrIt->c_str());
566         }
567     }
568 
569     ani_object argumentObj = {};
570     ani_method recordSetMethod = ImageAniUtils::GetRecordSetMethod(env, argumentObj);
571     if (recordSetMethod == nullptr) {
572         IMAGE_LOGE("[GetImageProperties] recordSetMethod nullptr");
573     }
574 
575     ani_status status;
576     for (auto iter = kVStrArray.begin(); iter != kVStrArray.end(); ++iter) {
577         string key = iter->first;
578         string value = iter->second;
579         ani_string ani_key;
580         ani_string ani_value;
581         status = env->String_NewUTF8(key.c_str(), key.length(), &ani_key);
582         if (status != ANI_OK) {
583             IMAGE_LOGE("String_NewUTF8 key failed status :%{public}u", status);
584             return nullptr;
585         }
586         status = env->String_NewUTF8(value.c_str(), value.length(), &ani_value);
587         if (status != ANI_OK) {
588             IMAGE_LOGE("String_NewUTF8 value failed status : %{public}u", status);
589             return nullptr;
590         }
591         status = env->Object_CallMethod_Void(argumentObj, recordSetMethod, ani_key, ani_value);
592         if (status != ANI_OK) {
593             IMAGE_LOGE("Object_CallMethod_Void value failed status : %{public}u", status);
594             return nullptr;
595         }
596     }
597     return argumentObj;
598 }
599 
Release(ani_env * env,ani_object obj)600 static void Release([[maybe_unused]] ani_env* env, [[maybe_unused]] ani_object obj)
601 {
602     ani_status ret;
603     ani_long nativeObj {};
604     if ((ret = env->Object_GetFieldByName_Long(obj, "nativeObj", &nativeObj)) != ANI_OK) {
605         IMAGE_LOGE("[Release] Object_GetField_Long fetch field ret:%{public}d", ret);
606         return;
607     }
608     ImageSourceAni* imageSourceAni = reinterpret_cast<ImageSourceAni*>(nativeObj);
609     imageSourceAni->nativeImageSource_ = nullptr;
610 }
611 
Init(ani_env * env)612 ani_status ImageSourceAni::Init(ani_env* env)
613 {
614     static const char *className = "L@ohos/multimedia/image/image/ImageSourceInner;";
615     ani_class cls;
616     if (ANI_OK != env->FindClass(className, &cls)) {
617         IMAGE_LOGE("Not found ");
618         return ANI_ERROR;
619     }
620     std::array methods = {
621         ani_native_function {"nativeGetImageInfo", "I:L@ohos/multimedia/image/image/ImageInfo;",
622             reinterpret_cast<void*>(OHOS::Media::GetImageInfo)},
623         ani_native_function {"nativeCreatePixelMap",
624             "L@ohos/multimedia/image/image/DecodingOptions;:L@ohos/multimedia/image/image/PixelMap;",
625             reinterpret_cast<void*>(OHOS::Media::CreatePixelMap)},
626         ani_native_function {"modifyImageProperty", "JLstd/core/String;Lstd/core/String;:V",
627             reinterpret_cast<void*>(OHOS::Media::ModifyImageProperty)},
628         ani_native_function {"nativeModifyImageProperties", "Lescompat/Record;:V",
629             reinterpret_cast<void*>(OHOS::Media::ModifyImageProperties)},
630         ani_native_function {"nativeGetImageProperties", "Lescompat/Array;:Lescompat/Record;",
631             reinterpret_cast<void*>(OHOS::Media::GetImageProperties)},
632         ani_native_function {"release", ":V", reinterpret_cast<void *>(OHOS::Media::Release)},
633     };
634     ani_status ret = env->Class_BindNativeMethods(cls, methods.data(), methods.size());
635     if (ANI_OK != ret) {
636         IMAGE_LOGE("[ImageSourceAni] Cannot bind native methods ret: %{public}d", ret);
637         return ANI_ERROR;
638     };
639     return ANI_OK;
640 }
641 } // Media
642 } // OHOS
643