一、setColorFilter
public ColorFilter setColorFilter(ColorFilter filter)
在前面我們學習過Paint的setColor方法泄私,這里又多了一個setColorFilter顏色過濾桨醋,看到這里你肯定會疑惑贤笆,你說你一個“筆”有顏色還算正常,你還能過濾顏色吟孙?
那么過濾顏色是什么意思呢澜倦?其實就像我們現(xiàn)實中的篩子,過濾掉不要的雜質(zhì)杰妓,得到想要的東西藻治,這里的意思就是把顏色“過濾”一遍,得到我們想要的色彩.
仔細觀察Paint的這個方法巷挥,它需要一個ColorFilter 對象桩卵,而且還會返回一個ColorFilter 對象,ColorFilter 翻譯為中文就是顏色過濾器,也就是篩子吸占,在繪圖軟件中被稱為顏色濾鏡.
我們再來看ColorFilter 的源碼:
public class ColorFilter {
public long native_instance;
@Override
protected void finalize() throws Throwable {
try {
super.finalize();
} finally {
destroyFilter(native_instance);
native_instance = 0;
}
}
static native void destroyFilter(long native_instance);
}
發(fā)現(xiàn)ColorFilter 源碼里面基本啥都沒有晴叨,這時候我們應(yīng)該想到:ColorFilter 肯定有子類.
不錯,ColorFilter 有3個子類:
那么接下來就是解析這3個子類了.
二矾屯、ColorMatrixColorFilter
這個類翻譯為中文就是色彩矩陣顏色過濾器兼蕊,我們來看一下這個類的成員變量、構(gòu)造方法:
public class ColorMatrixColorFilter extends ColorFilter {
private final ColorMatrix mMatrix = new ColorMatrix();
public ColorMatrixColorFilter(ColorMatrix matrix) {
mMatrix.set(matrix); //★
......
}
public ColorMatrixColorFilter(float[] array) {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
mMatrix.set(array); //★
......
}
......
這個類也很簡單件蚕,初始化的時候需要一個ColorMatrix 對象或者一個色彩矩陣數(shù)組孙技,這兩者最終都是設(shè)置給了其成員變量mMatrix ,所以我們需要關(guān)心的就是ColorMatrix (色彩矩陣)這個類了.
1排作、ColorMatrix
在Android中:一個色彩信息包含R牵啦、G、B妄痪、Alpha信息哈雏,而修改色彩信息,需要使用ColorMatrix:
public class ColorMatrix {
private final float[] mArray = new float[20];
public ColorMatrix() {
......
}
public ColorMatrix(float[] src) {
......
}
public ColorMatrix(ColorMatrix src) {
......
}
......
}
在ColorMatrix 中定義了一個4x5的float[]類型的矩陣用來表示衫生、修改顏色信息:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
R, 0, 0, 0, 0,
0, G, 0, 0, 0,
0, 0, B, 0, 0,
0, 0, 0, A, 0
});
其中:
一共四行裳瘪,分別代表:R、G罪针、B彭羹、A,為1時表示保持原色彩的R泪酱、G派殷、B、A值.
每一行最后一列我稱之為:增加量墓阀,比如:
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 88,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
});
在原有的色彩R色上增加88的量毡惜,使之更偏向紅色.
接下來我們通過實例來看看顏色矩陣的用法.
2、例(保持藍色通道斯撮、透明度通道的顏色矩陣)
private void gogogo(Canvas canvas) {
mPaint.setAntiAlias(true);
mPaint.setARGB(255, 255, 255, 255);
canvas.drawCircle(100, 100, 50, mPaint);
canvas.translate(0, 200);
ColorMatrix colorMatrix = new ColorMatrix(new float[]{//保持原色彩B虱黄、A信息的顏色矩陣
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
});
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix);//色彩矩陣顏色過濾器
mPaint.setColorFilter(filter);//為畫筆設(shè)置顏色過濾器
canvas.drawCircle(100, 100, 50, mPaint);
}
紅綠藍混合后為白色,所以一開始畫筆是白色的吮成,第一個圓是白色的橱乱,然后通過setColorFilter設(shè)置顏色過濾器,過濾器中僅保存B粱甫、A信息泳叠,所以第二個圓是藍色的.
3、顏色過濾器原理
最終的顏色其是通過矩陣相乘得到的茶宵,計算方式:
可能有的人會說危纫,這到底有什么用?其實這個顏色矩陣在相機應(yīng)用中使用最多:圖片是由一個個像素組成的,一張圖片可以有幾十萬像素种蝶,而每個像素都有對應(yīng)的色彩數(shù)組契耿,我們可以通過顏色矩陣ColorMatrix來轉(zhuǎn)換每個像素的色彩信息,得到經(jīng)過色彩處理的圖片螃征,那些美顏相機就是基于此原理做出來的.
4搪桂、常見顏色矩陣
(1)單通道
public class XView extends View {
private Paint mPaint;
private Bitmap bitmap;
public XView(Context context) {
this(context, null);
}
public XView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
bitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.lks);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
gogogo(canvas);
}
private void gogogo(Canvas canvas) {
mPaint.setAntiAlias(true);
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 600, 350), mPaint);//原圖
canvas.translate(0, 350);//畫布向下平移
// 色彩矩陣
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
});
// ColorMatrix colorMatrix = new ColorMatrix(new float[]{//綠色通道
// 0, 0, 0, 0, 0,
// 0, 1, 0, 0, 0,
// 0, 0, 0, 0, 0,
// 0, 0, 0, 1, 0
// });
// ColorMatrix colorMatrix = new ColorMatrix(new float[]{//藍色通道
// 0, 0, 0, 0, 0,
// 0, 0, 0, 0, 0,
// 0, 0, 1, 0, 0,
// 0, 0, 0, 1, 0
// });
mPaint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));//設(shè)置顏色過濾器
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 600, 350), mPaint);
}
}
(2)某個通道顏色加深
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 66,
0, 0, 0, 1, 0
});
(3)色彩縮放(顏色變暗、變亮)
ColorMatrix colorMatrix = new ColorMatrix(new float[]{//變暗
0.5f, 0, 0, 0, 0,
0, 0.5f, 0, 0, 0,
0, 0, 0.5f, 0, 0,
0, 0, 0, 1, 0
});
ColorMatrix colorMatrix = new ColorMatrix(new float[]{//變亮
1.5f, 0, 0, 0, 0,
0, 1.5f, 0, 0, 0,
0, 0, 1.5f, 0, 0,
0, 0, 0, 1, 0
});
(4)色彩反轉(zhuǎn)
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
});
5盯滚、顏色矩陣ColorMatrix 的方法
public void set(ColorMatrix src)
public void set(float[] src)
搭配無參構(gòu)造使用
public void reset()
重置色彩矩陣踢械,就是把colorMatrix恢復(fù)如下:
[ 1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0 ]
直接使用矩陣調(diào)節(jié)色彩,這對于很多不熟悉矩陣的人來說很困難.
ColorMatrix 也提供了一些方法用來調(diào)節(jié)色彩.
public void setScale(float rScale, float gScale, float bScale, float aScale)
色彩縮放:效果和上面例子中一樣魄藕,rScale内列、gScale、bScale背率、aScale分別是R话瞧、G、B寝姿、A的縮放比例.
public void setSaturation(float sat) 調(diào)節(jié)飽和度
還有一些色彩旋轉(zhuǎn)交排、色彩矩陣相乘方法,有興趣的可以去了解一下.
三会油、LightingColorFilter
光照顏色過濾器
public LightingColorFilter(int mul, int add)
mul:色彩倍增
add:色彩增加
mul个粱、add的取值都是0xRRGGBB古毛,對應(yīng)RGB顏色值
注意:LightingColorFilter只對RGB色值起作用翻翩,對透明度不起作用
源碼中給出了它的計算方式:
給定一個色彩R、G稻薇、B值嫂冻,最終色彩值為:
* R' = R * colorMultiply.R + colorAdd.R
* G' = G * colorMultiply.G + colorAdd.G
* B' = B * colorMultiply.B + colorAdd.B
1、mul 光照效果
LightingColorFilterw為什么叫光照顏色過濾器塞椎,其實就是因為第一個參數(shù)mul.
下面我們通過實例查看桨仿,還是在XView的gogogo方法里面做更改:
private void gogogo(Canvas canvas) {
mPaint.setAntiAlias(true);
mPaint.setColorFilter(new LightingColorFilter(Color.WHITE, 0));//白光照射,無變化
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
canvas.translate(0, 140);
mPaint.setColorFilter(new LightingColorFilter(Color.RED, 0));//紅光照射
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
canvas.translate(0, 140);
mPaint.setColorFilter(new LightingColorFilter(Color.GREEN, 0));//綠光照射
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
canvas.translate(0, 140);
mPaint.setColorFilter(new LightingColorFilter(Color.BLUE, 0));//藍光照射
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
canvas.translate(0, 140);
mPaint.setColorFilter(new LightingColorFilter(Color.GRAY, 0));//灰光照射
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
canvas.translate(0, 140);
mPaint.setColorFilter(new LightingColorFilter(Color.YELLOW, 0));//黃光照射
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 240, 140), mPaint);
}
可以發(fā)現(xiàn),在不同的光照下得到的圖片不一樣案狠,所以這個類叫:光照顏色過濾器服傍,上面給出的計算公式只是為了讓大家更好理解這個類,實際上這個類設(shè)計的本意不是為了讓我們?nèi)ミM行復(fù)雜的計算骂铁,而是顯示光照效果.
2吹零、add 色彩增強效果
add的作用是增強某個通道的顏色值,例:
private void gogogo(Canvas canvas) {
mPaint.setAntiAlias(true);
mPaint.setColorFilter(new LightingColorFilter(Color.WHITE, 0));//白光照射,無變化
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 600, 350), mPaint);
canvas.translate(0, 350);
mPaint.setColorFilter(new LightingColorFilter(Color.WHITE, 0x0000f0));//白光照射,加深藍色通道值拉庵,讓圖片更藍
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 600, 350), mPaint);
}
利用add這個參數(shù)灿椅,我們可以很容易作出圖片按壓后顏色變深的效果,只要改變相應(yīng)通道add值即可.
四、PorterDuffColorFilter
PorterDuff顏色過濾器(圖形混合過濾器)
這個過濾器類名用Tomas Proter和Tom Duff兩個人的名字組合而成茫蛹,因為這兩個人提出圖形混合的概念操刀,PorterDuffColorFilter正是圖形混合過濾器,所以用這兩個人名字命名.
1婴洼、構(gòu)造方法
public PorterDuffColorFilter(int color, PorterDuff.Mode mode)
color:16進制的顏色值(0xAARRGGBB)
mode:圖形混合模式骨坑,可選值是在PorterDuff這個類中,一共18個:
PorterDuff.Mode.CLEAR
PorterDuff.Mode.SRC
PorterDuff.Mode.DST
PorterDuff.Mode.SRC_OVER
PorterDuff.Mode.DST_OVER
PorterDuff.Mode.SRC_IN
PorterDuff.Mode.DST_IN
PorterDuff.Mode.SRC_OUT
PorterDuff.Mode.DST_OUT
PorterDuff.Mode.SRC_ATOP
PorterDuff.Mode.DST_ATOP
PorterDuff.Mode.XOR
PorterDuff.Mode.DARKEN 變暗
PorterDuff.Mode.LIGHTEN 變亮
PorterDuff.Mode.MULTIPLY 正片疊底
PorterDuff.Mode.SCREEN 濾色
PorterDuff.Mode.ADD 飽和度相加
PorterDuff.Mode.OVERLAY 疊加
這里我們需要關(guān)注的只有中文注釋的6個Mode窃蹋,因為PorterDuff.Mode這個類表示:圖形混合模式卡啰,而不是色彩混合模式,在PorterDuff.Mode這18個Mode中警没,只有注釋的6個Mode是與色彩混合相關(guān)的匈辱,而本節(jié)我們學習的是顏色過濾,使用其它的Mode在這里其實并沒有什么用杀迹,它們的用處在別的地方亡脸,后續(xù)的文章會介紹到.
ok,我們來看一下這6個Mode的具體效果:
private void gogogo(Canvas canvas) {
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(300, 0);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.DARKEN));//變暗
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(0, 170);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.LIGHTEN));//變亮
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(0, 170);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.MULTIPLY));//正片疊底
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(0, 170);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.SCREEN));//濾色
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(0, 170);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.ADD));//飽和度相加
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
canvas.translate(0, 170);
mPaint.setColorFilter(new PorterDuffColorFilter(Color.BLUE, PorterDuff.Mode.OVERLAY));//疊加
canvas.drawBitmap(bitmap, null, new RectF(0, 0, 300, 170), mPaint);
}