天天看點

Android圖檔壓縮(品質壓縮和尺寸壓縮)

在網上調查了圖檔壓縮的方法并實裝後,大緻上可以認為有兩類壓縮:品質壓縮(不改變圖檔的尺寸)和尺寸壓縮(相當于是像素上的壓縮);品質壓縮一般可用于上傳大圖前的處理,這樣就可以節省一定的流量,畢竟現在的手機拍照都能達到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

Android圖檔壓縮(品質壓縮和尺寸壓縮)
Android圖檔壓縮(品質壓縮和尺寸壓縮)

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形式的圖檔, 後果可想而知

Android圖檔壓縮(品質壓縮和尺寸壓縮)
Android圖檔壓縮(品質壓縮和尺寸壓縮)

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;  

  再看一個方法:

Android圖檔壓縮(品質壓縮和尺寸壓縮)
Android圖檔壓縮(品質壓縮和尺寸壓縮)

    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的像素, 進而減少了它所占用的記憶體

繼續閱讀