Java tutorial
/* * 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 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: * * <pre> * [ a, b, c, d, e, * f, g, h, i, j, * k, l, m, n, o, * p, q, r, s, t ]</pre> * * <p> * When applied to a color <code>[R, G, B, A]</code>, the resulting color * is computed as: * </p> * * <pre> * 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;</pre> * * <p> * That resulting color <code>[R’, G’, B’, A’]</code> * then has each channel clamped to the <code>0</code> to <code>255</code> * range. * </p> * * <p> * The sample ColorMatrix below inverts incoming colors by scaling each * channel by <code>-1</code>, and then shifting the result up by * <code>255</code> to remain in the standard color space. * </p> * * <pre> * [ -1, 0, 0, 0, 255, * 0, -1, 0, 0, 255, * 0, 0, -1, 0, 255, * 0, 0, 0, 1, 0 ]</pre> */ @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: * <pre> * [ 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 * </pre> */ 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. * <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(); } } /** * 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. * <p> * It is legal for either matA or matB to be the same colormatrix as this. * </p> */ 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. * <p> * This is logically the same as calling setConcat(this, prematrix); * </p> */ public void preConcat(ColorMatrix prematrix) { setConcat(this, prematrix); } /** * Concat this colormatrix with the specified postmatrix. * <p> * This is logically the same as calling setConcat(postmatrix, this); * </p> */ 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; } @Override public boolean equals(Object obj) { // if (obj == this) return true; -- NaN value would mean matrix != itself if (!(obj instanceof ColorMatrix)) { return false; } // we don't use Arrays.equals(), since that considers NaN == NaN final float[] other = ((ColorMatrix) obj).mArray; for (int i = 0; i < 20; i++) { if (other[i] != mArray[i]) { return false; } } return true; } }