在Flutter中将图像转换为灰度:ColorFiltered组件

背景

在最近的项目中,我遇到了一个需求:当满足特定条件时,需要将图像转换为灰度。例如,用户个人资料页面有一组用来显示个人社交信息,并展示相关社交平台图标,如果用设置了社交信息,则该社交平台的图标应处理点亮状态,如果没有设置,则应处于禁用状态,也就是是说,我需要把对应图标的颜色改为灰度模式。这看起来很简单,特别是对于那些单一颜色的图标,对吧?但实际上,有一些图标是彩色的而且色彩丰富,比如说instagram。

BlendMode

我首先研究了Flutter中的混合模式(BlendMode),结果发现它们确实效果很好 ------ 但这仅适用于没有透明度的JPEGPNG 图像。以下是我用于将彩色透明PNG图像显示为灰度图像的代码。

dart 复制代码
ColorFiltered(
        colorFilter: enabled ? ColorFilter.mode(
          Colors.transparent,
          BlendMode.multiply,
        ) : ColorFilter.mode(
          Colors.grey,
          BlendMode.saturation,
        ),
        child: Image.asset("assets/roundabout.png",),
      )

上面用的图片是一个带有透明的PNG图片,让我们看看效果:

再放一个没有经过处理的demo用的原图:

很显然,这样的效果很糟糕。混合模式(BlendMode)也会影响图像中的透明部分,并将它们也转换为灰色,但我们需要让这些透明区域也不受影响。

颜色矩阵

经过一番研究,我在Flutter文档的深处发现了这个内容。文档中提到了另一个构造函数,它可以用来定义一个矩阵,从而更精细地控制混合模式的应用方式。

于是,我用ColorFilter.matrix替换了ColorFilter.mode构造函数,并传入了这些神奇的数字。

dart 复制代码
ColorFilter.matrix(<double>[
 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,
])

没错,这正是我一直在寻找的解决方案。文档中还提到了更多示例。大家可以随意尝试这些示例,并对这些数值进行调整。

** 反色(Inversion)** 效果的颜色矩阵:

dart 复制代码
const ColorFilter invert = ColorFilter.matrix(<double>[
   -1, 0, 0, 0, 255,
   0, -1, 0, 0, 255,
   0, 0, -1, 0, 255,
   0, 0, 0, 1, 0, ]);

** 复古棕褐色(Sepia Tone)** 效果的颜色矩阵

dart 复制代码
const ColorFilter sepia = ColorFilter.matrix(<double>[ 
   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, ]);

个人感觉这个效果适用于复古风格 UI、老照片效果、特定主题界面

灰度滤镜(Grayscale Color Filter) 效果矩阵

标准灰度滤镜矩阵(最常用)

dart 复制代码
const ColorFilter greyscale = ColorFilter.matrix(<double>[ 
  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, //透明度保持不变
  ]);

上面的的灰度算法是一个标准的灰度算法,还两种算法可供参考:

简化版灰度矩阵(平均法)

dart 复制代码
ColorFilter.matrix([ 
0.333, 0.333, 0.333, 0, 0, // 红色通道取平均值 
0.333, 0.333, 0.333, 0, 0, // 绿色通道取平均值 
0.333, 0.333, 0.333, 0, 0, // 蓝色通道取平均值 
0, 0, 0, 1, 0, // 透明度保持不变 
])

高对比度灰度矩阵

dart 复制代码
ColorFilter.matrix([ 
0.299, 0.587, 0.114, 0, 0, // 红色通道(电视标准算法) 
0.299, 0.587, 0.114, 0, 0, // 绿色通道 
0.299, 0.587, 0.114, 0, 0, // 蓝色通道 
0, 0, 0, 1, 0, // 透明度保持不变
])

矩阵原理

  • 人眼对红、绿、蓝三色的敏感度不同,公式 亮度 = 0.2126*R + 0.7152*G + 0.0722*B 可模拟真实灰度效果。
  • 矩阵中每行对应一个颜色通道(红、绿、蓝、透明度),每列对应输入颜色的分量(R、G、B、A、偏移量)。

让我们再回头看看BlendMode相关属性:

关键属性解析

属性 说明
colorFilter 必需参数,指定颜色滤镜。可通过 ColorFilter.modeColorFilter.matrix 创建。
BlendMode 混合模式(如 colorBurnsrcIn 等),影响颜色过滤的最终效果。
child 待处理的子组件(通常为 ImageIcon 等可视化组件)。

注意事项

  1. 性能影响

    • 复杂的 ColorFilter.matrix 可能对性能产生轻微影响,建议对静态图像提前处理为灰度图。
    • 动态切换时,避免在列表或高频率刷新场景中大量使用。
  2. 混合模式选择

    • BlendMode.color 可保留亮度,仅修改色相和饱和度,适合部分灰度效果。
    • BlendMode.luminosity 直接提取亮度,是最纯净的灰度转换模式。

最后

通过 ColorFiltered 组件,Flutter 提供了简洁高效的图像灰度处理方案。无论是静态效果还是动态交互,合理选择混合模式或矩阵运算,均可灵活实现所需视觉效果。

也希望大家关注我的微信公众号OpenFlutter

相关推荐
weixin-a153003083161 小时前
【playwright篇】教程(十七)[html元素知识]
java·前端·html
ai小鬼头1 小时前
AIStarter最新版怎么卸载AI项目?一键删除操作指南(附路径设置技巧)
前端·后端·github
一只叫煤球的猫2 小时前
普通程序员,从开发到管理岗,为什么我越升职越痛苦?
前端·后端·全栈
vvilkim2 小时前
Electron 自动更新机制详解:实现无缝应用升级
前端·javascript·electron
vvilkim2 小时前
Electron 应用中的内容安全策略 (CSP) 全面指南
前端·javascript·electron
aha-凯心2 小时前
vben 之 axios 封装
前端·javascript·学习
遗憾随她而去.3 小时前
uniapp 中使用路由导航守卫,进行登录鉴权
前端·uni-app
xjt_09013 小时前
浅析Web存储系统
前端
foxhuli2294 小时前
禁止ifrmare标签上的文件,实现自动下载功能,并且隐藏工具栏
前端
青皮桔4 小时前
CSS实现百分比水柱图
前端·css