在網上調查了圖檔壓縮的方法并實裝後,大緻上可以認為有兩類壓縮:品質壓縮(不改變圖檔的尺寸)和尺寸壓縮(相當于是像素上的壓縮);品質壓縮一般可用于上傳大圖前的處理,這樣就可以節省一定的流量,畢竟現在的手機拍照都能達到3m左右了,尺寸壓縮一般可用于生成縮略圖。
兩種方法都實裝在了我的項目中,結果卻發現在品質壓縮的子產品中,本來1.9m的圖檔壓縮後反而變成3m多了,很是奇怪,再做了進一步調查終于知道原因了。下面這個部落格說的比較清晰:
android圖檔壓縮總結
總結來看,圖檔有三種存在形式:硬碟上時是file,網絡傳輸時是stream,記憶體中是stream或bitmap,所謂的品質壓縮,它其實隻能實作對file的影響,你可以把一個file轉成bitmap再轉成file,或者直接将一個bitmap轉成file時,這個最終的file是被壓縮過的,但是中間的bitmap并沒有被壓縮(或者說幾乎沒有被壓縮,我不确定),因為bigmap在記憶體中的大小是按像素計算的,也就是width
* height,對于品質壓縮,并不會改變圖檔的像素,是以就算品質被壓縮了,但是bitmap在記憶體的占有率還是沒變小,但你做成file時,它确實變小了;
而尺寸壓縮由于是減小了圖檔的像素,是以它直接對bitmap産生了影響,當然最終的file也是相對的變小了;
最後把自己總結的工具類貼出來:
延伸閱讀
1.檔案形式(即以二進制形式存在于硬碟上)
2.流的形式(即以二進制形式存在于記憶體中)
3.bitmap形式
這三種形式的差別: 檔案形式和流的形式對圖檔體積大小并沒有影響,也就是說,如果你手機sd卡上的如果是100k,那麼通過流的形式讀到記憶體中,也一定是占100k的記憶體,注意是流的形式,不是bitmap的形式,當圖檔以bitmap的形式存在時,其占用的記憶體會瞬間變大, 我試過500k檔案形式的圖檔加載到記憶體,以bitmap形式存在時,占用記憶體将近10m,當然這個增大的倍數并不是固定的
檢測圖檔三種形式大小的方法:
檔案形式: file.length()
流的形式: 講圖檔檔案讀到記憶體輸入流中,看它的byte數
bitmap: bitmap.getbytecount()
1. 将圖檔儲存到本地時進行壓縮, 即将圖檔從bitmap形式變為file形式時進行壓縮,
特點是: file形式的圖檔确實被壓縮了, 但是當你重新讀取壓縮後的file為 bitmap是,它占用的記憶體并沒有改變
[java] view
plaincopy
public static void compressbmptofile(bitmap bmp,file file){
bytearrayoutputstream baos = new bytearrayoutputstream();
int options = 80;//個人喜歡從80開始,
bmp.compress(bitmap.compressformat.jpeg, options, baos);
while (baos.tobytearray().length / 1024 > 100) {
baos.reset();
options -= 10;
bmp.compress(bitmap.compressformat.jpeg, options, baos);
}
try {
fileoutputstream fos = new fileoutputstream(file);
fos.write(baos.tobytearray());
fos.flush();
fos.close();
} catch (exception e) {
e.printstacktrace();
}
方法說明: 該方法是壓縮圖檔的品質, 注意它不會減少圖檔的像素,比方說, 你的圖檔是300k的, 1280*700像素的, 經過該方法壓縮後, file形式的圖檔是在100以下, 以友善上傳伺服器, 但是你bitmapfactory.decodefile到記憶體中,變成bitmap時,它的像素仍然是1280*700, 計算圖檔像素的方法是 bitmap.getwidth()和bitmap.getheight(), 圖檔是由像素組成的,
每個像素又包含什麼呢? 熟悉ps的人知道, 圖檔是有色相,明度和飽和度構成的.
該方法的官方文檔也解釋說, 它會讓圖檔重新構造, 但是有可能圖像的位深(即色深)和每個像素的透明度會變化,jpeg onlysupports opaque(不透明), 也就是說以jpeg格式壓縮後, 原來圖檔中透明的元素将消失.是以這種格式很可能造成失真
既然它是改變了圖檔的顯示品質, 達到了對file形式的圖檔進行壓縮, 圖檔的像素沒有改變的話, 那重新讀取經過壓縮的file為bitmap時, 它占用的記憶體并不會少.(不相信的可以試試)
因為: bitmap.getbytecount() 是計算它的像素所占用的記憶體, 請看官方解釋: returns the number of bytes used to store this bitmap's
pixels.
2. 将圖檔從本地讀到記憶體時,進行壓縮 ,即圖檔從file形式變為bitmap形式
特點: 通過設定采樣率, 減少圖檔的像素, 達到對記憶體中的bitmap進行壓縮
先看一個方法: 該方法是對記憶體中的bitmap進行品質上的壓縮, 由上面的理論可以得出該方法是無效的, 而且也是沒有必要的,因為你已經将它讀到記憶體中了,再壓縮多此一舉, 盡管在擷取系統相冊圖檔時,某些手機會直接傳回一個bitmap,但是這種情況下, 傳回的bitmap都是經過壓縮的,
它不可能直接傳回一個原聲的bitmap形式的圖檔, 後果可想而知
private bitmap compressbmpfrombmp(bitmap image) {
int options = 100;
image.compress(bitmap.compressformat.jpeg, 100, baos);
image.compress(bitmap.compressformat.jpeg, options, baos);
bytearrayinputstream isbm = new bytearrayinputstream(baos.tobytearray());
bitmap bitmap = bitmapfactory.decodestream(isbm, null, null);
return bitmap;
再看一個方法:
private bitmap compressimagefromfile(string srcpath) {
bitmapfactory.options newopts = new bitmapfactory.options();
newopts.injustdecodebounds = true;//隻讀邊,不讀内容
bitmap bitmap = bitmapfactory.decodefile(srcpath, newopts);
newopts.injustdecodebounds = false;
int w = newopts.outwidth;
int h = newopts.outheight;
float hh = 800f;//
float ww = 480f;//
int 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;//設定采樣率
newopts.inpreferredconfig = config.argb_8888;//該模式是預設的,可不設
newopts.inpurgeable = true;// 同時設定才會有效
newopts.ininputshareable = true;//。當系統記憶體不夠時候圖檔自動被回收
bitmap = bitmapfactory.decodefile(srcpath, newopts);
// return compressbmpfrombmp(bitmap);//原來的方法調用了這個方法企圖進行二次壓縮
//其實是無效的,大家盡管嘗試
方法說明: 該方法就是對bitmap形式的圖檔進行壓縮, 也就是通過設定采樣率, 減少bitmap的像素, 進而減少了它所占用的記憶體