xFermode是画笔的一个属性,有点类似于PS中的图层,有一个底层图层,和一个顶层图层,通过两个图层叠放层次的不同,可以做出很多好玩的效果。
谷歌官方的apidemo中生成了两个图层的各种叠放次序效果:
是不是有点摸不着头脑,让我们列个表格来解释一下吧:
属性名 | 属性常量 | 属性说明 |
---|---|---|
Clear | PorterDuff.Mode.CLEAR | 所有的图层都不会在画布上展示 |
Src | PorterDuff.Mode.SRC | 只显示顶层图层的图像 |
DST | PorterDuff.Mode.DST | 只显示底层图层的图像 |
SrcOver | PorterDuff.Mode.SRC_OVER | 显示所有图层,顶层图层位于底层图层上面(默认效果) |
DstOver | PorterDuff.Mode.DST_OVER | 显示所有图层,底层图层位于顶层图层上面 |
SrcIn | PorterDuff.Mode.SRC_IN | 显示两个图层的交集,顶层图层位于底层图层上面 |
DstIn | PorterDuff.Mode.DST_IN | 显示两个图层的交集,底层图层位于顶层图层上面 |
SrcOut | PorterDuff.Mode.SRC_OUT | 显示两个图层的部分非交集,只显示顶层图层的非交集部分 |
DstOut | PorterDuff.Mode.DST_OUT | 显示两个图层的部分非交集,只显示底层图层的非交集部分 |
SrcTop | PorterDuff.Mode.SRC_ATOP | 显示底层图层和两个图层的交集部分,顶层位于底层图层的上面 |
DstTop | PorterDuff.Mode.DST_ATOP | 显示顶层图层和两个图层的交集部分,底层图层位于顶层图层上面 |
Xor | PorterDuff.Mode.XOR | 显示两个图层的完整非交集 |
Darken | PorterDuff.Mode.DARKEN | 显示所有图层,顶层位于底层图层上面,相交部位变暗 |
Lighten | PorterDuff.Mode.LIGHTEN | 显示所有图层,顶层位于底层图层上面,相交部位变暗 |
Multiply | PorterDuff.Mode.MULTIPLY | 显示两个图层的交集,颜色变换类似于PS中的“正片叠底”效果 |
Screen | PorterDuff.Mode.SCREEN | 显示两个图层的并集,颜色变换类似于PS中的“滤色”效果 |
Tips:正片叠低效果就是把两个图层中的颜色进行叠加,这样暗的部分会被加强;
滤色效果也是对两个图层中的颜色进行叠加,但亮的部分会被加强。
原理:虽然上面的表格中将XFermode解释成图层的并集交集的叠放,但事实上系统是通过对Sa(Source alpha,Src的透明度)、Da(Destination alpha,Dat的透明度)、Sc(Source Color,Src的颜色)、Dc(Destination Color,Dat的透明度),四个值来进行运算来达到变换的效果。
我们可以在源码中看到相应的运算公式:
/** [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);
使用的时候我们需要设置两个图来进行叠加:
setLayerType(LAYER_TYPE_SOFTWARE, null); //关闭硬件加速
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ms);
mOut = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(mOut);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
RectF rt = new RectF();
rt.left = 0; //矩形的左起点
rt.top = 0; //矩形的顶部起点
rt.right = mBitmap.getWidth(); //矩形的右终点
rt.bottom = mBitmap.getHeight(); //矩形的底部终点
//Dat
canvas.drawRoundRect(rt, 50, 50, mPaint);
//设置Xfermode
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//Src
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
//还原Xfermode
mPaint.setXfermode(null);
通过上面的代码我们就将本来是直角的照片,变成了圆角矩形。
引用声明:慕课网《Android图像处理-变”换”莫测的图像》————eclipse_xu