天天看點

JPEG圖像密寫研究(一) JPEG圖像檔案結構JPEG圖像密寫研究(一) JPEG圖像檔案結構

JPEG圖像密寫研究(一) JPEG圖像檔案結構

【轉載】轉載自http://www.cnblogs.com/leaven/archive/2010/04/06/1705846.html

JPEG壓縮編碼算法的主要計算步驟如下:

(0) 8*8分塊。

(1) 正向離散餘弦變換(FDCT)。

(2) 量化(quantization)。

(3) Z字形編碼(zigzag scan)。

(4) 使用差分脈沖編碼調制(DPCM)對直流系數(DC)進行編碼。

(5) 使用行程長度編碼(RLE)對交流系數(AC)進行編碼。

(6) 熵編碼。

一、JPEG檔案格式介紹

JPEG檔案使用的資料存儲方式有多種。最常用的格式稱為JPEG檔案交換格式(JPEG File Interchange Format,JFIF)。而JPEG檔案大體上可以分成兩個部分:标記碼(Tag)和壓縮資料。

标記碼由兩個位元組構成,其前一個位元組是固定值0xFF,後一個位元組則根據不同意義有不同數值。在每個标記碼之前還可以添加數目不限的無意義的0xFF填充,也就說連續的多個0xFF可以被了解為一個0xFF,并表示一個标記碼的開始。而在一個完整的兩位元組的标記碼後,就是該标記碼對應的壓縮資料流,記錄了關于檔案的諸種資訊。

常用的标記有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。

注意,SOI等都是标記的名稱。在檔案中,标記碼是以标記代碼形式出現。例如SOI的标記代碼為0xFFD8,即在JPEG檔案中的如果出現資料0xFFD8,則表示此處為一個SOI标記。

SOI,Start of Image,圖像開始

标記代碼                                 2位元組     固定值0xFFD8

APP0,Application,應用程式保留标記0

标記代碼                                 2位元組     固定值0xFFE0

包含9個具體字段:

 ① 資料長度                         2位元組     ①~⑨9個字段的總長度

                                                            即不包括标記代碼,但包括本字段

 ② 辨別符                             5位元組    固定值0x4A46494600,即字元串“JFIF0”

  ③ 版本号                             2位元組    一般是0x0102,表示JFIF的版本号1.2

                                                            可能會有其他數值代表其他版本

 ④ X和Y的密度機關           1位元組     隻有三個值可選

                                                            0:無機關;1:點數/英寸;2:點數/厘米

 ⑤ X方向像素密度               2位元組     取值範圍未知

 ⑥ Y方向像素密度               2位元組     取值範圍未知   

  ⑦ 縮略圖水準像素數目        1位元組     取值範圍未知

 ⑧ 縮略圖垂直像素數目        1位元組     取值範圍未知

 ⑨ 縮略圖RGB位圖             長度可能是3的倍數           縮略圖RGB位圖資料

本标記段可以包含圖像的一個微縮版本,存為24位的RGB像素。如果沒有微縮圖像(這種情況更常見),則字段⑦“縮略圖水準像素數目”和字段⑧“縮略圖垂直像素數目”的值均為0。

APPn,Application,應用程式保留标記n,其中n=1~15(任選)

标記代碼                                 2位元組     固定值0xFFE1~0xFFF

包含2個具體字段:

 ① 資料長度                         2位元組     ①~②2個字段的總長度

                                                            即不包括标記代碼,但包括本字段

 ② 詳細資訊            資料長度-2位元組   内容不定

例如,Adobe Photoshop生成的JPEG圖像中就用了APP1和APP13兩個标記段分别存儲了一幅圖像的副本。

DQT,Define Quantization Table,定義量化表

标記代碼                          2位元組            固定值0xFFDB

包含9個具體字段:

 ① 資料長度                  2位元組            字段①和多個字段②的總長度

                                                            即不包括标記代碼,但包括本字段

 ② 量化表        資料長度-2位元組

a)精度及量化表ID   1位元組            高4位:精度,隻有兩個可選值

                                                              0:8位;1:16位

                                                低4位:量化表ID,取值範圍為0~3

b)表項       (64×(精度+1))位元組              例如8位精度的量化表

                                                其表項長度為64×(0+1)=64位元組

本标記段中,字段②可以重複出現,表示多個量化表,但最多隻能出現4次。

SOF0,Start of Frame,幀圖像開始

标記代碼                   2位元組     固定值0xFFC0

包含9個具體字段:

 ① 資料長度           2位元組     ①~⑥六個字段的總長度

                                              即不包括标記代碼,但包括本字段

 ② 精度                 1位元組     每個資料樣本的位數

                                              通常是8位,一般軟體都不支援 12位和16位

 ③ 圖像高度           2位元組     圖像高度(機關:像素),如果不支援 DNL 就必須 >0

  ④ 圖像寬度           2位元組     圖像寬度(機關:像素),如果不支援 DNL 就必須 >0

  ⑤ 顔色分量數        1位元組     隻有3個數值可選

                                              1:灰階圖;3:YCrCb或YIQ;4:CMYK

                                              而JFIF中使用YCrCb,故這裡顔色分量數恒為3

  ⑥顔色分量資訊      顔色分量數×3位元組(通常為9位元組)

a)顔色分量ID                 1位元組    

b)水準/垂直采樣因子      1位元組            高4位:水準采樣因子

                                                       低4位:垂直采樣因子

                                                       (曾經看到某資料把這兩者調轉了)

c) 量化表                         1位元組            目前分量使用的量化表的ID

本标記段中,字段⑥應該重複出現,有多少個顔色分量(字段⑤),就出現多少次(一般為3次)。

DHT,Difine Huffman Table,定義哈夫曼表

标記代碼                                 2位元組            固定值0xFFC4

包含2個具體字段:

 ①資料長度                             2位元組            字段①和多個字段②的總長度

                                                                   即不包括标記代碼,但包括本字段

 ② 哈夫曼表              資料長度-2位元組

a)表ID和表類型            1位元組            高4位:類型,隻有兩個值可選

                                                                     0:DC直流;1:AC交流

                                                        低4位:哈夫曼表ID,

                                                                     注意,DC表和AC表分開編碼

b)不同位數的碼字數量    16位元組

c)編碼内容       16個不同位數的碼字數量之和(位元組)

本标記段中,字段②可以重複出現(一般4次),也可以緻出現1次。例如,Adobe Photoshop 生成的JPEG圖檔檔案中隻有1個DHT标記段,裡邊包含了4個哈夫曼表;而Macromedia Fireworks生成的JPEG圖檔檔案則有4個DHT标記段,每個DHT标記段隻有一個哈夫曼表。

DRI,Define Restart Interval,定義差分編碼累計複位的間隔

标記代碼                                 2位元組     固定值0xFFDD

包含2個具體字段:

 ①資料長度                             2位元組     固定值0x0004,①~②兩個字段的總長度

                                                            即不包括标記代碼,但包括本字段

 ②MCU塊的單元中的重新開始間隔

                                              2位元組     設其值為n,則表示每n個MCU塊就有一個

                                                           RSTn标記。第一個标記是RST0,第二個是

                                                            RST1等,RST7後再從RST0重複。

如果沒有本标記段,或間隔值為0時,就表示不存在重開始間隔和标記RST

SOS,Start of Scan,掃描開始 12位元組

标記代碼                          2位元組     固定值0xFFDA

包含2個具體字段:

 ①資料長度                      2位元組     ①~④兩個字段的總長度

                                                     即不包括标記代碼,但包括本字段

 ②顔色分量數                 1位元組     應該和SOF中的字段⑤的值相同,即:

                                                     1:灰階圖是;3: YCrCb或YIQ;4:CMYK。

                                                         而JFIF中使用YCrCb,故這裡顔色分量數恒為3

   ③顔色分量資訊

        a) 顔色分量ID           1位元組

        b) 直流/交流系數表号 1位元組     高4位:直流分量使用的哈夫曼樹編号

                                                        低4位:交流分量使用的哈夫曼樹編号

 ④ 壓縮圖像資料

        a)譜選擇開始                     1位元組     固定值0x00

        b)譜選擇結束                     1位元組     固定值0x3F

        c)譜選擇                            1位元組     在基本JPEG中總為00

本标記段中,字段③應該重複出現,有多少個顔色分量(字段②),就出現多少次(一般為3次)。本段結束後,緊接着就是真正的圖像資訊了。圖像資訊直至遇到一個标記代碼就自動結束,一般就是以EOI标記表示結束。

EOI,End of Image,圖像結束 2位元組

标記代碼                   2位元組     固定值0xFFD9

這裡補充說明一下,由于在JPEG檔案中0xFF具有标志性的意思,是以在壓縮資料流(真正的圖像資訊)中出現0xFF,就需要作特别處理。具體方法是,在資料0xFF後添加一個沒有意義的0x00。換句話說,如果在圖像資料流中遇到0xFF,應該檢測其緊接着的字元,如果是

1)0x00,則表示0xFF是圖像流的組成部分,需要進行譯碼;

2)0xD9,則與0xFF組成标記EOI,則圖像流結束,同時圖像檔案結束;

3)0xD0~0xD7,則組成RSTn标記,則要忽視整個RSTn标記,即不對目前0xFF和緊接的0xDn兩個位元組進行譯碼,并按RST标記的規則調整譯碼變量;

3)0xFF,則忽視目前0xFF,對後一個0xFF再作判斷;

4)其他數值,則忽視目前0xFF,并保留緊接的此數值用于譯碼。

為了造福大衆,我把自己定義的檔案頭結構體給他家參考一下,歡迎讨論~

typedef struct APP0                            //應用程式保留标記0

{

    //char    value[2];                        //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char    symbol[5];                        //辨別符

    unsigned char    version[2];                        //版本号

    unsigned char    density;                        //X和Y的密度機關

    unsigned char    x_density[2];                    //X方向像素密度

    unsigned char    y_density[2];                    //Y方向像素密度

    unsigned char    x_num;                            //縮略圖水準像素數目

    unsigned char    y_num;                            //縮略圖垂直像素數目

    unsigned char*    RGB_bitmap;                        //縮略圖RGB位圖 

}APP0; APP0 app0;

typedef struct APPn                            //應用程式保留标記n,其中n=1~15(任選)

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char*    info;                            //詳細資訊,資料長度-2位元組

}APPn; APPn appn;

typedef struct DQT                                    //定義量化表

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char*    table;                            //量化表,資料長度-2位元組

                                                    //a.精度及量化表ID   1位元組            

                                                    //高4位:精度,隻有兩個可選值,0:8位;1:16位

                                                    //低4位:量化表ID,取值範圍為0~3

                                                    //b.表項(64×(精度 + 1))位元組

                                                    //例如8位精度的量化表,其表項長度為64×(0 + 1) = 64位元組

}DQT; DQT dqt;

typedef struct SOF0                                    //幀圖像開始

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char    accuracy;                        //精度

    unsigned char    height[2];                        //圖像高度

    unsigned char    width[2];                        //圖像寬度

    unsigned char    color;                            //顔色分量數

    unsigned char*    color_info;                        //顔色分量資訊

}SOF0; SOF0 sof0;

typedef struct DHT                                    //定義哈夫曼表

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char*    H_table;                        //哈夫曼表,資料長度-2位元組

                                                    //a.表ID和表類型,1位元組,

                                                    //高4位:0:DC直流;1:AC交流

                                                    //低4位:哈夫曼表ID,注意,DC表和AC表分開編碼

                                                    //b.不同位數的碼字數量,16位元組

                                                    //c.編碼内容,16個不同位數的碼字數量之和(位元組)

}DHT; DHT dht;

typedef struct DRI                                    //定義差分編碼累計複位的間隔

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char    interval[2];                    //MCU塊的單元中的重新開始間隔

                                                    //設其值為n,則表示每n個MCU塊就有一個RSTn标記。

}DRI; DRI dri;

typedef struct SOS                                    //掃描開始,12位元組

{

    //char    value[2];                                //标記代碼

    unsigned char    d_length[2];                    //資料長度

    unsigned char    color;                            //顔色分量數

    unsigned char*    color_info;                        //顔色分量資訊

    unsigned char    image_data[3];                    //壓縮圖像資料

}SOS; SOS sos;

繼續閱讀