歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Android ICON生成及優化

Android系統中Launcher桌面圖標簡答來講就是通過PackageManager獲取對應APP的Icon即可,所獲取的ICON就是簡單地標准圖標,對於Android來說,其標准的ICON為72*72簡單桌面實現可以直接根據自身ICON標准,對該icon進行放大縮小後繪制即可。不過就目前來說,由於Android並未規定圖標的標准樣式,所以各家所制作的ICON各式各樣,有的就是簡單圖標,有的是在方形背板基礎上繪制ICON。所以各家桌面在自己繪制ICON時,都會對其增加背板,以統一各廠家APP圖標,以標准的樣式進行展示。如果背板是標准的,那問題也很好辦,例如背板80*80的方形,圖標縮放為72*72,直接繪制在(4,4)的位置即可。而隨著各家桌面的不斷進化,對圖標繪制的要求也越來越高,各家允許使用自定義的背板,簡單來說就是背板可以使方的、圓的、甚至是不規則的圖形。這就使得ICON繪制時不能采用預定義配置的方式,需要根據背板的實際樣式對ICON進行裁剪後繪制。簡單來說就是按照背板的樣式裁剪ICON,使ICON在背板中留出一定寬度的邊沿後,在背板正中心位置進行繪制。

初拿到這個需求後,稍稍一考慮,很簡單!從實現角度分析需求就是按照比背板小的邊緣對ICON進行裁剪。分解來說就是:1.如何識別背板的邊緣。2.如何進行裁剪。背板的邊緣很好識別,通過getAlpha獲取背板的Alpha即可。如何裁剪那,有點圖像處理知識的就知道,只需要通過簡單地4點采樣,判斷當前點是否需要切掉即可。說干就干,第一版的代碼如下:

 /**/
    /*背板留出5像素邊*/
    private static final int EDGE_WIDTH = 5;
    /*alpha值的最低值,低於該值則認為是透明*/
    private static final int ALPHA_BLUR = 200;
    /**
    * 返回圖標按背板裁剪後得Bitmap
    * @param background 背板的Bitmap
    * @param icon 圖標的Bitmap
    * */
    public static Bitmap getBitmapWithNoScale(Drawable background, Bitmap icon){
        /*首先調整icon大小與背板一致,通過縮放或居中顯示*/
        if(icon.getWidth() > background.getIntrinsicWidth()){
           
          icon = Bitmap.createScaledBitmap(icon, background.getIntrinsicWidth(), background.getIntrinsicHeight(), true);
        }
        if(icon.getWidth() < background.getIntrinsicWidth() ){
            Bitmap tmp = null;
            try {
                tmp = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            } catch (OutOfMemoryError e) {
                // 如果發生了OOM問題, 重新申請一次
                tmp = Bitmap.createBitmap(background.getIntrinsicWidth(), background.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
                e.printStackTrace();
            }
           

            Canvas mCanvas = new Canvas(tmp);
            mCanvas.drawBitmap(icon,(background.getIntrinsicWidth()-icon.getWidth())/2,(background.getIntrinsicHeight()-icon.getHeight())/2, null);
            icon = tmp;
        }
        return getBitmapAlpha(background, icon);
       
    }
   
    private static ImageView mGarbage ;
   
    /*obj 背板,res 圖標*/
    private static Bitmap getBitmapAlpha(Drawable backgroundDrawable, Bitmap icon){
//        Bitmap myAlpha = obj.extractAlpha();
        Bitmap background = ((BitmapDrawable)backgroundDrawable).getBitmap();
        Bitmap alpha2 = background.extractAlpha();

        int back_width = background.getWidth();
        int back_height = background.getHeight();
        int icon_width = icon.getWidth();
        int icon_height = icon.getHeight();
        int alpha_arr[] = new int[back_width*back_height];
        alpha2 = alpha2.copy(Config.ARGB_8888, true);
        alpha2.getPixels(alpha_arr, 0, back_width, 0, 0, back_width, back_height);

        int icon_arr[] = new int[icon_width*icon_height];
        icon.getPixels(icon_arr, 0, icon_width, 0, 0, icon_width, icon_height);
       
        int back_startx = 0, back_starty = 0, back_endx = 0, back_endy = 0;
        /*在圖標比背板小的情況下,圖標在背板中心位置,相對於背板的位置*/
        int icon_startx,icon_starty,icon_endx,icon_endy;
        int icon_offset = 0;
        if(icon_width < back_width){
            /*圖標比較小哈,將其居中顯示裁剪*/
            Log.e("pluszhang","get icon smaller");
            back_startx = EDGE_WIDTH;
            back_endx = back_width-EDGE_WIDTH-1;
            back_starty = EDGE_WIDTH;
            back_endy = back_height-EDGE_WIDTH-1;
            icon_offset = back_width-icon_width > EDGE_WIDTH*2?0:EDGE_WIDTH-(back_width-icon_width)/2;
        }
        else if(icon_width == back_width){
            /*直接裁剪即可*/
            back_startx = EDGE_WIDTH;
            back_endx = back_width-EDGE_WIDTH-1;
            back_starty = EDGE_WIDTH;
            back_endy = back_height-EDGE_WIDTH-1;
           
        }

        for(int i=0; i<icon_height;i++){
            for(int j=0; j<icon_width;j++){
                if(i<back_starty||i>back_endy||j<back_startx||j>back_endx){
                    icon_arr[i*icon_width+j] = 0;
                }
                else{
                    if((alpha_arr[(i-EDGE_WIDTH)*back_width+j] >> 24 &0xff) < ALPHA_BLUR ||
                            (alpha_arr[(i+EDGE_WIDTH)*back_width+j]  >> 24&0xff)< ALPHA_BLUR ||
                            (alpha_arr[(j-EDGE_WIDTH)+i*back_width]  >> 24&0xff)< ALPHA_BLUR ||
                            (alpha_arr[(j+EDGE_WIDTH)+i*back_width]  >> 24&0xff)< ALPHA_BLUR){
                        icon_arr[i*icon_width+j] = 0;
                    }
                }
            }
        }
        mGarbage.setBackgroundDrawable(backgroundDrawable); 
        mGarbage.setImageBitmap(Bitmap.createBitmap(icon_arr, icon_width, icon_height, Config.ARGB_8888));
        return mGarbage.getDrawingCache();
    }

以上這段代碼是采用切的方法實現對圖標處理方法,主要來講就是首先進行標准化,將ICON與背板處理到相同大小,只縮不放大,防止ICON變形,通過背板的Alpha視圖,采樣繪制ICON,最終實現對ICON的繪制。通過對上述代碼分析,由於對圖標采用的是掃描方式進行處理,也就是說80X80的圖標,要計算6400次,一個圖標還好,要是有2,3百個圖標,效率確實有些低。關鍵是效果不太好,由於該方法采用的是采樣的方式,對於背板特別不規則的會導致圖標邊緣切割有許多毛刺,這個問題是該算法自身的問題,采用切的算法,不會有更好的效果,這是該算法本身決定的,如果要達到最優效果,只有更換算法換一種思路。

Copyright © Linux教程網 All Rights Reserved