【入门到精通】鸿蒙next开发:基于ImageEffect实现图片编辑

往期鸿蒙5.0全套实战文章必看:(文中附带全栈鸿蒙5.0学习资料)


基于ImageEffect实现图片编辑

场景描述

使用ImageEffect接口实现对图片添加滤镜链,添加的滤镜链由系统提供的对比度、亮度、裁剪等滤镜与自定义滤镜构成,以此实现对图片的编辑。

方案描述

1、在arkts侧解码resources下的图片,获取image.pixelMap,并设置图片滤镜亮度、对比度、裁剪等参数,调用napi接口将image.PixelMap和滤镜参数传递到native侧。

2、native侧将获取到的image.PixelMap转换成可作为ImageEffect输入的OH_PixelmapNative对象。

3、将OH_PixelmapNative作为ImageEffect的输入,根据传入的滤镜参数,以此往滤镜链路里添加亮度、对比度、裁剪滤镜以及自定义滤镜。

4、将添加滤镜效果的OH_PixelmapNative对象,转化成image.PixelMap对象返回给arkts层回显。

关键步骤及代码

1、构建传递给native侧的滤镜参数。

private confirmInfo() { 
  this.filterOptions = []; 
  if (this.brightnessSelect) { 
    let brightnessArray: (string | number)[] = []; 
    brightnessArray.push("Brightness", this.brightnessSetValue); 
    this.filterOptions.push(brightnessArray); 
  } 
  if (this.contrastSelect) { 
    let contrastArray: (string | number)[] = []; 
    contrastArray.push("Contrast", this.contrastSetValue); 
    this.filterOptions.push(contrastArray); 
  } 
  if (this.cropSelect) { 
    let cropArray: (string | number)[] = []; 
    cropArray.push("Crop", this.cropSetValue); 
    this.filterOptions.push(cropArray); 
  } 
  if (this.customSelect) { 
    let customArray: (string | number)[] = []; 
    customArray.push("CustomBrightness", this.customSetValue); 
    this.filterOptions.push(customArray); 
  } 
}

2、解码resources下的图片,获取image.pixelMap,并设置图片滤镜亮度、对比度、裁剪等参数,调用napi接口将image.PixelMap和滤镜参数传递到native侧。

if (this.brightnessSelect || this.contrastSelect || this.cropSelect || this.customSelect) { 
  let pixelMap = await ImageUtils.getInstance().getPixelMap($r('app.media.ic_1080x1920')); 
  // 调用napi接口,传入image.pixelMap对象及滤镜参数 
  this.displayPixelMap = imageEffect.apply(pixelMap, [...this.filterOptions]); 
} 
 
async getPixelMap(resource: Resource): Promise<image.PixelMap> { 
  const resourceStr = getContext(this).resourceManager; 
  let imageBuffer = await resourceStr.getMediaContent(resource); 
  return  await image.createImageSource(imageBuffer.buffer as object as ArrayBuffer).createPixelMap(); 
}

3、native侧将image.PixelMap转化成OH_PixelmapNative。

OH_PixelmapNative* pixelmapNativePtr = nullptr; 
OH_PixelmapNative_ConvertPixelmapNativeFromNapi(env, args[EXPECTED_ARGS_ZERO],&pixelmapNativePtr);

4、根据napi接口接收到的滤镜参数,构建滤镜链路。

std::vector<std::vector<FilterArrayData>> GetFilters(napi_env env, napi_value arg) 
{ 
  std::vector<std::vector<FilterArrayData>> data; 
  napi_status status; 
 
  bool is_array; 
  status = napi_is_array(env, arg, &is_array); 
  CHECK_AND_RETURN_RET_LOG(is_array == true, data, "GetFilters napi_is_array fail! status=%{public}d", status); 
 
  // Handle napi array length 
  auto array_length = GetNapiArrayLength(env, arg); 
  CHECK_AND_RETURN_RET_LOG(array_length.first == napi_ok, data, 
    "GetFilters napi_get_array_length fail! status=%{public}d", array_length.first); 
 
  for (uint32_t i = 0; i < array_length.second; i++) { 
  napi_value element; 
  status = napi_get_element(env, arg, i, &element); 
  CHECK_AND_RETURN_RET_LOG(status == napi_ok, data, "GetFilters napi_get_element fail! status=%{public}d", 
    status); 
 
  auto child_length = GetNapiArrayLength(env, element); 
  CHECK_AND_RETURN_RET_LOG(child_length.first == napi_ok, data, 
    "GetFilters child napi_get_array_length fail! status=%{public}d", child_length.first); 
 
  std::vector<FilterArrayData> row; 
  FilterArrayData filterArrayData; 
  for (uint32_t j = 0; j < child_length.second; j++) { 
    napi_value childElement; 
    status = napi_get_element(env, element, j, &childElement); 
 
    napi_valuetype valueType; 
    status = napi_typeof(env, childElement, &valueType); 
    CHECK_AND_RETURN_RET_LOG(status == napi_ok, data, 
      "GetFilters child napi_typeof fail! status=%{public}d, value=%{public}d", status, valueType); 
 
    if (valueType == napi_string) { 
      filterArrayData.name = HandleStringType(env, childElement, status); 
    } else if (valueType == napi_number) { 
      filterArrayData.value = HandleNumberType(env, childElement, status); 
    } 
  } 
  row.push_back(filterArrayData); 
  data.push_back(row); 
} 
 
  return data; 
}

5、构建并注册自定义滤镜。

static ImageEffect_FilterDelegate delegate; 
napi_value ImageEdit::RegisterCustomBrightness() 
{ 
    napi_value result = nullptr; 
    // 自定义算子能力信息 
    OH_EffectFilterInfo *effectInfo = OH_EffectFilterInfo_Create(); 
    OH_EffectFilterInfo_SetFilterName(effectInfo, "CustomBrightness"); 
    ImageEffect_BufferType bufferType = ImageEffect_BufferType::EFFECT_BUFFER_TYPE_PIXEL; 
    OH_EffectFilterInfo_SetSupportedBufferTypes(effectInfo, 1, &bufferType); 
    ImageEffect_Format format = ImageEffect_Format::EFFECT_PIXEL_FORMAT_RGBA8888; 
    OH_EffectFilterInfo_SetSupportedFormats(effectInfo, 1, &format); 
    // 自定义算子实现接口 
    delegate = { 
        .setValue = [](OH_EffectFilter *filter, const char *key, const ImageEffect_Any *value) { return true; }, 
        .render = [](OH_EffectFilter *filter, OH_EffectBufferInfo *src, 
            OH_EffectFilterDelegate_PushData pushData) {  
            return true;  
         }, 
        .save = [](OH_EffectFilter *filter, char **info) {  
            return true;  
        }, 
.restore = [](const char *info) { 
  return OH_EffectFilter_Create("CustomBrightness"); 
} 
}; 
// 注册自定义滤镜 
ImageEffect_ErrorCode errorCode = OH_EffectFilter_Register(effectInfo, &delegate); 
CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, 
"OH_EffectFilter_Register fail! errorCode = %{public}d", errorCode); 
return result; 
}

6、将OH_PixelmapNative作为ImageEffect的输入,根据传入的滤镜参数,以此往滤镜链路里添加亮度、对比度、裁剪滤镜以及自定义滤镜。

// 创建ImageEffect对象 
OH_ImageEffect *imageEffect = OH_ImageEffect_Create("imageEdit"); 
CHECK_AND_RETURN_RET_LOG(imageEffect != nullptr, result, "OH_ImageEffect_Create fail!"); 
std::shared_ptr<OH_ImageEffect> imageEffectPtr(imageEffect, [](OH_ImageEffect *imageEffect) { 
  OH_ImageEffect_Release(imageEffect); 
}); 
// 将步骤4中构建的滤镜链路添加到ImageEffect对象中 
for (int i = 0; i < filters.size(); i++) { 
  OH_EffectFilter *filter = AddFilter(imageEffectPtr.get(), filters[i][0].name.c_str()); 
  CHECK_AND_RETURN_RET_LOG(filter != nullptr, result, "OH_ImageEffect_AddFilter fail!"); 
  SetFilterValue(filter, filters[i][0].name.c_str(), filters[i][0].value, pixelmapNativePtr); 
} 
// 将由image.PixelMap转化得到的oh_PixelmapNative设置为ImageEffect的输入 
ImageEffect_ErrorCode errorCode = OH_ImageEffect_SetInputPixelmap(imageEffectPtr.get(), pixelmapNativePtr); 
CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, 
"OH_ImageEffect_SetInputPixelMap fail! errorCode = %{public}d", errorCode); 
// 开启滤镜效果 
errorCode = OH_ImageEffect_Start(imageEffectPtr.get()); 
CHECK_AND_RETURN_RET_LOG(errorCode == ImageEffect_ErrorCode::EFFECT_SUCCESS, result, 
"OH_ImageEffect_Start fail! errorCode = %{public}d", errorCode);

7、将添加滤镜效果的OH_PixelmapNative对象,转化成image.PixelMap对象返回给arkts层回显。

OH_PixelmapNative_ConvertPixelmapNativeToNapi(env, pixelmapNativePtr, &result); 
return result;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值