Canvas&Paint 知識梳理(3) 顏色合成 Paint#setColorFilter

1、概述

有時候,咱們但願對一個圖片或一個複雜圖形的顏色,進行處理,那麼這時候能夠採用PaintsetColorFilter方法,一個最多見的例子,就是圖片的濾鏡,固然,那裏面的算法可能更加複雜。算法

2、ColorFilter的分類

關於ColorFilter,源碼中是這麼解釋的,它能夠Paint所繪製區域的每一個像素進行顏色的改變canvas

/**
 * 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則由一個長度爲20float數組構造,傳入該數組後把該數組先從左到右,再從上到下排列,造成一個4*5的矩陣。bash

[ a, b, c, d, e,
  f, g, h, i, j,
  k, l, m, n, o,
  p, q, r, s, t ]
複製代碼

以後,再用矩陣和目標的RGBA進行計算,最後獲得新的RGBA,它的計算方法爲:ide

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);
    }
複製代碼

最終咱們會獲得一個蒙了灰的圖片: ui

固然咱們也能夠先設置畫筆的顏色,而後給它設置一個顏色矩陣,這樣最後花上去的圖形的就是就是等於畫筆顏色和矩陣一塊兒計算的結果。

2.2 LightingColorFilter

用來模擬光照的效果,它定義了兩個參數來和原color相乘,第一個colorMultiply原來相乘,而第二個參數colorAdd用來相加,而且會忽略其中的Aplha參數,這個32位的表示0xAARRGGBB,計算的公式爲:this

R' = R * colorMultiply.R + colorAdd.R G' = G * colorMultiply.G + colorAdd.G
B' = B * colorMultiply.B + colorAdd.B 複製代碼

須要注意的是這個倍數爲整形,也就是咱們只能增大,不能減少。spa

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);
    }
複製代碼

最終會獲得下面的結果: code

能夠看到,對於本來 RGB0的像素點,它不會作任何改變,它只會改變那些本來有顏色的像素點。

2.3 PorterDuffColorFilter

混合模式,其構造函數爲PorterDuffColorFilter(int dstColor, PorterDuff.Mode mode),其中color16進制的終點顏色,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}.
複製代碼

其中modePorterDuff.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不單單用於顏色合成,還用於圖像合成。
相關文章
相關標籤/搜索