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中模式介紹完畢。

實現不規則圖形的陰影效果:

爲不規則圖形,繪製陰影:
圖片

Bitmap bitmap = mBitmap;
Bitmap extractAlpha = bitmap.extractAlpha();
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLACK);
mBlurMaskFilter = new BlurMaskFilter(shaderSize, BlurMaskFilter.Blur.NORMAL);
mPaint.setMaskFilter(mBlurMaskFilter);
// 繪製圖形透明層的陰影
canvas.drawBitmap(extractAlpha, null, mShadowRect, mPaint);
// 繪製原圖
canvas.translate(shaderSize, shaderSize);
canvas.drawBitmap(bitmap, 0, 0, null);

實現效果:

圖片陰影實現效果
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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章