/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.graphics; import android.util.FloatMath; import java.util.Arrays; /** * 4x5 matrix for transforming the color and alpha components of a Bitmap. * The matrix can be passed as single array, and is treated as follows: * *
 *  [ a, b, c, d, e,
 *    f, g, h, i, j,
 *    k, l, m, n, o,
 *    p, q, r, s, t ]
* *

* When applied to a color [R, G, B, A], the resulting color * is computed as: *

* *
 *   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;
* *

* That resulting color [R’, G’, B’, A’] * then has each channel clamped to the 0 to 255 * range. *

* *

* The sample ColorMatrix below inverts incoming colors by scaling each * channel by -1, and then shifting the result up by * 255 to remain in the standard color space. *

* *
 *   [ -1, 0, 0, 0, 255,
 *     0, -1, 0, 0, 255,
 *     0, 0, -1, 0, 255,
 *     0, 0, 0, 1, 0 ]
*/ @SuppressWarnings({ "MismatchedReadAndWriteOfArray", "PointlessArithmeticExpression" }) public class ColorMatrix { private final float[] mArray = new float[20]; /** * Create a new colormatrix initialized to identity (as if reset() had * been called). */ public ColorMatrix() { reset(); } /** * Create a new colormatrix initialized with the specified array of values. */ public ColorMatrix(float[] src) { System.arraycopy(src, 0, mArray, 0, 20); } /** * Create a new colormatrix initialized with the specified colormatrix. */ public ColorMatrix(ColorMatrix src) { System.arraycopy(src.mArray, 0, mArray, 0, 20); } /** * Return the array of floats representing this colormatrix. */ public final float[] getArray() { return mArray; } /** * 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; } /** * Assign the src colormatrix into this matrix, copying all of its values. */ public void set(ColorMatrix src) { System.arraycopy(src.mArray, 0, mArray, 0, 20); } /** * Assign the array of floats into this matrix, copying all of its values. */ public void set(float[] src) { System.arraycopy(src, 0, mArray, 0, 20); } /** * Set this colormatrix to scale by the specified values. */ 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; } /** * Set the rotation on a color axis by the specified values. *

* axis=0 correspond to a rotation around the RED color * axis=1 correspond to a rotation around the GREEN color * axis=2 correspond to a rotation around the BLUE color *

*/ public void setRotate(int axis, float degrees) { reset(); float radians = degrees * (float)Math.PI / 180; float cosine = FloatMath.cos(radians); float sine = FloatMath.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(); } } /** * Set this colormatrix to the concatenation of the two specified * colormatrices, such that the resulting colormatrix has the same effect * as applying matB and then applying matA. *

* It is legal for either matA or matB to be the same colormatrix as this. *

*/ 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); } } /** * Concat this colormatrix with the specified prematrix. *

* This is logically the same as calling setConcat(this, prematrix); *

*/ public void preConcat(ColorMatrix prematrix) { setConcat(this, prematrix); } /** * Concat this colormatrix with the specified postmatrix. *

* This is logically the same as calling setConcat(postmatrix, this); *

*/ public void postConcat(ColorMatrix postmatrix) { setConcat(postmatrix, this); } /////////////////////////////////////////////////////////////////////////// /** * Set the matrix to affect the saturation of colors. * * @param sat A value of 0 maps the color to gray-scale. 1 is identity. */ public void setSaturation(float sat) { reset(); float[] m = mArray; final float invSat = 1 - sat; final float R = 0.213f * invSat; final float G = 0.715f * invSat; final float B = 0.072f * invSat; m[0] = R + sat; m[1] = G; m[2] = B; m[5] = R; m[6] = G + sat; m[7] = B; m[10] = R; m[11] = G; m[12] = B + sat; } /** * Set the matrix to convert RGB to YUV */ public void setRGB2YUV() { reset(); float[] m = mArray; // these coefficients match those in libjpeg m[0] = 0.299f; m[1] = 0.587f; m[2] = 0.114f; m[5] = -0.16874f; m[6] = -0.33126f; m[7] = 0.5f; m[10] = 0.5f; m[11] = -0.41869f; m[12] = -0.08131f; } /** * Set the matrix to convert from YUV to RGB */ public void setYUV2RGB() { reset(); float[] m = mArray; // these coefficients match those in libjpeg m[2] = 1.402f; m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f; m[10] = 1; m[11] = 1.772f; m[12] = 0; } }