[关闭]
@946898963 2020-03-06T15:08:00.000000Z 字数 3735 阅读 737

Paint Xfermode 学习小结

Canvas与Paint


Xfermode介绍

Xfermode国外有大神称之为过渡模式,这种翻译比较贴切但恐怕不易理解,大家也可以直接称之为图像混合模式,因为所谓的“过渡”其实就是图像混合的一种。Xfermode有三个子类:AvoidXfermode, PixelXorXfermode和PorterDuffXfermode。由于AvoidXfermode, PixelXorXfermode都已经被标注为过时了,所以这次主要研究的是仍然在使用的PorterDuffXfermode

PorterDuffXfermode

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

此处输入图片的描述

这张图片从一定程度上形象地说明了图形混合的作用:两个图形,按照不同模式,组合成不同的结果显示出来

模式介绍

Android 提供了 18 种图片混排模式(比上图多了两种ADD和OVERLAY),这些混排模式会用到两个图层:先绘制的图是目标图(DST) ,后绘制的图是源图(SRC)

此处输入图片的描述

各种模式的具体的作用,根据例子来学习。

例子

获取了屏幕宽高,然后画了一个矩形一个圆形,计算了一下它们的位置,然后设置下图层,接着设下下画笔 setXfermode,最后绘制到 canvas 上。

  1. public class XfermodeView extends View {
  2. private Context context;
  3. //屏幕宽高
  4. private int screenW;
  5. //绘制的图片宽高
  6. private int width = 200;
  7. private int height = 200;
  8. //上层SRC的Bitmap和下层Dst的Bitmap
  9. private Bitmap srcBitmap, dstBitmap;
  10. public XfermodeView(Context context) {
  11. this(context, null);
  12. }
  13. public XfermodeView(Context context, AttributeSet attrs) {
  14. this(context, attrs, 0);
  15. }
  16. public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) {
  17. super(context, attrs, defStyleAttr);
  18. this.context = context;
  19. WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  20. DisplayMetrics dm = new DisplayMetrics();
  21. manager.getDefaultDisplay().getMetrics(dm);
  22. screenW = dm.widthPixels;
  23. //实例化两个Bitmap
  24. srcBitmap = makeSrc(width, height);
  25. dstBitmap = makeDst(width, height);
  26. }
  27. @Override
  28. public void onMeasure(int width, int height) {
  29. setMeasuredDimension(screenW, 8000);
  30. }
  31. //定义一个绘制圆形 Bitmap 的方法
  32. private Bitmap makeDst(int w, int h) {
  33. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  34. Canvas c = new Canvas(bm);
  35. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  36. p.setColor(0xFFE54261);
  37. c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p);
  38. return bm;
  39. }
  40. //定义一个绘制矩形的 Bitmap 的方法
  41. private Bitmap makeSrc(int w, int h) {
  42. Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  43. Canvas c = new Canvas(bm);
  44. Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
  45. p.setColor(0xFF3097F3);
  46. c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p);
  47. return bm;
  48. }
  49. @Override
  50. protected void onDraw(Canvas canvas) {
  51. Paint paint = new Paint();
  52. paint.setFilterBitmap(false);
  53. paint.setStyle(Paint.Style.FILL);
  54. paint.setTextSize(48.0f);
  55. for (PorterDuff.Mode mode : PorterDuff.Mode.class.getEnumConstants()) {
  56. Log.d("modes", mode.name());
  57. canvas.drawText(mode.name(), 10, 50, paint);
  58. canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, 100, paint);
  59. canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, 100, paint);
  60. int sc = canvas.saveLayer(0, 0, screenW, 300, null, Canvas.ALL_SAVE_FLAG);
  61. canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
  62. 100, paint); //绘制
  63. //设置Paint的Xfermode
  64. paint.setXfermode(new PorterDuffXfermode(mode));
  65. canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2,
  66. 100, paint);
  67. paint.setXfermode(null);
  68. // 还原画布
  69. canvas.restoreToCount(sc);
  70. canvas.translate(0, 400);
  71. }
  72. }
  73. }

PorterDuff.Mode.CLEAR

所绘制不会提交到画布上

此处输入图片的描述

PorterDuff.Mode.SRC

只保留源图像的 alpha 和 color,所以绘制出来只有源图

此处输入图片的描述

PorterDuff.Mode.DST

只保留目标图的 alpha 和 color,所以绘制出来只有目标图

此处输入图片的描述

PorterDuff.Mode.SRC_OVER

把源图绘制在上方

此处输入图片的描述

PorterDuff.Mode.DST_OVER

目标图绘制在上方

此处输入图片的描述

PorterDuff.Mode.SRC_IN

两者相交的地方绘制源图

此处输入图片的描述

PorterDuff.Mode.DST_IN

两者相交的地方绘制目标图,绘制的效果会受到原图处的透明度影响

此处输入图片的描述

PorterDuff.Mode.SRC_OUT

不相交的地方绘制源图

此处输入图片的描述

PorterDuff.Mode.DST_OUT

在不相交的地方绘制目标图

此处输入图片的描述

PorterDuff.Mode.SRC_ATOP

源图和目标图相交处绘制源图,不相交的地方绘制目标图

此处输入图片的描述

PorterDuff.Mode.DST_ATOP

源图和目标图相交处绘制目标图,不相交的地方绘制源图

此处输入图片的描述

PorterDuff.Mode.XOR

不相交的地方按原样绘制源图和目标图

此处输入图片的描述

PorterDuff.Mode.DARKEN

取两图层全部区域,交集部分颜色加深

此处输入图片的描述

PorterDuff.Mode.LIGHTEN

取两图层全部区域,点亮交集部分颜色

此处输入图片的描述

PorterDuff.Mode.MULTIPLY

取两图层交集部分叠加后颜色

此处输入图片的描述

PorterDuff.Mode.SCREEN

取两图层全部区域,交集部分变为透明色

此处输入图片的描述

PorterDuff.Mode.ADD

饱和度叠加

此处输入图片的描述

PorterDuff.Mode.OVERLAY

叠加

此处输入图片的描述

源码:CanvasPractice

参考链接:

Android Paint Xfermode 学习小结

Android Paint PorterDuffXfermode

android Xfermode 的各种组合使用

Paint API之—— Xfermode与PorterDuff全面详解

Android绘制圆形图片的方法总结

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注