自定义控件绘制(Paint之setColorFilter)篇七

参考

  1. https://blog.csdn.net/harvic880925/article/details/51253944

上面使用了setColorFilter中使用ColorMatrixColorFilter包装的ColorMatrix;

setColorFilter

Paint的setColorFilter的API如下:

public ColorFilter setColorFilter(ColorFilter filter)  

ColorFilter这个类没啥实现,靠子类来实现一些效果:

ColorFilter的子类

ColorMatrixFilter

上篇就是这个;

LightingColorFilter

ColorMatrix很强大,但使用起来比较麻烦;Android提供了光照颜色过滤器,可以简单的完成色彩过滤色彩增强功能,这就是LightingColorFilter

构造函数

// mul乘法,add加法。mul和add取值都是0xRRGGBB,没有透明度,
// LightingColorFilter只针对RGB色值起作用 
public LightingColorFilter(int mul, int add)  

比如,当前有一个颜色值为(r,g,b),对它应用LightingColorFilter(mul, add)效果后的颜色值为:

结果R值 = (r*mul.R+add.R)%255; // % 255就是不超过255
结果G值 = (g*mul.G+add.G)%255;
结果B值 = (b*mul.B+add.B)%255;

也就是原来的色值 乘以 mul 对应的色值, 再 加上 add对应的色值;
因为 mul 与 add 取值都是0xRRGGBB类型的值,即mul和add中都是包含了R、G、B分量的;

以红色为例:mul.R是对当前红色值进行放大的倍数;而add.R则表示对当前红色增加的数值;它们对应ColorMatrix的位置如下:

图片来自源博客

利用mul进行颜色值放大并不好控制,所以更多的是用来过滤颜色,即当对应的颜色值取0时,就不会将对应的颜色显示出来;
而把要显示出来的颜色对应的mul值设置为ff,即255;从公式中可以知道设置为255不会对原始的这个颜色分量产生任何影响。所以这样就可以把想要的颜色给显示出来,把不想要的颜色给过滤掉;

示例代码 - 显示绿色

// 绘制原始位图
canvas.drawBitmap(bitmap, null, Rect(0, 0, 250, 250 * bitmap.height / bitmap.width), paint)
canvas.translate(260f, 0f)
val paint2 = Paint(Paint.ANTI_ALIAS_FLAG)

// mul参数设置为0x00ff00,即把绿色显示出来,把R和B过滤掉
// add参数全部设置为0,即没有对原始图像色彩做任何改变 
paint2.colorFilter = LightingColorFilter(0x00ff00,0x000000)    
canvas.drawBitmap(bitmap, null, Rect(0, 0, 250, 250 * bitmap.height / bitmap.width), paint2)
显示绿色-过滤其他颜色

加深蓝色

// mul参数设置为0xffffff,即没有对颜色做任何改变;add参数设置为0x0000f0,
// 即在每个像素的蓝色值在原来基础上增加0xf0,让原来的图像变得更蓝;
paint2.colorFilter = LightingColorFilter(0xffffff,0x0000f0)  

参考源博客;

PorterDuffColorFilter

PorterDuff颜色滤镜,也叫图形混合滤镜;其名称是Tomas Proter和Tom Duff两个人名的缩写,他们提出的图形混合的概念极大地推动了图形图像学的发展;

构造

public PorterDuffColorFilter(int color, PorterDuff.Mode mode)

参数:

  • color:0xAARRGGBB类型的颜色值;
  • mode:混合模式,枚举值有18个,表示各种图形混合模式,有:
    • Mode.CLEAR
    • Mode.SRC
    • Mode.DST
    • Mode.SRC_OVER
    • Mode.DST_OVER
    • Mode.SRC_IN
    • Mode.DST_IN
    • Mode.SRC_OUT
    • Mode.DST_OUT
    • Mode.SRC_ATOP
    • Mode.DST_ATOP
    • Mode.XOR
    • Mode.DARKEN
    • Mode.LIGHTEN
    • Mode.MULTIPLY
    • Mode.SCREEN
    • Mode.OVERLAY
    • Mode.ADD

在这里与filter相关的有6个:

  • Mode.ADD(饱和度相加)
  • Mode.DARKEN(变暗)
  • Mode.LIGHTEN(变亮)
  • Mode.MULTIPLY(正片叠底)
  • Mode.OVERLAY(叠加)
  • Mode.SCREEN(滤色)

示例代码:叠底

// 绘制原始位图
canvas.drawBitmap(bitmap, null, Rect(0, 0, 250, 250 * bitmap.height / bitmap.width), paint)

val paint2 = Paint(Paint.ANTI_ALIAS_FLAG)
canvas.translate(260f, 0f)
paint2.colorFilter = PorterDuffColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY)     // 正片叠底
canvas.drawBitmap(bitmap, null, Rect(0, 0, 250, 250 * bitmap.height / bitmap.width), paint2)
红色叠底

以红色为原色进行的PorterDuffColorFilter6个效果:

image.png

其他模式

除了上面的六个Mode,还有其它的三组Mode;

第一组:清空模式

  • Mode.CLEAR;
  • Mode.XOR;

这里表现的效果时,清空了原图;

第二组:目标图像模式
在Mode模式中,有一组DST相关的模式,DST所代表的意义就是被应用模式的图像,即上面的图;

  • Mode.DST;
  • Mode.DST_IN
  • Mode.DST_OUT
  • Mode.DST_OVER
  • Mode.DST_ATOP

几个模式在PorterDuffColorFilter的实际应用中,并没什么用

第三组:源图模式
在Mode模式中,有一组SRC相关的模式,SRC表示的颜色值所代表的图像

  • Mode.SRC
  • Mode.SRC_IN
  • Mode.SRC_OUT
  • Mode.SRC_OVER
  • Mode.SRC_ATOP

具体参考原博客,这块我经常搞混了;DST与SRC经常搞混了;

利用SRC,我们可以改变图片的演示,对应一些ICON,只要求一个颜色系,就可以实现多个颜色了;也是V4包中DrawableCompat类添加的一个setLint()函数所使用实现方法;

setLint示例
将图片改成想要的颜色

resources.getDrawable(R.mipmap.icon_map).mutate().let {
              DrawableCompat.setTint(it, Color.GREEN)
              setImageDrawable(it)
}
setTint 着色效果

利用setTint就可以把一个图片渲染为不同的颜色,这样就可以支持多主题,在不同的风格和不同的情境下使用不同的颜色的图片。

使用PorterDuffColorFilter着色

// 原图
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)

canvas.translate(70f, 0f)
mPaint.setColorFilter(PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC))
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)

canvas.translate(70f, 0f)
mPaint.setColorFilter(PorterDuffColorFilter(Color.GREEN, PorterDuff.Mode.SRC_ATOP))
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)

canvas.translate(70f, 0f)
mPaint.setColorFilter(PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN))
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)

canvas.translate(70f, 0f)
mPaint.setColorFilter(PorterDuffColorFilter(Color.GRAY, PorterDuff.Mode.SRC_OVER))
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)


canvas.translate(70f, 0f)
mPaint.setColorFilter(PorterDuffColorFilter(Color.YELLOW, PorterDuff.Mode.SRC_ATOP))
canvas.drawBitmap(mBmp, null, Rect(0, 0, width, height), mPaint)
效果

SRC相关的模式,只有Mode.SRC_ATOP和SRC_IN能够实现SetTint的功能;

参考源博客解释,后续详细说明 这几个模式;

当然这里也可以通过ColorMatrix来实现变色的;
如绿色:

// colorMatrix 00FF00
canvas.translate(70f, 0f)
mPaint.colorFilter = ColorMatrixColorFilter(ColorMatrix(floatArrayOf(
     0f,0f,0f,0f,0f,
     0f,0f,0f,0f,255f,
     0f,0f,0f,0f,0f,
     0f,0f,0f,1f,0f
)))

PorterDuffColorFilter总结:

  • PorterDuffColorFilter只能实现与一个特定颜色值的合成;
  • 通过Mode.ADD(饱和度相加),Mode.DARKEN(变暗),Mode.LIGHTEN(变亮),Mode.MULTIPLY(正片叠底),Mode.OVERLAY(叠加),Mode.SCREEN(滤色)可以实现与指定颜色的复合;
  • 通过Mode.SRC、Mode.SRC_IN、Mode.SRC_ATOP能够实现setTint()的功能,可以改变纯色图标的颜色;

你可能感兴趣的:(自定义控件绘制(Paint之setColorFilter)篇七)