自定义控件绘制(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()的功能,可以改变纯色图标的颜色;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容