实现图片的滤镜效果

提到这个到不是因为要做照片处理软件的滤镜效果,而是开发过程中设计师每每只提供一张icon图标,然后说点击效果你自己用程序实现吧;或者产品经理过来说,用户头像加个点击效果吧。以往的开发过程中,设计师多半会提供两张icon图标,一张正常状态,一张选中状态,这样点击的时候会有一个动态的效果。而现在一张图去实现点击效果还真有点难为了,车到山前必有路,谁让我是老司机呢。
首先我印象中Imageview会有个透明度Alpha的属性,于是我最先想到用setAlpha()来改变图片的透明度,但实际效果并不好。后来在Stay的点拨下终于找到了比较好的解决方案,ImageView有一个setColorFilter()的API,完全适合当前场景。

  /**
     * Set a tinting option for the image.
     * 
     * @param color Color tint to apply.
     * @param mode How to apply the color.  The standard mode is
     * {@link PorterDuff.Mode#SRC_ATOP}
     * 
     * @attr ref android.R.styleable#ImageView_tint
     */
    public final void setColorFilter(int color, PorterDuff.Mode mode) {
        setColorFilter(new PorterDuffColorFilter(color, mode));
    }

    /**
     * Set a tinting option for the image. Assumes
     * {@link PorterDuff.Mode#SRC_ATOP} blending mode.
     *
     * @param color Color tint to apply.
     * @attr ref android.R.styleable#ImageView_tint
     */
    @RemotableViewMethod
    public final void setColorFilter(int color) {
        setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
    }
    /**
     * Apply an arbitrary colorfilter to the image.
     *
     * @param cf the colorfilter to apply (may be null)
     *
     * @see #getColorFilter()
     */
    public void setColorFilter(ColorFilter cf) {
        if (mColorFilter != cf) {
            mColorFilter = cf;
            mColorMod = true;
            applyColorMod();
            invalidate();
        }
    }

setColorFilter有以上三种调用方式,可以直接传入色值和mode,mode缺省的默认值为PorterDuff.Mode.SRC_ATOP,具体各mode的效果可以参见http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.html, setColorFilter还可以传入ColorFilter的子类。

ColorFilter有三个子类ColorMatrixColorFilter,LightingColorFilter,PorterDuffColorFilter,它的功能应该就是按照一定的规则改变图片的颜色,三个子类各有各的不同的改法规则,其中ColorMatrixColorFilter的改变法则就是ColorMatrix的改变规则,它是ColorMatrix的应用。LightingColorFilter 乘以第一个颜色的RGB通道,然后加上第二个颜色。每一次转换的结果都限制在0到255之间。PorterDuffColorFilter 可以使用数字图像合成的16条Porter-Duff 规则中的任意一条来向Paint应用一个指定的颜色。

我们就挑第一个ColorMatrixColorFilter来举例,前面已经说过,ColorMatrixColorFilter的改变法则就是ColorMatrix的改变规则,它是ColorMatrix的应用。ColorMatrix是Android源码中一个颜色矩阵类,通过对这个类的一系列操作,可以控制改变图片的色调明暗饱和度等,这也就是图片处理软件实现滤镜效果的原理。这个类把颜色定义为一个4*5的矩阵,如果用一个一纬数组表示就是这样:
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]。

/** 
*  4x5 matrix for transforming the color+alpha components of a Bitmap. 
*  The matrix is stored in a single array, and its 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 * (after clamping) 
*   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; 
*/

这里是源码里的注释,已经解释的很清楚了,RGBA的运算公式也清晰明了,所以实际调用过程中,我们可以通过传入需要的参数来控制RGBA的值,进而改变图片的色彩。

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

这里是一张图片的默认色彩属性值,我们只需要根据需求去调校各参数值,就能实现图片的滤镜效果了。再回到最开始的诉求,我是想通过程序实现单张图片的点击效果,但是设计师只提供了一张图,那么我只需要在手指按下的时候去给当前图片加个滤镜,抬起时再移除即可。简单粗暴点,直接上代码。

/**
 * Created by yx on 16/4/3.
 */
public class DiscolorImageView extends ImageView{


    /**
     * 变暗
     */
    private final float[] SELECTED_DARK = new float[]
            {1, 0, 0, 0, -80,
            0, 1, 0, 0, -80,
            0, 0, 1, 0, -80,
            0, 0, 0, 1, 0};
    /**
     * 变亮
     */

    private final float[] SELECTED_BRIGHT = new float[]
            {1, 0, 0, 0, 80,
                    0, 1, 0, 0, 80,
                    0, 0, 1, 0, 80,
                    0, 0, 0, 1, 0};

    /**
     * 高对比度
     */

    private final float[] SELECTED_HDR = new float[]
            {5, 0, 0, 0, -250,
                    0, 5, 0, 0, -250,
                    0, 0, 5, 0, -250,
                    0, 0, 0, 1, 0};

    /**
     * 高饱和度
     */
    private final float[] SELECTED_HSAT = new float[]
            {(float) 3, (float) -2, (float) -0.2, 0, 50,
                    -1, 2, -0, 0, 50,
                    -1, -2, 4, 0, 50,
                    0, 0, 0, 1, 0};

    /**
     * 改变色调
     */
    private final float[] SELECTED_DISCOLOR = new float[]
            {(float) -0.5, (float) -0.6, (float) -0.8, 0, 0,
                    (float) -0.4, (float) -0.6, (float) -0.1, 0, 0,
                    (float) -0.3, 2, (float) -0.4, 0, 0,
                    0, 0, 0, 1, 0};

    public DiscolorImageView(Context context) {
        super(context);
        this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
    }

    public DiscolorImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
    }

    public DiscolorImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.setOnTouchListener(VIEW_TOUCH_DISCOLOR);
    }

    public OnTouchListener VIEW_TOUCH_DISCOLOR = new OnTouchListener() {


        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                ImageView iv = (ImageView) v;
                iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HDR));
              //iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_BRIGHT));
              //iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HDR));
              //iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_HSAT));
              //iv.setColorFilter(new ColorMatrixColorFilter(SELECTED_DISCOLOR));
            } else if (event.getAction() == MotionEvent.ACTION_UP) {
                ImageView iv = (ImageView) v;
                iv.clearColorFilter();
                mPerformClick();
            } else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
                ImageView iv = (ImageView) v;
                iv.clearColorFilter();
            }
            return true;

        }
    };

        private void mPerformClick() {
            DiscolorImageView.this.performClick();
        }
    }

我这里随便给出了几个滤镜效果的参数值,但是未经调教,有可能效果一塌糊涂,基本原理很简单了,又要说到onTouch事件了,按下去的时候显示滤镜效果图,抬起时移除滤镜显示原图,这样点击的时候就有了一个动态的selector效果了。如下图:

device-2016-04-06-004225.gif
device-2016-04-06-004356.gif

device-2016-04-06-004437.gif

参考资料:
http://blog.sina.com.cn/s/blog_5da93c8f01012pkj.htm
http://my.oschina.net/gavinjin/blog/208586

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 滤镜 滤镜;主要是用来实现图像的各种特殊效果。它在Photoshop中具有非常神奇的作用。滤镜通常需要同通道、图层...
    fengzhizi715阅读 10,257评论 3 12
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 14,838评论 4 61
  • 别看我每天发自拍,其实是越不自信的自己,越怀疑自己,才要看看我自己 一个对自我有充分了解的人,是不会像我这样,不知...
    爱娇阅读 1,819评论 0 0
  • “妈妈,去给我买豆腐脑吧。” “不去,想吃自己去!” 被硬邦邦的话拒绝后,我翻身下床直接进了厨房,决定自己做顿早餐...
    葵花岛杨亚宁阅读 4,117评论 0 4

友情链接更多精彩内容