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閱讀 227,797評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,179評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,628評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,642評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,444評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,948評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,040評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,185評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,717評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,794評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,418評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,414評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,750評論 2 370

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,603評論 25 707
  • 為什么在React中有時需要通過bind()綁定this?類似如下: 原因是:在setInterval()中定義的...
    小龍蝦Julian閱讀 549評論 0 1
  • 沿著小溪 路過古井 路過圓明庵 路過池塘 踩在縱橫交錯地田埂上 濕濕地 軟軟地 嫩綠的小草 向我們微笑 金燦燦地油...
    田小姣閱讀 480評論 6 11