Jetpack Compose - Canvas之BlendMode

Jetpack Compose - Canvas之BlendMode

    • 0、介绍
    • 1、属性一览
    • 2、使用示例
      • 2.1、Clear
      • 2.2、Src
      • 2.3、Dst
      • 2.4、SrcOver
      • 2.5、DstOver
      • 2.6、SrcIn
      • 2.7、DstIn
      • 2.8、SrcOut
      • 2.9、DstOut
      • 2.10、SrcAtop
      • 2.11、DstAtop
      • 2.12、Xor
      • 2.13、Plus
      • 2.14、Modulate
      • 2.15、Screen
      • 2.16、Overlay
      • 2.17、Darken
      • 2.18、Lighten
      • 2.19、ColorDodge
      • 2.20、ColorBurn
      • 2.21、Hardlight
      • 2.22、Softlight
      • 2.23、Difference
      • 2.24、Exclusion
      • 2.25、Multiply
      • 2.26、Hue
      • 2.27、Saturation
      • 2.28、Color
      • 2.29、Luminosity
    • 3、版本更新
    • 4、未解决问题

Compose系列文章,请点原文阅读。原文,是时候学习Compose了!

0、介绍

关于混合模式,具体请看 官网链接。

在画布上绘制时使用的算法。将形状或图像绘制到画布上时,可以使用不同的算法来混合像素。 BlendMode的不同值指定了不同的此类算法。

1、属性一览

关于混合模式,有多达十几种,在展示下文代码前,我们需要先达成一个共识,这个混合模式,是两个图片相交区域的混合模式,如果不相交,那么混合模式根本不会生效。

所以这就决定了你绘制图片绘制形状时,图形位置不同就可能会出现奇怪的混合结果。

下文的代码我们会分别绘制大小相同的png图片(如下图所示)以及绘制形状来展示其区别。

目标图像 源图像
Jetpack Compose - Canvas之BlendMode_第1张图片 Jetpack Compose - Canvas之BlendMode_第2张图片

注意上图两张图片的区别,大小都是300像素。但是目标图像圆形是直径200像素,位于图片左上角的位置。源图像正方形是宽高200像素,位于图片左下角的位置。

2、使用示例

我们会先绘制红色圆形,然后再绘制蓝色矩形,据此,再给大家灌输一个概念:

  • 先绘制的红色圆形,我们将其命名为目标图像,目标就是destination,简写Dst
  • 后绘制的蓝色矩形,我们将其命名为源图像,来源就是source,简写为Src

得到这样一个概念后我们再来看代码:
首先是使用绘制图片的函数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
        )
    }
}

绘制结果如下所示:
Jetpack Compose - Canvas之BlendMode_第3张图片

此时我们再来看下这个混合模式的含义: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
        )
    }
}

然而渲染出来的结果却是这样的:
Jetpack Compose - Canvas之BlendMode_第4张图片
大家思考下为什么会是这样呢???还记得文章开头说的一点么两个图像相交的区域,这里绘制出来的两个图像,相交区域只有最中间的那100像素的大小,其余的地方都不会混合,从而原样展示出来。而上面使用图片进行混合的话,整个区域都是相交的地方。


所以千万别再说官方的示例不正确了,只是各位审题不仔细啊!!!


下面的讲解会将绘制图片的效果示例放置在左侧,draw函数绘制形状效果放置在右侧,注意我们的draw函数绘制图像区域的问题,仅仅是对比而已。

2.1、Clear

删除源和目标图像,不留下任何东西。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第5张图片 Jetpack Compose - Canvas之BlendMode_第6张图片

2.2、Src

删除目标图像,只绘制源图像。
从概念上讲,首先清除目标,然后绘制源图像。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第7张图片 Jetpack Compose - Canvas之BlendMode_第8张图片

2.3、Dst

删除源图像,只绘制目标图像。
从概念上讲,源图像被丢弃,目标图像不受影响。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第9张图片 Jetpack Compose - Canvas之BlendMode_第10张图片

2.4、SrcOver

将源图像与目标图像合成。
这是默认值。它代表了最直观的情况,形状层层往上绘制,用透明区域显示目标层。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第11张图片 Jetpack Compose - Canvas之BlendMode_第12张图片

2.5、DstOver

在目标图像下合成源图像。
这是反面的SrcOver。
当源图像应该在目标图像之前绘制,但不能这样做时,这是很有用的。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第13张图片 Jetpack Compose - Canvas之BlendMode_第14张图片

2.6、SrcIn

显示源图像,但只显示两个图像重叠的地方。目标图像没有被渲染,它只是作为一个遮罩来处理。目标的颜色通道被忽略,只有不透明度有效果。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第15张图片 Jetpack Compose - Canvas之BlendMode_第16张图片

2.7、DstIn

显示目标图像,但只显示两个图像重叠的地方。源图像没有被渲染,它仅仅被当作遮罩来处理。源图像的颜色通道被忽略,只有不透明度有效果。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第17张图片 Jetpack Compose - Canvas之BlendMode_第18张图片

2.8、SrcOut

显示源图像,但只在两个图像不重叠的地方。目标图像没有被渲染,它只是作为一个遮罩来处理。目标的颜色通道被忽略,只有不透明度有效果。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第19张图片 Jetpack Compose - Canvas之BlendMode_第20张图片

2.9、DstOut

显示目标图像,但只在两个图像不重叠的地方。源图像没有被渲染,它仅仅被当作遮罩来处理。光源的颜色通道被忽略,只有不透明度有效果。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第21张图片 Jetpack Compose - Canvas之BlendMode_第22张图片

2.10、SrcAtop

将源图像与目标图像合成,但只在源图像与目标图像重叠的地方。
这本质上是SrcOver操作符,但是输出的不透明度通道被设置为目标图像的不透明度通道,而不是两个图像的不透明度通道的组合。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第23张图片 Jetpack Compose - Canvas之BlendMode_第24张图片

2.11、DstAtop

将目标图像与源图像合成,但只在目标图像与源图像重叠的地方。
这本质上是DstOver操作符,但是输出的不透明度通道被设置为源图像的不透明度通道,而不是两个图像的不透明度通道的组合。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第25张图片 Jetpack Compose - Canvas之BlendMode_第26张图片

2.12、Xor

对源图像和目标图像应用逐位异或运算符。这使得它们的重叠部分变得透明。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第27张图片 Jetpack Compose - Canvas之BlendMode_第28张图片

2.13、Plus

将源图像和目标图像的组件相加。
其中一幅图像的像素的透明度降低了该图像对相应输出像素的贡献,就好像该图像中的像素的颜色较暗一样。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第29张图片 Jetpack Compose - Canvas之BlendMode_第30张图片

2.14、Modulate

将源图像和目标图像的颜色组件相乘。
这只能导致相同或更深的颜色(乘以白色,1.0,结果没有变化;乘以黑色,0.0,结果为黑色)。
当合成两个不透明的图像时,这与在投影仪上重叠两个幻灯片的效果相似。
对于一个也会乘以alpha通道的变量,考虑乘法。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第31张图片 Jetpack Compose - Canvas之BlendMode_第32张图片

2.15、Screen

将源图像和目标图像的分量的逆值相乘,然后将结果相逆。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
这本质上与“调制”混合模式相同,但是颜色的值在乘法之前先反转,结果在渲染前先反转。
这只能导致颜色相同或更浅(乘以黑色1.0不会导致更改;乘以白色0.0则会导致白色)。同样,在Alpha通道中,它只能导致更不透明的颜色。
这与两台投影机在同一屏幕上同时显示其图像的效果相似。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第33张图片 Jetpack Compose - Canvas之BlendMode_第34张图片

2.16、Overlay

调整源图像和目标图像的分量以使其适合目标后,将它们相乘。
具体来说,如果目标值较小,则将其与源值相乘,而当源值较小时,则将源值的逆与目标值的相乘相乘,然后对结果求反。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第35张图片 Jetpack Compose - Canvas之BlendMode_第36张图片

2.17、Darken

通过从每个颜色通道中选择最小值来合成源图像和目标图像。
以与SrcOver相同的方式计算输出图像的不透明度。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第37张图片 Jetpack Compose - Canvas之BlendMode_第38张图片

2.18、Lighten

通过从每个颜色通道中选择最大值来合成源图像和目标图像。
以与SrcOver相同的方式计算输出图像的不透明度。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第39张图片 Jetpack Compose - Canvas之BlendMode_第40张图片

2.19、ColorDodge

将目标除以源的倒数。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第41张图片 Jetpack Compose - Canvas之BlendMode_第42张图片

2.20、ColorBurn

将目标的倒数除以源,然后将结果倒数。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第43张图片 Jetpack Compose - Canvas之BlendMode_第44张图片

2.21、Hardlight

调整源图像和目标图像的成分以使其适合源图像之后,将它们相乘。
具体来说,如果源值较小,则将其与目标值相乘,而当目标值较小时,则将目标值的逆与源值的逆相乘,然后求反。
反转分量意味着将完全饱和的通道(不透明的白色)视为值0.0,将通常视为0.0的值(黑色,透明)视为1.0。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第45张图片 Jetpack Compose - Canvas之BlendMode_第46张图片

2.22、Softlight

对于低于0.5的源值使用ColorDodge,对于高于0.5的源值使用ColorBurn。
与Overlay效果相比,这会产生相似但较柔和的效果。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第47张图片 Jetpack Compose - Canvas之BlendMode_第48张图片

2.23、Difference

从每个通道的较大值中减去较小的值。
合成黑色没有效果。 合成白色会使另一张图像的颜色反转。
以与SrcOver相同的方式计算输出图像的不透明度。
注意此BlendMode只能在Android API级别29及更高版本上使用
效果类似于“Exclusion”,但更苛刻。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第49张图片 Jetpack Compose - Canvas之BlendMode_第50张图片

2.24、Exclusion

从两个图像的总和中减去两个图像的乘积的两倍。
合成黑色没有效果。 合成白色会使另一张图像的颜色反转。
以与SrcOver相同的方式计算输出图像的不透明度。
注意此BlendMode只能在Android API级别29及更高版本上使用
效果类似于“Difference”,但较柔和。

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第51张图片 Jetpack Compose - Canvas之BlendMode_第52张图片

2.25、Multiply

将源图像和目标图像的组成部分相乘,包括alpha通道。
这只能产生相同或较深的颜色(乘以白色1.0,结果不变;乘以黑色0.0,结果黑色)。
由于alpha通道也被相乘,因此一幅图像中的全透明像素(不透明度0.0)导致输出中的全透明像素。 这类似于DstIn,但将颜色组合在一起。
对于多种颜色但不与Alpha通道相乘的变体,请考虑“Modulate”。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第53张图片 Jetpack Compose - Canvas之BlendMode_第54张图片

2.26、Hue

获取源图像的色相,以及目标图像的饱和度和光度。
效果是用源图像对目标图像进行着色。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域会从目标获得其色相。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第55张图片 Jetpack Compose - Canvas之BlendMode_第56张图片

2.27、Saturation

获取源图像的饱和度以及目标图像的色相和亮度。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目标位置开始饱和。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第57张图片 Jetpack Compose - Canvas之BlendMode_第58张图片

2.28、Color

获取源图像的色相和饱和度以及目标图像的光度。
效果是用源图像对目标图像进行着色。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目标位置获得其色相和饱和度。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第59张图片 Jetpack Compose - Canvas之BlendMode_第60张图片

2.29、Luminosity

获取源图像的亮度,以及目标图像的色相和饱和度。
以与SrcOver相同的方式计算输出图像的不透明度。 源图像中完全透明的区域从目的地获取其亮度。
注意此BlendMode只能在Android API级别29及更高版本上使用

绘制图片 绘制形状
Jetpack Compose - Canvas之BlendMode_第61张图片 Jetpack Compose - Canvas之BlendMode_第62张图片

3、版本更新

  • 暂无

4、未解决问题

哇~,这么多混合模式,头疼,不知道能用到几个[笑哭][笑哭][笑哭]。

我们上文示例的两个最简单的图片混合的效果,并不能完全展示出混合的强大,图片过于简单,展示效果有限。所以大家理解后可以自行更换其他图片尝试加深理解。

你可能感兴趣的:(Jetpack-Compose,Jetpack,Compose,Canvas,BlendMode,绘制)