美文网首页安卓知识安桌编解码
Matrix(三) 神奇的ColorMatrix(图片的颜色与色

Matrix(三) 神奇的ColorMatrix(图片的颜色与色

作者: MartinBZDQSM | 来源:发表于2016-08-03 22:11 被阅读2086次

    之前整了两章关于Android中的Matrix操作,本章来谈一谈Android中的另一个Matrix-ColorMatrix。

    本文讲述的具体内容如图:

    Color.jpg

    **如果不喜欢看描述的话,项目的demo地址如下:
    https://github.com/MartinBZDQSM/Matrix
    **

    ColorMatrix

    谈到ColorMatrix,那么先聊聊Android中颜色.
    我们在经常调整布局颜色的时候使用的是为八位的十六进制表示法的颜色值,例如:#0xd5d5d5;这种表示法也正对应着Android中使用的ARGB模式,也就是说颜色和透明度 (alpha) 的值都用以十六进制表示法表示。其首两位代表着透明度剩下的分别对应着红绿蓝三种颜色,其中任何一种颜色的值范围都是 0到 255(00到 ff)。

    而Android支持的颜色模式都有:

    颜色模式 说明
    ARGB8888 四通道高精度(32位)
    ARGB4444 四通道低精度(24位)
    RGB565 三通道(16位)
    Alpha8 透明通道(8位)

    所以看到这里,我们其实就能猜出来,为什么一张好好的透明PNG图片在某些加载框架中会变黑?正式因为其框架使用的默认通道是RGB565 缺少了一个透明通道,所以当我们修改了图片的颜色模式为ARGB8888或者ARGB4444后会变正常。

    现在我们来看看ColorMatrix 的官方描述:

    /**
     * 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:
     * 下面这个4x5的矩阵可以表达,为一张图的颜色以及透明图信息。
     *  [ 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.计算出来的结果,每个通道都在0-255之间
     * 
     * 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.
     * 好像用来举例说明的,前四列代表RGBA的偏向成分,第五列代表着颜色偏移量
     *
     *   [ -1, 0, 0, 0, 255,
     *     0, -1, 0, 0, 255,
     *     0, 0, -1, 0, 255,
     *     0, 0, 0, 1, 0 ]
     */
    

    总得来说就是,一张图可以通过设置 颜色矩阵 来改变它的颜色效果。

    1.颜色偏向

    为了测试ColorMatrix能够影响图片的颜色效果,我设置了4个SeekBar,来分别代表着R,G,B,A四个通道,其范围都是0-255.

     @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            //设置偏移量
            colorMatrix.setScale(caculate(seekBarR.getProgress()), caculate(seekBarG.getProgress()),
                    caculate(seekBarB.getProgress()), caculate(seekBarA.getProgress()));
    
           //偏向颜色的值
            colorText.setText("颜色值:#" + Integer.toHexString(seekBarA.getProgress())
                    + Integer.toHexString(seekBarR.getProgress())
                    + Integer.toHexString(seekBarG.getProgress())
                    + Integer.toHexString(seekBarB.getProgress()));
    
             //用来显示偏向的颜色
            colorView.setBackgroundColor(Color.argb(seekBarA.getProgress(),
                    seekBarR.getProgress(),
                    seekBarG.getProgress(),
                    seekBarB.getProgress()));
    
            //为组件设置新的过滤器
            imageView.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
            
        }
    

    效果演示如下:


    ColorMartix.gif

    2.色相

    本来还不是很明白色相指的什么,查查百度才知道:色相是色彩的首要特征,是区别各种不同色彩的最准确的标准。
    正如PS中使用的的色相/饱和度功能,它可以通过修改颜色的三个基本属性:色相彩度明度,来进行调节色彩。

    PS_HUE.png
    那么,在Android中如何做呢?同样 我写了三个SeekBar范围值也分别是0-255。
      @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    
            float mHueValue = (seekBarHue.getProgress() - 128f) * 1.0f / 128f * 180;
            float mSaturationValue = seekBarSaturation.getProgress() / 128f;
            float mLightnessValue = seekBarLightness.getProgress() / 128f;
    
            //设置色相
            mHueMatrix.reset();
            mHueMatrix.setRotate(0, mHueValue);
            mHueMatrix.setRotate(1, mHueValue);
            mHueMatrix.setRotate(2, mHueValue);
    
            //设置饱和度
            mSaturationMatrix.reset();
            mSaturationMatrix.setSaturation(mSaturationValue);
    
            //亮度
            mLightnessMatrix.reset();
            mLightnessMatrix.setScale(mLightnessValue, mLightnessValue, mLightnessValue, 1);
    
            colorMatrix.reset();// 效果叠加
            colorMatrix.postConcat(mLightnessMatrix);
            colorMatrix.postConcat(mSaturationMatrix);
            colorMatrix.postConcat(mHueMatrix);
    
            imageView.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        }
    

    效果如下:


    ColorHue.gif

    3.简单的颜色滤镜封装

    通过上方的举例,我们很容易将调节过后的偏移矩阵,封装成一些滤镜使用。
    我找了一些已经设置好了的偏移矩阵作为滤镜使用,具体效果如图:

    ColorFilter.png

    下面贴出我封装的固定颜色偏向滤镜和固定偏移矩阵滤镜的方法:

     /**
         * 为imageView设置颜色滤镜
         *
         * @param imageView
         * @param colormatrix
         */
        public static void imageViewColorFilter(ImageView imageView, float[] colormatrix) {
            setColorMatrixColorFilter(imageView, new ColorMatrixColorFilter(new ColorMatrix(colormatrix)));
        }
    
        /**
         * 为imageView设置颜色偏向滤镜
         *
         * @param imageView
         * @param color
         */
        public static void imageViewColorFilter(ImageView imageView, int color) {
            ColorMatrix colorMatrix = new ColorMatrix();
            colorMatrix.setScale(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
            setColorMatrixColorFilter(imageView, new ColorMatrixColorFilter(colorMatrix));
        }
    
    
        /**
         * 生成对应颜色偏向滤镜的图片,并回收原图
         *
         * @param bitmap
         * @param color
         * @return
         */
        public static Bitmap bitmapColorFilter(Bitmap bitmap, int color) {
            ColorMatrix colorMatrix = new ColorMatrix();
            colorMatrix.setScale(Color.alpha(color), Color.red(color), Color.green(color), Color.blue(color));
            return setColorMatrixColorFilter(bitmap, new ColorMatrixColorFilter(colorMatrix), true);
        }
    
        /**
         * 生成对应颜色滤镜的图片,并回收原图
         *
         * @param bitmap
         * @param colormatrix
         * @return
         */
        public static Bitmap bitmapColorFilter(Bitmap bitmap, float[] colormatrix) {
            return setColorMatrix(bitmap, colormatrix, true);
        }
    
        /**
         * 生成对应颜色滤镜的图片
         *
         * @param bitmap
         * @param colormatrix
         * @param isRecycle
         * @return
         */
        public static Bitmap setColorMatrix(Bitmap bitmap, float[] colormatrix, boolean isRecycle) {
            return setColorMatrixColorFilter(bitmap, new ColorMatrixColorFilter(new ColorMatrix(colormatrix)), isRecycle);
        }
    
    
        public static void setColorMatrixColorFilter(ImageView imageView, ColorMatrixColorFilter matrixColorFilter) {
            imageView.setColorFilter(matrixColorFilter);
        }
    
        public static Bitmap setColorMatrixColorFilter(Bitmap bitmap, ColorMatrixColorFilter matrixColorFilter, boolean isRecycle) {
            Bitmap resource = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColorFilter(matrixColorFilter);
            Canvas canvas = new Canvas(resource);
            canvas.drawBitmap(bitmap, 0, 0, paint);
            if (isRecycle)
                BitmapUtils.destroyBitmap(bitmap);
            return resource;
        }
    

    包括之前的Matrix的代码都在Git上的demo里有详细的举例,就先写到这里把,应该也没有什么好整理的了。过几天会可能会把之前的Android海报制作弄完。
    喜欢这边文章的话,别忘了点个赞哈。

    相关文章

      网友评论

      • 李翾:博主你写的真不错,我忍不住还要给你评论一个
      • 李翾:引用了楼主的原文链接,写的很全面清晰,感谢!
      • 捡淑:马克
      • alighters:666. 三通道的RGB565为什么是16位的?
        alighters:@MartinBZDQSM 恩,搜到了。 RGB565中一个像素占两个字节, 其中:第一个字节的前5位用来表示R(Red),第一个字节的后三位+第二个字节的前三位用来表示G(Green),第二个字节的后5位用来表示B(Blue)。
        MartinBZDQSM:@alighters 我觉得应该是精度问题,就好像你问ARGB8888与ARGB4444的区别一样,两者的颜色精度(色彩范围)不同而通道数量都是一样的,所以你用ARGB4444任然能显示有透明背景的png图片,而你使用一张jpg图片在RGB565与ARGB8888两者在显示效果上有着很明显的色彩区别,也正是因为精度不一样所以一张图在不同模式下其显示的色彩效果和内存使用都是不同的.

      本文标题:Matrix(三) 神奇的ColorMatrix(图片的颜色与色

      本文链接:https://www.haomeiwen.com/subject/gocgjttx.html