场景描述

使用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;

HarmonyOS码上奇行
11.7k 声望4.2k 粉丝

欢迎关注 HarmonyOS 开发者社区:[链接]