逐一认识PorterDuff.Mode
来源:互联网 发布:freebsd和ubuntu 编辑:程序博客网 时间:2024/05/22 15:43
setXfermode(Xfermode xfermode)
Xfermode被称为过渡模式,我们也可以称之为图像混合模式。Xfermode有三个实现类:AvoidXfermode, PixelXorXfermode以及PorterDuffXfermode。前两个类因为不支持硬件加速在API level 16被标记为Deprecated了,用也可以,但是需要关闭硬件加速.在最新的API中,只能看到PorterDuffXfermode这个子类。
在自定义View时,当一个Xfermode被分配给Paint,那么使用该Paint时,就使用了该模式。
/** * 设置或者清除过渡模式 * xfermode 可以设置为Null,用于清除之前设置的Xfermode */public Xfermode setXfermode(Xfermode xfermode) { int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; if (newMode != curMode) { nSetXfermode(mNativePaint, newMode); } mXfermode = xfermode; return xfermode;}
PorterDuffXfermode
PorterDuffXfermode用于图形合成时的图像过渡模式计算,它的概念来自于1984年在ACM SIGGRAPH计算机图形学出版物上发表了“Compositing digital images(合成数字图像)”的Tomas Porter和Tom Duff,有兴趣的可以查阅下。在其构造方法里只有一个参数 PorterDuff.Mode,由它来指定图形合成时颜色值的计算方式。
public PorterDuffXfermode(PorterDuff.Mode mode) { porterDuffMode = mode.nativeInt;}
这种图像混合模式,实现也是十分简单。
Paint paint = new Paint();canvas.drawBitmap(destinationImage, 0, 0, paint);PorterDuff.Mode mode = // choose a modepaint.setXfermode(new PorterDuffXfermode(mode));canvas.drawBitmap(sourceImage, 0, 0, paint);
PorterDuff.Mode
PorterDuff.Mode又分为Alpha合成模式和混合模式。图像合成就是将源像素和背景像素的颜色进行混合,最终显示的颜色取决于其RGB颜色分量和Alpha值。以PorterDuff.Mode.SRC_IN为例:
public enum Mode { *** /** * Aout = Asrc × (1 - Adst) * Cout = Csrc + (1 - Asrc) × Cdst */ SRC_IN (5), Mode(int nativeInt) { this.nativeInt = nativeInt; } /** * @hide */ public final int nativeInt;}
在上述代码中,解释了该模式下Alpha和颜色值的计算方式。其中:
- Aout:合成后图片的Alpha通道
- Cout:合成后的RGB颜色分量
- Asrc:源图片的Alpha通道
- Csrc:源图片的RGB颜色分量
- Adst:目标图片的Alpha通道
- Cdst:目标图片的RGB颜色分量
这也就是说,在SRC_IN模式中,Asrc × (1 - Adst) 计算的值是合成后的Alpha通道,而Csrc + (1 - Asrc) × Cdst计算的值是合成后的RGB颜色分量,合成后的图片以得到的这个ARGB来显示。
为了方便验证这些效果,自定义了一个View:
class XfermodeView : View { lateinit var mPaint: Paint // 源图 lateinit var mSource: Bitmap // 目标图 lateinit var mDst: Bitmap // 过渡模式 var mXfermode: Xfermode? = null *** override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) /* * 将绘制操作保存到新的图层(更官方的说法应该是离屏缓存) */ val sc = canvas?.saveLayer(0f, 0f, width.toFloat(), height.toFloat(), null, Canvas.ALL_SAVE_FLAG) // 先绘制dis目标图 canvas?.drawBitmap(mDst, 0f, 0f, mPaint) // 设置混合模式 mPaint.xfermode = mXfermode // 再绘制src源图 canvas?.drawBitmap(mSource, 0f, 0f, mPaint) // 还原混合模式 mPaint.xfermode = null // 还原画布 canvas?.restoreToCount(sc!!) } /** * 设置混合模式 */ fun setXfermode(mode: PorterDuff.Mode) { mXfermode = PorterDuffXfermode(mode) invalidate() }}
前面提到了,目标图和源图的概念。之前看到这里的时候,一直分不清什么哪个是目标图哪个是源图。尽管问了UI,也没有给出建设性的解答。那只能这么记了:先绘制的就是目标图。
Alpha合成模式
Source
Enumz值:PorterDuff.Mode.SRC
计算方式:
Aout = Asrc
Cout = Csrc
效 果:只保留源图像的 alpha 和 color ,所以绘制出来只有源图
Source Over
Enumz值:PorterDuff.Mode.SRC_OVER
计算方式:
Aout = Asrc + (1 - Asrc)×Adst
Cout = Csrc + (1 - Asrc)×Cdst
效 果:将源图像放到目标图像的上方
Source In
Enumz值:PorterDuff.Mode.SRC_IN
计算方式:
Aout = Asrc × (1 - Adst)
Cout = Csrc + (1 - Asrc) × Cdst
效 果:绘制源图像和目标图像相交的部分的源图像,舍弃原图像和目标图像其他的部分
Source Out
Enumz值:PorterDuff.Mode.SRC_OUT
计算方式:
Aout = (1 - Adst) × Asrc
Cout = (1 - Adst) × Csrc
效 果:只绘制目标图像未覆盖的源图像的部分
Source Atop
Enumz值:PorterDuff.Mode.SRC_ATOP
计算方式:
Aout = Adst
Cout = Csrc × Adst + (1 - Asrc) × Cdst
效 果:在源图像和目标图像相交的地方绘制源图像,在不相交的地方绘制目标图像
Destination
Enumz值:PorterDuff.Mode.DST
计算方式:
Aout = Adst
Cout = Cdst
效 果:只绘制目标图像
Destination Over
Enumz值:PorterDuff.Mode.DST_OVER
计算方式:
Aout = Adst + (1 - Adst)×Asrc
Cout = Cdst + (1 - Adst)×Csrc
效 果:在源图像的上方绘制目标图像
Destination In
Enumz值:PorterDuff.Mode.DST_IN
计算方式:
Aout = Adst × Asrc
Cout = Cdst × Csrc
效 果:绘制源图像和目标图像相交的部分的目标图像,舍弃原图像和目标图像其他的部分
Destination Out
Enumz值:PorterDuff.Mode.DST_OUT
计算方式:
Aout = (1 - Asrc) × Adst
Cout = (1 - Asrc) × Cdst
效 果:只绘制目标图像与源图像不相交的部分
Destination Atop
Enumz值:PorterDuff.Mode.DST_ATOP
计算方式:
Aout = Asrc
Cout = Asrc × Cdst + (1 - Adst) × Csrc
效 果:在源图像和目标图像相交的地方绘制目标图像,而在不相交的地方绘制源图像
Clear
Enumz值:PorterDuff.Mode.CLEAR
计算方式:
Aout = 0
Cout = 0
效 果:在源图像覆盖的目标图像的像素被清除为0
Exclusive Or
Enumz值:PorterDuff.Mode.XOR
计算方式:
Aout = (1 - Adst) × Asrc + (1 - Asrc) × Adst
Cout = (1 - Adst) × Csrc + (1 - Asrc) × Cdst
效 果:源图像和目标图像相交的部分的像素清除为0,然后绘制剩余的源图像
混合模式
混合模式应该关闭硬件加速(Clear、Adstrken、Ligten、)
Adstrken
Enumz值:PorterDuff.Mode.AdstRKEN
计算方式:
Aout = Adst + Asrc - Adst × Asrc
Cout = (1 - Adst) × Csrc + (1 - Asrc) × Cdst + min(Cdst, Csrc)
效 果:保留原图像和目标图像的像素的最小的分量,效果就是源图像和目标图像相交的部分变暗
Lighten
Enumz值:PorterDuff.Mode.LIGHTEN
计算方式:
Aout = Adst + Asrc - Adst × Asrc
Cout = (1 - Adst) × Csrc + (1 - Asrc) × Cdst + max(Cdst, Csrc)
效 果:保留原图像和目标图像的像素的最大的分量,效果就是源图像和目标图像相交的部分变亮
Multiply
Enumz值:PorterDuff.Mode.MULTIPLY
计算方式:
Aout = Adst × Asrc
Cout = Cdst × Csrc
效 果:只绘制源图像和目标图像相交的部分,而混合后图像像素的颜色值为源图像素颜色值乘以目标图像素颜色值除以255即得
Csrcreen
Enumz值:PorterDuff.Mode.CsrcREEN
计算方式:
Aout = Adst + Asrc - Adst × Asrc
Cout = Cdst+ Csrc - Cdst × Csrc
效 果:滤色:在源图像和目标图像相交的部分添加源图像和目标图像像素,然后减去目标图像与源像素相乘的。
Overlay
Enumz值:PorterDuff.Mode.OVERLAY
计算方式:
Aout = Adst + Asrc - Adst × Asrc
Cout = 2 × Cdst × Csrc 或者其他方式
效 果:根据目标图像的颜色,对源图片和目标图片的像素地进行倍增或屏蔽。
若想了解更多Paint相关的内容,请跳入: 自定义View系列文章目录
如果觉得我的文章对您有用,请随意点赞、评论。您的支持将鼓励我继续创作!
- 逐一认识PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- PorterDuff.Mode
- Graphics中PorterDuff.Mode!!!!!!
- PorterDuff.Mode说明
- PorterDuff.Mode说明
- PorterDuff.Mode详解
- setXfermode中PorterDuff.Mode
- android PorterDuff.Mode详解
- PorterDuff.Mode简介
- PorterDuff.Mode 效果
- 重建二叉树(前序和中序)
- 51Nod 1499 图(最小割)
- caffe添加新层windows
- 安卓ADB端口被占用/ADB无法使用解决办法
- 欢迎使用CSDN-markdown编辑器
- 逐一认识PorterDuff.Mode
- java定时任务实现的几种方式
- 欢迎使用CSDN-markdown编辑器
- Tablayoutdemo标题固定
- python学习(一)——基础
- 判断字符串为空的几种方法
- 马云重新定义技术 阿里云重新定义计算
- iPhone 8 A11处理器
- 通用电气要引燃一场AWS与微软的云战争?