android案例--图片取色并让图片融入背景色

需求背景分析:

产品和美工给了个根据专辑封面取主题色做背景,并且专辑封面还要融入背景的效果图,一开始看到取色觉得简单啊,不就是之前看过的palette嘛,可是专辑封面渐变消失融入背景怎么做呢,我们一步步分析。

1. 首先是背景取色,Palette
这个比较简单,因为已经有现成的API让我们调用

 Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
                            @Override
                            public void onGenerated(Palette palette) {
                                    //todo 
                                }
                            }
                        });

palette可以获取到6种颜色,而且palette还有其他功能,这里就不介绍了,网上有很多案例,我们继续。
因为背景色是渐变的,由深变浅,所以要这里取出两个颜色通过paint的shader绘制一张渐变效果的bitmap,具体代码如下

 //......省略一些

  Palette.from(resource).generate(new Palette.PaletteAsyncListener() {
                            @Override
                            public void onGenerated(Palette palette) {
                              //记得判空
                                if(palette==null)return;
                              //palette取色不一定取得到某些特定的颜色,这里通过取多种颜色来避免取不到颜色的情况
                                if (palette.getDarkVibrantColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
                                    createLinearGradientBitmap(palette.getDarkVibrantColor(Color.TRANSPARENT), palette.getVibrantColor(Color.TRANSPARENT));
                                } else if (palette.getDarkMutedColor(Color.TRANSPARENT) != Color.TRANSPARENT) {
                                    createLinearGradientBitmap(palette.getDarkMutedColor(Color.TRANSPARENT), palette.getMutedColor(Color.TRANSPARENT));
                                } else {
                                    createLinearGradientBitmap(palette.getLightMutedColor(Color.TRANSPARENT), palette.getLightVibrantColor(Color.TRANSPARENT));
                                }
                            }
                        });


//创建线性渐变背景色
 private void createLinearGradientBitmap(int darkColor,int color) {
        int bgColors[] = new int[2];
        bgColors[0] = darkColor;
        bgColors[1] = color;

        if(bgBitmap==null){
            bgBitmap= Bitmap.createBitmap(ivBg.getWidth(),ivBg.getHeight(), Bitmap.Config.ARGB_4444);
        }
        if(mCanvas==null){
            mCanvas=new Canvas();
        }
        if(mPaint==null){
            mPaint=new Paint();
        }
        mCanvas.setBitmap(bgBitmap);
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        LinearGradient gradient=new LinearGradient(0, 0, 0, bgBitmap.getHeight(),bgColors[0],bgColors[1], Shader.TileMode.CLAMP);
        mPaint.setShader(gradient);
        RectF rectF=new RectF(0,0,bgBitmap.getWidth(),bgBitmap.getHeight());
       // mCanvas.drawRoundRect(rectF,16,16,mPaint); 这个用来绘制圆角的哈
        mCanvas.drawRect(rectF,mPaint);
        ivBg.setImageBitmap(bgBitmap);
    }

先给大家看看目前效果,免得枯燥

image.png
image.png

ok,目前背景色就实现到这了

2. 接着是最蛋疼的让他渐变融入到背景色中了
我目前有两种思路(两种我都用过了,推荐第二种)

思路 优点 缺点
在图片上面叠加一层颜色渐变的图片 方便简单,只需多加一个控件 需要获取旁边背景色对应的颜色值,这个比较难,而且我目前才用的算法获得有时候不准确
通过修改图片的透明度来达到渐变效果 无需计算旁边颜色,最终效果较佳 图片较大时,计算量比较大,速度较慢

ok,由于我最后还是采用了第二种,这里就只介绍第二种方法了,思路很简单,就是获取图片的bitmap数组,通过遍历来判断修改相应的透明度,具体代码如下:

//修改透明度
    public static Bitmap getImageToChange(Bitmap mBitmap) {
        Log.d(TAG,"with="+mBitmap.getWidth()+"--height="+mBitmap.getHeight());
        Bitmap createBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_4444);
        int mWidth = mBitmap.getWidth();
        int mHeight = mBitmap.getHeight();
        for (int i = 0; i < mHeight; i++) {
            for (int j = 0; j < mWidth; j++) {
                int color = mBitmap.getPixel(j, i);
                int g = Color.green(color);
                int r = Color.red(color);
                int b = Color.blue(color);
                int a = Color.alpha(color);

                float index=i*1.0f/mHeight;
                if(index>0.5f ){
                    float temp=i-mHeight/2.0f;
                    a= 255-(int) (temp/375*255);
                }
                color = Color.argb(a, r, g, b);
                createBitmap.setPixel(j, i, color);
            }
        }
        return createBitmap;
    }

(ps:代码中采用的一些宽高和数值,要看具体效果来设置,这里仅做参考!)

2.1 增加一种修改透明度的方法
该算法使用位移和模运算来单独修改透明值,不用把ARGB的四个颜色都取出来,会比之前的速度快很多

        //透明渐变
        int[] argb=new int[ALBUM_SIZE*ALBUM_SIZE];
        localBitmap.getPixels(argb, 0, localBitmap.getWidth(), 0, 0, localBitmap.getWidth(), localBitmap.getHeight());

        //循环开始的下标,设置从什么时候开始改变
        int start = argb.length / 2;
        int mid = argb.length * 83 / 100;
        int lines = ((mid - start) / localBitmap.getHeight()) + 2;

        int width = localBitmap.getWidth();
        for (int i = 0; i < lines; i++) {
            for (int j = 0; j < width; j++) {
                int index = start - width + i * width + j;
                //由于默认图片透明色为0,所以要增加判断,不然后续处理的颜色会变为黑色
                if(argb[index]!=0){
                    argb[index] = ((int) ((1 - ((float) i / lines)) * 255) << 24) | (argb[index] & 0x00FFFFFF);
                }
            }
        }
        for (int i = mid; i < argb.length; i++) {
            argb[i] = (argb[i] & 0x00FFFFFF);
        }

        localBitmap = Bitmap.createBitmap(argb, localBitmap.getWidth(), localBitmap.getHeight(), Bitmap.Config.ARGB_8888);

(ps:算法中的数值也是仅供参考,具体还要看自己想要实现的效果,比如 <<24 和 0x00FFFFFF 是由于bitmap采用Config.ARGB_8888,大家根据自身需求修改就好,这里只提供思路)

2.2 适配图片透明处理
对于原图中带有透明的情况,获取像素点的时候透明的位置颜色值为0,所以在做透明渐变的时候要判断一下,避免后续颜色变成黑色

                if(argb[index]!=0){
                    argb[index] = ((int) ((1 - ((float) i / lines)) * 255) << 24) | (argb[index] & 0x00FFFFFF);
                }

最终效果如下:

image.png
image.png

总结

本次内容不难,重要是实现思路,我一开始采用第一种叠加图片的方法,寻找计算线性渐变某一位置的值,后来找到了但最终效果不如上述的第二种方法,但是我发现第二种方法在计算比较大的Bitmap的时候速度是真很慢的(遍历一个Bitmap数组,脑壳痛),所以具体还是看大家的需求吧

(ps:好久没写过文章了啊,自今年毕业来就一直忙东忙西,终于有点时间写东西了 TAT)

Demo地址:

https://github.com/returntolife455/DemoList

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,479评论 25 707
  • 为什么在React中有时需要通过bind()绑定this?类似如下: 原因是:在setInterval()中定义的...
    小龙虾Julian阅读 534评论 0 1
  • 沿着小溪 路过古井 路过圆明庵 路过池塘 踩在纵横交错地田埂上 湿湿地 软软地 嫩绿的小草 向我们微笑 金灿灿地油...
    田小姣阅读 465评论 6 11