jpeg圖片格式詳解

————————————————
版權聲明:本文爲CSDN博主「yun_hen」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/yun_hen/article/details/78135122

peg圖片格式詳解
1. JPEG文件簡介
JPEG的全稱是JointPhotographicExpertsGroup(聯合圖像專家小組),它是一種常用的圖像存儲格式, jpg/jpeg是24位的圖像文件格式,也是一種高效率的壓縮格式,文件格式是JPEG(聯合圖像專家組)標準的產物,該標準由ISO與CCI TT(國際電報電話諮詢委員會)共同制定,是面向連續色調靜止圖像的一種壓縮標準。其最初目的是使用64Kbps的通信線路傳輸720×576 分辨率壓縮後的圖像。通過損失極少的分辨率,可以將圖像所需存儲量減少至原大小的10%。由於其高效的壓縮效率和標準化要求,目前已廣泛用於彩色傳真、靜止圖像、電話會議、印刷及新聞圖片的傳送上。但那些被刪除的資料無法在解壓時還原,所以* .jpg/.jpeg文件並不適合放大觀看,輸出成印刷品時品質也會受到影響。不過,普通用戶不必擔心,因爲.jpg/.jpeg的壓縮算法十分先進,它對圖形圖像的損失影響不是很大,一幅1 6 M(24位)的.jpg/.jpeg圖像看上去與照片沒有多大差別,非專業人士甚至無法分辨。同樣一幅畫面,用.jpg/.jpeg格式儲存的文件是其他類型圖形文件的1 /10~1/20。一般情況下,.jpg/*.jpeg文件只有幾十KB,而色彩數最高可達到24位,所以它被廣泛運用在Internet上,以節約寶貴的網絡傳輸資源。同樣,爲了在一張光盤上儲存更多的圖形圖像,C D出版商也樂意採用jpg/jpeg格式。

JPEG的文件格式一般有兩種文件擴展名:.jpg和.jpeg,這兩種擴展名的實質是相同的,我們可以把.jpg的文件改名爲.jpeg,而對文件本身不會有任何影響。嚴格來講,JPEG的文件擴展名應該爲.jpeg,由於DOS時代的8.3文件名命名原則,就使用了.jpg的擴展名,這種情況類似於.htm和.html的區別。

JPEG格式可以分爲標準JPEG、漸進式JPEG和JPEG2000三種格式。

標準JPEG:該類型的圖片文件,在網絡上應用較多,只有圖片完全被加載和讀取完畢之後,才能看到圖片的全貌;它是一種很靈活的圖片壓縮方式,用戶可以在壓縮比和圖片品質之間進行權衡。不過,通常來講,其壓縮比在10:1到40:1之間,壓縮比越大,品質就越差,壓縮比越小,品質就越好。JPEG格式壓縮的主要是高頻信息,對色彩的信息保留較好,適合應用於互聯網,可減少圖像的傳輸時間,可以支持24bit真彩色,也普遍應用於需要連續色調的圖像。JPEG由於可以提供有損壓縮,因此壓縮比可以達到其他傳統壓縮算法無法比擬的程度。其壓縮模式有以下幾種:順序式編碼(SequentialEncoding),遞增式編碼(ProgressiveEncoding),無失真編碼(LosslessEncoding)和階梯式編碼(HierarchicalEncoding)。JPEG的壓縮,分爲四個步驟:

(1)顏色轉換:由於JPEG只支持YUV顏色模式,而不支持RGB顏色模式,所以在將彩色圖像進行壓縮之前,必須先對顏色模式進據轉換。轉換完成之後還需要進行數據採樣。一般採用的採樣比例是2:1:1或4:2:2。由於在執行了此項工作之後,每兩行數據只保留一行,因此,採樣後圖像數據量將壓縮爲原來的一半。

(2)DCT變換:DCT(DiscreteConsineTransform)是將圖像信號在頻率域上進行變換,分離出高頻和低頻信息的處理過程。然後再對圖像的高頻部分(即圖像細節)進行壓縮,以達到壓縮圖像數據的目的。首先將圖像劃分爲多個8*8的矩陣。然後對每一個矩陣作DCT變換(變換公式此略)。變換後得到一個頻率係數矩陣,其中的頻率係數都是浮點數。

(3)量化:由於在後面編碼過程中使用的碼本都是整數,因此需要對變換後的頻率係數進行量化,將之轉換爲整數。由於進行數據量化後,矩陣中的數據都是近似值,和原始圖像數據之間有了差異,這一差異是造成圖像壓縮後失真的主要原因。

(4)編碼:編碼採用兩種機制:一是0值的行程長度編碼;二是熵編碼(EntropyCoding)。在JPEG中,採用曲徊序列,即以矩陣對角線的法線方向作“之”字排列矩陣中的元素。這樣做的優點是使得靠近矩陣左上角、值比較大的元素排列在行程的前面,而行程的後面所排列的矩陣元素基本上爲0值。行程長度編碼是非常簡單和常用的編碼方式,在此不再贅述。編碼實際上是一種基於統計特性的編碼方法。在JPEG中允許採用HUFFMAN編碼或者算術編碼。

漸進式JPEG:該類型的圖片是對標準JPEG格式的改進,當在網頁上下載漸進式JPEG圖片時,首先呈現圖片的大概外貌,然後再逐漸呈現具體的細節部分,因而被稱之爲漸進式JPEG。

JPEG2002:一種全新的圖片壓縮發,壓縮品質更好,並且改善了無線傳輸時,因信號不穩定而造成的馬賽克及位置錯亂等問題。另外,作爲JPEG的升級版,JPEG2000的壓縮率比標準JPEG高約30%,同時支持有損壓縮和無損壓縮。它還支持漸進式傳輸,即,先傳輸圖片的粗略輪廓,然後,逐步傳輸細節數據,使得圖片由模糊到清晰逐步顯示。此外,JPEG2000還支持感興趣區域,也就是說,可以指定圖片上感興趣區域的壓縮質量,還可以選擇指定的部分先進行解壓。

2. android是如何識別JEPG文件的
其實很簡單,就是判斷前面3個字節是什麼,如果發現是FF D8 FF開始,那就認爲它是JEPG圖片。(注意android不是根據後綴名來判斷是什麼文件的,當然你必須是圖片的後綴名文件管理器纔可以打開)

//SkImageDecoder_libjpeg.cpp (external\skia\src\images)
static bool is_jpeg(SkStream* stream) {
    //需要匹配的字節
    static const unsigned char gHeader[] = { 0xFF, 0xD8, 0xFF };
    static const size_t HEADER_SIZE = sizeof(gHeader);

    char buffer[HEADER_SIZE];
    //從數據源中讀取3個字節
    size_t len = stream->read(buffer, HEADER_SIZE);

    if (len != HEADER_SIZE) {
        return false;   // can't read enough
    }
    //只有完全匹配纔會認爲是jpeg圖片
    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
        return false;
    }
    return true;
}

3. JPEG圖片格式詳解
JPEG圖片格式組成部分:SOI(文件頭)+APP0(圖像識別信息)+ DQT(定義量化表)+ SOF0(圖像基本信息)+ DHT(定義Huffman表) + DRI(定義重新開始間隔)+ SOS(掃描行開始)+ EOI(文件尾)

其中粗體部分是必須的,下面我就來解釋一下這些信息吧。

3.1 JPEG圖片的數據源
先打開一張jpeg.jpeg圖片,查看其圖片格式與信息。 

圖表 1 jpeg圖片詳細信息

接着以2進制形式打開該圖片,查看圖片的二進制原始數據=> 

圖表 2 jpeg圖片二進制數據

我們就以上面jpeg文件爲例子,講解我們接下去的內容。

3.2 JEPG的段結構
JPEG 文件的格式是分爲一個一個的段來存儲的,段的多少和長度並不是一定的。只要包含了足夠的信息,該JPEG文件就能夠被打開,呈現給人們。JPEG文件的每個段都一定包含兩部分一個是段的標識,它由兩個字節構成:第一個字節是十六進制0xFF,第二個字節對於不同的段,這個值是不同的。緊接着的兩個字節存放的是這個段的長度(除了前面的兩個字節0xFF和0xXX,X表示不確定。他們是不算到段的長度中的)。注意:這個長度的表示方法是按照高位在前,低位在後的,與 Intel 的表示方法不同。比方說一個段的長度是0x12AB,那麼它會按照0x12,0xAB的順序存儲。但是如果按照Intel的方式:高位在後,低位在前的方式會存儲成0xAB,0x12,而這樣的存儲方法對於JPEG是不對的。這樣的話如果一個程序不認識JPEG文件某個段,它就可以讀取後兩個字節,得到這個段的長度,並跳過忽略它。

段的一般結構 = >

-----------------------------------------------------------------
名稱  字節數     數據  說明
-----------------------------------------------------------------
段標識   1         FF      每個新段的開始標識
段類型   1                 類型編碼(稱作“標記碼”)
段長度   2                 包括段內容和段長度本身,不包括段標識和段類型
段內容                     ≤65533字節

①JPG 文件中所有關於寬度高度長度間隔這一類數據,凡是>1字節的,均採用Motorola格式,即:高位在前,低位在後。

②有些段沒有長度描述也沒有內容,只有段標識和段類型。文件頭和文件尾均屬於這種段。

③段與段之間無論有多少FF都是合法的,這些FF稱爲“填充字節”,必須被忽略掉。

3.3 段類型
段類型

---------------------------------------
名稱  標記碼     說明
---------------------------------------
SOI     D8          文件頭
EOI     D9          文件尾
SOF0    C0          幀開始(標準 JPEG)
SOF1    C1          同上
DHT     C4          定義 Huffman 表(霍夫曼表)
SOS DA          掃描行開始
DQT DB          定義量化表
DRI     DD          定義重新開始間隔
APP0    E0          定義交換格式和圖像識別信息
COM FE          註釋
-----------------------------------------------------------

說明:有的文章也將DNL段(標記碼=DC,定義掃描行數)列爲必須段。

ps:段類型有30種,但只有10種是必須被所有程序識別的,其它的類型都可以忽略。所以下面只列出這10種類型。

3.4 SOI文件頭
JPEG文件的開始2個字節都是FF D8這是JPEG協議規定的

SOI(文件頭)

-----------------
名稱  字節數 值
-----------------
段標識   1     FF
段類型   1     D8 
-----------------

說明:這兩個字節構成了JPEG文件頭。

圖表 3 SOI文件頭

=> 此處我們的數據是FF D8

3.5 APP0圖像識別信息

APP0(圖像識別信息)

--------------------------------------------------------------------------
名稱      字節數     值                   說明
--------------------------------------------------------------------------
段標識       1         FF
段類型       1         E0
段長度       2         0010                    如果有RGB縮略圖就=16+3n
  (以下爲段內容)
交換格式      5         4A46494600          “JFIF”的ASCII碼
主版本號      1
次版本號      1  
密度單位      1         0=無單位;1=點數/英寸;2=點數/釐米
X像素密度     2                             水平方向的密度   
Y像素密度     2                             垂直方向的密度
縮略圖X像素  1                           縮略圖水平像素數目  
縮略圖Y像素  1                           縮略圖垂直像素數目
(如果“縮略圖X像素”和“縮略圖Y像素”的值均>0,那麼纔有下面的數據)
RGB縮略圖  3×n         n=縮略圖像素總數=縮略圖X像素×縮略圖Y像素
--------------------------------------------------------------------------

說明:

①JFIF是JPEG File Interchange Forma的縮寫,即JPEG文件交換格式,另外還有TIFF等格式,很少用

②“如果有RGB縮略圖就=16+3n”是什麼意思呢?比如說“縮略圖X像素”和“縮略圖Y像素”的值均爲48,就表示有一個48×48像素的縮略圖(n=48×48),縮略圖是24位真彩位圖,用3個字節來表示一個像素,所以共佔用3n個字節。但大多數JPG文件都沒有這個“雞肋”縮略圖。

=>首先來看看我們圖片二進制數據 

圖表 4 APP0圖像識別信息

1)圖像識別信息頭:2個字節FF E0

2)段長度:00 10 => 16個字節

3)交換格式5個字節:4A 46 49 46 00 => 此處代表‘JFIF’,一般我們用的都是JFIF的jpeg交換格式,但是也有TFIF的jpeg交換格式,如果camera sensor直接輸出的是jpeg圖片,那麼在其sensor寄存器可以設置使用JFIF還是TFIF。

4)主版本號和次版本號一共2個字節: 01 01 => 說明主版本號和此版本號都爲1

5)單位密度1個字節:01 => 表示此處使用的是點數/英寸

6)X像素密度2個字節:00 60 => 水平像素密度是96

7)Y像素密度2個字節:00 60 => 垂直像素密度是96

8)縮略圖X像素:00 => 沒有縮略圖

9)縮略圖Y像素:00 => 沒有縮略圖

10)RGB縮略圖:此處沒有縮略圖,所以是空的

3.6 DQT定義量化表
DQT(定義量化表)

--------------------------------------------------------------------------
名稱  字節數 值       說明
--------------------------------------------------------------------------
段標識   1     FF
段類型   1     DB
段長度   2     43      其值=3+n(當只有一個QT時)
(以下爲段內容)
QT信息  1     0-3位:QT號
4-7位:QT精度(0=8bit,1字節;否則=16bit,2字節)
QT        n             n=64×QT精度的字節數
--------------------------------------------------------------------------

說明:

①JPEG文件一般有2個DQT段,爲Y值(亮度)定義1個, 爲C值(色度)定義1個。

②一個DQT段可以包含多個QT, 每個都有自己的信息字節

=> 接下來看看DQT的二進制數據 

圖表 5 DQT定義量化表

此處有2個DQT數據,第一個是亮度的,第二個是色度的。

以第一個亮度的爲例子解釋:

1)定義量化表的頭2個字節:FF DB

2)段長度2個字節:00 43 => 3(段長度2個字節,QT信息1個字節)+QT量化表的長度,此處QT量化表的長度是64

3)QT信息1個字節:

以①爲例子00 => 0-3位是QT號,4-7位QT精度,此處是0,所以精度是8bit,即1個字節。

以②爲例子 01 => QT號是1,精度是8bit

4)QT量化表:這個的長度是根據QT信息確定的,上面QT精度爲8bit,所以此處是64×1 = 64個字節

3.7 SOF0圖像基本信息
SOF0(圖像基本信息)

--------------------------------------------------------------------------
名稱  字節數 值       說明
--------------------------------------------------------------------------
段標識   1     FF
段類型   1     C0
段長度   2             其值=8+組件數量×3
  (以下爲段內容)
樣本精度 1      8       每個樣本位數(大多數軟件不支持12和16)
圖片高度 2
圖片寬度 2
組件數量 1      3       1=灰度圖,3=YCbCr/YIQ 彩色圖,4=CMYK 彩色圖
  (以下每個組件佔用3字節)
組件 ID     1             1=Y, 2=Cb, 3=Cr, 4=I, 5=Q
採樣係數 1              0-3位:垂直採樣係數
                        4-7位:水平採樣係數
量化表號 1
---------------------------------------------------------------------------

說明:

①JPEG大都採用yCrCb色彩模型(y表示亮度,Cr紅色分量,Cb表示藍色分量),所以組件數量一般=3

②樣本就是單個像素的顏色分量,也可理解爲一個樣本就是一個組件

③採樣係數是實際採樣方式與最高採樣係數之比,而最高採樣係數一般=0.5(分數表示爲1/2)。比如說,垂直採樣係數=2,那麼2×0.5=1,表示實際採樣方式是每個點採一個樣,也就是逐點採樣;如果垂直採樣係數=1,那麼:1×0.5=0.5(分數表示爲1/2),表示每2個點採一個樣

=> 接下來看看SOF0的二進制數據

圖表 6 SOF0圖像基本信息

1)圖像基本信息的:2個字節FF C0

2)段長度2個字節:00 11 => 17 = 8 + 3*3,說明組件數量有3個

3)樣本精度1個字節:08,每個樣本的信息是8bit

4)樣本高度2個字節:01 E0 => 480圖片高度與實際一致

5)樣本寬度2個字節:01 40 => 320圖片寬度與實際一致

6)組件數量1個字節:03 => 代表YCbCr 彩色圖,有3個組件分別是Y、Cb、Cr

7)每個組件佔用3個字節:第一個字節是組件ID,第二個字節是採樣係數,第三個字節是量化表號。

此處是:

01 22 00 => Y組件,垂直採樣係數和水平採樣係數都是2,量化表號是0

02 11 01 => Cb組件,垂直採樣係數和水平採樣係數都是1,量化表號是1

03 11 01 => Cr組件,垂直採樣係數和水平採樣係數都是1,量化表號是1

//此處可知此處Y採樣是逐點採樣,CbCr都是隔點採樣,這就是標準的YUV422的數據。

3.8 DHT定義huffman表
DHT(定義Huffman表)

--------------------------------------------------------------------------
名稱  字節數 值       說明
--------------------------------------------------------------------------
段標識   1     FF
段類型   1     C4
段長度   2             其值=19+n(當只有一個HT表時)
  (以下爲段內容)
HT信息  1             0-3位:HT號
                                4位:   HT類型, 0=DC表,1=AC表
            5-7位:必須=0
HT位表  16            這16個數的和應該≤256
HT值表  n             n=表頭16個數的和
--------------------------------------------------------------------------

說明:

①JPEG文件裏有2類Haffman 表:一類用於DC(直流量),一類用於AC(交流量)。一般有4個表:亮度的DC和AC,色度的DC和AC。最多可有6個。

②一個DHT 段可以包含多個HT表, 每個都有自己的信息字節

③HT表是一個按遞增次序代碼長度排列的符號表。

=> 接下來看看DHT的二進制數據

圖表 7 DHT定義Huffman表

1)定義Huffman表頭2個字節:FF C4

2)段長度2個字節:

以①爲例子 00 1F => 31 = 19(段長度2個字節+HT信息1個字節+HT位表16個字節) + 12(這個數代表HT表有12個字節)

3)HT信息1個字節:0-3位是HT號,4位是HT類型(0=DC表,1=AC表),5-7位必須爲0

以①爲例子 00 => HT號是0,DC表

以②爲例子 10 => HT號是0,AC表

以③爲例子 01 => HT號是1,DC表

以④爲例子 11 => HT號是1,AC表

//此處一共有4個Haffman 表,亮度DC Haffman 表,亮度AC Haffman 表,色度DC Haffman 表,色度AC Haffman 表

4)HT位表16個字節:這16個數字值和小於等於256

以①爲例子 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 => 共16個字節,加起來是12(此處和段長度是相匹配的),說明HT表有12個字節

5)HT值表:

以①爲例子00 01 02 03 04 05 06 07 08 09 0A 0B

ps: Huffman將在後續的文檔中講解,此處不細講。

3.9 SOS掃描行開始
SOS(掃描行開始)

--------------------------------------------------------------------------
名稱          字節數 值       說明
--------------------------------------------------------------------------
段標識            1    FF
段類型            1    DA
段長度            2    000C    其值=6+2×掃描行內組件數量
  (以下爲段內容)
掃描行內組件數量 1  3       必須≥1,≤4(否則錯誤),通常=3
  (以下每個組件佔用2字節)
組件ID               1    1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
Huffman表號      1    0-3位:AC表號 (其值=0...3)
                                    4-7位:DC表號(其值=0...3)
剩餘3個字節          3           最後3個字節用途不明,忽略
--------------------------------------------------------------------------

說明:緊接SOS段後的是壓縮的圖像數據(一個個掃描行),數據存放順序是從左到右、從上到下。

=> 接下來看看SOS的二進制數據

圖表 8 SOS掃描行開始

1)掃描行開始的頭,2個字節:FF DA

2)段長度2個字節:00 0C => 12 = 6(2個字節的掃描行開始頭+1個字節掃描行內組件數量+3個字節的剩餘位) + 2×3(掃描行內組件數量,每個組件2個字節)

3)掃描行內組件數量1個字節:03 => 代表組件數量數3

4)每個組件佔用2個字節:

第一個字節是組件ID(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q);第二個字節0-3位AC表號,4-7位DC表號。表號的值是0-3。

01 00 => Y組件,AC表號是0,DC表號是0

02 11 => Cb組件,AC表號是1,DC表號是1

03 11 => Cr組件,AC表號是1,DC表號是1

//此處跟DHT(定義Huffman表)的HT信息是一致的。

3.10 EOI文件尾
EOI(文件尾)

------------------
名稱  字節數   值
------------------
段標識   1     FF
段類型   1     D9 
------------------

說明:這兩個字節構成了JPEG文件尾。

=> EOI文件尾的二進制數據 

圖表 9 EOI文件尾

=> 此處我們的數據是FF D9

3.11 其它段

1) COM(註釋)

--------------------------------------------------------------------------
名稱  字節數 值    說明
--------------------------------------------------------------------------
段標識   1     FF
段類型   1     FE
段長度   2     其值=註釋字符的字節數+2
段內容         註釋字符
--------------------------------------------------------------------------

說明:有的JPEG文件沒有這個段。

2)DRI(定義重新開始間隔)

--------------------------------------------------------------------------
名稱  字節數 值   說明
--------------------------------------------------------------------------
段標識   1     FF
段類型   1     DD
段長度   2     4 
  (以下爲段內容)
開始間隔 2  n   復位標記的間隔距離
---------------------------------------------------------------------------

說明:

①開始間隔表示在壓縮數據流中,每隔n個MCU 塊就有一個RST標記,RST標記將Huffman 的解碼數據流復位,DC也重新從0開始,因此,RST標記是一種復位標記

②RST 標記是一種特殊的段,它只具有段標識和段類型(長度=2字節),但它不是獨立的段,只能穿插在數據流中(文件頭和文件尾段也只有段標識和段類型,卻都是獨立的段)。

③RST標記共有8個(RST0-RST7),從RST0起開始使用,然後是RST1….直至RST7,再從RST0重複。

④RST標記的標識碼是 FFD0-FFD7,對應 RST0-RST7

說明:這個不是必須段,很多JPEG都沒有。

4. JPEG壓縮編碼實例
DC是指直流係數,是8×8個像素的平均值;AC是交流係數,是8×8個像素的其它值。壓縮數據的排列方式是:亮度DC,AC,色差DC,AC,色差DC,AC。

1、每個分量如Y分量(DC+AC)完成後,如果還剩下位數,應該捨棄,後面的Cb分量是從下一個字節重新計算。

2、如果編碼到後面沒有壓縮數據了,後面實際編碼數據用0填充。

3、如果編碼已經完成,那麼剩餘壓縮數據用1填充。

4.1 8×8紅色色塊編碼

如下圖就是8×8紅色色塊的編碼數據=> 

圖表 10

8×8紅色

E2        E8       A2       8A    F9       93        F7       13
11100010 11101000 10100010 10001010 11111001 10010011 11110111 00010011

計算Y亮度分量=>

--------------------------------------------------------------------------------------------------
1110-0010 11-1010-00
--------------------------------------------------------------------------------------------------

首先有一個DC係數需要計算出來

DC亮度

1110代表碼長是4,類別是6,代表後面6個字節是它的值

001011是其值:最高位0代表是負數,反過來110100,代表-52

所以第一個數是:DC係數-52

AC亮度

1010:查表0/0,也就是後面都是0,代表這張圖亮度都是一樣的

 

 

 

 

 

發佈了17 篇原創文章 · 獲贊 38 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章