五、Android绘制知识总结(Xfermode和硬件加速)

一、Xfermode

Xfermode表示图层的混合模式,用于描述两个图层之间进行融合时,像素点进行计算的规则。

在API16之前,Xfermode有3个子类:AvoidXfermode、PixelXorXfermode、PorterDuffXfermode。但在API16以后,前两个已经过时,甚至从源码里移除,所以我们只需学习PorterDuffXfermode即可。

1.1、PorterDuffXfermode

PorterDuffXfermode最早是在1984年由Porter和Duff两人发表的论文《Compositing Digital Images》中出现,所以该混合模式也根据作者来命名。

PorterDuffXfermode构造函数需要指定一个PorterDuff.Mode,而PorterDuff.Mode在以下地方都会涉及:

  • 1、ComposeShader
  • 2、Paint.setXfermode()
  • 3、PorterDuffColorFilter

它提供18种模式可选项:

PorterDuff.Mode 公式
PorterDuff.Mode.CLEAR a l p h a o u t = 0 alpha_{out} = 0 alphaout=0 C o u t = 0 C_{out} = 0 Cout=0
PorterDuff.Mode.SRC a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} alphaout=alphasrc C o u t = C s r c C_{out} = C_{src} Cout=Csrc
PorterDuff.Mode.DST a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} alphaout=alphadst C o u t = C d s t C_{out} = C_{dst} Cout=Cdst
PorterDuff.Mode.SRC_OVER a l p h a o u t = a l p h a s r c + ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = alpha_{src} + (1 - alpha_{src}) * alpha_{dst} alphaout=alphasrc+(1−alphasrc)∗alphadst C o u t = C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = C_{src} + (1 - alpha_{src}) * C_{dst} Cout=Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DST_OVER a l p h a o u t = a l p h a d s t + ( 1 − a l p h a d s t ) ∗ a l p h a s r c alpha_{out} = alpha_{dst} + (1 - alpha_{dst}) * alpha_{src} alphaout=alphadst+(1−alphadst)∗alphasrc C o u t = C d s t + ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = C_{dst} + (1 - alpha_{dst}) * C_{src} Cout=Cdst+(1−alphadst)∗Csrc
PorterDuff.Mode.SRC_IN a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} alphaout=alphasrc∗alphadst C o u t = C s r c ∗ a l p h a d s t C_{out} = C_{src} * alpha_{dst} Cout=Csrc∗alphadst
PorterDuff.Mode.DST_IN a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} alphaout=alphasrc∗alphadst C o u t = C d s t ∗ a l p h a s r c C_{out} = C_{dst} * alpha_{src} Cout=Cdst∗alphasrc
PorterDuff.Mode.SRC_OUT a l p h a o u t = ( 1 − a l p h a d s t ) ∗ a l p h a s r c alpha_{out} = (1 - alpha_{dst}) * alpha_{src} alphaout=(1−alphadst)∗alphasrc C o u t = ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = (1 - alpha_{dst}) * C_{src} Cout=(1−alphadst)∗Csrc
PorterDuff.Mode.DST_OUT a l p h a o u t = ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = (1 - alpha_{src}) * alpha_{dst} alphaout=(1−alphasrc)∗alphadst C o u t = ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = (1 - alpha_{src}) * C_{dst} Cout=(1−alphasrc)∗Cdst
PorterDuff.Mode.SRC_ATOP a l p h a o u t = a l p h a d s t alpha_{out} = alpha_{dst} alphaout=alphadst C o u t = a l p h a d s t ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = alpha_{dst} * C_{src} + (1 - alpha_{src}) * C_{dst} Cout=alphadst∗Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DST_ATOP a l p h a o u t = a l p h a s r c alpha_{out} = alpha_{src} alphaout=alphasrc C o u t = a l p h a s r c ∗ C d s t + ( 1 − a l p h a d s t ) ∗ C s r c C_{out} = alpha_{src} * C_{dst} + (1 - alpha_{dst}) * C_{src} Cout=alphasrc∗Cdst+(1−alphadst)∗Csrc
PorterDuff.Mode.XOR a l p h a o u t = ( 1 − a l p h a d s t ) ∗ a l p h a s r c + ( 1 − a l p h a s r c ) ∗ a l p h a d s t alpha_{out} = (1 - alpha_{dst}) * alpha_{src} + (1 - alpha_{src}) * alpha_{dst} alphaout=(1−alphadst)∗alphasrc+(1−alphasrc)∗alphadst C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst
PorterDuff.Mode.DARKEN a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} alphaout=alphasrc+alphadst−alphasrc∗alphadst C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t + m i n ( C s r c , C d s t ) C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} + min(C_{src}, C_{dst}) Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+min(Csrc,Cdst)
PorterDuff.Mode.LIGHTEN a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} alphaout=alphasrc+alphadst−alphasrc∗alphadst C o u t = ( 1 − a l p h a d s t ) ∗ C s r c + ( 1 − a l p h a s r c ) ∗ C d s t + m a x ( C s r c , C d s t ) C_{out} = (1 - alpha_{dst}) * C_{src} + (1 - alpha_{src}) * C_{dst} + max(C_{src}, C_{dst}) Cout=(1−alphadst)∗Csrc+(1−alphasrc)∗Cdst+max(Csrc,Cdst)
PorterDuff.Mode.MULTIPLY a l p h a o u t = a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} * alpha_{dst} alphaout=alphasrc∗alphadst C o u t = C s r c ∗ C d s t C_{out} = C_{src} * C_{dst} Cout=Csrc∗Cdst
PorterDuff.Mode.SCREEN a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} alphaout=alphasrc+alphadst−alphasrc∗alphadst C o u t = C s r c + C d s t − C s r c ∗ C d s t C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst} Cout=Csrc+Cdst−Csrc∗Cdst
PorterDuff.Mode.ADD a l p h a o u t = m a x ( 0 , m i n ( a l p h a s r c + a l p h a d s t , 1 ) ) alpha_{out} = max(0, min(alpha_{src} + alpha_{dst}, 1)) alphaout=max(0,min(alphasrc+alphadst,1)) C o u t = m a x ( 0 , m i n ( C s r c + C d s t , 1 ) C_{out} = max(0, min(C_{src} + C_{dst}, 1) Cout=max(0,min(Csrc+Cdst,1)
PorterDuff.Mode.OVERLAY a l p h a o u t = a l p h a s r c + a l p h a d s t − a l p h a s r c ∗ a l p h a d s t alpha_{out} = alpha_{src} + alpha_{dst} - alpha_{src} * alpha_{dst} alphaout=alphasrc+alphadst−alphasrc∗alphadst C o u t = { 2 ∗ C s r c ∗ C d s t 2 ∗ C d s t < α d s t a l p h a s r c ∗ α d s t − 2 ( α d s t − C s r c ) ( α s r c − C d s t ) o t h e r w i s e C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & otherwise \end{cases} Cout={2∗Csrc∗Cdstalphasrc∗αdst−2(αdst−Csrc)(αsrc−Cdst)2∗Cdst<αdstotherwise

各种模式下的效果如下图所示:

  • 1、如果原图和目标图大小一致(图中,两者大小均占满整个小方格区域):

  • 2、如果原图和目标图大小不一致(图中,两者大小为可见大小):

这里可以发现,两种效果是不一样的,谷歌官方给的是第一种,但是,通常情况应该是第二种,具体原因可参考该文章

比如我们画一个矩形,应该按第二种效果来考虑,因为源图和目标图大小不一致;如果画相同大小的Bitmap,则按第一种做。

在实际应用中,我们可以从以下三个方面来决定使用哪种模式:

1、目标图像和源图像混合,需不需要生成颜色的叠加特效。如果需要,则从颜色叠加相关模式中选择,有Mode.ADD(饱和度相加)、Mode.DARKEN(变暗)、Mode.LIGHTEN(变亮)、Mode.MULTIPLY (正片叠底)、Mode.OVERLAY(叠加)、Mode.SCREEN(滤色)。

2、当不需要特效,而需要根据某张图片的透明像素来裁剪时,就需要使用SRC相关模式或DST相关模式了。而SRC相关模式与DST相关模式是相通的,唯一不同的是决定当前哪个图像是目标图像和源图像。

3、当需要清空图像时,使用Mode.CLEAR模式。

1.1、实例:

二、硬件加速

2.1、View的绘制模型

1、没有硬件加速:

invalidate the view hierarchy ------> draw the view hierarchy

2、有硬件加速:

invalidate the view hierarchy ------> record and update the display list ------> draw the display list

2.2、开启硬件加速后的异常

1、绘制不正确:可能使用了不支持硬件加速的操作, 需要关闭硬件加速或者绕过该操作

2、抛出异常:可能使用了不支持硬件加速的操作, 需要关闭硬件加速或者绕过该操作

2.3、禁用GPU硬件加速

在Android系统中,有4个不同级别的打开或者关闭硬件加速操作:

1、Application级别:

<application android:hardwareAccelerated="false">

默认为true,用于控制这个app是否开启硬件加速。

2、Activity级别:

<activity android:hardwareAccelerated="false">

3、Window级别:(只支持开启操作)

getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

4、View级别:(只支持关闭操作)

view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
LAYER_TYPE_HARDWARE,使用硬件加速(GPU)进行绘制
LAYER_TYPE_SOFTWARE,使用CPU进行绘制

或者布局文件中,指定以下属性:

android:layerType="software"

2.4、检测是否开启硬件加速

1、view.isHardwareAccelerated()

如果返回true,表示view挂在一个开启了硬件加速的Window之下,也就意味着,它在绘制时,并不一定开启了硬件加速。

2、canvas.isHardwareAccelerated()

如果返回true,因为着canvas在绘制的时候启用了硬件加速,尽量采用此方法来判断是否开启了硬件加速。


相关推荐
HLC++14 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼17 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼18 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon19 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138420 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记20 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难20 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin1 天前
Android随笔-Retrofit
android·retrofit
想取一个与众不同的名字好难1 天前
安卓自定义颜色选择器
android
我命由我123451 天前
Android 开发问题:java.lang.NoSuchMethodError:No virtual method readAllBytes()
android·java·java-ee·kotlin·android studio·android-studio·android runtime