给灭霸点颜色看看
前言
继续我们 Flutter 绘图相关的介绍,本篇我们引入一位重量级主角 —— 灭霸。通过绘图的颜色过滤器,我们要给灭霸点颜色看看。通过本篇,你会了解到如下内容:
- ColorFilter 颜色过滤器的介绍;
- 彩色图片转换为灰度图;
- 通过矩阵运算构建自定义的颜色过滤器。
ColorFilter 颜色过滤器
其实我们之前在给小姐姐的照片调个颜色滤镜有介绍过颜色滤镜,在 Flutter 中提供了一个 ColorFiltered
的组件,可以将颜色过滤器应用到其子组件上。实际上,颜色过滤器就是对一个图层的每个像素的颜色(包括透明度)进行数学运算,改变像素的颜色来实现特定的效果。数学公式如下:
在 Flutter 中,ColorFilter
类的继承自 ImageFilter
,像 ImageFilter
一样,也只提供了命名构造函数,一共有四个命名构造函数,分别如下:
ColorFilter.mode(Color color, BlendMode mode)
:按制定的混合模式(blend mode),将颜色混入到绘制的目标中。可以理解为图像的色值调整,我们可以用一个指定的颜色调整原图,调整的模式有很多种,具体可以查看 BlendMode 枚举。ColorFilter.linearToSrgbGamma()
:将一个 SRGB 的 gamma 曲线应用到 RGB 颜色通道中。ColorFilter.srgbToLinearGamma()
:ColorFilter.linearToSrgbGamma()
的反向过程。ColorFilter.matrix(List<double> matrix)
:应用一个矩阵做颜色变换,也就是我们上面说的矩阵,这是最通用的版本,要什么效果可以自己构建对应的矩阵。
这里说一下 SRGB 的 gamma 曲线的用途。我们人眼在显示屏中对图片进行调色等操作时,是按照线性空间的角度进行的,但显示器是在gamma空间中的,那么图像在计算机中的存储一般都应该是在 gamma 空间下了。也就是计算机存储的是非线性的,但是给我们展示的时候要转为线性的。因此,对于一张图像,可能是线性的也可能是 gamma 空间的,这个时候为了统一可能就需要进行转换,那就会用到linearToSrgbGamma
和srgbToLinearGamma
两个颜色过滤器。
彩色图片转成灰色图片
彩色图片转变为灰色图片有很2种方法,最简单的方法是使用ColorFilter.mode
,第一个参数颜色选择灰色或黑色,然后 第二个参数选择 BlendMode.color
或者接近的效果(比如 hue
和 saturation
)。BlendMode.color
是取源图的色调和饱和度,然后取目标(即要改变的图片)的亮度。因此,如果我们想更改一张图片的色调,用这种方式最好了。下面是对应的实现代码和变换前后的对比图。
var paint = Paint();
paint.colorFilter = ColorFilter.mode(Colors.grey, BlendMode.color);
canvas.drawImageRect(
bgImage,
Rect.fromLTRB(0, 0, bgImage.width.toDouble(), bgImage.height.toDouble()),
Offset.zero & size,
paint,
);
使用ColorFilter.mode
另一个用途就是简单的“修图”了,比如我们可以将一张蓝天白云图修成夕阳西下的效果。
当然,转换为灰度图我们也可以通过矩阵实现。
矩阵运算改变颜色
如果要想任意调换颜色,那么使用矩阵运算更合适。在 Flutter 中,ColorFilter.matrix
多增加了一行,这一行主要是在构建一些特殊的矩阵运算更方便,比如反转色的时候。
比如我们要让变换后的图像实现反转:
- 红色色值=255-原红色色值
- 绿色色值=255-原绿色色值
- 蓝色色值=255-原蓝色色值
那么构建如下矩阵就可以了。
由于最后一行数值对实际变化没影响,因此实际构建 ColorFilter.matrix
的时候,只需要传入20个参数就可以了。下面是应用了反转效果后的灭霸图,灭霸看起来像一个雕塑了。
下面我们先来看一下使用矩阵实现彩色图变灰度图,用下面的矩阵就能实现,最终得到变换后的 R、G、B值是相等的,而且三个色值的系数相加等于1(保证数值不会超出255)。这个矩阵是官方提供的,实际上也是经过图像学研究推导得到的。
对应灰度变换的 ColorFilter
的构造代码如下:
const 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,
]);
最后,我们来看看颜色循环变换的效果,颜色循环变换就是红色部分变为原先像素的绿色值,绿色部分变到原先像素的蓝色值,然后蓝色部分变到原先像素的红色值,对应的 ColorFilter
构造代码如下:
var colorRotation = ColorFilter.matrix(<double>[
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
1, 0, 0, 0, 0,
0, 0, 0, 1, 0
]);
有了这个我们其实就可以做一些动效了,比如我们把变化过程由动画值控制,得到下面的矩阵。
var colorRotation = ColorFilter.matrix(<double>[
animationValue, 1-animationValue, 0, 0, 0,
0, animationValue, 1-animationValue, 0, 0,
1-animationValue, 0, animationValue, 0, 0,
0, 0, 0, 1, 0
]);
我们看看灭霸图片颜色变化的动画效果,整个画面的色调在不断的变化,感觉像灭霸要开始“打响指”了。
ColorFilter 的应用
ColorFilter
的最佳应用场景应该是图片滤镜,我们在图片类应用经常会看到各种滤镜效果(取得名字都很好听,比如什么“清纯”、“蓝调”,“怀旧”等等),实际上这种效果就是将一个颜色预置的变换矩阵应用到图片上。
总结
本篇介绍了颜色过滤器 ColorFilter
的应用以及原理,我们绘图的时候可以使用 ColorFilter
处理图片,实现类似滤镜的效果。如果考虑简单使用,也可以直接使用 ColorFiltered
组件。
本篇源码已上传至:绘图相关源码,文件名为:color_filter_demo.dart
。
作者:岛上码农
链接:https://juejin.cn/post/7118320708786061325
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。