PorterDuffXfermode
- 该模式针对的时在处理结果时以源图像显示为主的模式,主要有:Mode.SRC, Mode.SRC_IN, Mode.SRC_OUT, Mode.SRC_OVER和Mode.SRC_ATOP
Mode.SRC:
//全部以源图像进行显示
[Sa, Sc]
Mode.SRC_IN:
//透明度和颜色值都是通过乘以目标图像的像素得到的
//利用这个特性可以实现,圆角效果,和图片倒影等
[Sa * Da, Sc * Da]
- 上述两者的唯一不同之处在于当目标图像为空白像素时,SRC_IN模式所对应的区域也会变成空白像素
- 圆角效果:
- 首先需要准备一个圆角的图片,通过图片和这个圆角的图片进行融合,透明的部分融合后显示透明即可
- 图片倒影:
package com.example.adminstator.myviewdesign.hunhemoshi.yuantuxiangmoshi.daoying;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import com.example.adminstator.myviewdesign.R;
/**
* Created with Android Studio.
* Description:
*
* @author: 王拣贤
* @date: 2019/06/21
* Time: 16:58
*/
public class InvertedImageView extends View {
private Paint paint;
private Bitmap BmpDST, BmpSRC, BmpRevert;
public InvertedImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_SOFTWARE, null);
paint = new Paint();
BmpDST = BitmapFactory.decodeResource(getResources(), R.drawable.dog_invert_shade, null);
BmpSRC = BitmapFactory.decodeResource(getResources(), R.drawable.dog,null);
Matrix matrix = new Matrix();
matrix.setScale(1F, -1F);
//翻转小狗图像
BmpRevert = Bitmap.createBitmap(BmpSRC, 0, 0, BmpSRC.getWidth(),
BmpSRC.getHeight(), matrix, true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = getWidth() / 2;
int height = width * BmpDST.getHeight()/BmpDST.getWidth();
//画出小狗图像
canvas.drawBitmap(BmpSRC, null, new RectF(0, 0, width, height), paint);
//将画布下移,画出倒影
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
canvas.translate(0, height);
//将小狗图的翻转和背景图结合
canvas.drawBitmap(BmpDST, null, new RectF(0, 0, width, height), paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(BmpRevert, null, new RectF(0, 0, width, height), paint);
paint.setXfermode(null);
canvas.restoreToCount(layerId);
}
}
Mode.SRC_OUT:
//当目标图像完全不透明的时候,计算结果是透明的,当目标图像是空白像素的时候,完全显示源图像。
//以目标图像的补值来调节图像的透明度和饱和度
//可以实现橡皮擦效果
//可以实现刮刮卡效果
[Sa * (1-Da), Sc * (1-Da)]
- eg:橡皮擦: 就是首先创建一个空白像素的Bitmap作为背景,这样在这个Bitmap上再创建一个画布,这样我们通过在这个画布上进行绘制手指的路径,将手指扫过的路径变的透明,这样原本不透明部分因为设置了Mode.SRC_OUT模式,而变得透明
package com.example.adminstator.myviewdesign.hunhemoshi.yuantuxiangmoshi.ModeSrcOut;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.example.adminstator.myviewdesign.R;
/**
* Created with Android Studio.
* Description:
*
* @author: 王拣贤
* @date: 2019/06/21
* Time: 17:18
*/
public class EraserView extends View {
private Paint paint;
private Bitmap BmpDST, BmpSRC;
private Path path;
private float mPreX, mPreY;
public EraserView(Context context,AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_SOFTWARE, null);
paint = new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(45);
BitmapFactory.Options options = new BitmapFactory.Options();
//设置采样率为2,将图片设置为原来的1/2
options.inSampleSize = 2;
BmpSRC = BitmapFactory.decodeResource(getResources(), R.drawable.dog,options);
BmpDST = Bitmap.createBitmap(BmpSRC.getWidth(), BmpSRC.getHeight(), Bitmap.Config.ARGB_8888);
path = new Path();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
path.moveTo(event.getX(), event.getY());
mPreX = event.getX();
mPreY = event.getY();
return true;
case MotionEvent.ACTION_MOVE:
float endX = (mPreX+event.getX())/2;
float endY = (mPreY+event.getY())/2;
path.quadTo(mPreX, mPreY, endX, endY);
mPreX = event.getX();
mPreY = event.getY();
break;
case MotionEvent.ACTION_UP:
break;
}
postInvalidate();
return super.onTouchEvent(event);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);
//先把手势轨迹画到目标图像上
Canvas c = new Canvas(BmpDST);
c.drawPath(path, paint);
//然后把目标图像画到画布上
canvas.drawBitmap(BmpDST,0, 0, paint);
//计算源图像区域
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
canvas.drawBitmap(BmpSRC, 0, 0, paint);
paint.setXfermode(null);
canvas.restoreToCount(layerId);
}
}
Mode.SRC_OVER:
//在目标图像的顶部绘制源图像,即在源图像的透明度的基础上增加一部分目标图像的透明度,增加的透明度是源图像透明度的补量,当源图像的透明度为100%时,原样显示源图像。
[Sa + (1 - Sa) * Da, Rc = Sc + (1-Sa)*Dc]
Mode.SRC_ATOP:
//效果和SRC_IN相同,它直接使用目标图像的透明度作为源图像的透明度
//当透明度时是100%或者0时,SRC_ATOP和SRC_IN是通用的,当透明度不是SRC_ATOP和SRC_IN时,SRC_ATOP相比SRC_IN源图像饱和度会增加
[Da, Sc * Da + (1 - Sa) * Dc]
目标图像模式和其他模式:
- 目标图像模式:在SRC的相关模式中,处理相交区域,优先以源图像显示为主,而在与DST相关模式中,在处理相交区域时,优先以目标图像显示为主。目标图像显示的模式有:Mode.DST, Mode.DST_IN, Mode.DST_OUT, Mode.DST_OVER, Mode.DST_ATOP,所以只需要将上述的代码中的目标图像与源图像的位置进行互调就可以了。
Mode.DST:
//全部以目标图像进行展示
[Da, Dc]
Mode.DST_IN:
//利用源图像的透明度来改变目标图像的透明度和饱和度,当源图像的透明度为0, 目标图像完全不显示
[Sa * Da, Sa * Dc]
Mode.DST_OUT:
//利用源图像的透明度的补值来改变目标图像的透明度和饱和度的
//当源图像的不透明度是100%,那么目标图像就是空白,如果源图像不透明度是0%,那么目标图像就是完全显示
[Da * (1-Sa), Dc * (1-Sa)]
Mode.DST_OVER:
//在源图像顶部绘制目标图像
[Sa + (1 - Sa) * Da, Rc = Dc + (1 - Da) * Sc]
Mode.DST_ATOP:
//DST_ATOP和DST_IN模式可以通用,但是DST_ATOP所产生的效果图在源图像 的头民发都不是0或者100%时,会比DST_IN模式产生的效果图更明亮
[Sa, Sa * Dc + Sc * (1 - Da)]
SRC与DST总结:
- DST的相关模式完全可以使用SRC对应的模式来实现,只需将目标图像和源图像对调一下即可
- 在SRC模式中,以显示源图像为主,通过目标图像的透明度来调节计算结果的透明渡河饱和度,而在DST模式中,通过源图像 的透明度来调节目标图像计算结果的透明度和饱和度
Mode.CLEAR:
//空白像素,也就是说源图像所在区域会变成空白像素,起到清空源图像所在区域的作用
[0, 0]
总结:
(1)目标图像和源图像混合,需不需要生成颜色的叠加块,如果需要,则从颜色的叠加相关模式中进行选择:Mode.ADD(饱和度相加),Mode.DARKEN(变暗), Mode.LIGHTEN(变亮)、Mode.MULTIPLY(正片叠底)、Mode.OVERLAY(叠加)、Mode.SCREEN(绿色)
(2)当不需要特效的时候,而是需要根据魔杖图片的透明像素来裁剪时,就需要使用SRC相关模式或者DST相关模式了,而SRC相关模式和DST相关模式时相通的,唯一不同的时决定当前那个图像是目标图像和源图像。
(3)当需要清空源图像的时候,使用Mode.CLEAR模式