做过图形图像处理coding的Android程序员一定用过或了解过PorterDuff.Mode这个枚举变量中的某些值,对此了解不多理解不深刻的时候是不是会很纠结到底该用那个模式呢?至少不能快速准确地用到恰当的模式,那么PorterDuff.Mode究竟是什么,它的各个枚举值有什么作用呢?这里我整理一下笔记,加深理解。
PorterDuff.Mode是什么public Xfermode setXfermode(Xfermode xfermode) {
long xfermodeNative = 0;
if (xfermode != null)
xfermodeNative = xfermode.native_instance;
native_setXfermode(mNativePaint, xfermodeNative);
mXfermode = xfermode;
return 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。下面是android SDK中PorterDuff的Mode枚举类型定义。
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。
如何应用PorterDuff.Mode
上面这张图从一定程度上形象地说明了运用PorterDuff.Mode进行图像合成的作用,两个图形一圆一方通过一定的计算产生了不同的合成效果,我们在实际工作中需要做图片处理时可以参考这张图的示意快速地选择合适的Mode。为了更清楚地理解各个Mode的作用效果,我自己写了一个Demo,逐一验证上面的Mode。
/**
* 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);
}
@Override
protected 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);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int width = w
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?


微信扫码登录