1# 使用ImageEffect编辑图片 2<!--Kit: Image Kit--> 3<!--Subsystem: Multimedia--> 4<!--Owner: @zyj208--> 5<!--Designer: @wangshoucheng--> 6<!--Tester: @gengfei--> 7<!--Adviser: @zengyawen--> 8## 场景介绍 9 10ImageEffect提供了一系列接口用于图像的编辑。开发者可以通过`ImageEffect`接口处理不同图像输入类型`Pixelmap`、`NativeWindow`、`NativeBuffer`或`Uri`,获得滤镜处理效果。 11针对ImageEffect,常见的开发场景如下: 12 13- 通过`ImageEffect`提供的Native API接口添加滤镜或滤镜链,设置输入图像,最终生效滤镜效果。 14- 通过注册自定义滤镜,实现开发者的定制化滤镜效果。 15- 通过`EffectFilter`提供的Native API接口快速实现单个滤镜的处理效果。 16 17## 接口说明 18 19详细的接口说明请参考[ImageEffect](../../reference/apis-image-kit/capi-imageeffect.md)。 20 21## 开发步骤 22 23**添加动态链接库** 24 25CMakeLists.txt中添加以下lib。 26 27```txt 28target_link_libraries(entry PUBLIC 29 libace_ndk.z.so 30 libimage_effect.so 31 libpixelmap.so 32 libnative_window.so 33 libnative_buffer.so 34) 35``` 36 37根据处理的图像类型添加对应动态链接库:`Pixelmap`(libpixelmap.so)、`NativeWindow`(libnative_window.so)、`NativeBuffer`(libnative_buffer.so) 38 39**添加头文件** 40 41```c++ 42#include <hilog/log.h> 43#include <multimedia/image_effect/image_effect.h> 44#include <multimedia/image_effect/image_effect_filter.h> 45#include <multimedia/image_effect/image_effect_errors.h> 46``` 47 48### 通过ImageEffect提供的接口生效图像效果 49 501. 创建ImageEffect实例。 51 52 ```c++ 53 // 创建imageEffect实例,“ImageEdit”是imageEffect实例别名。 54 OH_ImageEffect *imageEffect = OH_ImageEffect_Create("ImageEdit"); 55 ``` 56 572. 添加EffectFilter滤镜。 58 59 ```c++ 60 // 添加滤镜,获取 OH_EffectFilter 实例。多次调用该接口可以添加多个滤镜,组成滤镜链。 61 OH_EffectFilter *filter = OH_ImageEffect_AddFilter(imageEffect, OH_EFFECT_BRIGHTNESS_FILTER); 62 if (filter == nullptr) { 63 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_AddFilter fail!"); 64 return; 65 } 66 67 // 设置滤镜参数, 例如:滤镜强度设置为50。 68 ImageEffect_Any value = { .dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT, .dataValue.floatValue = 50.f }; 69 ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, OH_EFFECT_FILTER_INTENSITY_KEY, &value); 70 ``` 71 723. 设置处理数据。 73 74 **场景一:设置OH_PixelmapNative输入类型。** 75 76 OH_PixelmapNative的具体使用方法请参考[Pixelmap开发指导](image-pixelmap-operation-native.md)。 77 78 ```c++ 79 // 设置输入的Pixelmap。 80 errorCode = OH_ImageEffect_SetInputPixelmap(imageEffect, inputPixelmap); 81 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 82 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetInputPixelmap fail!"); 83 return; 84 } 85 86 // 设置输出的Pixelmap(可选),不调用该接口时会在输入Pixelmap上直接生效滤镜效果。 87 errorCode = OH_ImageEffect_SetOutputPixelmap(imageEffect, outputPixelmap); 88 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 89 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetOutputPixelmap fail!"); 90 return; 91 } 92 ``` 93 94 **场景二:设置OH_NativeBuffer输入类型。** 95 96 OH_NativeBuffer的具体使用方法请参考[NativeBuffer开发指导](../../graphics/native-buffer-guidelines.md)。 97 98 ```c++ 99 // 设置输入的NativeBuffer。 100 errorCode = OH_ImageEffect_SetInputNativeBuffer(imageEffect, inputNativeBuffer); 101 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 102 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetInputNativeBuffer fail!"); 103 return; 104 } 105 106 // 设置输出的NativeBuffer(可选),不调用该接口时会在输入NativeBuffer上直接生效滤镜效果。 107 errorCode = OH_ImageEffect_SetOutputNativeBuffer(imageEffect, outputNativeBuffer); 108 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 109 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetOutputNativeBuffer fail!"); 110 return; 111 } 112 ``` 113 114 **场景三:设置URI输入类型。** 115 116 ```c++ 117 // 设置输入的URI。 118 errorCode = OH_ImageEffect_SetInputUri(imageEffect, inputUri); 119 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 120 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetInputUri fail!"); 121 return; 122 } 123 124 // 设置输出的URI(可选),不调用该接口时会在输入URI上直接生效滤镜效果。 125 errorCode = OH_ImageEffect_SetOutputUri(imageEffect, outputUri); 126 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 127 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetOutputUri fail!"); 128 return; 129 } 130 ``` 131 **场景四:设置纹理输入类型。** 132 133 纹理输入场景是使用硬件GPU渲染的高性能场景,此场景下,应用需要提供合法的OpenGL上下文环境,并在正确的环境下,设置参数以及进行渲染操作。 134 ```c++ 135 // 设置输入的纹理ID。 136 errorCode = OH_ImageEffect_SetInputTextureId(imageEffect, inputTex, ColorSpaceName::SRGB); 137 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 138 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetInputTextureId fail!"); 139 return; 140 } 141 142 // 设置输出的纹理ID, 注意不能与输入是同一块纹理,否则可能产生渲染异常。 143 errorCode = OH_ImageEffect_SetOutputTextureId(imageEffect, outputTex); 144 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 145 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetOutputTextureId fail!"); 146 return; 147 } 148 ``` 149 150 **场景五:设置OHNativeWindow输入类型。** 151 152 以相机预览场景为例来说明OHNativeWindow输入场景。XComponent组件为相机预览流提供的SurfaceId,可在native c++层将SurfaceId转换成OHNativeWindow,下面提供一份代码示例。 153 XComponent模块的具体使用方法请参考[XComponent组件参考](../../reference/apis-arkui/arkui-ts/ts-basic-components-xcomponent.md)。 154 NativeWindow模块的具体使用方法请参考[OHNativeWindow](../../reference/apis-arkgraphics2d/capi-nativewindow.md)。 155 Camera的具体使用方法请参考[Camera预览参考](../camera/native-camera-preview.md)。 156 157 (1) 在xxx.ets中添加一个XComponent组件。 158 159 ```ts 160 XComponent({ 161 id: 'xcomponentId', 162 type: 'surface', 163 controller: this.mXComponentController, 164 libraryname: 'entry' 165 }) 166 .onLoad(() => { 167 // 获取XComponent的SurfaceId。 168 this.mSurfaceId = this.mXComponentController.getXComponentSurfaceId() 169 170 // 调用native接口获取输入SurfaceId。 171 this.mSurfaceId = imageEffect.getSurfaceId(this.mSurfaceId) 172 173 // 调用相机接口启动预览,将获取到的输入SurfaceId传递给相机框架。 174 // ... 175 }) 176 .width('100%') 177 .height('100%') 178 ``` 179 180 (2) imageEffect.getSurfaceId的native c++层具体实现。 181 182 ```c++ 183 // 根据SurfaceId创建NativeWindow,注意创建出来的NativeWindow在使用结束后需要主动调用OH_NativeWindow_DestoryNativeWindow进行释放。 184 uint64_t outputSurfaceId; 185 std::istrstream iss(outputSurfaceIdStr); 186 issue >> outputSurfaceId; 187 OHNativeWindow *outputNativeWindow = nullptr; 188 int32_t res = OH_NativeWindow_CreateNativeWindowFromSurfaceId(outputSurfaceId, &outputNativeWindow); 189 CHECK_AND_RETURN_LOG(res == 0, "OH_NativeWindow_CreateNativeWindowFromSurfaceId fail!"); 190 191 // 设置输出显示的Surface。 192 ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetOutputSurface(imageEffect, outputNativeWindow); 193 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 194 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_SetOutputSurface fail!"); 195 return; 196 } 197 198 // 获取输入的Surface。注意获取的inputNativeWindow在使用结束后需要主动调用OH_NativeWindow_DestoryNativeWindow进行释放。 199 OHNativeWindow *inputNativeWindow = nullptr; 200 errorCode = OH_ImageEffect_GetInputSurface(imageEffect, &inputNativeWindow); 201 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 202 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_GetInputSurface fail!"); 203 return; 204 } 205 206 // 从获取到输入的NativeWindow中获取SurfaceId。 207 uint64_t inputSurfaceId = 0; 208 res = OH_NativeWindow_GetSurfaceId(inputNativeWindow, &inputSurfaceId); 209 if (res != 0) { 210 OH_LOG_ERROR(LOG_APP, "OH_NativeWindow_GetSurfaceId fail!"); 211 return; 212 } 213 214 // 将SurfaceId转成字符串进行返回。 215 std::string inputSurfaceIdStr = std::to_string(inputSurfaceId); 216 ``` 217 2184. 启动效果器。 219 220 ```c++ 221 // 执行生效滤镜效果。 222 errorCode = OH_ImageEffect_Start(imageEffect); 223 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 224 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_Start fail!"); 225 return; 226 } 227 ``` 228 2295. 停止生效效果(可选,仅在输入Surface场景下才有效)。 230 231 ```c++ 232 // 停止生效滤镜效果。 233 errorCode = OH_ImageEffect_Stop(imageEffect); 234 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 235 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_Stop fail!"); 236 return; 237 } 238 ``` 239 2406. 序列化效果器(可选)。 241 242 ```c++ 243 char *info = nullptr; 244 errorCode = OH_ImageEffect_Save(imageEffect, &info); 245 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 246 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_Save fail!"); 247 return; 248 } 249 ``` 250 2517. 销毁效果器实例。 252 253 ```c++ 254 // 释放imageEffect实例资源。 255 errorCode = OH_ImageEffect_Release(imageEffect); 256 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 257 OH_LOG_ERROR(LOG_APP, "OH_ImageEffect_Release fail!"); 258 return; 259 } 260 ``` 261 262### 自定义滤镜 263 264以下步骤描述了如何实现并注册自定义滤镜接口: 265 2661. 定义 ImageEffect_FilterDelegate。 267 268 ```c++ 269 // 图像信息结构体。 270 struct EffectBufferInfo { 271 void *addr = nullptr; 272 int32_t width = 0; 273 int32_t height = 0; 274 int32_t rowSize = 0; 275 ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_UNKNOWN; 276 }; 277 278 // 自定义滤镜具体实现。 279 ImageEffect_FilterDelegate filterDelegate = { 280 .setValue = [](OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value) { 281 // 参数校验,校验成功时返回true,否则返回false。 282 // ... 283 return true; 284 }, 285 .render = [](OH_EffectFilter *filter, OH_EffectBufferInfo *info, OH_EffectFilterDelegate_PushData pushData) { 286 return Render(filter, info, pushData); 287 }, 288 .save = [](OH_EffectFilter *filter, char **info) { 289 // 获取自定义所设置的滤镜参数,其中"Brightness"为自定义滤镜的Key,由开发者自己任意指定。 290 ImageEffect_Any value; 291 ImageEffect_ErrorCode errorCode = OH_EffectFilter_GetValue(filter, "Brightness", &value); 292 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 293 OH_LOG_ERROR(LOG_APP, "OH_EffectFilter_GetValue fail!"); 294 return; 295 } 296 297 // 生成键值对信息。 298 json values; 299 values["Brightness"] = value.dataValue.floatValue; 300 json root; 301 root["name"] = "CustomBrightness"; 302 root["values"] = values; 303 304 // 将json对象转成字符串infoStr。 305 // ... 306 307 // 对*info赋值序列化字符串地址。 308 *info = infoStr; 309 return true; 310 }, 311 .restore = [](const char *info) { 312 // 创建 OH_EffectFilter 实例,其中"CustomBrightness"为自定义滤镜的滤镜名。 313 OH_EffectFilter *filter = OH_EffectFilter_Create("CustomBrightness"); 314 // 解析json字符串info获取key和value。 315 // ... 316 317 // 设置滤镜参数, value为info中按json解析出来的参数。 318 ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, "Brightness", &value); 319 320 // ... 321 return filter; 322 } 323 }; 324 ``` 325 326 其中Render接口的实现分两种场景。 327 328 **场景一:自定义算法可以直接修改info中的像素数据(比如:亮度调节滤镜)。** 329 330 ```c++ 331 bool Render(OH_EffectFilter *filter, OH_EffectBufferInfo *info, OH_EffectFilterDelegate_PushData pushData) 332 { 333 // 获取图像信息具体参数。 334 EffectBufferInfo inputBufferInfo; 335 OH_EffectBufferInfo_GetAddr(info, &inputBufferInfo.addr); 336 OH_EffectBufferInfo_GetWidth(info, &inputBufferInfo.width); 337 OH_EffectBufferInfo_GetHeight(info, &inputBufferInfo.height); 338 OH_EffectBufferInfo_GetRowSize(info, &inputBufferInfo.rowSize); 339 OH_EffectBufferInfo_GetEffectFormat(info, &inputBufferInfo.format); 340 341 // 调用自定义滤镜算法。 342 ApplyCustomAlgo(inputBufferInfo); 343 344 // 编辑完成后调用pushData直接传递原图。 345 pushData(filter, info); 346 return true; 347 } 348 ``` 349 350 **场景二:自定义算法不能直接修改info中的像素数据(比如:裁剪滤镜)。** 351 352 ```c++ 353 bool Render(OH_EffectFilter *filter, OH_EffectBufferInfo *info, OH_EffectFilterDelegate_PushData pushData) 354 { 355 // 获取图像信息具体参数。 356 EffectBufferInfo inputBufferInfo; 357 OH_EffectBufferInfo_GetAddr(info, &inputBufferInfo.addr); 358 OH_EffectBufferInfo_GetWidth(info, &inputBufferInfo.width); 359 OH_EffectBufferInfo_GetHeight(info, &inputBufferInfo.height); 360 OH_EffectBufferInfo_GetRowSize(info, &inputBufferInfo.rowSize); 361 OH_EffectBufferInfo_GetEffectFormat(info, &inputBufferInfo.format); 362 363 // 创建输出像素信息。 364 EffectBufferInfo outputBufferInfo = CreateOutputBufferInfo(inputBufferInfo); 365 366 // 调用自定义滤镜算法。 367 ApplyCustomAlgo(inputBufferInfo, outputBufferInfo); 368 369 // 生成outputOhInfo。 370 OH_EffectBufferInfo *outputOhInfo = OH_EffectBufferInfo_Create(); 371 OH_EffectBufferInfo_SetAddr(outputOhInfo, outputBufferInfo.addr); 372 OH_EffectBufferInfo_SetWidth(outputOhInfo, outputBufferInfo.width); 373 OH_EffectBufferInfo_SetHeight(outputOhInfo, outputBufferInfo.height); 374 OH_EffectBufferInfo_SetRowSize(outputOhInfo, outputBufferInfo.rowSize); 375 OH_EffectBufferInfo_SetEffectFormat(outputOhInfo, outputBufferInfo.format); 376 377 // 编辑完成后调用pushData传递outputOhInfo。 378 pushData(filter, outputOhInfo); 379 380 // 释放资源。 381 OH_EffectBufferInfo_Release(outputOhInfo); 382 ReleaseOutputBuffer(outputBufferInfo.addr); 383 384 return true; 385 } 386 ``` 387 3882. 生成自定义滤镜信息。 389 390 ```c++ 391 // 创建 OH_EffectFilterInfo 实例。 392 OH_EffectFilterInfo *customFilterInfo = OH_EffectFilterInfo_Create(); 393 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 394 OH_LOG_ERROR(LOG_APP, "OH_EffectFilter_GetValue fail!"); 395 return; 396 } 397 398 // 设置自定义滤镜滤镜名。 399 OH_EffectFilterInfo_SetFilterName(customFilterInfo, "CustomBrightness"); 400 401 // 设置自定义滤镜所支持的内存类型。 402 ImageEffect_BufferType bufferTypeArray[] = { ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL }; 403 OH_EffectFilterInfo_SetSupportedBufferTypes(customFilterInfo, sizeof(bufferTypeArray) / sizeof(ImageEffect_BufferType), bufferTypeArray); 404 405 // 设置自定义滤镜所支持的像素格式。 406 ImageEffect_Format formatArray[] = { ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888 }; 407 OH_EffectFilterInfo_SetSupportedFormats(customFilterInfo, sizeof(formatArray) / sizeof(ImageEffect_Format), formatArray); 408 ``` 409 4103. 将 ImageEffect_FilterDelegate 注册到效果器。 411 412 ```c++ 413 // 注册自定义滤镜。 414 ImageEffect_ErrorCode errorCode = OH_EffectFilter_Register(customFilterInfo, &filterDelegate); 415 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 416 OH_LOG_ERROR(LOG_APP, "OH_EffectFilter_Register fail!"); 417 return; 418 } 419 ``` 420 421### EffectFilter快速实现单个滤镜的处理效果 422 4231. 创建滤镜。 424 425 ```c++ 426 // 创建滤镜。比如:创建对比度效果器。 427 OH_EffectFilter *filter = OH_EffectFilter_Create(OH_EFFECT_CONTRAST_FILTER); 428 ``` 429 4302. 设置滤镜参数。 431 432 ```c++ 433 // 设置滤镜参数, 滤镜强度设置为50。 434 ImageEffect_Any value = {.dataType = ImageEffect_DataType::EFFECT_DATA_TYPE_FLOAT, .dataValue.floatValue = 50.f}; 435 ImageEffect_ErrorCode errorCode = OH_EffectFilter_SetValue(filter, OH_EFFECT_FILTER_INTENSITY_KEY, &value); 436 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 437 OH_LOG_ERROR(LOG_APP, "OH_EffectFilter_SetValue fail!"); 438 return; 439 } 440 ``` 441 4423. 生效滤镜。 443 444 ```c++ 445 // 生效滤镜效果。 446 errorCode = OH_EffectFilter_Render(filter, inputPixelmap, outputPixelmap); 447 ``` 448 4494. 销毁滤镜实例。 450 451 ```c++ 452 // 销毁滤镜实例。 453 errorCode = OH_EffectFilter_Release(filter); 454 ``` 455 456### 查询能力 457 458- 根据滤镜名查询滤镜信息。 459 460 ```c++ 461 // 创建 OH_EffectFilterInfo 实例。 462 OH_EffectFilterInfo *filterInfo = OH_EffectFilterInfo_Create(); 463 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 464 OH_LOG_ERROR(LOG_APP, "OH_EffectFilterInfo_Create fail"); 465 return; 466 } 467 468 // 根据滤镜名查询滤镜能力信息。 469 ImageEffect_ErrorCode errorCode = OH_EffectFilter_LookupFilterInfo(OH_EFFECT_BRIGHTNESS_FILTER, filterInfo); 470 if (errorCode != ImageEffect_ErrorCode::EFFECT_SUCCESS) { 471 OH_LOG_ERROR(LOG_APP, "OH_EffectFilter_LookupFilterInfo fail!"); 472 return; 473 } 474 475 // 从滤镜能力信息中获取滤镜名。 476 char *name = nullptr; 477 OH_EffectFilterInfo_GetFilterName(filterInfo, &name); 478 479 // 获取支持的内存类型。 480 uint32_t supportedBufferTypesCnt = 0; 481 ImageEffect_BufferType *bufferTypeArray = nullptr; 482 OH_EffectFilterInfo_GetSupportedBufferTypes(filterInfo, &supportedBufferTypesCnt, &bufferTypeArray); 483 484 // 获取支持的像素类型信息。 485 uint32_t supportedFormatsCnt = 0; 486 ImageEffect_Format *formatArray = nullptr; 487 OH_EffectFilterInfo_GetSupportedFormats(filterInfo, supportedFormatsCnt, &formatArray); 488 489 // 销毁 OH_EffectFilterInfo 实例。 490 OH_EffectFilterInfo_Release(filterInfo); 491 ``` 492 493- 根据条件查询满足条件的滤镜。 494 495 ```c++ 496 // 查询所有的Filter,需要主动进行资源释放。 497 ImageEffect_FilterNames *filterNames = OH_EffectFilter_LookupFilters("Default"); 498 499 // ... 500 501 // 释放FilterNames虚拟内存资源。 502 OH_EffectFilter_ReleaseFilterNames(); 503 ``` 504 505## 相关实例 506 507针对ImageEffect的开发,有以下相关实例可供参考: 508 509- [ImageEffect(API12)](https://gitcode.com/openharmony/applications_app_samples/tree/master/code/BasicFeature/Media/ImageEffect)