一種根據ImageView的大小縮放Bitmap的方法


     Bitmap是Android應用程序引起OOM的罪魁禍首之一,當我們從網絡上下載圖片的時候無法知道網絡圖片的准確大小,所以為了節約內存,一般會在服務器上緩存 一個縮略圖,提升下載速度。除此之外,我們還可以在本地顯示圖片前將圖片進行壓縮,使其完全符合imageview的大小,這樣可以最大限度避免內存浪費。
本文基本思路:
 (1)獲取ImageView的寬和高。
 (2)使用inJustDecodeBounds獲取bitmap的長和寬。
 (3)根據bitmap的長款和ImageView的長和寬,計算出壓縮比例inSampleSize的大小。
 (4)使用inSampleSize,加載一個比ImageView稍大一點的縮略圖a。
 (5)使用Bitmap.createScaseBitmap再次壓縮A,將縮略圖A生成需要的縮略圖B。

1.計算ImageView的寬高
   int ImageView.getWidth()
   int ImageView.getHeight()
這兩個方法可以得到ImageView的實際大小,單位為pix,需要在view加載完之后再調用。如果不知道什么時候加載完,可以使用下面方法在run()中獲取:
final ImageView iv = new ImageView(context);
   iv.post(new Runnable() {
       @Override
       public void run() {
         int w = iv.getWidth();
         int h = iv.getHeight();
       }
   })

 

2.通過BitmapFactory計算得到壓縮后的bitmap對象。

2.1 BitmapFactory.Options介紹
  BitmapFactory提供了多種方式根據不同的圖片源來創建Bitmap對象:
  (1)Bitmap BitmapFactory.decodeFile(String pathName, Options opts): 讀取SD卡上的圖片。
  (2)Bitmap BitmapFactory.decodeResource(Resources res, int id, Options opts) : 讀取網絡上的圖片。
  (3)Bitmap BitmapFactory.decodeResource(Resources res, int id, Options opts) : 讀取資源文件中的圖片。
  這三個函數默認會直接為bitmap分配內存,我們通過第二個參數Options來控制,讓它不分配內存,同時可以得到圖片的相關信息。具體參考:
  BitmapFactory.Options options = new BitmapFactory.Options();
  options.inJustDecodeBounds = true;
  BitmapFactory.decodeFile(pathName,options);
  int imageHeight = options.outHeight;
  int imageWidth = options.outWidth;

這樣就可以在不分配內存的情況下直接得到圖片的寬高。

2.2 計算圖片壓縮比例(采樣率)
  通常如果圖片是針對某種分辨率設計的,直接decode圖片不會有什么問題。但是,如果圖片不是特定設計,且比較大的話,容易造成OOM。
  假設,一個ImageView大小為512*384,有一張2048*1536的圖片需要顯示,那么如果加載整張圖片,那就造成了浪費,這時候就需要采用不同的采樣率對原圖片進行一定的壓縮。
  計算inSampleSize的值有兩種方法:
  方法一:
 public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
     // 源圖片的高度和寬度
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;
    if (height > reqHeight || width > reqWidth) {
        // 計算出實際寬高和目標寬高的比率
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        // 選擇寬和高中最小的比率作為inSampleSize的值,這樣可以保證最終圖片的寬和高
        // 一定都會大於等於目標的寬和高。
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }
    return inSampleSize;
  }
  方法二:
 
 private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // 源圖片的高度和寬度
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            // 計算出實際寬高和目標寬高的比率
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;
            while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
   }
需要注意的是,inSampleSize只能是2的整數次冪,如果不是的話,向下取得最大的2的整數次冪。因為按照2的次方進行壓縮會比較高效和方便。 方法一計算出來的inSampleSize值可能不是2的整數次冪,不如計算出來的值是inSampleSize=7,這時會被decode函數向下取為 inSampleSize=4。所以我們一般采用方法二進行計算。
   此時,將設置了inSampleSize的options傳給BitmapFactory.decode函數去獲取圖片,得到的會是一張比ImageView稍大的圖片,不過這個圖片要比原圖小了。
 public static Bitmap decodeSampledBitmapFromFile(String pathName, int reqWidth, int reqHeight) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(pathName, options);
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
        options.inJustDecodeBounds = false;
        Bitmap src = BitmapFactory.decodeFile(pathName, options);
        return createScaleBitmap(src, reqWidth, reqHeight);
    }

2.3 得到符合ImageView大小的圖片
這是通過Bitmap Bitmap.createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)函數來實現的。
這個函數返回一個按要求進行拉伸或者縮小后的bitmap.
    private static Bitmap createScaleBitmap(Bitmap src, int dstWidth, int dstHeight, int inSampleSize) {
    // 如果是放大圖片,filter決定是否平滑,如果是縮小圖片,filter無影響,我們這里是縮小圖片,所以直接設置為false
        Bitmap dst = Bitmap.createScaledBitmap(src, dstWidth, dstHeight, false);
        if (src != dst) { // 如果沒有縮放,那么不回收
            src.recycle(); // 釋放Bitmap的native像素數組
        }
        return dst;
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM