实现图片的滤镜效果

提到这个到不是因为要做照片处理软件的滤镜效果,而是开发过程中设计师每每只提供一张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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

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