Android在處理圖片時,如果不進行壓縮處理,很容易就出現OOM內存溢出(OutOfMemory)問題,所以無論是第三方圖片加載還是自己在處理圖片時,都要進行壓縮處理。
Android系統中,一張圖片所佔用的內存大小與圖片尺寸(像素點)和色彩格式(質量)有關,所以Android圖片壓縮分爲尺寸壓縮和質量壓縮:
- 尺寸壓縮:一張1920*1080的圖片尺寸壓縮一半後,即960*540,尺寸和像素點是未壓縮前的1/4,所佔內存也會變成1/4;
質量壓縮:
1.圖片的色彩格式壓縮即:
-Bitmap.Config ARGB_8888:每個像素佔四位,即A=8,R=8,G=8,B=8,那麼一個像素點佔8+8+8+8=32位
-Bitmap.Config ARGB_4444:每個像素佔四位,即A=4,R=4,G=4,B=4,那麼一個像素點佔4+4+4+4=16位
-Bitmap.Config RGB_565:每個像素佔四位,即R=5,G=6,B=5,沒有透明度,那麼一個像素點佔5+6+5=16位
-Bitmap.Config ALPHA_8:每個像素佔四位,只有透明度,沒有顏色。2.通過 bitmap.compress(CompressFormat format, int quality, OutputStream stream)方法進行壓縮,壓縮過程可能會損失透明度;
代碼
/**
* 壓縮圖片分辨率
*
* @param imgpath 文件路徑
* @param width 最大輸出寬度
* @param height 最大輸出高度
* @return
*/
public static Bitmap decodeBitmap(String imgpath, int width, int height) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;//解碼bitmap時可以只返回其高、寬和Mime類型,而不必爲其申請內存,從而節省了內存空間。
options.inPreferredConfig = Bitmap.Config.RGB_565;//圖像質量,565不帶透明度
BitmapFactory.decodeFile(imgpath, options);
//縮放倍數計算
int outHeight = options.outHeight;
int outWidth = options.outWidth;
if (outHeight / height > outWidth / width) {
int heightScale = outHeight / height;
if (outHeight % height == 0) {
options.inSampleSize = heightScale;
} else {
options.inSampleSize = heightScale + 1;
}
} else {
int widthScale = outWidth / width;
if (outWidth % width == 0) {
options.inSampleSize = widthScale;
} else {
options.inSampleSize = widthScale + 1;
}
}
LogUtil.e("options.inSampleSize:" + options.inSampleSize);
options.inJustDecodeBounds = false;//加載到內存中
Bitmap bitmap = BitmapFactory.decodeFile(imgpath, options);
return compressBitmap(bitmap);
// return Bitmap.createScaledBitmap(bitmap, width, height, filter);//將圖片縮放到指定大小
}
/**
* 壓縮圖片質量
*/
public static Bitmap compressBitmap(Bitmap bitmap) {
int maxSize = 300 * 1024;//最大文件大小300kb
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);// 質量壓縮方法,這裏100表示不壓縮,把壓縮後的數據存放到baos中
int quality = 90;
while (byteArrayOutputStream.toByteArray().length > maxSize) { // 循環判斷如果壓縮後圖片是否大於maxSize字節,大於繼續壓縮
byteArrayOutputStream.reset(); // 重置baos即清空baos
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream);// 這裏壓縮quality%,把壓縮後的數據存放到byteArrayOutputStream中
quality -= 5;
}
LogUtil.e(byteArrayOutputStream.toByteArray().length/1024+"kb");
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
Bitmap decodeBitmap = BitmapFactory.decodeStream(byteArrayInputStream, null, null);// 把ByteArrayInputStream數據生成bitmap
try {
byteArrayInputStream.close();
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return decodeBitmap;
}
================================下面是處理圖片時用得到的方法===========================
/**
* 保存bitmap到文件
*
* @param bitmap
* @param filePath
*/
public static void saveBitmapToFile(Bitmap bitmap, String filePath) {
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(filePath);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
} finally {
try {
if (out != null)
out.close();
} catch (Exception e3) {
e3.printStackTrace();
}
}
}
/**
* 讀取圖片屬性:旋轉的角度
*
* @param path 圖片絕對路徑
* @return degree旋轉的角度
*/
public static int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
/**
* 旋轉圖片
*
* @param angle
* @param bitmap
* @return Bitmap
*/
public static Bitmap rotaingImageView(int angle, Bitmap bitmap) {
//旋轉圖片 動作
Matrix matrix = new Matrix();
matrix.postRotate(angle);
// 創建新的圖片
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
return resizedBitmap;
}
/**
* 旋轉圖片
*
* @param imagePath
* @return true:旋轉成功;false:無需旋轉
*/
public static boolean rotaingImageView(String imagePath) {
int degree = ImageUtils.readPictureDegree(imagePath);
if (degree != 0) {
Bitmap decodeBitmap = decodeBitmap(imagePath, 1000, 1000);
//把圖片旋轉爲正的方向
Bitmap newbitmap = rotaingImageView(degree, decodeBitmap);
//同步保存文件(文件過大,同步保存會出現ANR異常,可採用異步保存)
saveBitmapToFile(newbitmap, imagePath);
decodeBitmap.recycle();
newbitmap.recycle();
// new Thread(new Runnable() {
// @Override
// public void run() {
// //異步保存文件
// saveBitmapToFile(newbitmap, new File(curimgpath));
// handler.sendEmptyMessage(0);
// }
// }).start();
return true;
}
return false;
}