引言:
Android系統支持幾種圖片(.png (preferred), .jpg (acceptable), .gif (discouraged)), 其中Bitmap位圖#ffffffff,包括圖片透明度Alpha和RGB,圖片質量很好,每一個像素位占4個字節,如果圖片很大將會占據很大的內存空間。存儲在SDCard的image很小,加載進內存可能就會很大。因此,對bitmap圖像進行操作,應該特別小心,可能出現內存溢出問題。為此對于大圖片,應該引入該圖片的二次采樣生成縮略圖。
一、圖片二次采樣
/**
*?根據圖片字節數組,對圖片可能進行二次采樣,不致于加載過大圖片出現內存溢出
*?@param?bytes
*?@return
*/
public static Bitmap?getBitmapByBytes(byte[]?bytes){
//對于圖片的二次采樣,主要得到圖片的寬與高
int width?=0;
int height?=0;
int sampleSize?=1;//默認縮放為1
BitmapFactory.Options?options?=new BitmapFactory.Options();
options.inJustDecodeBounds?=true;//僅僅解碼邊緣區域
//如果指定了inJustDecodeBounds,decodeByteArray將返回為空
BitmapFactory.decodeByteArray(bytes,0,?bytes.length,?options);
//得到寬與高
height?=?options.outHeight;
width?=?options.outWidth;
//圖片實際的寬與高,根據默認最大大小值,得到圖片實際的縮放比例
while((height?/?sampleSize?>?Cache.IMAGE_MAX_HEIGHT)||?(width?/?sampleSize?>?Cache.IMAGE_MAX_WIDTH))?{
sampleSize?*=2;
}
//不再只加載圖片實際邊緣
options.inJustDecodeBounds?=false;
//并且制定縮放比例
options.inSampleSize?=?sampleSize;
return BitmapFactory.decodeByteArray(bytes,0,?bytes.length,?options);
}
//默認大小
class Cache{
public static final int IMAGE_MAX_HEIGH=854;
public static final int IMAGE_MAX_WIDTH=480;
}
二、圖像質量壓縮
private Bitmap?compressImage(Bitmap?image)?{
ByteArrayOutputStream?baos?=newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100,?baos);//質量壓縮方法,這里100表示不壓縮,把壓縮后的數據存放到baos中
int options?=100;
while(?baos.toByteArray().length?/1024>100)?{//循環判斷如果壓縮后圖片是否大于100kb,大于繼續壓縮
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG,?options,?baos);//這里壓縮options%,把壓縮后的數據存放到baos中
options?-=10;//每次都減少10
}
ByteArrayInputStream?isBm?=new ByteArrayInputStream(baos.toByteArray());//把壓縮后的數據baos存放到ByteArrayInputStream中
Bitmap?bitmap?=?BitmapFactory.decodeStream(isBm,null,null);//把ByteArrayInputStream數據生成圖片
return bitmap;
}
三、圖片按比例大小壓縮(根據路徑獲取圖片并壓縮)
private Bitmap?getimage(String?srcPath)?{
BitmapFactory.Options?newOpts?=newBitmapFactory.Options();
//開始讀入圖片,此時把options.inJustDecodeBounds?設回true了
newOpts.inJustDecodeBounds?=true;
Bitmap?bitmap?=?BitmapFactory.decodeFile(srcPath,newOpts);//此時返回bm為空
newOpts.inJustDecodeBounds?=false;
int w?=?newOpts.outWidth;
int h?=?newOpts.outHeight;
//現在主流手機比較多是800*480分辨率,所以高和寬我們設置為
float hh?=?800f;//這里設置高度為800f
float ww?=?480f;//這里設置寬度為480f
//縮放比。由于是固定比例縮放,只用高或者寬其中一個數據進行計算即可
int be?=1;//be=1表示不縮放
if(w?>?h?&&?w?>?ww)?{//如果寬度大的話根據寬度固定大小縮放
be?=?(int)?(newOpts.outWidth?/?ww);
}else if(w?<?h?&&?h?>?hh)?{//如果高度高的話根據寬度固定大小縮放
be?=?(int)?(newOpts.outHeight?/?hh);
}
if(be?<=0)
be?=1;
newOpts.inSampleSize?=?be;//設置縮放比例
//重新讀入圖片,注意此時已經把options.inJustDecodeBounds?設回false了
bitmap?=?BitmapFactory.decodeFile(srcPath,?newOpts);
return compressImage(bitmap);//壓縮好比例大小后再進行質量壓縮
}
四、圖片按比例大小壓縮方法(根據Bitmap圖片壓縮):
private Bitmap?comp(Bitmap?image)?{
ByteArrayOutputStream?baos?=newByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG,100,?baos);
if(?baos.toByteArray().length?/1024>1024)?{//判斷如果圖片大于1M,進行壓縮避免在生成圖片(BitmapFactory.decodeStream)時溢出
baos.reset();//重置baos即清空baos
image.compress(Bitmap.CompressFormat.JPEG,50,?baos);//這里壓縮50%,把壓縮后的數據存放到baos中
}
ByteArrayInputStream?isBm?=newByteArrayInputStream(baos.toByteArray());
BitmapFactory.Options?newOpts?=newBitmapFactory.Options();
//開始讀入圖片,此時把options.inJustDecodeBounds?設回true了
newOpts.inJustDecodeBounds?=true;
Bitmap?bitmap?=?BitmapFactory.decodeStream(isBm,null,?newOpts);
newOpts.inJustDecodeBounds?=false;
int w?=?newOpts.outWidth;
int h?=?newOpts.outHeight;
//現在主流手機比較多是800*480分辨率,所以高和寬我們設置為
float hh?=?800f;//這里設置高度為800f
float ww?=?480f;//這里設置寬度為480f
//縮放比。由于是固定比例縮放,只用高或者寬其中一個數據進行計算即可
int be?=1;//be=1表示不縮放
if(w?>?h?&&?w?>?ww)?{//如果寬度大的話根據寬度固定大小縮放
be?=?(int)?(newOpts.outWidth?/?ww);
}else if(w?<?h?&&?h?>?hh)?{//如果高度高的話根據寬度固定大小縮放
be?=?(int)?(newOpts.outHeight?/?hh);
}
if(be?<=0)
be?=1;
newOpts.inSampleSize?=?be;//設置縮放比例
//重新讀入圖片,注意此時已經把options.inJustDecodeBounds?設回false了
isBm?=newByteArrayInputStream(baos.toByteArray());
bitmap?=?BitmapFactory.decodeStream(isBm,null,?newOpts);
return compressImage(bitmap);//壓縮好比例大小后再進行質量壓縮
}