Android圖片壓縮加密上傳 JPEG壓縮算法解析

1. 概述


  咱們在開發的過程當中,確定不少項目都須要上傳圖片文件,咱們每每都是直接上傳,相信不少都並未對其作過壓縮。固然不少哥們估計也在這方面費勁心思,每每都是採用google提供好的BitmapFactory,可是效果不太理想,若是以爲還行那請把3M的圖片壓縮到30K或者更小試試看看效果,這裏考你們一個常常問到的面試題:一張 421x633 的 PNG 圖片,我把它放到 drawable-xhdpi 目錄下,在紅米NOTE3上加載,佔用內存是多少?java

效果演示

  爲何要壓縮圖片而後再上傳這個就不用說了,十張5M的圖片直接上傳到服務器想一想都以爲可怕,那爲何咱們BitmapFactory壓縮的圖片效果並不理想呢?又或者說爲何Android一張5M還比不過蘋果一張500K的清晰呢?這就須要從Android的發展史開始講起,可是你若看過BitmapFactory的NDK部分的源碼就會清晰的找到這麼一段代碼:面試

static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding,
        jobject options, bool allowPurgeable, bool forcePurgeable = false) {

    // ....省略
    float scale = 1.0f;
    // 請留意一下這個C++對象
    SkBitmap outputBitmap;

    // 判斷圖片是否須要縮放
    const bool willScale = scale != 1.0f;
    isPurgeable &= !willScale;
   
    // 更新options
    if (options != NULL) {
        // 設置圖片最終顯示出來的寬高爲縮放後的寬高
        env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
        env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
        env->SetObjectField(options, gOptions_mimeFieldID,
                getMimeTypeString(env, decoder->getFormat()));
    }

    // ....省略

    // 建立Bitmap對象
    return GraphicsJNI::createBitmap(env, outputBitmap, javaAllocator.getStorageObj(),
            bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
}
複製代碼

  上面咱們只要留意一下SkBitmap這個對象就行了,若是你可以找到doDecode這個方法而且可以看得懂裏面的全部代碼,那麼你就能夠回答出個人問題了,這裏我沒有詳細說明對於圖片壓縮,我提的這個問題然並卵,但這是我面試必問的一個題目。   SkBitmap中的前綴SK你能夠認爲是Skia,這是google所採用的一套圖片算法,爲何要採用這個算法呢?圖片又大,3M的圖片可能還不夠清晰,具體請看Skia官網算法

2. JPEG壓縮算法解析


  既然咱們知道了緣由,那麼咱們打算採用JPEG來壓縮,後面壓縮的時候你會發現內存蹭蹭的往上走,好在咱們如今手機都不是用的Android第一代了,對於這點內存仍是小Case。接下來咱們主要分析JPEG的壓縮算法,若是聽JPEG的發展史請自行google或者百度。目前絕大部分圖片都使用了JPEG壓縮技術,一般JPEG文件相對於原始圖像,可以獲得1/8的壓縮比,反編譯BAT的一些apk你會發現也在使用。數組

2.1 RGB轉YCbCr

  圖像被分割成大小爲8X8的小塊,這些小塊在整個壓縮過程當中都是單獨被處理的。咱們常見的「RGB」模型,就是把顏色分解成紅綠藍三種份量,這樣一張圖片就能夠分解成三張灰度圖,數學表達上,每個8X8的圖案,能夠表達成三個8X8的矩陣,其中的數值的範圍通常在[0,255]之間。而在JPEG壓縮算法中,須要把圖案轉換成爲YCbCr模型,這裏的Y表示亮度(Luminance),Cb和Cr分別表示綠色和紅色的「色差值」。最終能夠獲得RGB轉換爲YCbCr的數學公式爲:bash

  對於一張圖片RGB能夠獲得三張灰度圖,YCbCr也可以獲得三張圖片 服務器

  咱們可以發現有一張圖片咱們感受比較好就是Y,而Cb和Cr基本沒感受,因此咱們能夠對Cr和Cb作一下處理,反正沒感受能夠再搞得更加沒感受。這種方式就是針對數據的重要程度不一樣作不一樣的處理。這就是爲何JPEG使用這種顏色空間的緣由。

2.2 離散餘弦變換

  離散餘弦變換(Discrete cosine transform),簡稱DCT。離散餘弦變換屬於傅里葉變換的另一種形式,沒錯,就是大名鼎鼎的傅里葉變換。傅里葉是法國著名的數學家和物理學家,他認爲任何週期性的函數,均可以分解爲爲一系列的三角函數的組合,這個想法一開始並無獲得當時科學界的認可,好比當時著名的數學家拉格朗日提出質疑,三角函數不管如何組合,都沒法表達帶有「尖角」的函數,一直到1822年拉格朗日死後,傅里葉的想法才正式在他的著做《熱的解析理論》一書中正式發表。金子總會閃光,傅里葉變換現在普遍應用於數學、物理、信號處理等等領域,變換除了它在數學上的意義外,還有其哲學上的偉大意義,那就是,世上任何複雜的事物,均可以分解爲簡單的事物的組合,而這個過程只須要藉助數學工具就能夠了。可是當年拉格朗日的質疑是正確的,三角函數的確沒法表達出尖角形狀的函數,不過只要三角函數足夠多,能夠無限逼近最終結果。好比下面這張動圖,就動態描述了一個矩形方波,是如何作傅里葉分析的。數據結構

  一些公式我就不貼了你們能夠上網找找,我估計沒個兩年確定是看不懂的,實話說就算有個兩年的數據結構和算法也不必定行,不要問我我也不行,若是是作應用開發若是沒有多少時間其實不必去深究,瞭解就好,固然閒得不行仍是能夠研究一下的。數據結構和算法

2.3 哈弗曼編碼

  對於哈弗曼編碼咱們仍是有可能明白的,JPEG壓縮的最後一步是對數據進行哈弗曼編碼(Huffman coding),哈弗曼幾乎是全部壓縮算法的基礎,它的基本原理是根據數據中元素的使用頻率,調整元素的編碼長度,以獲得更高的壓縮比。   舉個例子,好比下面這段數據   AABCBABBCDBBDDBAABDBBDABBBBDDEDBD   這段數據裏面包含了33個字符,每種字符出現的次數統計以下函數

  若是咱們用咱們常見的定長編碼,每一個字符都是3個bit。
  那麼這段文字共須要3 x 33 = 99個bit來保存,但若是咱們根據字符出現的機率,使用以下的編碼
  這段文字共須要3 x 6 + 1 x 15 + 4 x 2 + 2 x 9 + 4 x 1 = 63個bit來保存,壓縮比爲63%,哈弗曼編碼通常都是使用二叉樹來生成的,這樣獲得的編碼符合前綴規則,也就是較短的編碼不可以是較長編碼的前綴,好比上面這個編碼,就是由下面的這顆二叉樹生成的。

  最終通過一系列的處理以及數據的量化,咱們保存長度爲64的數組大概10字節就能夠了,固然還能夠更優只要你能想到。工具

全部分享大綱:2017Android進階之路與你同行

視頻講解地址:http://pan.baidu.com/s/1boUdYdL

相關文章
相關標籤/搜索