当前位置:   article > 正文

图像混合模式:Android Paint Xfermode 使用和demo_paint xfermode andrioid

paint xfermode andrioid

一、setXfermode(Xfermode xfermode)

Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种,这个方法跟我们上面讲到的setColorFilter蛮相似的。查看API文档发现其果然有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode,这三个子类实现的功能要比setColorFilter的三个子类复杂得多。

由于AvoidXfermode, PixelXorXfermode都已经被标注为过时了,所以这次主要研究的是仍然在使用的PorterDuffXfermode:

 

二、PorterDuffXfermode

该类同样有且只有一个含参的构造方法PorterDuffXfermode(PorterDuff.Mode mode),虽说构造方法的签名列表里只有一个PorterDuff.Mode的参数,但是它可以实现很多酷毙的图形效果!!而PorterDuffXfermode就是图形混合模式的意思,其概念最早来自于SIGGRAPH的Tomas Proter和Tom Duff,混合图形的概念极大地推动了图形图像学的发展,延伸到计算机图形图像学像Adobe和AutoDesk公司著名的多款设计软件都可以说一定程度上受到影响,而我们PorterDuffXfermode的名字也来源于这俩人的人名组合PorterDuff,那PorterDuffXfermode能做些什么呢?我们先来看一张API DEMO里的图片:

这张图片从一定程度上形象地说明了图形混合的作用,两个图形一圆一方通过一定的计算产生不同的组合效果,在API中Android为我们提供了18种(比上图多了两种ADD和OVERLAY)模式: 

  ADD:饱和相加,对图像饱和度进行相加,不常用

  CLEAR:清除图像

  DARKEN:变暗,较深的颜色覆盖较浅的颜色,若两者深浅程度相同则混合

  DST:只显示目标图像

  DST_ATOP:在源图像和目标图像相交的地方绘制【目标图像】,在不相交的地方绘制【源图像】,相交处的效果受到源图像和目标图像alpha的影响

  DST_IN:只在源图像和目标图像相交的地方绘制【目标图像】,绘制效果受到源图像对应地方透明度影响

  DST_OUT:只在源图像和目标图像不相交的地方绘制【目标图像】,在相交的地方根据源图像的alpha进行过滤,源图像完全不透明则完全过滤,完全透明则不过滤

  DST_OVER:将目标图像放在源图像上方

  LIGHTEN:变亮,与DARKEN相反,DARKEN和LIGHTEN生成的图像结果与Android对颜色值深浅的定义有关

  MULTIPLY:正片叠底,源图像素颜色值乘以目标图像素颜色值除以255得到混合后图像像素颜色值

  OVERLAY:叠加

  SCREEN:滤色,色调均和,保留两个图层中较白的部分,较暗的部分被遮盖

  SRC:只显示源图像

  SRC_ATOP:在源图像和目标图像相交的地方绘制【源图像】,在不相交的地方绘制【目标图像】,相交处的效果受到源图像和目标图像alpha的影响

  SRC_IN:只在源图像和目标图像相交的地方绘制【源图像】

  SRC_OUT:只在源图像和目标图像不相交的地方绘制【源图像】,相交的地方根据目标图像的对应地方的alpha进行过滤,目标图像完全不透明则完全过滤,完全透明则不过滤

  SRC_OVER:将源图像放在目标图像上方

  XOR:在源图像和目标图像相交的地方之外绘制它们,在相交的地方受到对应alpha和色值影响,如果完全不透明则相交处完全不绘制

 

而上面这张图片对应的官方DEMO代码如下:https://android.googlesource.com/platform/development/+/master/samples/ApiDemos/src/com/example/android/apis/graphics/Xfermodes.java

  1. public class sampleActivity extends AppCompatActivity {
  2. // create a bitmap with a circle, used for the "dst" image
  3. static Bitmap makeDst(int w, int h) {
  4. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  5. Canvas c = new Canvas(bm);
  6. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  7. p.setColor(0xFFFFCC44);
  8. c.drawOval(new RectF(0, 0, w*3/4, h*3/4), p);
  9. return bm;
  10. }
  11. // create a bitmap with a rect, used for the "src" image
  12. static Bitmap makeSrc(int w, int h) {
  13. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  14. Canvas c = new Canvas(bm);
  15. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  16. p.setColor(0xFF66AAFF);
  17. c.drawRect(w/3, h/3, w*19/20, h*19/20, p);
  18. return bm;
  19. }
  20. @Override
  21. protected void onCreate(Bundle savedInstanceState) {
  22. super.onCreate(savedInstanceState);
  23. setContentView(new SampleView(this));
  24. }
  25. private static class SampleView extends View {
  26. private static final int W = 200;
  27. private static final int H = 200;
  28. private static final int ROW_MAX = 4; // number of samples per row
  29. private Bitmap mSrcB;
  30. private Bitmap mDstB;
  31. private Shader mBG; // background checker-board pattern
  32. private static final Xfermode[] sModes = {
  33. new PorterDuffXfermode(PorterDuff.Mode.CLEAR),
  34. new PorterDuffXfermode(PorterDuff.Mode.SRC),
  35. new PorterDuffXfermode(PorterDuff.Mode.DST),
  36. new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER),
  37. new PorterDuffXfermode(PorterDuff.Mode.DST_OVER),
  38. new PorterDuffXfermode(PorterDuff.Mode.SRC_IN),
  39. new PorterDuffXfermode(PorterDuff.Mode.DST_IN),
  40. new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT),
  41. new PorterDuffXfermode(PorterDuff.Mode.DST_OUT),
  42. new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP),
  43. new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP),
  44. new PorterDuffXfermode(PorterDuff.Mode.XOR),
  45. new PorterDuffXfermode(PorterDuff.Mode.DARKEN),
  46. new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN),
  47. new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY),
  48. new PorterDuffXfermode(PorterDuff.Mode.SCREEN)
  49. };
  50. private static final String[] sLabels = {
  51. "Clear", "Src", "Dst", "SrcOver",
  52. "DstOver", "SrcIn", "DstIn", "SrcOut",
  53. "DstOut", "SrcATop", "DstATop", "Xor",
  54. "Darken", "Lighten", "Multiply", "Screen"
  55. };
  56. public SampleView(Context context) {
  57. super(context);
  58. mSrcB = makeSrc(W, H);
  59. mDstB = makeDst(W, H);
  60. // make a ckeckerboard pattern
  61. Bitmap bm = Bitmap.createBitmap(new int[] { 0xFFFFFFFF, 0xFFCCCCCC,
  62. 0xFFCCCCCC, 0xFFFFFFFF }, 2, 2,
  63. Bitmap.Config.RGB_565);
  64. mBG = new BitmapShader(bm,
  65. Shader.TileMode.REPEAT,
  66. Shader.TileMode.REPEAT);
  67. Matrix m = new Matrix();
  68. m.setScale(6, 6);
  69. mBG.setLocalMatrix(m);
  70. }
  71. @Override protected void onDraw(Canvas canvas) {
  72. canvas.drawColor(Color.WHITE);
  73. Paint labelP = new Paint(Paint.ANTI_ALIAS_FLAG);
  74. labelP.setTextAlign(Paint.Align.CENTER);
  75. Paint paint = new Paint();
  76. paint.setFilterBitmap(false);
  77. canvas.translate(15, 35);
  78. int x = 0;
  79. int y = 0;
  80. for (int i = 0; i < sModes.length; i++) {
  81. // draw the border
  82. paint.setStyle(Paint.Style.STROKE);
  83. paint.setShader(null);
  84. canvas.drawRect(x - 0.5f, y - 0.5f,
  85. x + W + 0.5f, y + H + 0.5f, paint);
  86. // draw the checker-board pattern
  87. paint.setStyle(Paint.Style.FILL);
  88. paint.setShader(mBG);
  89. canvas.drawRect(x, y, x + W, y + H, paint);
  90. // draw the src/dst example into our offscreen bitmap
  91. int sc = canvas.saveLayer(x, y, x + W, y + H, null,
  92. Canvas.MATRIX_SAVE_FLAG |
  93. Canvas.CLIP_SAVE_FLAG |
  94. Canvas.HAS_ALPHA_LAYER_SAVE_FLAG |
  95. Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
  96. Canvas.CLIP_TO_LAYER_SAVE_FLAG);
  97. canvas.translate(x, y);
  98. canvas.drawBitmap(mDstB, 0, 0, paint);
  99. paint.setXfermode(sModes[i]);
  100. canvas.drawBitmap(mSrcB, 0, 0, paint);
  101. paint.setXfermode(null);
  102. canvas.restoreToCount(sc);
  103. // draw the label
  104. canvas.drawText(sLabels[i],
  105. x + W/2, y - labelP.getTextSize()/2, labelP);
  106. x += W + 10;
  107. // wrap around when we've drawn enough for one row
  108. if ((i % ROW_MAX) == ROW_MAX - 1) {
  109. x = 0;
  110. y += H + 30;
  111. }
  112. }
  113. }
  114. }
  115. }

 

对于上面这些mode的详细介绍在GA_STUDIO的这篇文章和AIGESTUDIO的这篇文章都有非常详尽的介绍

 

三、使用场景

以下是PorterDuffXfermode的一些使用场景:

1、自定义loading样式:

代码如下:

  1. public class LogoLoadingView extends View {
  2. private int totalW,totalH;
  3. private Paint paint;
  4. private Bitmap bitmap;
  5. private int currentTop;
  6. private RectF rectF;
  7. private PorterDuffXfermode xfermode;
  8. public LogoLoadingView(Context context) {
  9. super(context);
  10. init();
  11. }
  12. public LogoLoadingView(Context context, AttributeSet attrs) {
  13. super(context, attrs);
  14. init();
  15. }
  16. private void init(){
  17. paint=new Paint();
  18. paint.setAntiAlias(true);//设置抗锯齿
  19. paint.setStyle(Paint.Style.FILL);//设置填充样式
  20. paint.setDither(true);//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
  21. paint.setFilterBitmap(true);//加快显示速度,本设置项依赖于dither和xfermode的设置
  22. bitmap= BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);//从资源文件中解析获取Bitmap
  23. xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
  24. /**
  25. * 设置当前矩形的高度为0
  26. */
  27. currentTop=bitmap.getHeight();
  28. rectF=new RectF(0,currentTop,bitmap.getWidth(),bitmap.getHeight());
  29. }
  30. @Override
  31. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  32. setMeasuredDimension(bitmap.getWidth(),bitmap.getHeight());
  33. }
  34. @Override
  35. protected void onDraw(Canvas canvas) {
  36. super.onDraw(canvas);
  37. rectF.top=currentTop;
  38. /**
  39. * 设置View的离屏缓冲。在绘图的时候新建一个“层”,所有的操作都在该层而不会影响该层以外的图像
  40. * 必须设置,否则设置的PorterDuffXfermode会无效,具体原因不明
  41. */
  42. int sc=canvas.saveLayer(0,0,totalW,totalH,paint,Canvas.ALL_SAVE_FLAG);
  43. canvas.drawBitmap(bitmap,0,0,null);
  44. paint.setXfermode(xfermode);
  45. paint.setColor(Color.RED);
  46. canvas.drawRect(rectF,paint);
  47. paint.setXfermode(null);
  48. /**
  49. * 还原画布,与canvas.saveLayer配套使用
  50. */
  51. canvas.restoreToCount(sc);
  52. if (currentTop>0){
  53. currentTop--;
  54. postInvalidate();
  55. }
  56. }
  57. @Override
  58. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  59. super.onSizeChanged(w, h, oldw, oldh);
  60. totalW=w;
  61. totalH=h;
  62. }
  63. }

 

2、圆形图片

  1. 代码如下:
  2. public class CircleImageView extends View {
  3. private int resId;
  4. private Bitmap bitmap;
  5. private Paint paint;
  6. private int bitmapWidth,bitmapHeight;
  7. private int size;
  8. private PorterDuffXfermode xfermode;
  9. public CircleImageView(Context context, AttributeSet attrs) {
  10. super(context, attrs);
  11. TypedArray array=context.obtainStyledAttributes(attrs, R.styleable.CircleImageView);
  12. resId=array.getResourceId(R.styleable.CircleImageView_imageRes,R.mipmap.ic_launcher);
  13. array.recycle();
  14. init();
  15. }
  16. private void init(){
  17. paint=new Paint(Paint.ANTI_ALIAS_FLAG);
  18. paint.setDither(true);//设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰
  19. paint.setFilterBitmap(true);//加快显示速度,本设置项依赖于dither和xfermode的设置
  20. bitmap= BitmapFactory.decodeResource(getResources(),resId);
  21. bitmapWidth=bitmap.getWidth();
  22. bitmapHeight=bitmap.getHeight();
  23. xfermode=new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
  24. size=Math.min(bitmapWidth,bitmapHeight);
  25. }
  26. @Override
  27. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  28. setMeasuredDimension(size,size);
  29. }
  30. /**
  31. * 生成圆形Bitmap
  32. * @return
  33. */
  34. private Bitmap makeCircle(){
  35. Bitmap bitmap=Bitmap.createBitmap(size,size, Bitmap.Config.ARGB_8888);
  36. Canvas canvas=new Canvas(bitmap);
  37. Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
  38. paint.setColor(Color.BLUE);
  39. paint.setStyle(Paint.Style.FILL);
  40. int radius=size/2;
  41. canvas.drawCircle(size/2,size/2,radius,paint);
  42. return bitmap;
  43. }
  44. @Override
  45. protected void onDraw(Canvas canvas) {
  46. super.onDraw(canvas);
  47. int sc=canvas.saveLayer(0,0,size,size,paint,Canvas.ALL_SAVE_FLAG);
  48. Bitmap dst=makeCircle();
  49. canvas.drawBitmap(dst,0,0,paint);
  50. paint.setXfermode(xfermode);
  51. canvas.drawBitmap(bitmap,0,0,paint);
  52. paint.setXfermode(null);
  53. canvas.restoreToCount(sc);
  54. }
  55. }

 

对应属性定义:

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <resources>
  3. <declare-styleable name="CircleImageView">
  4. <attr name="imageRes" format="reference"/>
  5. </declare-styleable>
  6. </resources>

关于圆形图片的详细介绍可以看鸿洋大大的这篇博文,介绍的非常详尽:

http://blog.csdn.net/lmj623565791/article/details/42094215

 

关于PorterDuffXfermode的应用还有非常多,这里简单介绍这几个。

以上内容大部分参考自:

http://blog.csdn.net/tianjian4592/article/details/44783283     //详解Xfermode

http://blog.csdn.net/aigestudio/article/details/41316141       //把api玩出了ps的效果,图片处理大牛

http://www.cnblogs.com/tianzhijiexian/p/4297172.html        //也是详解

 

原文链接:https://www.cnblogs.com/libertycode/p/6290497.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/332683
推荐阅读
相关标签
  

闽ICP备14008679号