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