当前位置: 首页 > news >正文

【共创季稿事节】鸿蒙ArkTS颜色滤镜实战

鸿蒙 ArkTS 实战:ColorFilter 颜色矩阵滤镜——从原理到 7 种经典效果完整实现

一、为什么需要 ColorFilter?

图像滤镜是移动应用的常见需求——从社交 App 的美化功能、电商的商品展示,到工具 App 的禁用灰度状态,都需要动态改变图像的色彩表现。

传统做法是编写 GPU 着色器,这对 ArkTS 开发者过于底层。HarmonyOS NEXT 的Image组件直接提供了colorFilter属性,允许传入一个4×5 的颜色变换矩阵,在 GPU 层面并行计算每个像素的 RGBA 变换。一行.colorFilter(matrix)即可生效,零额外依赖。


二、颜色矩阵原理 | 4×5 矩阵的数学本质

2.1 矩阵结构(行主序)

索引 0 1 2 3 4 → R 通道变换系数 5 6 7 8 9 → G 通道变换系数 10 11 12 13 14 → B 通道变换系数 15 16 17 18 19 → A 通道变换系数

2.2 数学公式

新 R = m[0]×R + m[1]×G + m[2]×B + m[3]×A + m[4] 新 G = m[5]×R + m[6]×G + m[7]×B + m[8]×A + m[9] 新 B = m[10]×R + m[11]×G + m[12]×B + m[13]×A + m[14] 新 A = m[15]×R + m[16]×G + m[17]×B + m[18]×A + m[19]

前 4 列是缩放系数,决定当前输出通道受 R、G、B、A 输入的影响权重;第 5 列是偏移量,与输入像素值无关。例如反色中偏移设为 +1,结合 -1 系数,实现新值 = 1 - 原值

2.3 单位矩阵(原图效果)

[1,0,0,0,0,// 新 R = R0,1,0,0,0,// 新 G = G0,0,1,0,0,// 新 B = B0,0,0,1,0]// 新 A = A

对角为 1、其余为 0、偏移为 0,就是"原图"。


三、API 24 下的 colorFilter 属性

3.1 属性签名

// 方式一:直接传入 20 个 number 的数组(推荐,0 依赖,兼容性最好)Image(src).colorFilter([r0,r1,r2,r3,r4,g0,g1,g2,g3,g4,b0,b1,b2,b3,b4,a0,a1,a2,a3,a4])// 方式二:使用 ColorFilter 对象(API 24 从 @kit.ArkGraphics2D 导入)import{ColorFilter}from'@kit.ArkGraphics2D';Image(src).colorFilter(newColorFilter(matrix))

⚠️ API 24 中ColorFilter/ColorMatrix不在@kit.ArkUI中,推荐直接用数组传参,省去 import 烦恼。

3.2 与简化属性对比

属性等价效果示例
.grayscale(v)灰度,v∈[0,1].grayscale(0.8)
.sepia(v)怀旧,v∈[0,1].sepia(0.6)
.invert(v)反色,v∈[0,1].invert(0.5)
.saturate(v)饱和度,v≥0.saturate(2.0)
.hueRotate(deg)色相旋转.hueRotate(90)
.brightness(v)亮度.brightness(1.2)
.contrast(v)对比度.contrast(1.5)
.colorFilter(matrix)通用矩阵核心 API

简化属性适合单一效果,colorFilter适合多通道混合变换。


四、7 种滤镜矩阵逐行解读

4.1 原图

对角全 1,不做变换,作为对比基准。

4.2 灰度(Grayscale)

[0.2126,0.7152,0.0722,0,0,0.2126,0.7152,0.0722,0,0,0.2126,0.7152,0.0722,0,0,0,0,0,1,0]

三行系数相同,输出R=G=B = 0.2126R + 0.7152G + 0.0722B。权重来自ITU-R BT.709亮度标准:人眼对绿色最敏感(0.7152),对蓝色最不敏感(0.0722)。若均分 0.333,灰度图会偏暗。

4.3 怀旧/复古(Sepia)

[0.393,0.769,0.189,0,0,0.349,0.686,0.168,0,0,0.272,0.534,0.131,0,0,0,0,0,1,0]

R 行和 G 行从其他通道"借"来大量能量,B 通道被大幅削弱,产生暖黄褐色的老照片效果。三行系数相加均大于 1,整体亮度提升约 35%。

4.4 反色(Invert)

[-1,0,0,0,1,0,-1,0,0,1,0,0,-1,0,1,0,0,0,1,0]

对角线 -1 + 偏移 +1 =新值 = 1 - 原值。黑变白、白变黑,完美反转。

4.5 高饱和度

[1.438,-0.122,-0.016,0,-0.03,-0.062,1.378,-0.016,0,-0.05,-0.062,-0.122,1.483,0,-0.02,0,0,0,1,0]

对角系数 > 1 增强本色,负的非对角系数削弱串扰。红更红、绿更绿、蓝更蓝。

4.6 冷色调

[1,0,0,0,0,0,0.9,0,0,0,0,0,1.2,0,0,0,0,0,1,0]

R 不变、G 略降(0.9)、B 提升(1.2),模拟色温降低时蓝光增多的效果。适合科技感 UI。

4.7 黑白高对比

[1.5,1.5,1.5,0,-1,1.5,1.5,1.5,0,-1,1.5,1.5,1.5,0,-1,0,0,0,1,0]

放大灰度增益至 1.5 倍,引入 -1 偏移,将中间色调"撕裂"成近乎二值化的黑白分明的效果。RGB 均值低于 0.67 的像素压至 0,高于的被裁剪到 1。


五、完整代码实现

5.1 接口定义与状态声明

interfaceFilterOption{label:string;matrix:number[];}@Entry@Componentstruct Index{@StatecurrentFilterIndex:number=0;@StateshowMatrixDebug:boolean=false;privatereadonlyfilters:FilterOption[]=[{label:'原图',matrix:[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},{label:'灰度',matrix:[0.2126,0.7152,0.0722,0,0,0.2126,0.7152,0.0722,0,0,0.2126,0.7152,0.0722,0,0,0,0,0,1,0]},{label:'怀旧/复古',matrix:[0.393,0.769,0.189,0,0,0.349,0.686,0.168,0,0,0.272,0.534,0.131,0,0,0,0,0,1,0]},{label:'反色',matrix:[-1,0,0,0,1,0,-1,0,0,1,0,0,-1,0,1,0,0,0,1,0]},{label:'高饱和度',matrix:[1.438,-0.122,-0.016,0,-0.03,-0.062,1.378,-0.016,0,-0.05,-0.062,-0.122,1.483,0,-0.02,0,0,0,1,0]},{label:'冷色调',matrix:[1,0,0,0,0,0,0.9,0,0,0,0,0,1.2,0,0,0,0,0,1,0]},{label:'黑白高对比',matrix:[1.5,1.5,1.5,0,-1,1.5,1.5,1.5,0,-1,1.5,1.5,1.5,0,-1,0,0,0,1,0]}];getcurrentMatrix():number[]{returnthis.filters[this.currentFilterIndex].matrix;}getcurrentLabel():string{returnthis.filters[this.currentFilterIndex].label;}

5.2 build() 布局

build(){Scroll(){// ★ Scroll 实现页面滚动Column(){// ---- 标题 ----Text('🎨 ColorFilter 颜色滤镜演示').fontSize(22).fontWeight(FontWeight.Bold).width('100%').padding({top:16,bottom:8})Text('通过 4×5 RGBA 颜色矩阵实现图像滤镜效果').fontSize(13).fontColor('#888888').width('100%').padding({bottom:12})// ---- 当前滤镜名 ----Text(this.currentLabel).fontSize(18).fontWeight(FontWeight.Medium).fontColor('#ff6600').width('100%').padding({bottom:8})// ---- 图片展示区(核心) ----Stack(){Image($r('app.media.background')).width('95%').aspectRatio(1.6).objectFit(ImageFit.Cover).borderRadius(16)// ★★★ 核心:colorFilter ★★★.colorFilter(this.currentMatrix).animation({duration:400,curve:Curve.EaseInOut})}.width('100%').padding({bottom:16})// ---- 滤镜按钮(Flex + wrap 流式布局) ----Flex({direction:FlexDirection.Row,wrap:FlexWrap.Wrap,justifyContent:FlexAlign.Center}){ForEach(this.filters,(item,index)=>{Button(item.label).height(40).fontSize(14).borderRadius(20).margin(6).backgroundColor(this.currentFilterIndex===index?'#ff6600':'#f0f0f0').fontColor(this.currentFilterIndex===index?'#ffffff':'#333333').onClick(()=>{this.currentFilterIndex=index;})},(_,i)=>i.toString())}.width('100%').padding({left:12,right:12,bottom:12})// ---- 矩阵调试面板 ----Button(this.showMatrixDebug?'收起 ▲':'展开 ▼').fontSize(12).height(32).borderRadius(12).onClick(()=>{this.showMatrixDebug=!this.showMatrixDebug;})if(this.showMatrixDebug){Scroll(){Column(){Text('🎯 4×5 颜色矩阵').fontSize(13).fontColor('#666')this.MatrixRow('R 通道',0)this.MatrixRow('G 通道',5)this.MatrixRow('B 通道',10)this.MatrixRow('A 通道',15)}.padding(16)}.height(160).backgroundColor('#fafafa').borderRadius(12).padding(8)}// ---- 底部说明 ----Text('布局要点说明').fontSize(14).fontWeight(FontWeight.Bold).padding({top:16,bottom:4})Column(){Text('① .colorFilter() 传入 20 个数值的数组,无需 import').fontSize(12).fontColor('#666')Text('② 每行 5 值:4 个通道系数 + 1 个偏移量').fontSize(12).fontColor('#666')Text('③ 灰度:R_out = G_out = B_out = 0.2126R + 0.7152G + 0.0722B').fontSize(12).fontColor('#666')Text('④ 反色利用 -1 对角系数 + 偏移 +1 实现').fontSize(12).fontColor('#666')Text('⑤ 也可从 @kit.ArkGraphics2D 导入 ColorFilter 类').fontSize(12).fontColor('#666')}.alignItems(HorizontalAlign.Start).width('90%').padding({bottom:20})}.width('100%').padding(8)}.scrollable(ScrollDirection.Vertical)}

5.3 @Builder 矩阵行

@BuilderMatrixRow(label:string,offset:number){Row(){Text(label).fontSize(12).width(55).textAlign(TextAlign.End)Text(this.currentMatrix[offset].toFixed(3)).fontSize(12).width(50)Text(this.currentMatrix[offset+1].toFixed(3)).fontSize(12).width(50)Text(this.currentMatrix[offset+2].toFixed(3)).fontSize(12).width(50)Text(this.currentMatrix[offset+3].toFixed(3)).fontSize(12).width(50)Text(this.currentMatrix[offset+4].toFixed(3)).fontSize(12).width(50).fontColor('#cc5500')// 偏移量橙色高亮}.justifyContent(FlexAlign.Center).padding({top:4,bottom:4})}}

六、避坑指南:API 24 常见编译错误

6.1 ColorFilter/ColorMatrix 未导出

Module '"@kit.ArkUI"' has no exported member 'ColorFilter'

修复:用数组传参代替类实例。或从@kit.ArkGraphics2D导入。

6.2 Curve.FadeIn 不存在

Curve枚举没有FadeIn。用Curve.EaseIn/Curve.EaseOut/Curve.EaseInOut

6.3 自定义组件 6 个参数

ArkTS@Component不支持位置参数传值。改用@Builder函数传参:

// ✅ 用 @Builder@BuilderMatrixRow(label:string,offset:number){...}this.MatrixRow('R 通道',0)// ❌ 不行MatrixRow('R 通道',0.1,0.2,0.3,0.4,0.5)

6.4 Column 没有 scrollable()

Scroll包裹Columnscrollable()设置方向。

6.5 build() 内不能声明变量

build()中不允许let/const。变量提取为get计算属性:

getcurrentMatrix():number[]{returnthis.filters[idx].matrix;}

七、性能优化

  • GPU 管线colorFilter在片段着色器阶段完成,1920×1080 图片处理 < 1ms
  • 矩阵复用:将矩阵定义为private readonly常量,避免每次 re-render 重建
  • 动画开销.animation({ duration: 400 })会触发属性插值,列表场景建议减少动画组件数
  • 列表场景:配合LazyForEach+.syncLoad(true)获得流畅滚动体验

八、总结

本文从颜色矩阵的数学原理出发,用 7 个具体滤镜(原图、灰度、怀旧、反色、高饱和、冷色调、黑白高对比)展示了 HarmonyOS NEXT API 24 中Image.colorFilter()的完整用法,并附带了可运行的 ArkTS 代码和常见编译错误的解决方案。

颜色矩阵的核心规律可概括为:

  • 对角 > 1→ 增强该通道
  • 对角 < 1→ 减弱该通道
  • 对角为负→ 反相
  • 非对角非零→ 颜色串扰 / 混合
  • 第 5 列→ 整体偏移

掌握了这五条规律,任何色彩变换需求你都能写出对应的矩阵。下一步可以尝试滑块实时调节矩阵参数、多层滤镜叠加、AI 自动推荐滤镜等进阶功能。


API 参考:

  • Image 组件 colorFilter 属性
  • ArkTS 声明式语法



http://www.rkmt.cn/news/1524350.html

相关文章:

  • 如何快速掌握BepInEx:终极Unity游戏插件框架完全指南
  • 终极指南:使用Dism++免费完成Windows系统维护与优化
  • MAA明日方舟助手:开源智能自动化工具完全指南
  • 选择合适的后端技术栈:项目需求与技术匹配策略
  • AI 推理服务冷启动优化:轻量化容器镜像构建与按需分层加载实践
  • TensorFlow原生PSO:GPU加速的粒子群优化实现
  • UCC BISYNC模式错误处理:从硬件原理到工程实践
  • Path of Building PoE2:终极流放之路2角色构建指南,轻松打造百万DPS角色!
  • 3步掌握UI-TARS桌面版:用自然语言实现GUI自动化的实用指南
  • Paperless-ngx多语言配置指南:打造全球化文档管理系统
  • 湖州装修公司怎么选?2026年湖州靠谱装修公司推荐攻略 - 匠言榜单
  • MPC8313E IPIC中断控制器:从原理到实战配置与优化
  • 2026年六安家长必看:孩子落榜别将就,共达复读班再战一年稳上全日制大专联系方式多少?官方最新发布 - cc江江
  • 如何用Wayback Machine浏览器扩展永久保存互联网记忆:终极网页存档指南
  • SpringBoot项目实战:构建高可用的电商系统
  • 别再只看价格了!阿里云、AWS、GCP隐藏成本大起底(附账单优化技巧)
  • LSTM时间序列预测实战:疫情数据建模与工程落地
  • 5步精通BG3ModManager:博德之门3模组管理终极实战指南
  • Selenium 与 Scrapy 双框架实战:网站防护机制下的稳定数据采集方案
  • 5个步骤高效掌握Beat Saber模组管理:ModAssistant终极指南
  • 深入解析PCI总线配置与仲裁机制:以MPC8323E为例的实战调试指南
  • Meshroom完全指南:从照片到专业3D模型的免费开源神器
  • MPC8272硬件安全引擎:数据包描述符驱动与硬件加速实战解析
  • Rust trait系统与泛型约束:从零尺寸类型到动态分发的类型架构
  • 2026年六安没考上高中上什么学校好?中考不是终点,换条赛道照样拿本科 - 我叫小周
  • 如何在Windows 10/11上运行经典游戏联机?IPXWrapper完美解决方案
  • 2026 南京箱包回收服务排行,五家奢侈品门店全方位测评 TOP5 - 讯息早知道
  • Kilo Code 安装、使用方法详细全解
  • MPC8272 UPM编程实战:从时序原理到DRAM接口配置
  • (十八)西门子S7-1200 PLC Modbus通讯功能介绍