一、概述
有時候,我們希望對一個圖片或一個複雜圖形的顏色,進行處理,那麼這時候可以採用Paint
的setColorFilter
方法,一個最常見的例子,就是圖片的濾鏡,當然,那裡面的演算法可能更加複雜。
二、ColorFilter
的分類
關於ColorFilter
,原始碼中是這麼解釋的,它可以對Paint
所繪製區域的每個畫素進行顏色的改變。
/**
* A color filter can be used with a {@link Paint} to modify the color of
* each pixel drawn with that paint. This is an abstract class that should
* never be used directly.
*/
複製程式碼
當我們使用ColorFilter
的時候,不一樣直接使用它,而是使用它的子類:
ColorMatrixColorFilter
LightingColorFilter
PoterDuffColorFilter
2.1 ColorMatrixColorFilter
ColorMatrixColorFilter
的通過ColorMatrix
構造,而ColorMatrix
則由一個長度為20
的float
陣列構造,傳入該陣列後把該陣列先從左到右,再從上到下排列,形成一個4*5
的矩陣。
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]
複製程式碼
之後,再用矩陣和目標的RGBA
進行計算,最後得到新的RGBA
,它的計算方法為:
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
會被限制在0-255
的範圍內。在實際使用的時候,我們先通過一個ColorMatrix
輔助類來確定需要相乘的這個顏色矩陣,之後再把它作為ColorMatrixColorFilter
建構函式的引數來構造它。
我們一般有兩種用法:改變畫筆的顏色,或者改變整個Bitmap
的畫素點的顏色。下面我們用第二種方式來舉例。
private void drawColorMatrixFilter(Canvas canvas) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
//1,得到一個顏色矩陣
ColorMatrix colorMatrix = new ColorMatrix();
colorMatrix.setSaturation(0.5f);
//2.通過顏色矩陣構建ColorMatrixColorFilter物件
ColorMatrixColorFilter colorMatrixColorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint matrixPaint = new Paint();
//3.把構建的物件設定給Paint
matrixPaint.setColorFilter(colorMatrixColorFilter);
canvas.drawBitmap(bitmap, 0, 0, matrixPaint);
}
複製程式碼
最終我們會得到一個蒙了灰的圖片:
當然我們也可以先設定畫筆的顏色,然後給它設定一個顏色矩陣,這樣最後花上去的圖形的就是就是等於畫筆顏色和矩陣一起計算的結果。2.2 LightingColorFilter
用來模擬光照的效果,它定義了兩個引數來和原color
相乘,第一個colorMultiply
原來相乘,而第二個引數colorAdd
用來相加,並且會忽略其中的Aplha
引數,這個32
位的表示0xAARRGGBB
,計算的公式為:
R' = R * colorMultiply.R + colorAdd.R
G' = G * colorMultiply.G + colorAdd.G
B' = B * colorMultiply.B + colorAdd.B
複製程式碼
需要注意的是這個倍數為整形,也就是我們只能增大,不能減小。
private void drawLightingColorFilter(Canvas canvas) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
//1.構建一個LightingColorFilter
LightingColorFilter lightingColorFilter = new LightingColorFilter(3, 0);
Paint matrixPaint = new Paint();
//2.設定給畫筆
matrixPaint.setColorFilter(lightingColorFilter);
//3.繪製
canvas.drawBitmap(bitmap, 0, 0, matrixPaint);
}
複製程式碼
最終會得到下面的結果:
可以看到,對於原本RGB
為0
的畫素點,它不會做任何改變,它只會改變那些原本有顏色的畫素點。
2.3 PorterDuffColorFilter
混合模式,其建構函式為PorterDuffColorFilter(int dstColor, PorterDuff.Mode mode)
,其中color
為16
進位制的終點顏色,mode
為混合策略,它會根據起點顏色Sc
,起點透明度Sa
,終點顏色Dc
和終點透明度Da
最終計算得出要顯示的RGBA
。
* A color filter that can be used to tint the source pixels using a single
* color and a specific {@link PorterDuff Porter-Duff composite mode}.
複製程式碼
其中mode
為PorterDuff.Mode
,其對應的模式和計算公式如下:
public enum Mode {
/** [0, 0] */
CLEAR (0),
/** [Sa, Sc] */
SRC (1),
/** [Da, Dc] */
DST (2),
/** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */
SRC_OVER (3),
/** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */
DST_OVER (4),
/** [Sa * Da, Sc * Da] */
SRC_IN (5),
/** [Sa * Da, Sa * Dc] */
DST_IN (6),
/** [Sa * (1 - Da), Sc * (1 - Da)] */
SRC_OUT (7),
/** [Da * (1 - Sa), Dc * (1 - Sa)] */
DST_OUT (8),
/** [Da, Sc * Da + (1 - Sa) * Dc] */
SRC_ATOP (9),
/** [Sa, Sa * Dc + Sc * (1 - Da)] */
DST_ATOP (10),
/** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */
XOR (11),
/** [Sa + Da - Sa*Da,
Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */
DARKEN (16),
/** [Sa + Da - Sa*Da,
Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */
LIGHTEN (17),
/** [Sa * Da, Sc * Dc] */
MULTIPLY (13),
/** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */
SCREEN (14),
/** Saturate(S + D) */
ADD (12),
OVERLAY (15);
Mode(int nativeInt) {
this.nativeInt = nativeInt;
}
/**
* @hide
*/
public final int nativeInt;
}
複製程式碼
其中,Sa
表示起點的Alpha
值,而Sc
表示起點的color
值,對於Dx
也是同理,最終會得到[Ra, Rc]
,這樣組成之後就是終點對應畫素點的顏色。
private void drawPorterDuffColorFilter(Canvas canvas) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
Paint paint = new Paint();
paint.setColorFilter(new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.DARKEN));
canvas.drawBitmap(bitmap, 0, 0, paint);
}
複製程式碼
最終會得到下面的結果:
後面我們會發現PorterDuff.Mode
中定義的這些Mode
不僅僅用於顏色合成,還用於影像合成。