1. 程式人生 > >android圖片壓縮的三種方式

android圖片壓縮的三種方式

為了避免oom的出現,幾乎每個應用都會對大圖進行壓縮,我現在手頭做的產品就有很多地方用到,以前封裝工具類的時候,都是在網上找東找西,然後拼拼湊湊,有效果就行了,一直用的迷迷糊糊,這幾天工作比較閒,正好系統的總結梳理一下圖片壓縮方式:

圖片壓縮現在常見的有三種方式:

1、等比壓縮,等比壓縮是保持原圖長寬比例的壓縮,只是圖片變小,展示的還是原圖的所有內容(區別於第二種通過Matrix壓縮,可以選取圖片的一部分,類似於上傳頭像時,讓你在圖上選一塊zoom的形式)。等比壓縮用的的主要是BitmapFactory.Options,通過options縮放比例的設定,來生成縮圖:

/**
	 * @param path 圖片路徑
	 * @param targetSize 縮放後期待的長邊(圖片長和寬大的那一個邊)的長度
	 * @param targetW 期待的縮放後寬度
	 * @param targetH 期待的縮放後高度
	 * @return
	 */
	public static Bitmap equalRatioScale(String path,int targetW,int targetH){
		// 獲取option
		BitmapFactory.Options options = new BitmapFactory.Options();
		// inJustDecodeBounds設定為true,這樣使用該option decode出來的Bitmap是null,
		// 只是把長寬存放到option中
		options.inJustDecodeBounds = true;
		// 此時bitmap為null
		Bitmap bitmap = BitmapFactory.decodeFile(path, options);
		int inSampleSize = 1; // 1是不縮放
		// 計算寬高縮放比例
		int inSampleSizeW = options.outWidth / targetW;
		int inSampleSizeH = options.outHeight / targetH;
		// 最終取大的那個為縮放比例,這樣才能適配,例如寬縮放3倍才能適配螢幕,而
		// 高不縮放就可以,那樣的話如果按高縮放,寬在螢幕內就顯示不下了
		if (inSampleSizeW > inSampleSizeH) { 
			inSampleSize = inSampleSizeW;
		}else {
			inSampleSize = inSampleSizeH;
		}
		// 設定縮放比例
		options.inSampleSize = inSampleSize;
		// 一定要記得將inJustDecodeBounds設為false,否則Bitmap為null
		options.inJustDecodeBounds = false;
		bitmap = BitmapFactory.decodeFile(path, options);
		return bitmap;
	}

2、通過Matrix進行更加靈活的縮放:這種方式主要是通過構建縮放矩陣和Bitmap.createBitmap方法來實現靈活縮放,寬和高縮放的比例可以不一致,而且通過Bitmap.createBitmap方法創建出來的是新的點陣圖,這個點陣圖可以是選取原圖的一部分,而不是對原圖進行整體縮放!類似於上傳頭像時,讓你在原圖上扣下來一塊的效果,控制非常靈活。

/**
	 * @param path 原圖路徑
	 * @param offsetX 擷取開始點在X軸偏移量
	 * @param offsetY 擷取開始點在Y軸偏移量
	 * @param targetW 擷取多寬(畫素)
	 * @param targetH 擷取多高(畫素)
	 * @return
	 */
	public static Bitmap matrixScale(String path,int offsetX,int offsetY,int targetW,int targetH){
		// 構建原始點陣圖
		Bitmap bitmap = BitmapFactory.decodeFile(path);
		// 獲取原始寬高
		int width = bitmap.getWidth();
		int height = bitmap.getHeight();
		// 計算寬高縮放比例,targetW,targetH即期待縮放完成後點陣圖的寬高
		float scaleW = (float)targetW / width;
		float scaleH = (float)targetH / height;
		// 將縮放比例放進矩陣
		Matrix matrix = new Matrix();
		matrix.postScale(scaleW, scaleH);
		// 這個方法作用非常多,詳細解釋一下各個引數的意義!
		// bitmap:原始點陣圖
		// 第二到第五個引數,即擷取原圖哪一部分構建新點陣圖,
		// offsetX和offsetY代表在X軸和Y軸上的畫素偏移量,即從哪個位置開始擷取
		// width和height代表擷取多少個畫素,但是要注意,offsetX+width應該小於等於原圖的寬度
		// offsetY+height小於等於原圖高度,要不然會報錯,因為截到原圖外面去了
		// 像下面這樣填寫,就代表擷取整個原圖,
		// Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, false);
		// 如果填寫100,100,200,200,就代表
		// 從原圖左上角往右和下各偏移100畫素,然後往後和往下各擷取200構建新點陣圖
		// matrix:縮放矩陣
		// 最後一個引數表示如果矩陣裡面還存放了過濾條件,是否按條件過濾(如果matrix裡面只放了平移資料),最後一個引數設定成什麼都不會生效
		bitmap = Bitmap.createBitmap(bitmap, offsetX, offsetY, width, height, matrix, false);
		return bitmap;
	}

3、無失真壓縮,無失真壓縮是說圖片大小和清晰度看上去和原圖沒有什麼差別,但是確實size縮小了,這裡縮小的原理是犧牲了解析度等其他直觀看不到的東西,看起來和原圖一樣,但是一放大就立馬失真了,不會和原圖一樣放大很多才會逐漸變得不清晰。無失真壓縮後的圖片畫素並不會減少,而Bitmap佔用記憶體的定義就是畫素點佔的記憶體,所以以Bitmap的方式載入到記憶體中時,和壓縮前佔用的記憶體是同樣大的,原來會oom的圖片,質量壓縮後同樣會oom;但是,質量壓縮後將流輸出到檔案中,檔案的size會大幅度減小,所以質量壓縮特別適合在Android端進行圖片上傳的時候進行圖片壓縮,既能保持上傳後的清晰度,又能減小size。另外質量壓縮不是可以無限縮小的,降低到一定程度,就算把quality設定的再小,size也不會再降低了。另外這種方式最好返回儲存壓縮後的圖片儲存的檔案路徑,而不要直接返回Bitmap,示例就懶得改了。

<pre name="code" class="java">/**
	 * @param path 圖片路徑
	 * @param quality 質量 0-100,100表示原圖
	 * @return
	 */
	public static Bitmap losslessScale(String path,int quality){
		Bitmap bitmap = BitmapFactory.decodeFile(path);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
        bitmap.compress(CompressFormat.JPEG, quality, baos);
        Log.e("哈哈","原始大小:" + baos.toByteArray().length);
        // 因為質量壓縮不是可以無限縮小的,所以一張高質量的圖片,再怎麼壓縮,
        // 最終size可能還是大於你指定的size,造成異常
        // 所以不建議迴圈壓縮,而是指定quality,進行一次壓縮就可以了
//        while (baos.toByteArray().length / 1024 > maxSize) {  
//            quality -= 10;  
//            baos.reset();  
//            bitmap.compress(CompressFormat.JPEG, quality, baos);  
//            Log.e("哈哈","過程中大小為:"  
//                    + baos.toByteArray().length);
//        }  
        bitmap.compress(CompressFormat.JPEG, quality, baos);  
        Log.e("哈哈","最終大小" + baos.toByteArray().length);
        Bitmap compressedBitmap = BitmapFactory.decodeByteArray(  
                baos.toByteArray(), 0, baos.toByteArray().length);  
        return compressedBitmap;  
	}


 
 

一張圖片處理過程,建議先進行等比壓縮或者Matrix壓縮後,再進行質量壓縮,這樣組合使用,不管是生成縮圖還是圖片上傳,效果都不錯