Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Paint之ColorFilter詳解

Android Paint之ColorFilter詳解

編輯:關於Android編程

在之前講到Android Paint的使用詳解的時候,其中setColorFilter(ColorFilter filter)方法沒有講,今天就來簡單的分析一下,在Android中ColorFilter共有3個子類,ColorMatrixColorFilter,LightingColorFilter,PorterDuffColorFilter,今天先來看第一個ColorMatrixColorFilter,ColorMatrixColorFilter的構造方法很簡單,一個是傳入數組,一個是傳入ColorMatrix類型的對象

    public ColorMatrixColorFilter(ColorMatrix matrix) {
        mMatrix.set(matrix);
        update();
    }
    public ColorMatrixColorFilter(float[] array) {
        if (array.length < 20) {
            throw new ArrayIndexOutOfBoundsException();
        }
        mMatrix.set(array);
        update();
    }
這裡主要來看一下ColorMatrix這個類,它內部有一個數組mArray,其實他保存的是一個4x5顏色矩陣,
 *  [ a, b, c, d, e,
 *    f, g, h, i, j,
 *    k, l, m, n, o,
 *    p, q, r, s, t ]
可以用來修改ARGB的值,其中第一行決定紅色R,第二行決定綠色G,第三行決定藍色B,第四行決定了透明度A,第五列是顏色的偏移量

而圖像的ARGB值存儲在一個5*1的顏色分量矩陣中[R, G, B, A,1]。最終運算的結果是兩矩陣相乘

   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;
我們看到mArray的大小為20,也就相當於一個4*5的數組,
  private final float[] mArray = new float[20];
在初始化的時候,矩陣的數值會進行初始化
    /**
     * Set this colormatrix to identity:
     * 
* [ 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 void reset() { final float[] a = mArray; Arrays.fill(a, 0); a[0] = a[6] = a[12] = a[18] = 1; }其中第五列是偏移量,比如
[ 1 0 0 0 8  
  0 1 0 0 8   
  0 0 1 0 8   
  0 0 0 1 0 ] 

表示個顏色分量計算完成之後要在加上8,其中最後一行是表示透明度的,一般不要修改。我們來演示一下

public class ColorFilterView extends View {
	private Paint mPaint;
	private Bitmap mBitmap;
	private int padding = 12;
	float[] colorMatrix = { 
		    1, 0, 0, 0, 0, //red
		    0, 0, 0, 0, 0, //green
		    0, 0, 0, 0, 0, //blue
		    0, 0, 0, 1, 0 //alpha  
		  };
	private ColorMatrixColorFilter mLightingColorFilter= new ColorMatrixColorFilter(colorMatrix);

	public ColorFilterView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < 8; i++) {
			mPaint.setColorFilter(mLightingColorFilter);
			canvas.drawBitmap(mBitmap,
					(i % 4) * (mBitmap.getWidth() + padding), (i / 4)
							* (mBitmap.getHeight() + padding), mPaint);
		}
	}

}
看一下結果

 

\

再來修改一下

	float[] colorMatrix = { 
		    1, 0, 0, 0, 0, //red
		    0, 1, 0, 0, 0, //green
		    0, 0, 0, 0, 0, //blue
		    0, 0, 0, 1, 0 //alpha  
		  };
看一下運行結果

 

\

最後在修改一下,讓他還原正常圖片

	float[] colorMatrix = { 
		    1, 0, 0, 0, 0, //red
		    0, 1, 0, 0, 0, //green
		    0, 0, 1, 0, 0, //blue
		    0, 0, 0, 1, 0 //alpha  
		  };
看一下結果

 

\

OK,上面的演示完了,我們看下面的一個矩陣。

[ 1 0 0 0 8  
  0 2 0 0 8   
  0 0 3 0 8   
  0 0 0 1 0 ] 
他表示紅色分量偏移8,綠色分量*2在偏移8,藍色分量*3在偏移8。下面看一下主要的方法,setScale(float rScale, float gScale, float bScale,float aScale)
    public void setScale(float rScale, float gScale, float bScale,
                         float aScale) {
        final float[] a = mArray;

        for (int i = 19; i > 0; --i) {
            a[i] = 0;
        }
        a[0] = rScale;
        a[6] = gScale;
        a[12] = bScale;
        a[18] = aScale;
    }
這個和矩陣剛初始化的時候差不多,不過這裡的值不是1,是我們傳入的值,代表的是亮度,我們看一下
public class ColorFilterView extends View {
	private Paint mPaint;
	private Bitmap mBitmap;
	private ColorMatrix colorMatrix = new ColorMatrix();
	private ColorMatrixColorFilter matrixColorFilter[] = new ColorMatrixColorFilter[24];
	private int padding = 12;

	public ColorFilterView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
		for (int i = 0; i < 24; i++) {
			if (i < 8)
				colorMatrix.setScale(i * .1f, i * .1f, i * .1f, i * .1f);
			else if (i < 16)
				colorMatrix.setScale(i * .1f, i * .1f, i * .1f, i * .1f);
			else
				colorMatrix.setScale(i * .1f, i * .1f, i * .1f, i * .1f);
			matrixColorFilter[i] = new ColorMatrixColorFilter(colorMatrix);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < 24; i++) {
			mPaint.setColorFilter(matrixColorFilter[i]);
			canvas.drawBitmap(mBitmap,
					(i % 4) * (mBitmap.getWidth() + padding), (i / 4)
							* (mBitmap.getHeight() + padding), mPaint);
		}
	}
}

我們看一下運行結果

\

再來修改一下

		for (int i = 0; i < 24; i++) {
			if (i < 8)
				colorMatrix.setScale(i * .1f, i * .3f, i * .9f, i * .1f);
			else if (i < 16)
				colorMatrix.setScale(i * .1f, i * .3f, i * .9f, i * .1f);
			else
				colorMatrix.setScale(i * .1f, i * .3f, i * .9f, i * .1f);
			matrixColorFilter[i] = new ColorMatrixColorFilter(colorMatrix);
		}
看一下運行結果

\

再看另一個方法setRotate(int axis, float degrees),表示的是色相
 

 /**
     * Set the rotation on a color axis by the specified values.
     * <p>
     * <code>axis=0</code> correspond to a rotation around the RED color
     * <code>axis=1</code> correspond to a rotation around the GREEN color
     * <code>axis=2</code> correspond to a rotation around the BLUE color
     * </p>
     */
    public void setRotate(int axis, float degrees) {
        reset();
        double radians = degrees * Math.PI / 180d;
        float cosine = (float) Math.cos(radians);
        float sine = (float) Math.sin(radians);
        switch (axis) {
        // Rotation around the red color
        case 0:
            mArray[6] = mArray[12] = cosine;
            mArray[7] = sine;
            mArray[11] = -sine;
            break;
        // Rotation around the green color
        case 1:
            mArray[0] = mArray[12] = cosine;
            mArray[2] = -sine;
            mArray[10] = sine;
            break;
        // Rotation around the blue color
        case 2:
            mArray[0] = mArray[6] = cosine;
            mArray[1] = sine;
            mArray[5] = -sine;
            break;
        default:
            throw new RuntimeException();
        }
    }
其中axis為0時表示的是紅色分量旋轉的角度,為1時是綠色分量旋轉的角度,為2時是藍色分量旋轉的角度,
		for (int i = 0; i < 24; i++) {
			if (i < 8)
				colorMatrix.setRotate(0, i*50);
			else if (i < 16)
				colorMatrix.setRotate(1, i*50);
			else
				colorMatrix.setRotate(2, i*50);
			matrixColorFilter[i] = new ColorMatrixColorFilter(colorMatrix);
		}
看一下運行結果

\

再來修改一下

		for (int i = 0; i < 24; i++) {
			if (i < 8)
				colorMatrix.setRotate(0, i*50);
			else if (i < 16)
				colorMatrix.setRotate(1, (i%8)*50);
			else
				colorMatrix.setRotate(2, (i%8)*50);
			matrixColorFilter[i] = new ColorMatrixColorFilter(colorMatrix);
		}

看一下運行結果

\

 

再看另一個方法setSaturation(float sat),代表的是飽和度,其中0是灰色,1是正常

		for (int i = 0; i < 24; i++) {
			if (i < 8)
				colorMatrix.setSaturation(i*.2f);
			else if (i < 16)
				colorMatrix.setSaturation(i*.5f);
			else
				colorMatrix.setSaturation(i*2f);
			matrixColorFilter[i] = new ColorMatrixColorFilter(colorMatrix);
		}
運行結果為

 

\

setConcat(ColorMatrix matA, ColorMatrix matB),兩矩陣相乘

    public void setConcat(ColorMatrix matA, ColorMatrix matB) {
        float[] tmp;
        if (matA == this || matB == this) {
            tmp = new float[20];
        } else {
            tmp = mArray;
        }

        final float[] a = matA.mArray;
        final float[] b = matB.mArray;
        int index = 0;
        for (int j = 0; j < 20; j += 5) {
            for (int i = 0; i < 4; i++) {
                tmp[index++] = a[j + 0] * b[i + 0] +  a[j + 1] * b[i + 5] +
                               a[j + 2] * b[i + 10] + a[j + 3] * b[i + 15];
            }
            tmp[index++] = a[j + 0] * b[4] +  a[j + 1] * b[9] +
                           a[j + 2] * b[14] + a[j + 3] * b[19] +
                           a[j + 4];
        }

        if (tmp != mArray) {
            System.arraycopy(tmp, 0, mArray, 0, 20);
        }
    }
preConcat(ColorMatrix prematrix)前乘,postConcat(ColorMatrix postmatrix)後乘,調用的都是setConcat(ColorMatrix matA, ColorMatrix matB)方法,因為矩陣的乘法不具有交換律,改變兩個矩陣的位置會產生不同的結果。

 

再來看ColorFilter的另一個子類LightingColorFilter光線顏色過濾,就一個構造方法

    public LightingColorFilter(int mul, int add) {
        mMul = mul;
        mAdd = add;
        update();
    }
mul表示顏色增加的倍數,add為色彩增加,
public class ColorFilterView extends View {
	private Paint mPaint;
	private Bitmap mBitmap;
	private LightingColorFilter mLightingColorFilter[] = new LightingColorFilter[8];
	private int padding = 12;

	public ColorFilterView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
		//不變
		mLightingColorFilter[0] = new LightingColorFilter(0xFFFFFFFF,
				0x00000000);
		//去掉紅色
		mLightingColorFilter[1] = new LightingColorFilter(0xFF00FFFF,
				0x00000000);
		//去掉綠色
		mLightingColorFilter[3] = new LightingColorFilter(0xFFFF00FF,
				0x00000000);
		//去掉藍色
		mLightingColorFilter[4] = new LightingColorFilter(0xFFFFFF00,
				0x00000000);
		//增加紅色
		mLightingColorFilter[5] = new LightingColorFilter(0xFFFFFFFF,
				0x00560000);
		//增加綠色
		mLightingColorFilter[6] = new LightingColorFilter(0xFFFFFFFF,
				0x00006400);
		//增加藍色
		mLightingColorFilter[7] = new LightingColorFilter(0xFFFFFFFF,
				0x00000056);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < 8; i++) {
			mPaint.setColorFilter(mLightingColorFilter[i]);
			canvas.drawBitmap(mBitmap,
					(i % 4) * (mBitmap.getWidth() + padding), (i / 4)
							* (mBitmap.getHeight() + padding), mPaint);
		}
	}

}
運行結果為

 

\
再來看ColorFilter的最後一個子類PorterDuffColorFilter,他也是只有一個構造方法

    /**
     * Create a color filter that uses the specified color and Porter-Duff mode.
     *
     * @param color The ARGB source color used with the specified Porter-Duff mode
     * @param mode The porter-duff mode that is applied
     *
     * @see Color
     * @see #setColor(int)
     * @see #setMode(android.graphics.PorterDuff.Mode)
     */
    public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
        mColor = color;
        mMode = mode;
        update();
    }
我們看一下
public class ColorFilterView extends View {
	private Paint mPaint;
	private Bitmap mBitmap;
	private int length = PorterDuff.Mode.values().length;
	private PorterDuffColorFilter mLightingColorFilter[] = new PorterDuffColorFilter[length];
	private int padding = 12;

	public ColorFilterView(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	private void init() {
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
		int i = 0;
		for (PorterDuff.Mode e : PorterDuff.Mode.values())
			mLightingColorFilter[i++] = new PorterDuffColorFilter(Color.YELLOW,
					e);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < length; i++) {
			mPaint.setColorFilter(mLightingColorFilter[i]);
			canvas.drawBitmap(mBitmap,
					(i % 4) * (mBitmap.getWidth() + padding), (i / 4)
							* (mBitmap.getHeight() + padding), mPaint);
		}
	}

}
運行結果為
\
其中Mode是之前在講到Android Paint的使用詳解的時候講到的18種混合模式,OK,到此為止,已經分析完畢。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved