HarmonyOS APP实战-画图APP - 第8篇:图像效果应用(亮度/模糊/灰度)
HarmonyOS APP实战-画图APP - 第8篇使用effectKit处理图像1. 开篇上一篇我们实现了在画布上添加文字的功能用户可以通过对话框输入文字内容、选择字体大小和颜色并通过拖拽将文字放置在画布任意位置。文字绘制基于CanvasRenderingContext2D的fillText方法配合measureText实现精准定位。至此画图APP已经具备了形状绘制、手绘、颜色调节、文字标注等核心交互能力。然而用户还希望对自己的作品应用滤镜效果——比如调节整体亮度、添加模糊或变为灰度风格。HarmonyOS提供的ohos.effectKit正能满足这一需求它能对PixelMap图像高效地进行亮度调节、模糊化、灰度调节等操作。本篇我们将将这个能力集成到APP中用户选择一个效果并调整参数后画布图像会实时更新并支持反复应用不同效果。2. 核心实现2.1 基础配置 – 导入模块与类型定义首先在项目根目录的oh-package.json5中确认ohos.effectKit已被包含默认系统能力无需额外安装。然后在需要使用的地方导入模块// utils/EffectProcessor.tsimport{effectKit}fromohos.effectKit;// 图像效果模块import{image}fromohos.multimedia.image;// PixelMap 类型ohos.effectKit提供了EffectKit类通过createEffect方法为PixelMap创建图像效果对象再调用blur、brightness、grayscale等方法应用效果最后通过getPixelMap获取结果。关键点说明effectKit的createEffect接受一个PixelMap参数返回ImageEffect实例。brightness(brightness: number)参数范围-1到1-1为全黑0为原始1为全白。blur(radius: number)参数为模糊半径数值越大越模糊。grayscale()无参数直接转为灰度。每个方法返回ImageEffect自身可以链式调用但建议分开调用以保持清晰。2.2 核心逻辑 – EffectProcessor封装封装一个工具类EffectProcessor包含三个静态方法分别对传入的PixelMap进行处理并返回新的PixelMap。注意原始PixelMap不应被修改因此每次处理都通过createEffect创建副本。// utils/EffectProcessor.tsimport{effectKit,ImageEffect}fromohos.effectKit;import{image}fromohos.multimedia.image;exportclassEffectProcessor{/** * 亮度调节 * param source 源PixelMap * param brightness 亮度值-1~1 * returns 处理后的PixelMap */staticasyncapplyBrightness(source:image.PixelMap,brightness:number):Promiseimage.PixelMap{// 创建效果对象consteffect:ImageEffecteffectKit.createEffect(source);// 应用亮度调节effect.brightness(brightness);// 获取结果PixelMapreturnawaiteffect.getPixelMap();}/** * 模糊化 * param source 源PixelMap * param radius 模糊半径 * returns 处理后的PixelMap */staticasyncapplyBlur(source:image.PixelMap,radius:number):Promiseimage.PixelMap{consteffect:ImageEffecteffectKit.createEffect(source);effect.blur(radius);returnawaiteffect.getPixelMap();}/** * 灰度调节 * param source 源PixelMap * returns 处理后的PixelMap */staticasyncapplyGrayscale(source:image.PixelMap):Promiseimage.PixelMap{consteffect:ImageEffecteffectKit.createEffect(source);effect.grayscale();returnawaiteffect.getPixelMap();}}关键点说明createEffect不会修改源PixelMap它会基于源数据生成一个内部副本。getPixelMap()是异步方法返回PromisePixelMap需要await。每次调用均应捕获异常如参数越界可能导致崩溃。实际应用中建议增加参数校验和try-catch。2.3 完整模块 – EffectDialog与集成接下来实现EffectDialog自定义弹窗让用户选择效果类型并调节对应参数。同时需要修改主页面增加“效果”按钮并调用此对话框。2.3.1 EffectDialog组件创建pages/EffectDialog.ets文件使用CustomDialog装饰器。对话框包含三个单选按钮亮度/模糊/灰度、对应的滑块亮度和模糊需要调节以及确定/取消按钮。// pages/EffectDialog.etsimport{EffectProcessor}from../utils/EffectProcessor;import{image}fromohos.multimedia.image;CustomDialogexportstruct EffectDialog{controller:CustomDialogController;// 传入当前画布的PixelMapcurrentPixelMap:image.PixelMap|nullnull;// 回调函数返回处理后的PixelMaponConfirm:(result:image.PixelMap)void;// 内部状态StateselectedEffect:number0;// 0:亮度 1:模糊 2:灰度StatebrightnessValue:number0;// -1~1StateblurRadius:number5;// 0~20build(){Column(){Text(选择图像效果).fontSize(18).margin({bottom:16});// 效果类型选择Radio({value:brightness,group:effectGroup}).checked(true).onChange((){this.selectedEffect0;}).height(30)Text(亮度调节).margin({left:8});Radio({value:blur,group:effectGroup}).onChange((){this.selectedEffect1;}).height(30)Text(模糊化).margin({left:8});Radio({value:grayscale,group:effectGroup}).onChange((){this.selectedEffect2;}).height(30)Text(灰度).margin({left:8});// 动态参数调节if(this.selectedEffect0){Row(){Text(亮度).width(60);Slider({value:this.brightnessValue,min:-1,max:1,step:0.01}).onChange((val:number){this.brightnessValueval;}).width(200);}.margin({top:12});}elseif(this.selectedEffect1){Row(){Text(模糊半径).width(80);Slider({value:this.blurRadius,min:0,max:20,step:1}).onChange((val:number){this.blurRadiusval;}).width(200);}.margin({top:12});}// 预览与确认按钮Row(){Button(取消).onClick((){this.controller.close();});Button(应用).onClick(async(){if(!this.currentPixelMap){console.error(No pixelmap to process);return;}try{letresult:image.PixelMap;switch(this.selectedEffect){case0:resultawaitEffectProcessor.applyBrightness(this.currentPixelMap,this.brightnessValue);break;case1:resultawaitEffectProcessor.applyBlur(this.currentPixelMap,this.blurRadius);break;case2:resultawaitEffectProcessor.applyGrayscale(this.currentPixelMap);break;}this.onConfirm(result);this.controller.close();}catch(err){console.error(Effect application failed: err);}});}.justifyContent(FlexAlign.Center).width(100%).margin({top:20});}.padding(20).width(80%);}}关键点说明CustomDialog的组件需要传入controller和回调。通过selectedEffect变量控制显示对应的滑块。点击“应用”后调用EffectProcessor的静态方法并通过onConfirm将结果传回主页面。由于getPixelMap()是异步这里使用async/await。2.3.2 主页面集成效果按钮与画布快照修改主页面pages/Index.ets在顶部工具栏添加一个“效果”按钮。点击时通过Canvas的snapshot方法获取当前画布的PixelMap。弹出EffectDialog将PixelMap传入。对话框确认后使用CanvasRenderingContext2D的drawImage将处理后的PixelMap绘制回画布。// pages/Index.ets部分代码仅展示新增部分import{EffectDialog}from./EffectDialog;import{image}fromohos.multimedia.image;// ... 已有状态和组件声明StatecanvasContext:CanvasRenderingContext2DnewCanvasRenderingContext2D();privatecanvasController:CanvasControllernewCanvasController();dialogController:CustomDialogController|nullnull;// 效果按钮点击事件asynconEffectClick(){// 步骤1: 获取当前画布快照为PixelMaptry{constpixelMap:image.PixelMapawaitthis.canvasController.snapshot();// 步骤2: 创建并打开效果对话框this.dialogControllernewCustomDialogController({builder:EffectDialog({currentPixelMap:pixelMap,onConfirm:(result:image.PixelMap){// 步骤3: 将处理后的PixelMap绘制到画布this.canvasContext.drawImage(result,0,0);}}),cancel:(){console.log(效果取消);},autoCancel:true});this.dialogController.open();}catch(err){console.error(Snapshot failed: err);}}// build()中添加效果按钮ToolbarButton({text:效果,onClick:this.onEffectClick.bind(this)})关键点说明CanvasController的snapshot()方法返回PromisePixelMap是HarmonyOS Canvas组件提供的官方API。drawImage可以将PixelMap直接绘制到Canvas上完整替换画布内容之前绘制的图形都会保留但被覆盖。如果需要保留历史建议在应用效果前将原始PixelMap推入撤销栈下一系列会实现这里为了简洁直接替换。2.3.4 工具方法异常处理补充在EffectProcessor中添加基本的异常捕获避免应用崩溃// 在applyBrightness中添加 try-catch 示例staticasyncapplyBrightness(source:image.PixelMap,brightness:number):Promiseimage.PixelMap{try{consteffecteffectKit.createEffect(source);effect.brightness(brightness);returnawaiteffect.getPixelMap();}catch(error){console.error(applyBrightness error:${error.code},${error.message});throwerror;// 向上传递由调用方处理}}3. 运行验证完成上述代码后运行APP。在顶部工具栏可以看到新增的“效果”按钮图标可自定义本文略。点击后弹出效果选择对话框默认选中“亮度调节”滑块范围-1到1。调节滑块并点击“应用”画布上的所有内容包括之前绘制的图形和文字会实时应用亮度效果。选择“模糊化”并调节半径画布变模糊选择“灰度”后画布变为黑白风格。可通过多次点击“效果”应用不同效果的组合例如先模糊再调整亮度。每次应用前都会基于当前画布快照进行处理叠加效果自然。注意由于snapshot获取的是当前画布像素因此应用效果会覆盖原来的绘制内容。若要保留原始图层可考虑在前端维护一个单独的PixelMap副本但本系列聚焦于功能完整性暂不深入。4. 小结与预告第8篇我们成功将ohos.effectKit集成到画图APP中实现了亮度调节、模糊化和灰度调节三个实用图像效果。核心模块EffectProcessor封装了效果处理逻辑EffectDialog提供了友好的交互界面。通过本次集成APP的功能从“绘制”扩展到“图像后期处理”用户体验更加丰富。下一篇《智能取色与色板生成》将继续使用effectKit的智能取色能力让用户从画布中提取主色并自动生成色板进一步提升画图工具的专业性。我们将实现取色区域选择、主色提取算法以及色板UI展示敬请期待。