圖片分析及圖片壓縮原理

要了解圖片壓縮首先要了解一些圖片相關(guān)的其他概念

點(diǎn)陣圖和矢量圖

1. 點(diǎn)陣圖(位圖)或者叫 像素圖

構(gòu)成點(diǎn)陣圖的最小單位是象素,位圖就是由象素陣列的排列來實(shí)現(xiàn)其顯示效果的,每個(gè)象素有自己的顏色信息。所以在對位圖圖像進(jìn)行編輯操作的時(shí)候,可操作的對象是每個(gè)象素,可以通過改變圖像的色相、飽和度、明度,從而改變圖像的顯示效果

總結(jié):點(diǎn)陣圖縮放會(huì)失真

2. 矢量圖(向量圖)

矢量圖每一點(diǎn)上紀(jì)錄的元素形狀及顏色的算法,而不是像素信息,在打開矢量圖的時(shí)候,軟件對圖形象對應(yīng)的函數(shù)進(jìn)行運(yùn)算,將運(yùn)算結(jié)果 即(圖形的形狀和顏色)顯示出來。無論顯示畫面是大還是小,畫面上的對象對應(yīng)的算法是不變的,so, 矢量圖無論放大縮小其顯示效果都一樣

總結(jié):圖片任意放大或縮小都不會(huì)失真

顏色

計(jì)算機(jī)在表示顏色的時(shí)候,有兩種形式,一種稱作索引顏色(Index Color),一種稱作直接顏色(Direct Color)。

索引色

用一個(gè)數(shù)字來代表(索引)一種顏色,在存儲(chǔ)圖片的時(shí)候,存儲(chǔ)一個(gè)數(shù)字的組合,同時(shí)存儲(chǔ)數(shù)字到圖片顏色的映射。這種方式只能存儲(chǔ)有限種顏色,通常是256種顏色,對應(yīng)到計(jì)算機(jī)系統(tǒng)中,使用一個(gè)字節(jié)的數(shù)字來索引一種顏色。

直接色

使用四個(gè)數(shù)字來代表一種顏色,這四個(gè)數(shù)字分別代表這個(gè)顏色中紅色、綠色、藍(lán)色以及透明度?,F(xiàn)在主流顯示設(shè)備可以在這四個(gè)維度分別支持256種變化,所以直接色可以表示2的32次方種顏色。當(dāng)然并非所有的直接色都支持這么多種,為壓縮空間使用,有可能只有表達(dá)紅、綠、藍(lán)的三個(gè)數(shù)字,每個(gè)數(shù)字也可能不支持256種變化之多。

壓縮方式

有損壓縮

指在壓縮文件大小的過程中會(huì)損失了一部分圖片的信息,也即降低了圖片的質(zhì)量,并且這種損失是不可逆的。

無損壓縮。

指在壓縮文件大小的過程中圖片的質(zhì)量沒有任何損耗。無損壓縮過的圖片中恢復(fù)出原來的信息

圖片格式

常見的圖片格式有 bmp、gif、png、jpeg(jpg)、webp 等6種格式

BMP (BitMap簡稱)

是無損的、既支持索引色也支持直接色的、點(diǎn)陣圖,這種圖片格式幾乎沒有對數(shù)據(jù)進(jìn)行壓縮,所以bmp格式的圖片文件通常比較大?,F(xiàn)在在Windows操作系統(tǒng)中比較常見,其他地方不常見

GIF (Graphics Interchange Format)

是無損的、采用索引色的、點(diǎn)陣圖。使用GIF格式保存圖片時(shí)不會(huì)降低圖片質(zhì)量。

優(yōu)點(diǎn):1.由于數(shù)據(jù)的壓縮,GIF格式的圖片要遠(yuǎn)小于BMP格式的圖片,

2.GIF格式還具有支持動(dòng)畫以及透明的優(yōu)點(diǎn)。

缺點(diǎn):GIF格式僅支持8bit的索引色,即在整個(gè)圖片中,只能存在256種不同的顏色。

JPEG(Joint Photographic Experts Group)

JPEG是有損的、采用直接色的、點(diǎn)陣圖。JPEG圖片格式的設(shè)計(jì)目標(biāo),是在不影響人類可分辨的圖片質(zhì)量的前提下,盡可能的壓縮文件大小。也就是說JPEG去掉了一部分圖片的原始信息,即是進(jìn)行了有損壓縮

優(yōu)點(diǎn):采用了直接色,色彩更豐富

缺點(diǎn):有損的

WebP

WebP是谷歌開發(fā)的一種新圖片格式,WebP是同時(shí)支持有損和無損壓縮的、使用直接色的、點(diǎn)陣圖。

WebP具有更小的文件體積。這種圖片格式在pc 端應(yīng)用更廣泛,因?yàn)閳D片體積小,可以將大大減少瀏覽器和服務(wù)器之間的數(shù)據(jù)傳輸量,進(jìn)而降低訪問延遲,提升訪問體驗(yàn)。

在無損壓縮的情況下,相同質(zhì)量的WebP圖片,文件大小要比PNG小26%;

在有損壓縮的情況下,具有相同圖片精度的WebP圖片,文件大小要比JPEG小25%~34%;

PNG(Portable Network Graphics)

PNG-8 是PNG的索引色版本,PNG-8是無損的、使用索引色的、點(diǎn)陣圖。

文件體積小,另外PNG-8支持透明度的調(diào)節(jié)、支持動(dòng)畫,只不過瀏覽器對這個(gè)支持不好,所以應(yīng)用并不廣泛

PNG-24 是PNG的直接色版本,PNG-24是無損的、使用直接色的、點(diǎn)陣圖

PNG-24和BMP類似,PNG-24和BMP對比,前者的文件體積更小,但是比JPEG,GIF,PNG-8 都要大

總結(jié)

image.png

圖片壓縮原理

質(zhì)量壓縮

原理:質(zhì)量壓縮是通過改變圖片的位深和透明度來來減小圖片占用的磁盤空間大小。

所以質(zhì)量壓縮不會(huì)改變圖片在內(nèi)存中的大小(PS 圖片內(nèi)存大小是根據(jù)圖片的寬度、高度和一個(gè)像素所占用的字節(jié)數(shù)來計(jì)算的,因?yàn)橘|(zhì)量壓縮沒有改變高度和寬度,自然內(nèi)存的大小不會(huì)改變)其次質(zhì)量壓縮不會(huì)改變分圖片的辨率

示例:

 /**
     * 壓縮圖片:限制圖片的質(zhì)量,比如需要把5M的圖片壓縮到2M,可采取此方法
     *
     * @param filePath  被壓縮的圖片路徑
     * @param format    壓縮圖片格式,jpg,webp
     * @param sizeLimit 大小限制 單位是kb
     * @return 壓縮后的圖片
     */
    public static Bitmap compressBitmap(String filePath, Bitmap.CompressFormat format, int sizeLimit) {
        if (TextUtils.isEmpty(filePath)) {
            return null;
        }
        try {
            Bitmap bm = BitmapFactory.decodeFile(filePath);
            ByteArrayOutputStream byteAos = new ByteArrayOutputStream();
            // 質(zhì)量壓縮方法,這里100表示不壓縮,把壓縮后的數(shù)據(jù)存放到baos中
            int quality = 100;
            bm.compress(format, quality, byteAos);
            if (enableLog) {
                Log.d(TAG, " 壓縮前size = " + byteAos.toByteArray().length / 1024);
            }
            int minus = 10;
            if (byteAos.toByteArray().length / 1024 > 3 * 1024) {
                minus = 50;
            }
            // 循環(huán)判斷如果壓縮后圖片是否大于sizeLimit(單位是k),大于繼續(xù)壓縮
            while (byteAos.toByteArray().length / 1024 > sizeLimit && quality > 0 && quality <= 100) {
                // 重置baos即清空baos
                byteAos.reset();
                // 這里壓縮options%,把壓縮后的數(shù)據(jù)存放到baos中
                bm.compress(format, quality, byteAos);
                quality -= minus;// 每次都減少10
                if (byteAos.toByteArray().length / 1024 > 2 * 1024) {
                    minus = 20;
                } else if (byteAos.toByteArray().length / 1024 > 1024) {
                    minus = 10;
                }
                if (enableLog) {
                    Log.d(TAG, " quality = " + quality);
                }
            }
            if (enableLog) {
                Log.d(TAG, " 壓縮后size = " + byteAos.toByteArray().length / 1024);
            }
            byte[] result = byteAos.toByteArray();
            byteAos.close();
            if (result != null) {
                return BitmapFactory.decodeStream(new ByteArrayInputStream(result), null, null);
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

采樣壓縮(按比例壓縮)

原理:采樣率壓縮是通過設(shè)置BitmapFactory.Options.inSampleSize,通過改變圖片的分辨率,進(jìn)而減小圖片所占用的磁盤空間和內(nèi)存大小。

示例:

computeSize 算法計(jì)算

private static int computeSize(int srcWidth, int srcHeight) {
        srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth;
        srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight;

        int longSide = Math.max(srcWidth, srcHeight);
        int shortSide = Math.min(srcWidth, srcHeight);

        float scale = ((float) shortSide / longSide);
        if (scale <= 1 && scale > 0.5625) {
            if (longSide < 1664) {
                return 1;
            } else if (longSide < 4990) {
                return 2;
            } else if (longSide > 4990 && longSide < 10240) {
                return 4;
            } else {
                return longSide / 1280 == 0 ? 1 : longSide / 1280;
            }
        } else if (scale <= 0.5625 && scale > 0.5) {
            return longSide / 1280 == 0 ? 1 : longSide / 1280;
        } else {
            return (int) Math.ceil(longSide / (1280.0 / scale));
        }
    }

[1, 0.5625) 即圖片處于 [1:1 ~ 9:16) 比例范圍內(nèi)

[0.5625, 0.5) 即圖片處于 [9:16 ~ 1:2) 比例范圍內(nèi)

[0.5, 0) 即圖片處于 [1:2 ~ 1:∞) 比例范圍內(nèi)

image.png

例如測試機(jī)魅族t16屏幕比是4:3 ,那么圖片壓縮比就是3/4 =0.75,或者用圖片的的寬高進(jìn)行比較也行,, 拍出來的照片是 3024x 3042 3024/4032 =0.75

計(jì)算壓縮圖片的實(shí)際文件大小,圖片比例越大則文件越大

則圖片壓縮后的大小就是2268*3024

代碼示例:

     * 按照比例壓縮,按照默認(rèn)要鎖后的比例
     *
     * @param context 上線文
     * @param srcPath 圖片原始路徑
     * @return Uri
     */
    public static Uri ratioCompressSaveToGallery(Context context, String srcPath) {
        try {
            BitmapFactory.Options newOpts = new BitmapFactory.Options();
            //開始讀入圖片,此時(shí)把options.inJustDecodeBounds 設(shè)回true了
            newOpts.inJustDecodeBounds = true;
            Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);//此時(shí)返回bm為空
            newOpts.inJustDecodeBounds = false;
            int w = newOpts.outWidth;
            int h = newOpts.outHeight;
            if (enableLog) {
                Log.d(TAG, "src width = " + w + " height = " + h);
            }
            int size = computeSize(w, h);
            newOpts.inSampleSize = size;//設(shè)置縮放比例
            if (enableLog) {
                Log.d(TAG, "computeSize = " + size);
            }
            //重新讀入圖片,注意此時(shí)已經(jīng)把options.inJustDecodeBounds 設(shè)回false了
            bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
            ByteArrayOutputStream byteAos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 60, byteAos);
            byte[] result = byteAos.toByteArray();
            Bitmap resultBitMap = BitmapFactory.decodeStream(new ByteArrayInputStream(result), null, null);
            if (enableLog) {
                Log.d(TAG, "result width = " + resultBitMap.getWidth() + " height = " + resultBitMap.getHeight());
            }
            bitmap.recycle();
            if (result != null) {
                Uri uri = saveImageToGallery(context, result);
                if (uri != null) {
                    return uri;
                } else {
                    return null;
                }
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

圖片庫對比

目前流行的開源庫對比

tiny官方圖片壓縮效果對比詳情

github 地址:https://github.com/Sunzxyong/Tiny

image.png

luban 官方圖片壓縮效果對比詳

gitHub地址:https://github.com/Curzibn/Luban

image.png

真機(jī)測試

魅族16th和OPPO findx 圖片壓縮對比參照


image.png

Luban 框架優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

是根據(jù)微信圖片算法你推算的,適用真機(jī)測試豐富

缺點(diǎn):

1,當(dāng)沒有設(shè)定壓縮路徑時(shí),拋異常無閃退

2,源碼中,壓縮比率固定住60,無法修改

3,壓縮配置,參數(shù)不太適應(yīng)真實(shí)項(xiàng)目需求

4,不能指定壓縮大小,比如100kb 以內(nèi)

5,內(nèi)部封裝已AsyncTasky異步的圖片壓縮,對RxJava的支持不好

tiny 框架的優(yōu)缺點(diǎn)

優(yōu)點(diǎn):

1,支持批量壓縮

2,libjpeg-turbo的價(jià)值是利用SIMD指令集,加速了編解碼過程,時(shí)間縮短1/3

3, 解碼的時(shí)候是由內(nèi)部分配,不會(huì)造成資源浪費(fèi)

缺點(diǎn):

需要導(dǎo)入so庫導(dǎo)致包的體積會(huì)變大,

android 7.0一下的手機(jī)壓縮后比android7.0以上的手機(jī)壓縮大小會(huì)偏大一點(diǎn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在 App 中,如果分享、發(fā)布、上傳功能涉及到圖片,必不可少會(huì)對圖片進(jìn)行一定程度的壓縮。筆者最近在公司項(xiàng)目中恰好重...
    Nemocdz閱讀 9,606評論 4 42
  • 非原創(chuàng),只是整理,如果里面發(fā)現(xiàn)引用的內(nèi)容沒有標(biāo)識(shí)出來,歡迎指出。 一、基本知識(shí) (1)兩種圖片: 1)矢量圖: 矢...
    風(fēng)再起時(shí)ME閱讀 2,707評論 0 19
  • Bitmap 在內(nèi)存當(dāng)中占用的大小影響因素 色彩格式,如果是 ARGB8888 那么就是一個(gè)像素4個(gè)字節(jié),如果是 ...
    liaowenhao閱讀 577評論 0 0
  • 本文原創(chuàng):huhongtao 一、圖片格式有哪些? BMP、JPEG、GIF、PSD、PNG、TIFF、TGA、E...
    jad_design閱讀 4,219評論 0 1
  • 一提到圖片,我們就不得不從位圖開始說起,位圖圖像(bitmap),也稱為點(diǎn)陣圖像或繪制圖像,是由稱作像素(圖片元素...
    螢火蟲de夢閱讀 3,053評論 0 3

友情鏈接更多精彩內(nèi)容