Android自定义View之PorterDuff.Mode
2017-02-21 00:00
405 查看
在自定义View的时候,少不了遇到由两个图片(两种颜色等)拼接、混合而成,这个时候就会用到PorterDuff.Mode 这个类。
以下为Mode的源码:
从源码上看各种类型都是由四个变量计算而来:
Sa:全称为Source alpha,表示源图的Alpha通道;
Sc:全称为Source color,表示源图的颜色;
Da:全称为Destination alpha,表示目标图的Alpha通道;
Dc:全称为Destination color,表示目标图的颜色.
1)CLEAR
清除模式,[0, 0],即图像中所有像素点的alpha和颜色值均为0,Demo中的实际效果就是白色背景
2)SRC
[Sa, Sc],只保留源图像的 alpha 和 color ,所以绘制出来只有源图,如source。有时候会感觉分不清先绘制的是源图还是后绘制的是源图,这个时候可以这么记,先绘制的是目标图。
3)DST
[Da, Dc],只保留了目标图像的alpha和color值,所以绘制出来的只有目标图
4)SRC_OVER
[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc],在目标图像上层绘制源图像
5)DST_OVER
[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc],与SRC_OVER相反,此模式是目标图像被绘制在源图像的上方
6)SRC_IN
[Sa * Da, Sc * Da],在两者相交的地方绘制源图像,并且绘制的效果会受到目标图像对应地方透明度的影响
7)DST_IN
[Sa * Da, Sa * Dc],可以和SRC_IN 进行类比,在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响
8)SRC_OUT
[Sa * (1 - Da), Sc * (1 - Da)],从字面上可以理解为在不相交的地方绘制源图像,那么我们来看看效果是不是这样。实际上color 是 Sc * ( 1 - Da ) ,表示如果相交处的目标色的alpha是完全不透明的,这时候源图像会完全被过滤掉,否则会受到相交处目标色 alpha 影响,呈现出对应色值。
9)DST_OUT
[Da * (1 - Sa), Dc * (1 - Sa)],可以类比SRC_OUT , 在不相交的地方绘制目标图像,相交处根据源图像alpha进行过滤,完全不透明处则完全过滤,完全透明则不过滤
10)SRC_ATOP
[Da, Sc * Da + (1 - Sa) * Dc],源图像和目标图像相交处绘制源图像,不相交的地方绘制目标图像,并且相交处的效果会受到源图像和目标图像alpha的影响
11)DST_ATOP
[Sa, Sa * Dc + Sc * (1 - Da)],源图像和目标图像相交处绘制目标图像,不相交的地方绘制源图像,并且相交处的效果会受到源图像和目标图像alpha的影响
12)XOR
[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc],在不相交的地方按原样绘制源图像和目标图像,相交的地方受到对应alpha和颜色值影响,按公式进行计算,如果都完全不透明则相交处完全不绘制
13)DARKEN
[Sa + Da - SaDa, Sc(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)],该模式处理过后,会感觉效果变暗,即进行对应像素的比较,取较暗值,如果色值相同则进行混合;
从算法上看,alpha值变大,色值上如果都不透明则取较暗值,非完全不透明情况下使用上面算法进行计算,受到源图和目标图对应色值和alpha值影响。
14)LIGHTEN
[Sa + Da - SaDa, Sc(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)],可以和 DARKEN 对比起来看,DARKEN 的目的是变暗,LIGHTEN 的目的则是变亮,如果在均完全不透明的情况下,色值取源色值和目标色值中的较大值,否则按上面算法进行计算。
15)MULTIPLY
[Sa * Da, Sc * Dc],正片叠底,即查看每个通道中的颜色信息,并将基色与混合色复合。结果色总是较暗的颜色,任何颜色与黑色复合产生黑色,任何颜色与白色复合保持不变,当用黑色或白色以外的颜色绘画时,绘画工具绘制的连续描边产生逐渐变暗的颜色。
16)SCREEN
[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc],滤色,滤色模式与我们所用的显示屏原理相同,所以也有版本把它翻译成屏幕;简单的说就是保留两个图层中较白的部分,较暗的部分被遮盖;当一层使用了滤色(屏幕)模式时,图层中纯黑的部分变成完全透明,纯白部分完全不透明,其他的颜色根据颜色级别产生半透明的效果。
17)ADD
Saturate(S + D),饱和度叠加
18)OVERLAY(覆盖)
像素是进行 Multiply (正片叠底)混合还是 Screen (屏幕)混合,取决于底层颜色,但底层颜色的高光与阴影部分的亮度细节会被保留
若将坐标位置更改如下:
则运行结果如下:
另外,如果目标(圆形)图片和源(矩形)图片相互交互,又会出现不一样的情况
参考链接:http://www.jianshu.com/p/d11892bbe055
http://blog.csdn.net/iispring/article/details/50472485
以下为Mode的源码:
package android.graphics; public class PorterDuff { // these value must match their native equivalents. See SkXfermode.h 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 (16), /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ LIGHTEN (17), /** [Sa * Da, Sc * Dc] */ MULTIPLY (13), /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ SCREEN (14), /** Saturate(S + D) */ ADD (12), OVERLAY (15); Mode(int nativeInt) { this.nativeInt = nativeInt; } /** * @hide */ public final int nativeInt; } /** * @hide */ public static final int modeToInt(Mode mode) { return mode.nativeInt; } /** * @hide */ public static final Mode intToMode(int val) { switch (val) { default: case 0: return Mode.CLEAR; case 1: return Mode.SRC; case 2: return Mode.DST; case 3: return Mode.SRC_OVER; case 4: return Mode.DST_OVER; case 5: return Mode.SRC_IN; case 6: return Mode.DST_IN; case 7: return Mode.SRC_OUT; case 8: return Mode.DST_OUT; case 9: return Mode.SRC_ATOP; case 10: return Mode.DST_ATOP; case 11: return Mode.XOR; case 16: return Mode.DARKEN; case 17: return Mode.LIGHTEN; case 13: return Mode.MULTIPLY; case 14: return Mode.SCREEN; case 12: return Mode.ADD; case 15: return Mode.OVERLAY; } } }
从源码上看各种类型都是由四个变量计算而来:
Sa:全称为Source alpha,表示源图的Alpha通道;
Sc:全称为Source color,表示源图的颜色;
Da:全称为Destination alpha,表示目标图的Alpha通道;
Dc:全称为Destination color,表示目标图的颜色.
1)CLEAR
清除模式,[0, 0],即图像中所有像素点的alpha和颜色值均为0,Demo中的实际效果就是白色背景
2)SRC
[Sa, Sc],只保留源图像的 alpha 和 color ,所以绘制出来只有源图,如source。有时候会感觉分不清先绘制的是源图还是后绘制的是源图,这个时候可以这么记,先绘制的是目标图。
3)DST
[Da, Dc],只保留了目标图像的alpha和color值,所以绘制出来的只有目标图
4)SRC_OVER
[Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc],在目标图像上层绘制源图像
5)DST_OVER
[Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc],与SRC_OVER相反,此模式是目标图像被绘制在源图像的上方
6)SRC_IN
[Sa * Da, Sc * Da],在两者相交的地方绘制源图像,并且绘制的效果会受到目标图像对应地方透明度的影响
7)DST_IN
[Sa * Da, Sa * Dc],可以和SRC_IN 进行类比,在两者相交的地方绘制目标图像,并且绘制的效果会受到源图像对应地方透明度的影响
8)SRC_OUT
[Sa * (1 - Da), Sc * (1 - Da)],从字面上可以理解为在不相交的地方绘制源图像,那么我们来看看效果是不是这样。实际上color 是 Sc * ( 1 - Da ) ,表示如果相交处的目标色的alpha是完全不透明的,这时候源图像会完全被过滤掉,否则会受到相交处目标色 alpha 影响,呈现出对应色值。
9)DST_OUT
[Da * (1 - Sa), Dc * (1 - Sa)],可以类比SRC_OUT , 在不相交的地方绘制目标图像,相交处根据源图像alpha进行过滤,完全不透明处则完全过滤,完全透明则不过滤
10)SRC_ATOP
[Da, Sc * Da + (1 - Sa) * Dc],源图像和目标图像相交处绘制源图像,不相交的地方绘制目标图像,并且相交处的效果会受到源图像和目标图像alpha的影响
11)DST_ATOP
[Sa, Sa * Dc + Sc * (1 - Da)],源图像和目标图像相交处绘制目标图像,不相交的地方绘制源图像,并且相交处的效果会受到源图像和目标图像alpha的影响
12)XOR
[Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc],在不相交的地方按原样绘制源图像和目标图像,相交的地方受到对应alpha和颜色值影响,按公式进行计算,如果都完全不透明则相交处完全不绘制
13)DARKEN
[Sa + Da - SaDa, Sc(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)],该模式处理过后,会感觉效果变暗,即进行对应像素的比较,取较暗值,如果色值相同则进行混合;
从算法上看,alpha值变大,色值上如果都不透明则取较暗值,非完全不透明情况下使用上面算法进行计算,受到源图和目标图对应色值和alpha值影响。
14)LIGHTEN
[Sa + Da - SaDa, Sc(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)],可以和 DARKEN 对比起来看,DARKEN 的目的是变暗,LIGHTEN 的目的则是变亮,如果在均完全不透明的情况下,色值取源色值和目标色值中的较大值,否则按上面算法进行计算。
15)MULTIPLY
[Sa * Da, Sc * Dc],正片叠底,即查看每个通道中的颜色信息,并将基色与混合色复合。结果色总是较暗的颜色,任何颜色与黑色复合产生黑色,任何颜色与白色复合保持不变,当用黑色或白色以外的颜色绘画时,绘画工具绘制的连续描边产生逐渐变暗的颜色。
16)SCREEN
[Sa + Da - Sa * Da, Sc + Dc - Sc * Dc],滤色,滤色模式与我们所用的显示屏原理相同,所以也有版本把它翻译成屏幕;简单的说就是保留两个图层中较白的部分,较暗的部分被遮盖;当一层使用了滤色(屏幕)模式时,图层中纯黑的部分变成完全透明,纯白部分完全不透明,其他的颜色根据颜色级别产生半透明的效果。
17)ADD
Saturate(S + D),饱和度叠加
18)OVERLAY(覆盖)
像素是进行 Multiply (正片叠底)混合还是 Screen (屏幕)混合,取决于底层颜色,但底层颜色的高光与阴影部分的亮度细节会被保留
public class CustomView extends View { private int width = 800; private int height = 800; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); setLayerType(View.LAYER_TYPE_SOFTWARE, null); srcBmp = makeSrc(width, height); dstBmp = makeDst(width, height); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // canvas.drawColor(Color.WHITE); int layerID = canvas.saveLayer(0,0,width*2,height*2,mPaint,Canvas.ALL_SAVE_FLAG); //两个bitmap的位置相同 canvas.drawBitmap(dstBmp, 0, 0, mPaint); // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.XOR)); canvas.drawBitmap(srcBmp,0,0, mPaint); // mPaint.setColor(0xFFFFCC44); // canvas.drawCircle(width/2,height/2,width/4,mPaint); // mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); // mPaint.setColor(0xFF66AAFF); // canvas.drawRect(width/2,height/2, width, height, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(layerID); } // create a bitmap with a circle, used for the "dst" image static Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); //此处坐标不要随意更改 c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p); return bm; } // create a bitmap with a rect, used for the "src" image static Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); //此处坐标不要随意更改 c.drawRect(w/3, h/3, w*19/20, h*19/20, p); return bm; }
若将坐标位置更改如下:
public class CustomView extends View { private int width = 800; private int height = 800; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public CustomView(Context context, AttributeSet attrs) { super(context, attrs); setLayerType(View.LAYER_TYPE_SOFTWARE, null); srcBmp = makeSrc(width, height); dstBmp = makeDst(width, height); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // canvas.drawColor(Color.WHITE); int layerID = canvas.saveLayer(0,0,width*2,height*2,mPaint,Canvas.ALL_SAVE_FLAG); //两个bitmap的位置不相同 canvas.drawBitmap(dstBmp, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); canvas.drawBitmap(srcBmp,width/2,height/2, mPaint); mPaint.setXfermode(null); canvas.restoreToCount(layerID); } // create a bitmap with a circle, used for the "dst" image static Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } // create a bitmap with a rect, used for the "src" image static Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0, w, h, p); return bm; }
则运行结果如下:
另外,如果目标(圆形)图片和源(矩形)图片相互交互,又会出现不一样的情况
参考链接:http://www.jianshu.com/p/d11892bbe055
http://blog.csdn.net/iispring/article/details/50472485
相关文章推荐
- 0917Android基础自定义View(颜色渲染PorterDuff及Xfermode)
- Android 自定义View之PorterDuffXfermode的使用(刮刮卡的效果实现)
- Android自定义View---PorterDuffXfermode两个交叠图形的显示
- 关于自定义View的Paint、Canvas和PorterDuffXfermode的用法
- 自定义view之PorterDuffXfermode实现刮刮卡
- 自定义View--圆形头像(用PorterDuff.Mode)
- PorterDuffXfermode实例,将自定义View变为图片
- Xfermode和PorterDuff详解、自定义View的属性、涂鸦和悬浮球绘制
- 自定义View——PorterDuffXfermode
- 自定义View通过PorterDuffXfermode实现图片遮罩效果
- android图形图像处理PorterDuffXfermode
- android PorterDuffXfermode ,PorterDuff.Mode 使用 以及Porter-Duff规则详解
- android Xfermode PorterDuffXfermode 实现遮罩层
- Android PorterDuff.Mode与Canvas实际使用
- [转]Android PorterDuff.Mode效果
- android PorterDuffXfermode ,PorterDuff.Mode 使用 以及Porter-Duff规则详解
- Android 颜色渲染(九) PorterDuff及Xfermode详解
- Android PorterDuffXfermode,PorterDuff.Mode的使用以及Porter-Duff规则
- android PorterDuffXfermode ,PorterDuff.Mode 使用 以及Porter-Duff规则详解
- Android[api]PorterDuff及Xfermode详解