26
2017
09

Paint滤镜效果

paint的滤镜效果,即对图像进行一定的过滤处理,可以实现如模糊阴影效果,浮雕效果,高亮图片,黑白照片,复古照片等效果。
Android的绘图颜色值是32位的int值,即ARGB :A—Alpha值,RGB—颜色值,根据对Alpha和RGB值的处理,滤镜的实现方式分类有:Alpha滤镜处理,颜色RGB的滤镜处理(矩阵Matrix实现)和两者混合叠加—Matrix,PortDuffColorFilter。

一、Alpha滤镜处理:
通过Paint的setMaskFilter(MaskFilter maskfilter)方法,就可以实现不同的Alpha滤镜效果。setMaskFilter需要传MaskFilter 类型的参数,查看源码可以发现,MaskFilter 有两个子类:BlurMaskFilter和EmbossMaskFilter。
BlurMaskFilter:可以用来绘制模糊阴影
EmbossMaskFilter:可以用来实现浮雕效果

1、BlurMaskFilter滤镜的使用:
BlurMaskFilter的唯一构造函数:

/** * Create a blur maskfilter. * * @param radius 阴影的半径大小 * @param style 滤镜采用的类型,在BlurMaskFilter类的内部由一个枚举类型指定 */
    public BlurMaskFilter(float radius, Blur style)

Blur 类型如下:

public enum Blur {
        /** * 整个图像都会被模糊掉 */
        NORMAL(0),

        /** * 图像边界外产生一层与Paint(图像)颜色一致的阴影效果,不影响图像的本身 */
        SOLID(1),

        /** * 图像边界外产生一层阴影,并且将图像变成透明效果 */
        OUTER(2),

        /** * 在图像内部边沿产生模糊效果 */
        INNER(3);
    }

下面是实例:

1.1正常情况下,画一个矩形,代码如下:

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 400, 400);
canvas.drawRect(rectF, paint);

实现效果如图:
这里写图片描述

为paint设置滤镜效果:
1.2 BlurMaskFilter.Blur.NORMAL模式:整个图像都会被模糊掉

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 400, 400);
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.NORMAL));
canvas.drawRect(rectF, paint);

实现效果如下:可以看到整个图片都被模糊了
这里写图片描述

1.3、BlurMaskFilter.Blur.SOLID模式:图像边界外产生一层与Paint(图像)颜色一致的阴影效果,不影响图像的本身

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 400, 400);
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.SOLID));
canvas.drawRect(rectF, paint);

实现效果:
这里写图片描述
1.4、BlurMaskFilter.Blur.OUTER:图像边界外产生一层阴影,并且将图像变成透明效果

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 400, 400);
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.OUTER));
canvas.drawRect(rectF, paint);

实现效果:
这里写图片描述
1.5、BlurMaskFilter.Blur.INNER模式:在图像内部边沿产生模糊效果

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 400, 400);
paint.setMaskFilter(new BlurMaskFilter(50, BlurMaskFilter.Blur.INNER));
canvas.drawRect(rectF, paint);

实现效果:
这里写图片描述
至此,BlurMaskFilter的4中模式介绍完毕。

2、EmbossMaskFilter滤镜效果的使用:
EmbossMaskFilter类的唯一构造函数:

/** * Create an emboss maskfilter * * @param direction 指定光源的位置,长度为xxx的数组标量,array of 3 scalars [x, y, z]指定光源的方向 * @param ambient 环境光的因子(0~1),越接近0的时候,环境光越暗 * @param specular 镜面反射系数,,越接近0,镜面反射越强 * @param blurRadius 模糊半径,值越大,模糊效果越明显 */
    public EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius)

使用方式如下:

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);
RectF rectF = new RectF(100, 100, 600, 600);
paint.setMaskFilter(new EmbossMaskFilter(new float[]{1, 1, 1}, 0.2f, 60, 80));
canvas.drawRect(rectF, paint);

实现效果:
这里写图片描述

二、颜色RGB的滤镜处理:
对颜色值RGB的滤镜处理,需要用到颜色矩阵,即使用Paint的setColorFilter(ColorFilter filter)
setColorFilter(int clor, Mode mode); //mode 就是 PorterDuff.Mode 指示ColorFilter如何展示,其对应的color就是src层。关于PorterDuff.Mode ,详见(http://blog.csdn.net/jjwwmlp456/article/details/46912561)
等方法来实现,ColorFilter的继承关系如下:
这里写图片描述

1、色彩信息的矩阵表示
四阶表示
这里写图片描述
如果想将色彩(0,255,0,255)更改为半透明时,可以使用下面的的矩阵运算来表示:
这里写图片描述

而真正的运算使用五阶矩阵
考虑下面这个变换:
1、红色分量值更改为原来的2倍;
2、绿色分量增加100;
则使用4阶矩阵的乘法无法实现,所以,应该在四阶色彩变换矩阵上增加一个“哑元坐标”,来实现所列的矩阵运算:
这里写图片描述
这个矩阵中,分量值用的是100
1*100+100

2、PorterDuffColorFilter,LightingColorFilter 和ColorMatrixColorFilter的区别:

PorterDuffColorFilter:以PorterDuff.mode 模式进行混合图像的颜色。

public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode)  

指定一个用于混合的ARGB颜色值color,及相应的混合mode 参与构造。
LightingColorFilter: 只是修改RGB值,alpha值被忽略;构造时要指定两个色值,先混合第一种颜色,再混合第二种,所以色值的顺序不一样,结果也不一定一样:

public LightingColorFilter(int mul, int add)  

构造参数:mul,用于乘法;add,用于加法。 关于乘法和加法运算,可以参考下面的ColorMatrix。
ColorMatrixColorFilter:通过颜色矩阵对颜色值,饱和度等进行处理。

//ColorMatrix 颜色矩阵
public ColorMatrixColorFilter(ColorMatrix matrix)  

以ColorMatrix为基础进行颜色变换。

ColorMatrix 颜色矩阵:

public ColorMatrix() {  
   reset(); //重置  
/*  
reset(): 
 [ 1 0 0 0 0   - red vector 
   0 1 0 0 0   - green vector 
   0 0 1 0 0   - blue vector 
   0 0 0 1 0 ] - alpha vector 

*/  
}  
public ColorMatrix(float[] src) {  
   ...  
}  
public ColorMatrix(ColorMatrix src) {//基于一个ColorMatrix 进行构造  
   ...  
}  

其构造方法需要一个数组,其实就是一个4x5的矩阵,用来对bitmap的颜色和alpha进行转换。形式如下:

[ a, b, c, d, e,  
  f, g, h, i, j,  
  k, l, m, n, o,  
  p, q, r, s, t ]  

计算规则:

R’ = a*R + b*G + c*B + d*A + e;  
G’ = f*R + g*G + h*B + i*A + j;  
B’ = k*R + l*G + m*B + n*A + o;  
A’ = p*R + q*G + r*B + s*A + t;  

即前四列,为RGBA,用于在source的基础上进行相乘;后一列用于相加

如下,对RGB取反色,即源图像的RGB区都乘以-1再加255:

[ -1, 0, 0, 0, 255,  
  0, -1, 0, 0, 255,  
  0,  0, -1, 0, 255,  
  0,  0,  0, 1,  0 ]  

ColorMatrix的主要方法:

set(float[] src); 设置颜色矩阵数组

set(ColorMatrix src); 设置颜色矩阵

setConcat(ColorMatrix a, ColorMatrix b;连结ab两个颜色矩阵;效果为先应用b,再应用a

setRGB2YUV(); 将RGB矩阵转为YUV(与RGB类似,是一种颜色编码方案)矩阵

setYUV2RGB();将YUV(与RGB类似,是一种颜色编码方案)矩阵转为RGB矩阵

setSaturation(float sat);设置色彩的饱和度(百科中说:对于人的视觉,每种色彩的饱和度可分为20个可分辨等级)

setScale(float rScale, float gScale, float bScale, float aScale);设置用于缩放(即乘法)的RGBA值,原始比例为1

setRotate(int axis, float degrees);绕axis轴旋转degrees度;axis:0为RED,1为GREEN,2为BLUE

3、实例演示:
3.1、ColorMatrixColorFilter,修改透明度:

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                1, 0, 0, 0, 0,
                0, 1, 0, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 0, 0.5f, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setTextSize(50);
canvas.drawText("通过矩阵,使用颜色滤镜实现,", 120, 700, paint);
canvas.drawText("A*0.5f效果对比", 120, 550, paint);

实现效果:
这里写图片描述

颜色矩阵的缩放运算:乘法,颜色增强。

Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.RED);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                1.2f, 0, 0, 0, 0,
                0, 1.2f, 0, 0, 0,
                0, 0, 1.2f, 0, 0,
                0, 0, 0, 1.2f, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setTextSize(50);
canvas.drawText("通过矩阵,使用颜色滤镜实现,", 120, bitmap.getHeight() + 50, paint);
canvas.drawText("ARGB分别乘以1.2倍效果对比", 120, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述
反向效果——相片的底片效果:

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                -1, 0, 0, 0, 255,
                0, -1, 0, 0, 255,
                0, 0, -1, 0, 255,
                0, 0, 0, 1, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("ARGB分别乘以-1然后在+255即可反向,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:

这里写图片描述
黑白照片的实现:去色原理:只要把R,G,B三通道的色彩信息设置成一样,那么图像就会同时为了保证图像亮度不变,同一个通道的值满足R+G+B=1。

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0.213f, 0.715f, 0.072f, 0, 0,
                0.213f, 0.715f, 0.072f, 0, 0,
                0.213f, 0.715f, 0.072f, 0, 0,
                0, 0, 0, 1, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("黑白照片的实现,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述
发色效果—-(红色和绿色交换):

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0, 1, 0, 0, 0,
                1, 0, 0, 0, 0,
                0, 0, 1, 0, 0,
                0, 0, 0, 1, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("发色效果,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述
复古效果的实现:

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                1 / 2f, 1 / 2f, 1 / 2f, 0, 0,
                1 / 3f, 1 / 3f, 1 / 3f, 0, 0,
                1 / 4f, 1 / 4f, 1 / 4f, 0, 0,
                0, 0, 0, 1, 0,
        });
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("复古效果,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述

颜色通道过滤

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
        1, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 1, 0,
});
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("颜色通道过滤,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述

颜色增强,即高亮

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

ColorMatrix colorMatrix = new ColorMatrix();
/** * *与ColorMatrixSub方法中的矩阵实现效果一样,ColorMatrix封装了很多方法,方便我们使用,避免了自己写矩阵 * 颜色矩阵的缩放运算就是乘法运算 */
colorMatrix.setScale(1.2f, 1.2f, 1.2f, 1);
// colorMatrix.setSaturation(10f);//增加饱和度,就是加法运算
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("通过矩阵,使用颜色滤镜实现,反向效果", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("高亮,效果对比", 0, bitmap.getHeight() + 100, paint);

实现效果:

这里写图片描述

LightingColorFilter 对颜色值RGB的乘法和加法运算

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);

/** * LightingColorFilter只是修改RGB值,对透明度没有影响 */
paint.setColorFilter(new LightingColorFilter(0x00ff00, 0xff0000));
// paint.setColorFilter(new LightingColorFilter(0xffffff, 0xff0000));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("LightingColorFilter的使用,", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("对颜色值RGB的乘法和加法运算", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述
PorterDuffColorFilter的使用

Paint paint = new Paint();
paint.setAntiAlias(true);

RectF rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF, paint);
/** * LightingColorFilter只是修改RGB值,对透明度没有影响 */
//        paint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.DST_IN));
paint.setColorFilter(new PorterDuffColorFilter(Color.argb(255, 140, 90, 200), PorterDuff.Mode.MULTIPLY));
RectF rectF2 = new RectF(600, 0, 600 + bitmap.getWidth(), bitmap.getHeight());
canvas.drawBitmap(bitmap, null, rectF2, paint);

paint.setColorFilter(null);
paint.setTextSize(45);
paint.setColor(Color.RED);
canvas.drawText("PorterDuffColorFilter的使用,", 0, bitmap.getHeight() + 50, paint);
canvas.drawText("对颜色的混合叠加效果实现", 0, bitmap.getHeight() + 100, paint);

实现效果:
这里写图片描述

Demo源码见:
https://github.com/meiSThub/DN_Homework/blob/master/app/src/main/java/com/mei/test/ui/filter/widget/FilterView.java

上一篇:Android性能优化一点理解 下一篇:设计模式最佳实之工厂模式