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