1 /*
2 * Copyright (c) 2024 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_edit.h"
17 #include <map>
18 #include <bits/alltypes.h>
19
20 #include <multimedia/image_effect/image_effect.h>
21 #include <multimedia/image_framework/image_pixel_map_mdk.h>
22 #include "logging.h"
23 #include "utils/common_utils.h"
24 #include "utils/pixelmap_helper.h"
25
26 struct FilterArrayData {
27 std::string name;
28 int value;
29 };
30
31 struct PixelmapInfo {
32 uint32_t width = 0;
33 uint32_t height = 0;
34 int32_t format = PIXEL_FORMAT::PIXEL_FORMAT_UNKNOWN;
35 uint32_t rowStride = 0;
36 };
37
38 static ImageEffect_FilterDelegate delegate;
39
40 std::vector<std::vector<FilterArrayData>> GetFilters(napi_env env, napi_value arg);
41
42 OH_EffectFilter *AddFilter(OH_ImageEffect *imageEffect, const char *filterName);
43 napi_value SetFilterValue(OH_EffectFilter *filter, const char *filterName, float filterValue,
44 OH_PixelmapNative *pixelmap);
45
46 const double PI = 3.14159265;
47
48 constexpr int EXPECTED_ARGS_ZERO = 0;
49 constexpr int EXPECTED_ARGS_ONE = 1;
50 constexpr int EXPECTED_ARGS_TWO = 2;
51
52 constexpr int AREA_INFO_ZERO = 0;
53 constexpr int AREA_INFO_ONE = 1;
54 constexpr int AREA_INFO_TWO = 2;
55 constexpr int AREA_INFO_THREE = 3;
56
57 constexpr int RGB_IDX_ONE = 1;
58 constexpr int RGB_IDX_TWO = 2;
59 constexpr int RGB_IDX_THREE = 3;
60
61 constexpr int EXPECTED_CONSTANT_THREE = 3;
62 constexpr int EXPECTED_CONSTANT_FOUR = 4;
63 constexpr int EXPECTED_LUT_SIZE_LIMIT = 256;
64
65 const int LUT_CYCLE_SIZE = 256;
66
Apply(napi_env env,napi_callback_info info)67 napi_value ImageEdit::Apply(napi_env env, napi_callback_info info)
68 {
69 napi_value result = nullptr;
70 napi_get_undefined(env, &result);
71
72 size_t argc = EXPECTED_ARGS_TWO;
73 napi_value args[EXPECTED_ARGS_TWO] = {nullptr};
74 napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
75 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
76
77 std::string path = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
78 std::vector<std::vector<FilterArrayData>> filters = GetFilters(env, args[EXPECTED_ARGS_ONE]);
79
80 OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit");
81 CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!");
82 std::shared_ptr<OH_ImageEffect> imageEffectPtr(imageEffect, [](OH_ImageEffect *imageEffect) {
83 OH_ImageEffect_Release(imageEffect);
84 });
85
86 std::shared_ptr<OH_PixelmapNative> pixelmapNativePtr = PixelMapHelper::Decode(path);
87 CHECK_AND_RETURN_RET_LOG(pixelmapNativePtr != nullptr, result, "Decode path fail! path=%{public}s", path.c_str());
88
89 for (int i = 0; i < filters.size(); i++) {
90 OH_EffectFilter *filter = AddFilter(imageEffectPtr.get(), filters[i][0].name.c_str());
91 CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!");
92 SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, pixelmapNativePtr.get());
93 }
94
95 ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetInputPixelmap(imageEffectPtr.get(), pixelmapNativePtr.get());
96 CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
97 "OH_ImageEffect_SetInputPixelMap fail! errorCode = %{public}d", errorCode);
98
99 errorCode = OH_ImageEffect_Start(imageEffectPtr.get());
100 CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
101 "OH_ImageEffect_Start fail! errorCode = %{public}d", errorCode);
102
103 bool encodeRes = PixelMapHelper::Encode(pixelmapNativePtr.get(), path);
104 CHECK_AND_RETURN_RET_LOG(encodeRes, result, "Encode path fail! path=%{public}s", path.c_str());
105
106 return result;
107 }
108
AddFilter(OH_ImageEffect * imageEffect,const char * filterName)109 OH_EffectFilter *AddFilter(OH_ImageEffect *imageEffect, const char *filterName)
110 {
111 OH_EffectFilter *filter = OH_ImageEffect_AddFilter(imageEffect, filterName);
112 CHECK_AND_RETURN_RET_LOG(filter != nullptr, filter, "OH_ImageEffect_AddFilter fail!");
113 return filter;
114 }
115
GetPixelmapInfo(OH_PixelmapNative * pixelmap)116 PixelmapInfo GetPixelmapInfo(OH_PixelmapNative *pixelmap)
117 {
118 OH_Pixelmap_ImageInfo *imageInfo = nullptr;
119 OH_PixelmapImageInfo_Create(&imageInfo);
120 OH_PixelmapNative_GetImageInfo(pixelmap, imageInfo);
121 PixelmapInfo info;
122 OH_PixelmapImageInfo_GetWidth(imageInfo, &info.width);
123 OH_PixelmapImageInfo_GetHeight(imageInfo, &info.height);
124 OH_PixelmapImageInfo_GetPixelFormat(imageInfo, &info.format);
125 OH_PixelmapImageInfo_GetRowStride(imageInfo, &info.rowStride);
126 OH_PixelmapImageInfo_Release(imageInfo);
127
128 return info;
129 }
130
SetFilterValue(OH_EffectFilter * filter,const char * filterName,float filterValue,OH_PixelmapNative * pixelmap)131 napi_value SetFilterValue(OH_EffectFilter *filter, const char *filterName, float filterValue,
132 OH_PixelmapNative *pixelmap)
133 {
134 napi_value result;
135 ImageEffect_Any value;
136 std::string key;
137
138 if (strcmp(filterName, OH_EFFECT_CROP_FILTER) == 0) {
139 PixelmapInfo pixelMapInfo = GetPixelmapInfo(pixelmap);
140 uint32_t *areaInfo = new uint32_t[4];
141 CHECK_AND_RETURN_RET_LOG(areaInfo, result, "areaInfo fail!");
142 areaInfo[AREA_INFO_ZERO] = pixelMapInfo.width / 100.f * (100.f - static_cast<int>(filterValue));
143 areaInfo[AREA_INFO_ONE] = pixelMapInfo.height / 100.f * (100.f - static_cast<int>(filterValue));
144 areaInfo[AREA_INFO_TWO] = pixelMapInfo.width;
145 areaInfo[AREA_INFO_THREE] = pixelMapInfo.height;
146 value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_PTR;
147 value.dataValue.ptrValue = areaInfo;
148 key = OH_EFFECT_FILTER_REGION_KEY;
149 } else if (strcmp(filterName, "CustomBrightness") == 0) {
150 value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
151 value.dataValue.floatValue = filterValue;
152 key = "brightness";
153 } else {
154 value.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT;
155 value.dataValue.floatValue = filterValue;
156 key = OH_EFFECT_FILTER_INTENSITY_KEY;
157 }
158
159 ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, key.c_str(), &value);
160 CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, nullptr,
161 "OH_EffectFilter_SetValue fail! errorCode = %{public}d", errorCode);
162 return result;
163 }
164
GetNapiArrayLength(napi_env env,napi_value element)165 std::pair<napi_status, uint32_t> GetNapiArrayLength(napi_env env, napi_value element)
166 {
167 uint32_t length = 0;
168 napi_status status = napi_get_array_length(env, element, &length);
169 return std::make_pair(status, length);
170 }
171
HandleStringType(napi_env env,napi_value childElement,napi_status & status)172 std::string HandleStringType(napi_env env, napi_value childElement, napi_status &status)
173 {
174 std::string name;
175
176 size_t bufferLength = 0;
177 status = napi_get_value_string_utf8(env, childElement, nullptr, 0, &bufferLength);
178 CHECK_AND_RETURN_RET_LOG(status == napi_ok && bufferLength > 0, name,
179 "GetFilters napi_get_value_string_utf8 fail! status = %{public}d", status);
180 char *buffer = nullptr;
181 buffer = reinterpret_cast<char *>(malloc((bufferLength + 1) * sizeof(char)));
182 status = napi_get_value_string_utf8(env, childElement, buffer, bufferLength + 1, &bufferLength);
183 if (status == napi_ok) {
184 name = buffer;
185 }
186 free(buffer);
187 return name;
188 }
189
HandleNumberType(napi_env env,napi_value childElement,napi_status & status)190 int HandleNumberType(napi_env env, napi_value childElement, napi_status &status)
191 {
192 int32_t result = 0;
193 status = napi_get_value_int32(env, childElement, &result);
194 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "GetFilters napi_get_value_int32 fail! status = %{public}d",
195 status);
196 return result;
197 }
198
GetFilters(napi_env env,napi_value arg)199 std::vector<std::vector<FilterArrayData>> GetFilters(napi_env env, napi_value arg)
200 {
201 std::vector<std::vector<FilterArrayData>> data;
202 napi_status status;
203
204 bool is_array;
205 status = napi_is_array(env, arg, &is_array);
206 CHECK_AND_RETURN_RET_LOG(is_array == true, data, "GetFilters napi_is_array fail! status=%{public}d", status);
207
208 // Handle napi array length
209 auto array_length = GetNapiArrayLength(env, arg);
210 CHECK_AND_RETURN_RET_LOG(array_length.first == napi_ok, data,
211 "GetFilters napi_get_array_length fail! status=%{public}d", array_length.first);
212
213 for (uint32_t i = 0; i < array_length.second; i++) {
214 napi_value element;
215 status = napi_get_element(env, arg, i, &element);
216 CHECK_AND_RETURN_RET_LOG(status == napi_ok, data, "GetFilters napi_get_element fail! status=%{public}d",
217 status);
218
219 auto child_length = GetNapiArrayLength(env, element);
220 CHECK_AND_RETURN_RET_LOG(child_length.first == napi_ok, data,
221 "GetFilters child napi_get_array_length fail! status=%{public}d", child_length.first);
222
223 std::vector<FilterArrayData> row;
224 FilterArrayData filterArrayData;
225 for (uint32_t j = 0; j < child_length.second; j++) {
226 napi_value childElement;
227 status = napi_get_element(env, element, j, &childElement);
228
229 napi_valuetype valueType;
230 status = napi_typeof(env, childElement, &valueType);
231 CHECK_AND_RETURN_RET_LOG(status == napi_ok, data,
232 "GetFilters child napi_typeof fail! status=%{public}d, value=%{public}d", status, valueType);
233
234 if (valueType == napi_string) {
235 filterArrayData.name = HandleStringType(env, childElement, status);
236 } else if (valueType == napi_number) {
237 filterArrayData.value = HandleNumberType(env, childElement, status);
238 }
239 }
240 row.push_back(filterArrayData);
241 data.push_back(row);
242 }
243
244 return data;
245 }
246
LookupFilterInfo(napi_env env,napi_callback_info info)247 napi_value ImageEdit::LookupFilterInfo(napi_env env, napi_callback_info info)
248 {
249 napi_value result = nullptr;
250 napi_get_undefined(env, &result);
251 size_t argc = EXPECTED_ARGS_ONE;
252 napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
253 napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
254 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
255 std::string filterName = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
256
257 OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create();
258 // 示例代码: 传入nullptr的format, 获取OH_Formats的size
259 ImageEffect_ErrorCode errorCode = OH_EffectFilter_LookupFilterInfo(filterName.c_str(), effectInfo);
260 CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
261 "OH_EffectFilter_LookupFilterInfo fail! errorCode = %{public}d", errorCode);
262
263 char *name = nullptr;
264 OH_EffectFilterInfo_GetFilterName(effectInfo, &name);
265
266 uint32_t supportedBufferTypesCount = 0;
267 ImageEffect_BufferType *bufferTypeArray = nullptr;
268 OH_EffectFilterInfo_GetSupportedBufferTypes(effectInfo, &supportedBufferTypesCount, &bufferTypeArray);
269
270 uint32_t supportedFormatsCount = 0;
271 ImageEffect_Format *formatArray = nullptr;
272 OH_EffectFilterInfo_GetSupportedFormats(effectInfo, &supportedFormatsCount, &formatArray);
273
274 LOG_I("LookupFilterInfo: name=%{public}s, bufferTypesCount=%{public}d, formatsCount=%{public}d", name,
275 supportedBufferTypesCount, supportedFormatsCount);
276
277 std::string infoStr = CommonUtils::EffectInfoToString(effectInfo);
278 LOG_I("LookupFilterInfo:%{public}s", infoStr.c_str());
279 status = napi_create_string_utf8(env, infoStr.c_str(), strlen(infoStr.c_str()), &result);
280 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_create_string_utf8 fail!");
281
282 OH_EffectFilterInfo_Release(effectInfo);
283 return result;
284 }
285
RegisterCustomBrightness()286 napi_value ImageEdit::RegisterCustomBrightness()
287 {
288 napi_value result = nullptr;
289 // 自定义算子能力信息
290 OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create();
291 OH_EffectFilterInfo_SetFilterName(effectInfo, "CustomBrightness");
292 ImageEffect_BufferType bufferType = ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL;
293 OH_EffectFilterInfo_SetSupportedBufferTypes(effectInfo, 1, &bufferType);
294 ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888;
295 OH_EffectFilterInfo_SetSupportedFormats(effectInfo, 1, &format);
296 // 自定义算子实现接口
297 delegate = {
298 .setValue = [](OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value) { return true; },
299 .render = [](OH_EffectFilter *filter, OH_EffectBufferInfo *src,
300 OH_EffectFilterDelegate_PushData pushData) { return true; },
301 .save = [](OH_EffectFilter *filter, char **info) { return true; },
302 .restore = [](const char *info) { return OH_EffectFilter_Create("CustomBrightness"); }};
303 ImageEffect_ErrorCode errorCode = OH_EffectFilter_Register(effectInfo, &delegate);
304 CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result,
305 "OH_EffectFilter_Register fail! errorCode = %{public}d", errorCode);
306 return result;
307 }
308
LookupFilters(napi_env env,napi_callback_info info)309 napi_value ImageEdit::LookupFilters(napi_env env, napi_callback_info info)
310 {
311 napi_value result = nullptr;
312 napi_get_undefined(env, &result);
313 size_t argc = EXPECTED_ARGS_ONE;
314 napi_value args[EXPECTED_ARGS_ONE] = {nullptr};
315 napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
316 CHECK_AND_RETURN_RET_LOG(status == napi_ok, result, "napi_get_cb_info fail! status = %{public}d", status);
317 const char *key = CommonUtils::GetStringArgument(env, args[EXPECTED_ARGS_ZERO]);
318
319 ImageEffect_FilterNames *filterNames = OH_EffectFilter_LookupFilters(key);
320 CHECK_AND_RETURN_RET_LOG(filterNames != nullptr, result, "OH_EffectFilter_LookupFilters fail!");
321
322 std::string res = "size: " + std::to_string(filterNames->size) + std::string(", name: ");
323 for (int i = 0; i < filterNames->size; i++) {
324 res += filterNames->nameList[i];
325 if (i < filterNames->size - 1) {
326 res += " | ";
327 }
328 }
329 status = napi_create_string_utf8(env, res.c_str(), res.size(), &result);
330 return result;
331 }