Android應用開發之圖片(Bitmap)壓縮(二)---------質量壓縮

博客爲 有時個哥 原創,如需轉載請標明出處:http://blog.csdn.net/ls703/article/details/40394719

質量壓縮:

這種壓縮方式是讓圖片經行重組,通過改變色深和透明度來經行壓縮,但是像素是沒有改變的,所以是不會減少bitmap佔用的內存。質量壓縮是使用Bitmap類裏面的compress(Bitmap.CompressFormat format, int quality,OutputStream stream)具體的方法在上一篇(一)中已經說過了,下面做測試的代碼如下。通過輸出數據來比較各種格式的不同。

package com.example.bitmapdemo.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;

public class ImageUtils {
	/**
	 * 從本地讀取圖片,通過路徑,獲得bitmap
	 * @param path 圖片路徑
	 * @return Bitmap
	 */
	public static Bitmap getBitmapFromLocal(String pathName){
		Bitmap bitmap = BitmapFactory.decodeFile(pathName);
		return bitmap;
	}
	/**
	 * 通過給出的bitmap進行質量壓縮
	 * @param bitmap
	 * @return
	 */
	public static Bitmap compressBitmap(Bitmap bitmap){
		System.out.println("bitmap=="+bitmap.getByteCount());
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		//通過這裏改變壓縮類型,其有不同的結果
		bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
		System.out.println("bos====="+bos.size());
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		System.out.println("bis====="+bis.available());
		return BitmapFactory.decodeStream(bis);
	}
	/**
	 * 通過給出的圖片路徑進行圖片壓縮
	 * @param pathName
	 * @return
	 */
	public static Bitmap compressBitmap(String pathName){
		return compressBitmap(getBitmapFromLocal(pathName));
	}
	/**
	 * 把圖片寫入sd卡
	 * @param bitmap  圖片的bitmap形式
	 */
	public static void writeImage(Bitmap bitmap){
		String storageState = Environment.getExternalStorageState();
		System.out.println();
		if(!storageState.equals(Environment.MEDIA_MOUNTED)){
			return;
		}
		File file =new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath()+"/rr");
		if(!file.exists()){
			file.mkdirs();
		}
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
//		bitmap.compress(Bitmap.CompressFormat.WEBP, 60, bos);
//		bitmap.compress(Bitmap.CompressFormat.JPEG, 60, bos);
		bitmap.compress(Bitmap.CompressFormat.PNG, 60, bos);
		FileOutputStream fos;
		try {
			//WEBP
//			File f = new File(file,"song.jpg");
//			File f = new File(file,"song.png");
//			File f = new File(file,"song.webp");
			//壓縮格式是JPEG的時候,保存成各種格式圖片測試
//			File f = new File(file,"song1.jpg");
//			File f = new File(file,"song1.png");
//			File f = new File(file,"song1.webp");
			//PNG
//			File f = new File(file,"song2.jpg");
//			File f = new File(file,"song2.png");
//			File f = new File(file,"song2.webp");
			
//			File f = new File(file,"song_png.jpg");
//			File f = new File(file,"song_png.png");
//			File f = new File(file,"song_png.webp");
//			File f = new File(file,"song_png1.jpg");
//			File f = new File(file,"song_png1.png");
//			File f = new File(file,"song_png1.webp");
//			File f = new File(file,"song_png2.jpg");
//			File f = new File(file,"song_png3.png");
			File f = new File(file,"song_png4.webp");
//			System.out.println("fpath==========================>>"+f.getAbsolutePath());
			fos = new FileOutputStream(f);
			fos.write(bos.toByteArray());
			fos.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}


 

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
//		String imagePath = "/mnt/sdcard/image.png";
		String imagePath = "/mnt/sdcard/5.jpg";
		getBitmap(imagePath);
		getInputStreanm(imagePath);
		getCompess(imagePath);
	}

	public void getBitmap(String pathName){
//		Bitmap bm = ImageUtils.getBitmapFromLocal(pathName);
		Bitmap bm = BitmapFactory.decodeFile(pathName);;
		System.out.println("bitmap:::"+bm.getRowBytes()*bm.getHeight());
//		System.out.println("bitmap:::"+bm.getByteCount());
		System.out.println("bitmap的另一種求法:::"+bm.getWidth() * bm.getHeight()*4 ); 
	}
	
	public void getInputStreanm(String pathName){
		try {
			FileInputStream fis = new FileInputStream(pathName);
			System.out.println("inputStream:::"+fis.available());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void getCompess(String pathName){
		Bitmap bm = ImageUtils.compressBitmap(pathName);
		System.out.println("bitmap後::"+bm.getRowBytes()*bm.getHeight());
//		System.out.println("bitmap後::"+bm.getByteCount());
		ImageUtils.writeImage( bm);
	}
}

這就是做質量測試的代碼:然後我給出測試結果:

壓縮格式設置爲jpg時:

壓縮格式設置爲png時:

前後的bitmap對象的大小是沒有改變的,這就說明質量壓縮不能改變圖片在內存中的佔用大小。然後看看壓縮前後的大小對比:

壓縮前的圖片大小9005,差不多快9k。

壓縮後的圖片質量:

 

這上面的結果是一張後綴名爲jpg的圖片,分貝設置成jpg壓縮格式或png壓縮格式,然後在保存成png或jpg得到的不同結果。song1名字的圖片是吧壓縮格式設置成JPEG得到的,song2名字的圖片是把壓縮格式設置成PNG得到的。

從上面結果可以看出只要設定壓縮格式之後(即bitmap.compress(Bitmap.CompressFormat.PNG, 60, bos);)無論你的圖片再生成什麼格式的圖片其圖片的大小是不會隨格式改變了。上面song1.png和song1.jpg是一樣大小的。相比較之下,把壓縮格式設置成jpeg壓縮出來的圖片比較小。但是在測試中,如果你要壓縮的圖片本身如果是JPG格式的話,而設置的壓縮格式是PNG,則圖片反而會變大,有可能變大十幾倍。這是和圖片的格式有關,涉及到圖片的色深透明度。在相同像素情況下,一般PNG的圖片在色彩上要比JPG的鮮豔。所以這一點要注意,不要把Jpg格式的圖片壓縮是吧壓縮格式設置成PNG。當然上面所說的壓縮是指的在硬盤活sd卡形成file文件形式的前後對比。通過上面的數據可以看出,bitmap的大小前後沒有變化,也就說明其在內存中的佔用大小沒變,所以說質量壓縮沒有改變其在內存中佔用的大小,只是通過改變圖片的色深透明來壓縮圖片,其像素的個數是沒有變化的。大家也可以試試把原圖爲png的圖片,然後設置不同壓縮格式的變化,然後再重新生成新的png活jpg格式的圖片,看看前後變化。這可以使我們做出更好的選擇,一般情況下是設置jpeg壓縮格式。不過具體的還是按自己的需求來。

至於質量壓縮的工具類可以通過上面經行整理一下就出來了。

質量壓縮的工具類:

package com.example.bitmapdemo.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;

public class ImageUtils2 {
	/**
	 * 通過圖片路徑獲得bitmap(無壓縮形式)
	 * @param path 圖片路徑
	 * @return Bitmap
	 */
	public static Bitmap getBitmapFromLocal(String pathName){
		Bitmap bitmap = BitmapFactory.decodeFile(pathName);
		return bitmap;
	}
	
	/**
	 * 通過bitmap得到輸出流(無壓縮形式)
	 * @param bitmap bitmap對象
	 * @return OutputStream
	 */
	public static ByteArrayOutputStream getOutStreamFromBitmap(Bitmap bitmap){
		 return getOutStreamFromBitmap( bitmap,100);
	}
	/**
	 * 通過bitmap得到輸出流(質量壓縮)
	 * @param bitmap bitmap對象
	 * @param quality 要壓縮到的質量(0-100)
	 * @return OutputStream
	 */
	public static ByteArrayOutputStream getOutStreamFromBitmap(Bitmap bitmap,int quality){
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		bitmap.compress(Bitmap.CompressFormat.JPEG, quality, bos);
		if(bos != null){
			try {
				bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return bos;
	}
	/**
	 * 通過流獲得bitmap
	 * @param os 輸出流
	 * @return Bitmap
	 */
	public static Bitmap getBitmapFromOutStream(ByteArrayOutputStream os){
		ByteArrayInputStream bis = new ByteArrayInputStream(os.toByteArray());
			if(bis !=null){
				try {
					bis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}		
			}
		return 	BitmapFactory.decodeStream(bis);
	}
	/**
	 * 通過路徑得到圖片並對圖片進行壓縮,並再生成圖片(質量壓縮)
	 * @param imagePath 圖片的路徑
	 * @param savePath 新圖片的保存路徑
	 * @param quality 要壓縮到的質量
	 * @return Boolean true 成功false失敗
	 */
	public static boolean writeCompressImage2File(String imagePath ,String savePath,int quality){
		if(TextUtils.isEmpty(imagePath)){
			return false;
		}
		String imageName  = imagePath.substring(imagePath.lastIndexOf("/")+1,imagePath.lastIndexOf("."));
		return writeImage2File(getOutStreamFromBitmap(getBitmapFromLocal(imagePath), quality),savePath ,imageName);
	}
	/**
	 * 把bitmap寫入指定目錄下,重新生成圖片
	 * @param bitmap bitmap對象
	 * @param savePath 新圖片保存路徑
	 * @param imageName 新圖片的名字,會根據時間來命名
	 * @return Boolean true 成功false失敗
	 */
	public static boolean writeImage2File(Bitmap bitmap ,String savePath,String imageName){
		return writeImage2File(getOutStreamFromBitmap(bitmap),savePath ,imageName);
	}
	/**
	 * 通過輸出流,重組圖片,並保存帶指定目錄下
	 * @param bos 圖片輸入流
	 * @param savePath 新圖片的保存路徑
	 * @param imageName 新圖片的名字,字段爲空時,會根據時間來命名
	 * @return Boolean true 成功false失敗
	 */
	public static boolean writeImage2File(ByteArrayOutputStream bos,String savePath,String imageName){
		if(TextUtils.isEmpty(savePath)){
			return false;
		}
		File file =new File(savePath);
		if(!file.exists()){
			file.mkdirs();
		}
		FileOutputStream fos;
		try {
			if(TextUtils.isEmpty(imageName)){
				imageName = System.currentTimeMillis()+"";
			}
			File f = new File(file,imageName+".jpg");
			fos = new FileOutputStream(f);
			fos.write(bos.toByteArray());
			fos.flush();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}
}

 

總結:質量壓縮只是改變其存儲的形式的大小,不改變其在內存中的大小。一般用於不失真壓縮,上傳圖片等。值得注意的事,由於這種壓縮不會改變bitmap的大小,所以,大家要注意,不要以這種過程壓縮,圖片->bitmap->質量壓縮->io->bitmap->圖片,如果你按照這個流程走,你會發現你重組的圖片會變大。因爲你又獲得bitmap就說明你質量壓縮是做無用功,因爲他不會改變bitmap大小,這樣你重組獲得的圖片反而會變大。一般是在質量壓縮獲得流之後,對流直接經行操作,因爲你這個流已經經行了壓縮。然後對流直接操作,上傳,或直接寫入文件。

下一篇整理採樣率壓縮

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章