Compose系列文章,请点原文阅读。原文,是时候学习Compose了!
关于混合模式,具体请看 官网链接。
在画布上绘制时使用的算法。将形状或图像绘制到画布上时,可以使用不同的算法来混合像素。 BlendMode的不同值指定了不同的此类算法。
关于混合模式,有多达十几种,在展示下文代码前,我们需要先达成一个共识,这个混合模式,是两个图片相交区域的混合模式,如果不相交,那么混合模式根本不会生效。
所以这就决定了你绘制图片和绘制形状时,图形位置不同就可能会出现奇怪的混合结果。
下文的代码我们会分别绘制大小相同的png图片(如下图所示)以及绘制形状来展示其区别。
目标图像 | 源图像 |
---|---|
注意上图两张图片的区别,大小都是300像素。但是目标图像圆形是直径200像素,位于图片左上角的位置。源图像正方形是宽高200像素,位于图片左下角的位置。
我们会先绘制红色圆形,然后再绘制蓝色矩形,据此,再给大家灌输一个概念:
得到这样一个概念后我们再来看代码:
首先是使用绘制图片的函数drawImage(),然后混合模式为:blendMode = BlendMode.Src
,代码如下所示:
@Composable
fun SrcOverImage() {
val destination = ImageBitmap.imageResource(id = R.drawable.canvas_dst)
val source = ImageBitmap.imageResource(id = R.drawable.canvas_src)
Canvas(
modifier = androidx.compose.ui.Modifier
.size(defaultSizeImage)
) {
drawImage(
image = destination,
)
drawImage(
image = source,
blendMode = BlendMode.Src
)
}
}
此时我们再来看下这个混合模式的含义:Src,Src也就是源图像。所以就是说只显示源图像,效果就是只显示出了蓝色矩形,虽然红色矩形是先绘制的。(至于黑色区域,只是因为截图产生的,其实真实显示效果依旧是透明色,请大家理解)。
好了,以上是根据图片混合得到的结果,下面我们使用draw()函数来进行展示(大致意思是一样的,分别在左上角绘制了红色圆形,在右下角绘制了蓝色矩形):
@Composable
fun SrcOver() {
Canvas(
modifier = Modifier
.size(defaultSizeDraw)
) {
val radius = size.width / 3
drawCircle(
color = myRed,
radius = radius,
center = Offset(radius, radius),
)
drawRect(
color = myBlue,
topLeft = Offset(radius, radius),
size = Size(radius * 2, radius * 2),
blendMode = BlendMode.Src
)
}
}
然而渲染出来的结果却是这样的:
大家思考下为什么会是这样呢???还记得文章开头说的一点么两个图像相交的区域,这里绘制出来的两个图像,相交区域只有最中间的那100像素的大小,其余的地方都不会混合,从而原样展示出来。而上面使用图片进行混合的话,整个区域都是相交的地方。
所以千万别再说官方的示例不正确了,只是各位审题不仔细啊!!!
下面的讲解会将绘制图片的效果示例放置在左侧,draw函数绘制形状效果放置在右侧,注意我们的draw函数绘制图像区域的问题,仅仅是对比而已。
删除源和目标图像,不留下任何东西。
绘制图片 | 绘制形状 |
---|---|
删除目标图像,只绘制源图像。
从概念上讲,首先清除目标,然后绘制源图像。
绘制图片 | 绘制形状 |
---|---|
删除源图像,只绘制目标图像。
从概念上讲,源图像被丢弃,目标图像不受影响。
绘制图片 | 绘制形状 |
---|---|
将源图像与目标图像合成。
这是默认值。它代表了最直观的情况,形状层层往上绘制,用透明区域显示目标层。
绘制图片 | 绘制形状 |
---|---|
在目标图像下合成源图像。
这是反面的SrcOver。
当源图像应该在目标图像之前绘制,但不能这样做时,这是很有用的。
绘制图片 | 绘制形状 |
---|---|
显示源图像,但只显示两个图像重叠的地方。目标图像没有被渲染,它只是作为一个遮罩来处理。目标的颜色通道被忽略,只有不透明度有效果。
绘制图片 | 绘制形状 |
---|---|
显示目标图像,但只显示两个图像重叠的地方。源图像没有被渲染,它仅仅被当作遮罩来处理。源图像的颜色通道被忽略,只有不透明度有效果。
绘制图片 | 绘制形状 |
---|---|
显示源图像,但只在两个图像不重叠的地方。目标图像没有被渲染,它只是作为一个遮罩来处理。目标的颜色通道被忽略,只有不透明度有效果。
绘制图片 | 绘制形状 |
---|---|
显示目标图像,但只在两个图像不重叠的地方。源图像没有被渲染,它仅仅被当作遮罩来处理。光源的颜色通道被忽略,只有不透明度有效果。
绘制图片 | 绘制形状 |
---|---|
将源图像与目标图像合成,但只在源图像与目标图像重叠的地方。
这本质上是SrcOver操作符,但是输出的不透明度通道被设置为目标图像的不透明度通道,而不是两个图像的不透明度通道的组合。
绘制图片 | 绘制形状 |
---|---|
将目标图像与源图像合成,但只在目标图像与源图像重叠的地方。
这本质上是DstOver操作符,但是输出的不透明度通道被设置为源图像的不透明度通道,而不是两个图像的不透明度通道的组合。
绘制图片 | 绘制形状 |
---|---|
对源图像和目标图像应用逐位异或运算符。这使得它们的重叠部分变得透明。
绘制图片 | 绘制形状 |
---|---|
将源图像和目标图像的组件相加。
其中一幅图像的像素的透明度降低了该图像对相应输出像素的贡献,就好像该图像中的像素的颜色较暗一样。
绘制图片 | 绘制形状 |
---|---|
将源图像和目标图像的颜色组件相乘。
这只能导致相同或更深的颜色(乘以白色,1.0,结果没有变化;乘以黑色,0.0,结果为黑色)。
当合成两个不透明的图像时,这与在投影仪上重叠两个幻灯片的效果相似。
对于一个也会乘以alpha通道的变量,考虑乘法。
绘制图片 | 绘制形状 |
---|---|
将源图像和目标图像的分量的逆值相乘,然后将结果相逆。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
这本质上与“调制”混合模式相同,但是颜色的值在乘法之前先反转,结果在渲染前先反转。
这只能导致颜色相同或更浅(乘以黑色1.0不会导致更改;乘以白色0.0则会导致白色)。同样,在Alpha通道中,它只能导致更不透明的颜色。
这与两台投影机在同一屏幕上同时显示其图像的效果相似。
绘制图片 | 绘制形状 |
---|---|
调整源图像和目标图像的分量以使其适合目标后,将它们相乘。
具体来说,如果目标值较小,则将其与源值相乘,而当源值较小时,则将源值的逆与目标值的相乘相乘,然后对结果求反。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
绘制图片 | 绘制形状 |
---|---|
通过从每个颜色通道中选择最小值来合成源图像和目标图像。
以与SrcOver相同的方式计算输出图像的不透明度。
绘制图片 | 绘制形状 |
---|---|
通过从每个颜色通道中选择最大值来合成源图像和目标图像。
以与SrcOver相同的方式计算输出图像的不透明度。
绘制图片 | 绘制形状 |
---|---|
将目标除以源的倒数。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
将目标的倒数除以源,然后将结果倒数。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
调整源图像和目标图像的成分以使其适合源图像之后,将它们相乘。
具体来说,如果源值较小,则将其与目标值相乘,而当目标值较小时,则将目标值的逆与源值的逆相乘,然后求反。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
对于低于0.5的源值使用ColorDodge,对于高于0.5的源值使用ColorBurn。
与Overlay效果相比,这会产生相似但较柔和的效果。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
从每个通道的较大值中减去较小的值。
合成黑色没有效果。 合成白色会使另一张图像的颜色反转。
以与SrcOver相同的方式计算输出图像的不透明度。
注意此BlendMode只能在Android API级别29及更高版本上使用
效果类似于“Exclusion”,但更苛刻。
绘制图片 | 绘制形状 |
---|---|
从两个图像的总和中减去两个图像的乘积的两倍。
合成黑色没有效果。 合成白色会使另一张图像的颜色反转。
以与SrcOver相同的方式计算输出图像的不透明度。
注意此BlendMode只能在Android API级别29及更高版本上使用
效果类似于“Difference”,但较柔和。
绘制图片 | 绘制形状 |
---|---|
将源图像和目标图像的组成部分相乘,包括alpha通道。
这只能产生相同或较深的颜色(乘以白色1.0,结果不变;乘以黑色0.0,结果黑色)。
由于alpha通道也被相乘,因此一幅图像中的全透明像素(不透明度0.0)导致输出中的全透明像素。 这类似于DstIn,但将颜色组合在一起。
对于多种颜色但不与Alpha通道相乘的变体,请考虑“Modulate”。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
获取源图像的色相,以及目标图像的饱和度和光度。
效果是用源图像对目标图像进行着色。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域会从目标获得其色相。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
获取源图像的饱和度以及目标图像的色相和亮度。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目标位置开始饱和。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
获取源图像的色相和饱和度以及目标图像的光度。
效果是用源图像对目标图像进行着色。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目标位置获得其色相和饱和度。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
获取源图像的亮度,以及目标图像的色相和饱和度。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目的地获取其亮度。
注意此BlendMode只能在Android API级别29及更高版本上使用
绘制图片 | 绘制形状 |
---|---|
哇~,这么多混合模式,头疼,不知道能用到几个[笑哭][笑哭][笑哭]。
我们上文示例的两个最简单的图片混合的效果,并不能完全展示出混合的强大,图片过于简单,展示效果有限。所以大家理解后可以自行更换其他图片尝试加深理解。