ColorFilter

ColorFilter

颜色过滤器可以与Paint一起使用,以修改使用该Paint的每个像素的颜色。
这是一个不应该直接使用的抽象类。

public class ColorFilter {

    private static class NoImagePreloadHolder {
        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
                ColorFilter.class.getClassLoader(), nativeGetFinalizer(), 50);
    }

    /** @deprecated 使用子类构造函数直接替代。 */
    @Deprecated
    public ColorFilter() {}

    /** 当前native SkColorFilter实例。 */
    private long mNativeInstance;
    // 可以立即销毁
    private Runnable mCleaner;

    long createNativeInstance() {
        return 0;
    }

    void discardNativeInstance() {
        if (mNativeInstance != 0) {
            mCleaner.run();
            mCleaner = null;
            mNativeInstance = 0;
        }
    }

    /** @hide */
    public long getNativeInstance() {
        if (mNativeInstance == 0) {
            mNativeInstance = createNativeInstance();
            if (mNativeInstance != 0) {
            	// 注意:这里必须检查null,因为如果native SkColorFilter在绘制时是no-op,
            	// 那么createNativeInstance()可能返回nullptr。
            	// 有关更多信息,请参见子类创建方法的native实现。
                mCleaner = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                        this, mNativeInstance);
            }
        }
        return mNativeInstance;
    }

    private static native long nativeGetFinalizer();
}

LightingColorFilter

可用于模拟简单lighting效果的颜色过滤器。LightingColorFilter由两个参数定义,一个用于乘以源颜色(称为colorMultiply),另一个用于相加源颜色(称为colorAdd)。alpha通道不受此颜色过滤器的影响。

给定源颜色RGB,计算得到的R’G’B’颜色:
R’ = R * colorMultiply.R + colorAdd.R
G’ = G * colorMultiply.G + colorAdd.G
B’ = B * colorMultiply.B + colorAdd.B
结果固定到每个通道的[0…255]范围。

public class LightingColorFilter extends ColorFilter {
    @ColorInt
    private int mMul;
    @ColorInt
    private int mAdd;

    /** 创建一个ColorFilter,将RGB乘以一个颜色,然后相加第二个颜色。mul和add的alpha被忽略。 */
    public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
        mMul = mul;
        mAdd = add;
    }

    /** 应用ColorFilter时,返回用于乘以源颜色的RGB颜色。 */
    @ColorInt
    public int getColorMultiply() {
        return mMul;
    }

    /** 应用ColorFilter时,指定用于乘以源颜色的RGB颜色。忽略此颜色的alpha。 @hide */
    public void setColorMultiply(@ColorInt int mul) {
        if (mMul != mul) {
            mMul = mul;
            discardNativeInstance();
        }
    }

    /** 应用ColorFilter时,返回将相加源颜色的RGB颜色。 */
    @ColorInt
    public int getColorAdd() {
        return mAdd;
    }

    /** 应用ColorFilter时,指定将相加源颜色的RGB。忽略此颜色的alpha。 @hide */
    public void setColorAdd(@ColorInt int add) {
        if (mAdd != add) {
            mAdd = add;
            discardNativeInstance();
        }
    }

    @Override
    long createNativeInstance() {
        return native_CreateLightingFilter(mMul, mAdd);
    }

    private static native long native_CreateLightingFilter(int mul, int add);
}

PoterDuffColorFilter

一种颜色过滤器,可用于使用单一颜色和特定PorterDuff混合模式对源像素进行着色。

public class PorterDuffColorFilter extends ColorFilter {
    @ColorInt
    private int mColor;
    private PorterDuff.Mode mMode;

    /** 
     * 创建使用指定颜色和PorterDuff模式的ColorFilter。
     *
     * @param color 与指定PorterDuff模式一起使用的ARGB源颜色
     * @param mode 应用的PorterDuff模式
     */
    public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
        mColor = color;
        mMode = mode;
    }

    /** 应用此filter时,返回用于着色源像素的ARGB颜色。 @hide */
    @ColorInt
    public int getColor() {
        return mColor;
    }

    /** 在应用此ColorFilter时,指定对源像素进行着色的颜色。 @hide */
    public void setColor(@ColorInt int color) {
        if (mColor != color) {
            mColor = color;
            discardNativeInstance();
        }
    }

    /** 应用此filter时,返回用于将此ColorFilter的颜色与源像素混合的PorterDuff模式。 @hide */
    public PorterDuff.Mode getMode() {
        return mMode;
    }

    /** 绘制时,将此ColorFilter的颜色与源像素混合时使用指定的PorterDuff模式。 @hide */
    public void setMode(@NonNull PorterDuff.Mode mode) {
        if (mode == null) {
            throw new IllegalArgumentException("mode must be non-null");
        }
        mMode = mode;
        discardNativeInstance();
    }

    @Override
    long createNativeInstance() {
        return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (object == null || getClass() != object.getClass()) {
            return false;
        }
        final PorterDuffColorFilter other = (PorterDuffColorFilter) object;
        return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt);
    }

    @Override
    public int hashCode() {
        return 31 *  mMode.hashCode() + mColor;
    }

    private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode);
}

ColorMatrixColorFilter

通过4x5颜色矩阵变换颜色的ColorFilter。该filter可用于改变像素的饱和度、由YUV到RGB的转换等。

public class ColorMatrixColorFilter extends ColorFilter {

    private final ColorMatrix mMatrix = new ColorMatrix();

    /**
     * 创建一个通过4x5颜色矩阵变换颜色的ColorFilter。
     *
     * @param matrix 用于变换颜色的4x5矩阵。它被复制到filter中,因此在构造filter后
     * 				 对矩阵所做的更改不会反映在filter中。
     */
    public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) {
        mMatrix.set(matrix);
    }

    /**
     * 创建一个通过4x5颜色矩阵变换颜色的ColorFilter。
     *
     * @param array 用于转换颜色的float数组,作为4x5矩阵处理。
     * 				数组的前20个条目被复制到filter中。请参见ColorMatrix。 
     */
    public ColorMatrixColorFilter(@NonNull float[] array) {
        if (array.length < 20) {
            throw new ArrayIndexOutOfBoundsException();
        }
        mMatrix.set(array);
    }

    /**
     * 将filter中的mMatrix复制到传入的ColorMatrix中。
     *
     * @param colorMatrix 设置为filter颜色矩阵的当前值。
     */
    public void getColorMatrix(ColorMatrix colorMatrix) {
        colorMatrix.set(mMatrix);
    }

    /**
     * 复制由该filter使用的所提供的颜色矩阵。 
     * 如果指定的颜色矩阵为null,则此filter的颜色矩阵将重置为标识矩阵。
     * @hide
     */
    public void setColorMatrix(@Nullable ColorMatrix matrix) {
        discardNativeInstance();
        if (matrix == null) {
            mMatrix.reset();
        } else {
            mMatrix.set(matrix);
        }
    }

    /**
     * 复制由该filter使用的所提供的颜色矩阵。
     * 如果指定的颜色矩阵为null,则此filter的颜色矩阵将重置为标识矩阵。
     *
     * @param array 用于转换颜色的float数组,作为4x5矩阵处理。数组的前20个条目被复制到筛选器中。
     * 				请参见ColorMatrix。
     * @throws ArrayIndexOutOfBoundsException 如果指定数组的长度小于20。
     * @hide
     */
    public void setColorMatrixArray(@Nullable float[] array) {
        // 调用“…Array”,以便传递null不含糊
        discardNativeInstance();
        if (array == null) {
            mMatrix.reset();
        } else {
            if (array.length < 20) {
                throw new ArrayIndexOutOfBoundsException();
            }
            mMatrix.set(array);
        }
    }

    @Override
    long createNativeInstance() {
        return nativeColorMatrixFilter(mMatrix.getArray());
    }

    private static native long nativeColorMatrixFilter(float[] array);
}

ColorMatrix

4x5矩阵,用于变换Bitmap的color和alpha分量。矩阵可以作为单个数组传递,处理方法如下:
[ a b c d e f g h i j k l m n o p q r s t ] = [ a , b , c , d , e , f , g , h , i , j , k , l , m , n , o , p , q , r , s , t ] \left[ \begin {matrix} a&b&c&d&e \\ f&g&h&i&j \\ k&l&m&n&o \\ p&q&r&s&t \end {matrix} \right] = [ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
当应用于颜色 [ R , G , B , A ] [R, G, B, A] 时,得到的颜色计算如下:

R' = aR + bG + cB + dA + e
G' = fR + gG + hB + iA + j 
B' = kR + lG + mB + nA + o
A' = pR + qG + rB + sA + t

由此得到的颜色 [ R , G , B , A ] [R', G', B', A'] 将每个通道固定在 0255 的范围内。

下面示例ColorMatrix通过将每个通道乘以-1来反转传入的颜色,然后将结果上移255以保留在标准颜色空间中。
[ 1 0 0 0 255 0 1 0 0 255 0 0 1 0 255 0 0 0 1 0 ] \left[ \begin {matrix} -1&0&0&0&255 \\ 0&-1&0&0&255 \\ 0&0&-1&0&255 \\ 0&0&0&1&0 \end {matrix} \right]

@SuppressWarnings({ "MismatchedReadAndWriteOfArray", "PointlessArithmeticExpression" })
public class ColorMatrix {

    private final float[] mArray = new float[20];

    /** 创建一个初始化为identity的新ColorMatrix(就像调用了reset()一样)。 */
    public ColorMatrix() {
        reset();
    }

    /** 创建一个用指定值数组初始化的新ColorMatrix。 */
    public ColorMatrix(float[] src) {
        System.arraycopy(src, 0, mArray, 0, 20);
    }

    /** 创建用指定的ColorMatrix初始化的新ColorMatrix。 */
    public ColorMatrix(ColorMatrix src) {
        System.arraycopy(src.mArray, 0, mArray, 0, 20);
    }

    /** 返回表示此ColorMatrix的float数组。 */
    public final float[] getArray() { return mArray; }

    /**
     * 将此ColorMatrix设置为标识:
     * <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;
    }

    /** 将src ColorMatrix赋给这个矩阵,复制它的所有值。 */
    public void set(ColorMatrix src) {
        System.arraycopy(src.mArray, 0, mArray, 0, 20);
    }

    /** 将float数组赋给这个矩阵,复制它的所有值。 */
    public void set(float[] src) {
        System.arraycopy(src, 0, mArray, 0, 20);
    }

    /** 将此ColorMatrix设置为按指定值缩放。 */
    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;
    }

    /** 
     * 设置颜色轴(axis)上的rotation为指定值。
     * <p>
     * <code>axis=0</code> 对应于围绕红轴旋转
     * <code>axis=1</code> 对应于围绕绿轴旋转
     * <code>axis=2</code> 对应于围绕蓝轴旋转
     * </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) {
        // 围绕红轴旋转
        case 0:
            mArray[6] = mArray[12] = cosine;
            mArray[7] = sine;
            mArray[11] = -sine;
            break;
        // 围绕绿轴旋转
        case 1:
            mArray[0] = mArray[12] = cosine;
            mArray[2] = -sine;
            mArray[10] = sine;
            break;
        // 围绕蓝轴旋转
        case 2:
            mArray[0] = mArray[6] = cosine;
            mArray[1] = sine;
            mArray[5] = -sine;
            break;
        default:
            throw new RuntimeException();
        }
    }

    /**
     * 将此ColorMatrix设置为两个指定的ColorMatrix的连接,
     * 以便生成的ColorMatrix具有与应用matB然后应用matA相同的效果。
     * <p>
     * 无论matA或matB与此ColorMatrix相同是合法的。
     * </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);
        }
    }

    /**
     * 用指定的前矩阵连接此ColorMatrix。
     * <p>
     * 这在逻辑上与调用setConcat(this, prematrix)相同
     * </p>
     */
    public void preConcat(ColorMatrix prematrix) {
        setConcat(this, prematrix);
    }

    /**
     * 将此ColorMatrix与指定的后矩阵连接。
     * <p>
     * 这在逻辑上与调用setConcat(postmatrix,this)相同
     * </p>
     */
    public void postConcat(ColorMatrix postmatrix) {
        setConcat(postmatrix, this);
    }

    ///////////////////////////////////////////////////////////////////////////

    /**
     * 设置矩阵以影响颜色的饱和度。
     *
     * @param sat 值为0将颜色映射到灰度级,1是本身。
     */
    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;
    }

    /** 设置矩阵以将RGB转换为YUV */
    public void setRGB2YUV() {
        reset();
        float[] m = mArray;
        // 这些系数与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;
    }

    /** 设置矩阵以将YUV转换为RGB */
    public void setYUV2RGB() {
        reset();
        float[] m = mArray;
        // 这些系数与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(空值)值意味着matrix != itself
        if (!(obj instanceof ColorMatrix)) {
            return false;
        }

        // 我们不使用Arrays.equals(),因为它考虑了NaN==NaN
        final float[] other = ((ColorMatrix) obj).mArray;
        for (int i = 0; i < 20; i++) {
            if (other[i] != mArray[i]) {
                return false;
            }
        }
        return true;
    }
}

发布了19 篇原创文章 · 获赞 0 · 访问量 863

猜你喜欢

转载自blog.csdn.net/qq_32036981/article/details/103840940