PorterDuff.Mode及Xfermode详解
在android SDK Paint类中有一个很重要的方法setXfermode(源码如上),这个方法用于设置图像的过渡模式,所谓过渡是指图像的饱和度、颜色值等参数的计算结果的图像表现。在SDK中Xfermode有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,前两个类在API 16被遗弃了,而且不是本文的主题内容,所以这里不作介绍。PorterDuffXfermode类主要用于图形合成时的图像过渡模式计算,其概念来自于1984年在ACM SIGGRAPH计算机图形学出版物上发表了“Compositing digital images(合成数字图像)”的Tomas Porter和Tom Duff,合成图像的概念极大地推动了图形图像学的发展,PorterDuffXfermode类名就来源于这俩人的名字组合PorterDuff。
利用ProterBuff.Mode我们可以完成任意2D图像测操作, 比如涂鸦画板应用中的橡皮擦效果,绘制各种自定义的进度,等等很强大的效果,下面请看具体的介绍:
1. Xfermode:
Xfermode有三个子类 :
AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素异或操作。
PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
要应用转换模式,可以使用setXferMode方法,如下所示:
AvoidXfermode avoid = new AvoidXfermode(Color.BLUE, 10, AvoidXfermode.Mode. AVOID); borderPen.setXfermode(avoid);
2.PorterDuff:
首先看一下效果图(来自ApiDemos/Graphics/XferModes)
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
public enum Mode {/** [0, 0] */CLEAR (0),/** [Sa, Sc] */SRC (1),/** [Da, Dc] */DST (2),/** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */SRC_OVER (3),/** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */DST_OVER (4),/** [Sa * Da, Sc * Da] */SRC_IN (5),/** [Sa * Da, Sa * Dc] */DST_IN (6),/** [Sa * (1 - Da), Sc * (1 - Da)] */SRC_OUT (7),/** [Da * (1 - Sa), Dc * (1 - Sa)] */DST_OUT (8),/** [Da, Sc * Da + (1 - Sa) * Dc] */SRC_ATOP (9),/** [Sa, Sa * Dc + Sc * (1 - Da)] */DST_ATOP (10),/** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */XOR (11),/** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */DARKEN (12),/** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */LIGHTEN (13),/** [Sa * Da, Sc * Dc] */MULTIPLY (14),/** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */SCREEN (15),/** Saturate(S + D) */ADD (16),OVERLAY (17);Mode(int nativeInt) {this.nativeInt = nativeInt;}/*** @hide*/public final int nativeInt;
}
上面代码中每种模式的注释都说明了该模式的alpha通道和颜色值的计算方式,要理解各个模式的计算方式需要先弄明白公式中各个元素的具体含义:
Sa:全称为Source alpha,表示源图的Alpha通道;
Sc:全称为Source color,表示源图的颜色;
Da:全称为Destination alpha,表示目标图的Alpha通道;
Dc:全称为Destination color,表示目标图的颜色.
当Alpha通道的值为1时,图像完全可见;当Alpha通道值为0时,图像完全不可见;当Alpha通道的值介于0和1之间时,图像只有一部分可见。Alpha通道描述的是图像的形状,而不是透明度。
以SCREEN的计算方式为例:[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc],“[……]”里分为两部分,其中“,”前的部分“Sa + Da - Sa * Da”计算的值代表SCREEN模式的Alpha通道,而“,”后的部分“Sc + Dc - Sc * Dc”计算SCREEN模式的颜色值,图形混合后的图片依靠这个矢量来计算ARGB的值。关于图像Alpha合成的知识详见维基百科Alpha compositing。
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色
/*** Created by Alex Pang on 2016/8/20.* 自定义View,使用PorterDuff.Mode验证图像合成效果*/
public class PorterDuffXfermodeView extends View {private Paint mPaint;private Bitmap dstBmp, srcBmp;private RectF dstRect, srcRect;private Xfermode mXfermode;private PorterDuff.Mode mPorterDuffMode = PorterDuff.Mode.MULTIPLY;public PorterDuffXfermodeView(Context context) {super(context);mPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);dstBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.destination);srcBmp = BitmapFactory.decodeResource(getResources(), R.mipmap.source);mXfermode = new PorterDuffXfermode(mPorterDuffMode);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//背景色设为白色,方便比较效果canvas.drawColor(Color.WHITE);//将绘制操作保存到新的图层,因为图像合成是很昂贵的操作,将用到硬件加速,这里将图像合成的处理放到离屏缓存中进行int saveCount = canvas.saveLayer(srcRect, mPaint, Canvas.ALL_SAVE_FLAG);//绘制目标图canvas.drawBitmap(dstBmp, null, dstRect, mPaint);//设置混合模式mPaint.setXfermode(mXfermode);//绘制源图canvas.drawBitmap(srcBmp, null, srcRect, mPaint);//清除混合模式mPaint.setXfermode(null);//还原画布canvas.restoreToCount(saveCount);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);int width = w <= h ? w : h;int centerX = w/2;int centerY = h/2;int quarterWidth = width /4;srcRect = new RectF(centerX-quarterWidth, centerY-quarterWidth, centerX+quarterWidth, centerY+quarterWidth);dstRect = new RectF(centerX-quarterWidth, centerY-quarterWidth, centerX+quarterWidth, centerY+quarterWidth);}
}
其中用到的图片资源分别如下,destination沿图片左上到右下的对角线将图片分成两部分,左下部分是完全不透明的,右上部分是半透明的;source沿图片左下到右上的对角线将图片分成两部分,左上部分是半透明的,右下部分是完全不透明的。图中有颜色的区域外都是完全透明的,这样当两张图片合成时可以让各种情况交叉呈现,便于分析理解。
![](http://upload-images.jianshu.io/upload_images/2041548-da63fde65e3c664b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](http://upload-images.jianshu.io/upload_images/2041548-07e5795782d143d1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
CLEAR
清除模式,[0, 0],即图像中所有像素点的alpha和颜色值均为0,Demo中的实际效果就是白色背景,图略。
SRC
[Sa, Sc],只保留源图像的 alpha 和 color ,所以绘制出来只有源图,如source。有时候会感觉分不清先绘制的是源图还是后绘制的是源图,这个时候可以这么记,先绘制的是目标图。
DST
[Da, Dc],只保留了目标图像的alpha和color值,所以绘制出来的只有目标图,如destination。
SRC_OVER
[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc],在目标图像上层绘制源图像
![](http://upload-images.jianshu.io/upload_images/2041548-6bfe1ff0fa510170.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DST_OVER
[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc],与SRC_OVER相反,此模式是目标图像被绘制在源图像的上方
![](http://upload-images.jianshu.io/upload_images/2041548-55f51a5bf1458b10.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
SRC_IN
[Sa * Da, Sc * Da],在两者相交的地方绘制源图像,并且绘制的效果会受到目标图像对应地方透明度的影响
![](http://upload-images.jianshu.io/upload_images/2041548-235c8656ed8f519c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DST_IN
[Sa * Da, Sa * Dc],可以和SRC_IN 进行类比,在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响
![](http://upload-images.jianshu.io/upload_images/2041548-87864df5a15ccc8a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
SRC_OUT
[Sa * (1 - Da), Sc * (1 - Da)],从字面上可以理解为在不相交的地方绘制源图像,那么我们来看看效果是不是这样,如下图。实际上color 是 Sc * ( 1 - Da ) ,表示如果相交处的目标色的alpha是完全不透明的,这时候源图像会完全被过滤掉,否则会受到相交处目标色 alpha 影响,呈现出对应色值。
![](http://upload-images.jianshu.io/upload_images/2041548-214da308cfd66307.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DST_OUT
[Da * (1 - Sa), Dc * (1 - Sa)],可以类比SRC_OUT , 在不相交的地方绘制目标图像,相交处根据源图像alpha进行过滤,完全不透明处则完全过滤,完全透明则不过滤
![](http://upload-images.jianshu.io/upload_images/2041548-a81cb1f294485199.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
SRC_ATOP
[Da, Sc * Da + (1 - Sa) * Dc],源图像和目标图像相交处绘制源图像,不相交的地方绘制目标图像,并且相交处的效果会受到源图像和目标图像alpha的影响
![](http://upload-images.jianshu.io/upload_images/2041548-27456d1a3bbae7dd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DST_ATOP
[Sa, Sa * Dc + Sc * (1 - Da)],源图像和目标图像相交处绘制目标图像,不相交的地方绘制源图像,并且相交处的效果会受到源图像和目标图像alpha的影响
![](http://upload-images.jianshu.io/upload_images/2041548-b8377ca9a8033189.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
XOR
[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc],在不相交的地方按原样绘制源图像和目标图像,相交的地方受到对应alpha和颜色值影响,按公式进行计算,如果都完全不透明则相交处完全不绘制
![](http://upload-images.jianshu.io/upload_images/2041548-ebf53bac280eb5fc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
DARKEN
[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)],该模式处理过后,会感觉效果变暗,即进行对应像素的比较,取较暗值,如果色值相同则进行混合;
从算法上看,alpha值变大,色值上如果都不透明则取较暗值,非完全不透明情况下使用上面算法进行计算,受到源图和目标图对应色值和alpha值影响。
![](http://upload-images.jianshu.io/upload_images/2041548-dcbee4e0f0409499.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
LIGHTEN
[Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)],可以和 DARKEN 对比起来看,DARKEN 的目的是变暗,LIGHTEN 的目的则是变亮,如果在均完全不透明的情况下,色值取源色值和目标色值中的较大值,否则按上面算法进行计算。
![](http://upload-images.jianshu.io/upload_images/2041548-a6faa15df404d012.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
MULTIPLY
[Sa * Da, Sc * Dc],正片叠底,即查看每个通道中的颜色信息,并将基色与混合色复合。结果色总是较暗的颜色,任何颜色与黑色复合产生黑色,任何颜色与白色复合保持不变,当用黑色或白色以外的颜色绘画时,绘画工具绘制的连续描边产生逐渐变暗的颜色。
![](http://upload-images.jianshu.io/upload_images/2041548-c070bf10b30a9ef2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
SCREEN
[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc],滤色,滤色模式与我们所用的显示屏原理相同,所以也有版本把它翻译成屏幕;简单的说就是保留两个图层中较白的部分,较暗的部分被遮盖;当一层使用了滤色(屏幕)模式时,图层中纯黑的部分变成完全透明,纯白部分完全不透明,其他的颜色根据颜色级别产生半透明的效果。
![](http://upload-images.jianshu.io/upload_images/2041548-b8e797eab9d74d52.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
ADD
Saturate(S + D),饱和度叠加
![](http://upload-images.jianshu.io/upload_images/2041548-a7012f0457dee9c8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
OVERLAY
像素是进行 Multiply (正片叠底)混合还是 Screen (屏幕)混合,取决于底层颜色,但底层颜色的高光与阴影部分的亮度细节会被保留
![](http://upload-images.jianshu.io/upload_images/2041548-be8231f9cf868ca5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
相关的文章:
各个击破搞明白PorterDuff.Mode
Android Paint之 setXfermode PorterDuffXfermode 讲解
PorterDuff.Mode及Xfermode详解相关推荐
- Android 颜色渲染(九) PorterDuff及Xfermode详解
Android 颜色渲染(九) PorterDuff及Xfermode详解 之前已经讲过了除ComposeShader之外Shader的全部子类, 在讲ComposeShader(组合渲染)之前, ...
- Android基础入门教程——8.3.5 Paint API之—— Xfermode与PorterDuff详解(二)
Android基础入门教程--8.3.5 Paint API之-- Xfermode与PorterDuff详解(二) 标签(空格分隔): Android基础入门教程 本节引言: 上一节,我们学习了Xf ...
- android PorterDuffXfermode ,PorterDuff.Mode 使用 以及Porter-Duff规则详解
android PorterDuffXfermode ,PorterDuff.Mode 使用 以及Porter-Duff规则详解 1.下面的Xfermode子类可以改变这种行为: AvoidXferm ...
- 详解Paint的setXfermode(Xfermode xfermode)
一.setXfermode(Xfermode xfermode) Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的"过渡 ...
- Android中Canvas绘图之Shader使用图文详解
概述 我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader,这样就可以绘制出多彩的图形.那么Shader是什 ...
- 转载爱哥自定义View系列--Paint详解
上图是paint中的各种set方法 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfermode.ColorFilt ...
- Android项目刮刮奖详解(二)
Android项目刮刮奖详解(一) 前言 上期我们简单地实现了一个画板的功能,用户可以在上面乱写乱画,其实,刮刮奖也是如此,用户刮奖的时候也是乱写乱画的. 刮刮奖原理 一共有两层画布,底层画布存放中奖 ...
- Android 绘图详解-思维导图版
绘图(101题) 版本:2018/5/15-1(18:30) 绘图(101题) 基础知识 View的绘制顺序 Canvas 图层 图层的保存(save-) 图层标志 绘制 颜色绘制(drawColor ...
- Android绘图Canvas十八般武器之Shader详解及实战篇(上)
本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 前言 Android中绘图离不开的就是Canvas了,Canvas是一个庞大的知识体系,有java层的,也有jni层深入到Frame ...
最新文章
- html修改上传文件名,input(file)样式修改及上传文件名显示
- Http请求Response Code含义
- Helm 从入门到实践 | 从 0 开始制作一个 Helm Charts
- python中with的用法
- 铺地毯pascal程序
- oracle result_cache_max_size,oracle database 11g新特性之设置result cache-Oracle
- centos7防火墙操作
- ACM团队周赛题解(2)
- Symbian S60 签名工具
- eclipse 中警告信息汇总
- 周鸿祎重申360不依靠弹窗广告盈利 增值服务是主要模式
- 柯马机器人示教器编程_CR 17911080,COMAU柯马机器人示教器 ,编程器更换显示器维修...
- 一分钟搞懂NB-IoT行业发展
- stm32f107rc使用系统时钟延时不准
- Unirech阿里云国际版云服务器代充-使用Python批量创建实例
- Mutex与Semaphore 第一部分:Semephore
- 【超详细】嵌入式软件学习大纲
- 食物相克表食物最佳搭配
- 为网站添加视频、音乐
- DNS信息查询 ,子域名爆破工具
热门文章
- linux下C语言main函数参数解析
- 软件测试如何进入月薪过两万的大厂(字节跳动、腾讯、阿里......)总结了一些面试经验【建议收藏】
- 矿泉水除溴酸盐解决方案
- oracle分类函数总结,Oracle分组函数之ROLLUP的基本用法
- 向日葵全面科普,为你的远程控制设备及时规避漏洞
- 英语四级真题作文 计算机,英语四级作文 Computers-计算机
- [随想]关于移动支付
- RK3588S Android预置apk
- 抓住偷懒的年轻人,味知香想靠预制菜掀起“厨房革命”难
- mysql主从配置 ssl,MySQL配置SSL主从复制