為什麼要對Android中的圖片進行採樣縮放呢? 是為了更加高效的載入Bitmap。假設通過imageView來顯示圖片,很多時候ImageView並沒有圖片的原始尺寸那麼大,這時候把整張圖片載入進來後再設給ImageView是沒有必要的,因為ImagView並沒有辦法顯示原始的圖片。 所以我們可以 ...
為什麼要對Android中的圖片進行採樣縮放呢?
是為了更加高效的載入Bitmap。假設通過imageView來顯示圖片,很多時候ImageView並沒有圖片的原始尺寸那麼大,這時候把整張圖片載入進來後再設給ImageView是沒有必要的,因為ImagView並沒有辦法顯示原始的圖片。
所以我們可以使用BitmapFactory.Options按照一定的採樣率載入縮小後的圖片,將縮小後的圖片在ImageView中顯示,這樣就能降低記憶體占用,在一定程度上避免OOM,提高bitma載入時候的性能。
BitmapFactory有一個參數:inSampleSize(採樣率)。
inSampleSize為1,那麼採樣後圖片大小等於原始圖片大小。
inSampleSize為2,那麼採樣後圖片寬高均為原始圖片的1/2,像素為原圖的1/4,占有的記憶體大小為原圖的1/4。
例如:一張的圖片像素為1024*1024,儲存格式為ARGB8888格式儲存,那麼它占有記憶體1024*1024*4=4M,用採樣率為2採樣後記憶體占用為512*512*4=1M。
總結:inSampleSize是必須大於1的整數才有效果,小與1就相當於1,並且同時作用於寬高,所以縮放後的圖片大小以採樣率的2次方形式遞減.根據最新的官方文檔,inSampleSize的取值應該總是為2的指數,若給系統的inSampleSize不為2的指數,那麼系統會向下取整並且選擇一個最接近2的指數來代替,不過經過驗證,這個結論並不是在所有的Android版本上都成立。
那麼我們如何獲取採樣率呢?
1、將BitmapFactory.Option的inJustDecodeBound參數設為true,載入圖片,這個時候圖片並沒有載入進記憶體,僅僅是去解析圖片原始寬高信息而已。
2、從BitmapFactory.Option取出圖片的原始寬高信息,對應於outWidth,outHeight參數。
3、根據採樣率的規則和目標原始View的所需大小計算出採樣率inSampleSize。
4、將BitmapFactory.Option的inJustDecodeBound參數設為false,重新載入圖片,這時候圖片才真正被載進記憶體。
以下提供一份代碼模板:package com.example.chatting.chatting.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.util.DisplayMetrics;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
public class ImagesTool
{
/**
* 根據ImageView的大小壓縮圖片
* @param path
* @param imageView
* @return
*/
public static Bitmap decodeSampledBitmapFromPath(String path,ImageView imageView)
{
Options options = new Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(path,options);
ImageSize imageSize=getImageViewSize(imageView); //獲取圖片大小,ImageSize是封裝著ImageView大小的類
//計算採樣率
options.inSampleSize=caculateInSampleSize(options,imageSize.width,imageSize.height);
options.inJustDecodeBounds=false;
Bitmap bitmap=BitmapFactory.decodeFile(path, options);
return bitmap;
}
//計算採樣率
public static int caculateInSampleSize(Options options,ImageView imageView)
{
ImageSize imageSize=getImageViewSize(imageView);
int inSampleSize=caculateInSampleSize(options, imageSize.width,imageSize.height);
return inSampleSize;
}
/**
* 根據具體的大小要求解析圖片
* @param path
* @param reqWidth
* @param reqHeight
* @return
*/
public static Bitmap decodeSampledBitmapFromPath(String path,int reqWidth, int reqHeight)
{
Options options = new Options();
options.inJustDecodeBounds=true;
BitmapFactory.decodeFile(path,options);
//計算採樣率
options.inSampleSize=caculateInSampleSize(options,reqWidth,reqHeight);
options.inJustDecodeBounds=false;
Bitmap bitmap=BitmapFactory.decodeFile(path, options);
return bitmap;
}
//計算採樣率
private static int caculateInSampleSize(Options options, int reqWidth, int reqHeight)
{
int width=options.outWidth; //原始圖片寬
int height=options.outHeight; //原始圖片高
int inSampleSize=1; //採樣率
if(width>reqWidth || height>reqHeight) //原始的寬比目標寬大,或者原始高比目標高大
{
int widthRadio=Math.round(width *1.0f/reqWidth);
int heightRadio = Math.round(height * 1.0f / reqHeight);
inSampleSize = Math.max(widthRadio, heightRadio);
}
return inSampleSize;
}
//獲取ImageView的大小
protected static ImageSize getImageViewSize(ImageView imageView)
{
ImageSize imageSize = new ImageSize();
DisplayMetrics metrics = imageView.getContext().getResources().getDisplayMetrics();
LayoutParams lp = imageView.getLayoutParams();
int width = imageView.getWidth();
if (width <= 0) {
width = lp.width;
}
if (width <= 0) {
width = imageView.getMaxWidth();
}
if (width <= 0) {
width = metrics.widthPixels;
}
int height = imageView.getHeight();
if (height <= 0) {
height = lp.height;
}
if (height <= 0) {
height = imageView.getMaxHeight();
}
if (height <= 0) {
height = metrics.heightPixels;
}
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
//ImageView大小的封裝類
private static class ImageSize
{
int width;
int height;
}
}