Graphics2D API:Paint之顏色過濾

一、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);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末树酪,一起剝皮案震驚了整個濱河市闪水,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌错邦,老刑警劉巖引谜,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疮茄,居然都是意外死亡滥朱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進店門力试,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徙邻,“玉大人,你說我怎么就攤上這事畸裳$掷纾” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵怖糊,是天一觀的道長帅容。 經(jīng)常有香客問我,道長伍伤,這世上最難降的妖魔是什么并徘? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮嚷缭,結(jié)果婚禮上饮亏,老公的妹妹穿的比我還像新娘耍贾。我一直安慰自己,他們只是感情好路幸,可當我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布荐开。 她就那樣靜靜地躺著,像睡著了一般简肴。 火紅的嫁衣襯著肌膚如雪晃听。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天砰识,我揣著相機與錄音能扒,去河邊找鬼。 笑死辫狼,一個胖子當著我的面吹牛初斑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膨处,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼见秤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了真椿?” 一聲冷哼從身側(cè)響起鹃答,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎突硝,沒想到半個月后测摔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡解恰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年锋八,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片修噪。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡查库,死狀恐怖路媚,靈堂內(nèi)的尸體忽然破棺而出黄琼,到底是詐尸還是另有隱情,我是刑警寧澤整慎,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布脏款,位于F島的核電站,受9級特大地震影響裤园,放射性物質(zhì)發(fā)生泄漏撤师。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一拧揽、第九天 我趴在偏房一處隱蔽的房頂上張望剃盾。 院中可真熱鬧腺占,春花似錦、人聲如沸痒谴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽积蔚。三九已至意鲸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尽爆,已是汗流浹背怎顾。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漱贱,地道東北人槐雾。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像幅狮,于是被迫代替她去往敵國和親蚜退。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容