1. 程式人生 > >android大圖、高清圖片處理

android大圖、高清圖片處理

Android大圖、高清圖片處理

Android中,系統分配給手機app的記憶體是有限的,現階段根據不同的手機分配的最大記憶體也不一樣,少的只有幾十M。當我們Bitmap的形式把高清的大圖載入到記憶體當中時,它佔用的記憶體會成倍數的增加。佔用的記憶體超過了系統能夠提供給app的記憶體時,會產生OOM。

1、圖片佔用記憶體的估計計算(並非實際值):

佔用的記憶體 = 圖片長度 * 圖片寬度 * 單位畫素佔用的位元組數

圖片格式:

ALPHA_8 :      1byte            只儲存alpha

ARGB_4444:   2byte       圖片有可能會被破壞,效果差

ARGB_8888:    4byte      主流的儲存方式

RGB_565:        2byte       不考慮alpha時推薦使用

2、pngjpg圖片的選擇

png:能用png最好是用png,32位的png顏色過渡平滑且支援透明。

jpg:是畫素化壓縮過的圖片,質量已經下降了,一般不拿來做.9path的平鋪拉伸的控制元件。

對於顏色繁雜的,比如照片牆紙,啟動頁面之類的圖片,可用jpg。如果儲存成png體積將是jpg的幾倍甚至幾十倍,嚴重浪費體積。其他的資原始檔使用png

3、畫素壓縮法

可以按照當前view的大小進行壓縮,壓縮成縮圖顯示在view中,減少記憶體的消耗,防止OOM,同時保證圖片不失真。

設定opts.inJustDecodeBounds

= true時,圖片的讀取不會寫入記憶體,可以獲取圖片的大小,從而設定需要壓縮的Optios引數;opts.inJustDecodeBounds= false時圖片的讀取會寫入記憶體中。

/**
 * 對資源中的大圖片進行解析度大小的壓縮
 * @param context
 * @param resourceId   資源的id
 * @param view          顯示圖片的控制元件Imageview
 */
public static void setImageResource(Context context, int resourceId, ImageView view)
{
    BitmapFactory.Options opts = new BitmapFactory.Options();
    // 不讀取畫素陣列到記憶體中,僅讀取圖片的資訊
    opts.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(context.getResources(), resourceId,opts);
    // 從Options中獲取圖片的解析度
    int imageHeight = opts.outHeight;
    int imageWidth = opts.outWidth;

    int scaleX;
    int scaleY;

    // 計算取樣率
    if(view.getWidth() > 0 && view.getHeight() > 0)
    {
        //採用view的尺寸對應得大小進行壓縮
        scaleX = imageWidth / view.getWidth();
        scaleY = imageHeight / view.getHeight();
    }
    else
    {
        //view未初始化完成,獲得的寬高為0,採用螢幕的解析度尺寸來進行壓縮
        WindowManager wm = (WindowManager) context.getSystemService(context.WINDOW_SERVICE); 
        scaleX = imageWidth / wm.getDefaultDisplay().getWidth();
        scaleY = imageHeight / wm.getDefaultDisplay().getHeight();
    }
    int scale = 1;
    // 取樣率依照最大的方向為準
    if (scaleX > scaleY && scaleY >= 1) {
        scale = scaleX;
    }
    if (scaleX < scaleY && scaleX >= 1) {
        scale = scaleY;
    }
    Log.e("measure","scale = "+scale);
    // false表示讀取圖片畫素陣列到記憶體中,依照設定的取樣率
    opts.inJustDecodeBounds = false;
    // 取樣率
    opts.inSampleSize = scale;
    opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.mipmap.larg,opts);
    view.setImageBitmap(bitmap);
}

opts.inSampleSize= scale;為設定取樣率,scale的最終等級為2的n次方,如1,2,4,8....;如果是scale為2,3,最終系統都會取2作為取樣率;如果是4,5,6,7系統會自動取4作為取樣率....


如上圖所示,opts.inSampleSize設定為2則佔用記憶體約為未壓縮前的1/4,設定為4則為未壓縮前的1/16 ..... 對應的壓縮率最好是通過view在手機上的顯示大小進行計算,這樣可以更好的適配到手機上,不影響顯示效果。

2、質量壓縮法

用於壓縮後儲存在disk下,會破壞圖片的質量,不會改變圖片的大小尺寸。但佔用的記憶體不會減少,通常用於壓縮上傳伺服器的圖片。

    /**
     * 質量壓縮方法
     *
     * @param image
     * @return
     */
    private static Bitmap compressImage(Bitmap image) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        int options = 100;
        while (baos.toByteArray().length / 1024 > 100 && options > 50) {
            baos.reset();
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);
            options -= 10;
        }
        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
        Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);

        return bitmap;
    }

圖片上傳伺服器:

1、圖片進行畫素壓縮

2、圖片進行質量壓縮

3、本地儲存

4、上傳伺服器

5、上傳成功後刪除本地圖片