JPEG 壓縮簡(jiǎn)介
-------------

1. 色彩模型

JPEG 的圖片使用的是 YCrCb 顏色模型, 而不是計(jì)算機(jī)上最常用的 RGB. 關(guān)于色
彩模型, 這里不多闡述. 只是說(shuō)明, YCrCb 模型更適合圖形壓縮. 因?yàn)槿搜蹖?duì)圖片上
的亮度 Y 的變化遠(yuǎn)比色度 C 的變化敏感. 我們完全可以每個(gè)點(diǎn)保存一個(gè) 8bit 的亮
度值, 每 2x2 個(gè)點(diǎn)保存一個(gè) Cr Cb 值, 而圖象在肉眼中的感覺(jué)不會(huì)起太大的變化. 
所以, 原來(lái)用 RGB 模型, 4 個(gè)點(diǎn)需要 4x3=12 字節(jié). 而現(xiàn)在僅需要 4+2=6 字節(jié); 平
均每個(gè)點(diǎn)占 12bit. 當(dāng)然 JPEG 格式里允許每個(gè)點(diǎn)的 C 值都記錄下來(lái); 不過(guò) MPEG 里
都是按 12bit 一個(gè)點(diǎn)來(lái)存放的, 我們簡(jiǎn)寫(xiě)為 YUV12.

[R G B] -> [Y Cb Cr] 轉(zhuǎn)換
-------------------------

(R,G,B 都是 8bit unsigned)

| Y | | 0.299 0.587 0.114 | | R | | 0 |
| Cb | = |- 0.1687 - 0.3313 0.5 | * | G | + |128|
| Cr | | 0.5 - 0.4187 - 0.0813| | B | |128|

Y = 0.299*R + 0.587*G + 0.114*B (亮度)
Cb = - 0.1687*R - 0.3313*G + 0.5 *B + 128
Cr = 0.5 *R - 0.4187*G - 0.0813*B + 128

[Y,Cb,Cr] -> [R,G,B] 轉(zhuǎn)換
-------------------------

R = Y + 1.402 *(Cr-128)
G = Y - 0.34414*(Cb-128) - 0.71414*(Cr-128)
B = Y + 1.772 *(Cb-128)


一般, C 值 (包括 Cb Cr) 應(yīng)該是一個(gè)有符號(hào)的數(shù)字, 但這里被處理過(guò)了, 方法
是加上了 128. JPEG 里的數(shù)據(jù)都是無(wú)符號(hào) 8bit 的.

2. DCT (離散余弦變換)

JPEG 里, 要對(duì)數(shù)據(jù)壓縮, 先要做一次 DCT 變換. DCT 變換的原理, 涉及到數(shù)學(xué)
知識(shí), 這里我們不必深究. 反正和傅立葉變換(學(xué)過(guò)高數(shù)的都知道) 是差不多了. 經(jīng)過(guò)
這個(gè)變換, 就把圖片里點(diǎn)和點(diǎn)間的規(guī)律呈現(xiàn)出來(lái)了, 更方便壓縮.JPEG 里是對(duì)每 8x8 
個(gè)點(diǎn)為一個(gè)單位處理的. 所以如果原始圖片的長(zhǎng)寬不是 8 的倍數(shù), 都需要先補(bǔ)成 8 
的倍數(shù), 好一塊塊的處理. 另外, 記得剛才我說(shuō)的 Cr Cb 都是 2x2 記錄一次嗎? 所
以大多數(shù)情況, 是要補(bǔ)成 16x16 的整數(shù)塊.按從左到右, 從上到下的次序排列 (和我
們寫(xiě)字的次序一樣). JPEG 里是對(duì) Y Cr Cb 分別做 DCT 變換的.

JPEG 編碼時(shí)使用的是 Forward DCT (FDCT) 解碼時(shí)使用的 Inverse DCT (IDCT)
下面給出公式:

FDCT:
c(u,v) 7 7 2*x+1 2*y+1
F(u,v) = --------- * sum sum f(x,y) * cos (------- *u*PI)* cos (------ *v*PI)
4 x=0 y=0 16 16

u,v = 0,1,...,7

{ 1/2 當(dāng) u=v=0 時(shí)
c(u,v) = {
{ 1 其他情況


IDCT:
1 7 7 2*x+1 2*y+1
f(x,y) = --- * sum sum c(u,v)*F(u,v)*cos (------- *u*PI)* cos (------ *v*PI)
4 u=0 v=0 16 16

x,y=0,1...7

這個(gè)步驟很花時(shí)間, 另外有種 AA&N 優(yōu)化算法, 大家可以去 inet 自己找一下. 
在 Intel 主頁(yè)上可以找到 AA&N IDCT 的 MMX 優(yōu)化代碼.

3. 重排列 DCT 結(jié)果
DCT 將一個(gè) 8x8 的數(shù)組變換成另一個(gè) 8x8 的數(shù)組. 但是內(nèi)存里所有數(shù)據(jù)都是線
形存放的, 如果我們一行行的存放這 64 個(gè)數(shù)字, 每行的結(jié)尾的點(diǎn)和下行開(kāi)始的點(diǎn)就
沒(méi)有什么關(guān)系, 所以 JPEG 規(guī)定按如下次序整理 64 個(gè)數(shù)字.

 0, 1, 5, 6,14,15,27,28,
 2, 4, 7,13,16,26,29,42,
 3, 8,12,17,25,30,41,43,
 9,11,18,24,31,40,44,53,
10,19,23,32,39,45,52,54,
20,22,33,38,46,51,55,60,
21,34,37,47,50,56,59,61,
35,36,48,49,57,58,62,63


這樣數(shù)列里的相鄰點(diǎn)在圖片上也是相鄰的了.

4. 量化
對(duì)于前面得到的 64 個(gè)空間頻率振幅值, 我們將對(duì)它們作幅度分層量化操作.方
法就是分別除以量化表里對(duì)應(yīng)值并四舍五入.

for (i = 0 ; i<=63; i++ )
    vector[i] = (int) (vector[i] / quantization_table[i] + 0.5)


下面有張 JPEG 標(biāo)準(zhǔn)量化表. (按上面同樣的彎曲次序排列)

16 11 10 16  24  40  51 61
12 12 14 19  26  58  60 55
14 13 16 24  40  57  69 56
14 17 22 29  51  87  80 62
18 22 37 56  68 109 103 77
24 35 55 64  81 104 113 92
49 64 78 87 103 121 120 101
72 92 95 98 112 100 103 99


這張表依據(jù)心理視覺(jué)閥制作, 對(duì) 8bit 的亮度和色度的圖象的處理效果不錯(cuò).
當(dāng)然我們可以使用任意的量化表. 量化表是定義在 jpeg 的 DQT 標(biāo)記后. 一般
為 Y 值定義一個(gè), 為 C 值定義一個(gè). 
量化表是控制 JPEG 壓縮比的關(guān)鍵. 這個(gè)步驟除掉了一些高頻量, 損失了很高
細(xì)節(jié). 但事實(shí)上人眼對(duì)高空間頻率遠(yuǎn)沒(méi)有低頻敏感.所以處理后的視覺(jué)損失很小.
另一個(gè)重要原因是所有的圖片的點(diǎn)與點(diǎn)之間會(huì)有一個(gè)色彩過(guò)渡的過(guò)程. 大量的圖象
信息被包含在低空間頻率中. 經(jīng)過(guò)量化處理后, 在高空間頻率段, 將出現(xiàn)大量連續(xù)
的零.

5. 0 RLC 編碼
現(xiàn)在我們矢量中有許多連續(xù)的 0. 我們可以使用 RLC 來(lái)壓縮掉這些 0. 這里我們
將跳過(guò)第一個(gè)矢量 (后面將解釋為什么) 因?yàn)樗木幋a比較特別. 假設(shè)有一組矢量
(64 個(gè)的后 63 個(gè)) 是
57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,..,0
經(jīng)過(guò) RLC 壓縮后就是
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB
EOB 是一個(gè)結(jié)束標(biāo)記, 表示后面都是 0 了. 實(shí)際上, 我們用 (0,0) 表示 EOB
但是, 如果這組數(shù)字不以 0 結(jié)束, 那么就不需要 EOB.
由于后面 huffman 編碼的要求, 每組數(shù)字前一個(gè)表示 0 的數(shù)量的必須是 4 bit,
就是說(shuō), 只能是 0~15, 所以我們實(shí)際這樣編碼:
(0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)
注意 (15,0) 表示了 16 個(gè)連續(xù)的 0.

6. huffman 編碼
為了提高儲(chǔ)存效率, JPEG 里并不直接保存數(shù)值, 而是將數(shù)值按位數(shù)分成 16 組:

數(shù)值 組 實(shí)際保存值
0 0 -
-1,1 1 0,1
-3,-2,2,3 2 00,01,10,11
-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111
-15,..,-8,8,..,15 4 0000,..,0111,1000,..,1111
-31,..,-16,16,..,31 5 00000,..,01111,10000,..,11111
-63,..,-32,32,..,63 6 .
-127,..,-64,64,..,127 7 .
-255,..,-128,128,..,255 8 .
-511,..,-256,256,..,511 9 .
-1023,..,-512,512,..,1023 10 .
-2047,..,-1024,1024,..,2047 11 .
-4095,..,-2048,2048,..,4095 12 .
-8191,..,-4096,4096,..,8191 13 .
-16383,..,-8192,8192,..,16383 14 .
-32767,..,-16384,16384,..,32767 15 .


還是來(lái)看前面的例子:
(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)
只處理每對(duì)數(shù)右邊的那個(gè):
57 是第 6 組的, 實(shí)際保存值為 111001 , 所以被編碼為 (6,111001)
45 , 同樣的操作, 編碼為 (6,101101)
23 -> (5,10111)
-30 -> (5,00001)
-8 -> (4,0111)
1 -> (1,1)


前面的那串?dāng)?shù)字就變成了:
(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;
(2,1), 1 ; (0,0)

括號(hào)里的數(shù)值正好合成一個(gè)字節(jié). 后面被編碼的數(shù)字表示范圍是 -32767..32767.
合成的字節(jié)里, 高 4 位是前續(xù) 0 的個(gè)數(shù), 低 4 位描述了后面數(shù)字的位數(shù).

繼續(xù)剛才的例子, 如果 06 的 huffman 編碼為 111000
69 = (4,5) --- 1111111110011001
21 = (1,5) --- 11111110110
4 = (0,4) --- 1011
33 = (2,1) --- 11011
0 = EOB = (0,0) --- 1010


那么最后對(duì)于前面的例子表示的 63 個(gè)系數(shù) (記得我們將第一個(gè)跳過(guò)了嗎?) 按位流
寫(xiě)入 JPG 文件中就是這樣的:
111000 111001 111000 101101 1111111110011001 10111 11111110110 00001
1011 0111 11011 1 1010


DC 的編碼
---------
記得剛才我們跳過(guò)了每組 64 個(gè)數(shù)據(jù)的第一個(gè)吧, DC 就是指的這個(gè)數(shù)字 (后面 63 
個(gè)簡(jiǎn)稱 AC) 代入前面的 FDCT 公式可以得到
c(0,0) 7 7 
DC = F(0,0) = --------- * sum sum f(x,y) * cos 0 * cos 0 其中 c(0,0) = 1/2
4 x=0 y=0 

1 7 7 
= --- * sum sum f(x,y) 
8 x=0 y=0 


即一塊圖象樣本的平均值. 就是說(shuō), 它包含了原始 8x8 圖象塊里的很多能量. (通常
會(huì)得到一個(gè)很大的數(shù)值)

JPEG 的作者指出連續(xù)塊的 DC 率之間有很緊密的聯(lián)系, 因此他們決定對(duì) 8x8 塊的
DC 值的差別進(jìn)行編碼. (Y, Cb, Cr 分別有自己的 DC)

Diff = DC(i) - DC(i-1)

所以這一塊的 DC(i) 就是: DC(i) = DC(i-1) + Diff

JPG 從 0 開(kāi)始對(duì) DC 編碼, 所以 DC(0)=0. 然后再將當(dāng)前 Diff 值加在上一個(gè)值上得
到當(dāng)前值.

下面再來(lái)看看上面那個(gè)例子: (記住我們保存的 DC 是和上一塊 DC 的差值 Diff)

例如上面例子中, Diff 是 -511, 就編碼成

(9, 000000000)

如果 9 的 Huffman 編碼是 1111110 (在 JPG 文件中, 一般有兩個(gè) Huffman 表, 一
個(gè)是 DC 用, 一個(gè)是 AC 用) 那么在 JPG 文件中, DC 的 2 進(jìn)制表示為

1111110 000000000

它將放在 63 個(gè) AC 的前面, 上面上個(gè)例子的最終 BIT 流如下:

1111110 000000000 111000 111001 111000 101101 1111111110011001 10111
11111110110 00001 1011 0111 11011 1 1010

下面簡(jiǎn)單敘述一下針對(duì)一個(gè)數(shù)據(jù)單元的圖片 Y 的解碼
-----------------------------------------------

在整個(gè)圖片解碼的開(kāi)始, 你需要先初始化 DC 值為 0.

1) 先解碼 DC:
a) 取得一個(gè) Huffman 碼 (使用 Huffman DC 表)
b) Huffman解碼, 看看后面的數(shù)據(jù)位數(shù) N
c) 取得 N 位, 計(jì)算 Diff 值
d) DC + = Diff
e) 寫(xiě)入 DC 值: " vector[0]=DC "

2) 解碼 63 個(gè) AC:

------- 循環(huán)處理每個(gè) AC 直到 EOB 或者處理到 64 個(gè) AC

a) 取得一個(gè) Huffman 碼 (使用 Huffman AC 表)
b) Huffman 解碼, 得到 (前面 0 數(shù)量, 組號(hào))
[記住: 如果是(0,0) 就是 EOB 了]

c) 取得 N 位(組號(hào)) 計(jì)算 AC
d) 寫(xiě)入相應(yīng)數(shù)量的 0
e) 接下來(lái)寫(xiě)入 AC
-----------------

下一步的解碼
------------
上一步我們得到了 64 個(gè)矢量. 下面我們還需要做一些解碼工作:

1) 反量化 64 個(gè)矢量 : "for (i=0;i<=63;i++) vector[i]*=quant[i]"
2) 重排列 64 個(gè)矢量到 8x8 的塊中
3) 對(duì) 8x8 的塊作 IDCT

對(duì) 8x8 塊的 (Y,Cb,Cr) 重復(fù)上面的操作 [Huffman 解碼, 步驟 1), 2), 3)]

4) 將所有的有符號(hào)的 8bit 數(shù)加上 128
5) 轉(zhuǎn)換 YCbCr 到 RGB

JPG 文件(Byte 級(jí))里怎樣組織圖片信息
-----------------------------------
注意 JPEG/JFIF 文件格式使用 Motorola 格式, 而不是 Intel 格式, 就是說(shuō), 如果
是一個(gè)字的話, 高字節(jié)在前, 低字節(jié)在后.

JPG 文件是由一個(gè)個(gè)段 (segments) 構(gòu)成的. 每個(gè)段長(zhǎng)度 <=65535. 每個(gè)段從一個(gè)標(biāo)
記字開(kāi)始. 標(biāo)記字都是 0xff 打頭的, 以非 0 字節(jié)和 0xFF 結(jié)束. 例如 'FFDA' , 
'FFC4', 'FFC0'. 每個(gè)標(biāo)記有它特定意義, 這是由第2字節(jié)指明的. 例如, SOS (Start
Of Scan = 'FFDA') 指明了你應(yīng)該開(kāi)始解碼. 另一個(gè)標(biāo)記 DQT (Define Quantization
Table = 0xFFDB) 就是說(shuō)它后面有 64 字節(jié)的 quantization 表

在處理 JPG 文件時(shí), 如果你碰到一個(gè) 0xFF, 而它后面的字節(jié)不是 0, 并且這個(gè)字節(jié)
沒(méi)有意義. 那么你遇到的 0xFF 字節(jié)必須被忽略. (一些 JPG 里, 常用用 0xFF 做某
些填充用途) 如果你在做 huffman 編碼時(shí)碰巧產(chǎn)生了一個(gè) 0xFF, 那么就用 0xFF 
0x00 代替. 就是說(shuō)在 jpeg 圖形解碼時(shí)碰到 FF00 就把它當(dāng)作 FF 處理.

另外在 huffman 編碼區(qū)域結(jié)束時(shí), 碰到幾個(gè) bit 沒(méi)有用的時(shí)候, 應(yīng)該用 1 去填充.
然后后面跟 FF.

下面是幾個(gè)重要的標(biāo)記
--------------------

SOI = Start Of Image = 'FFD8'
這個(gè)標(biāo)記只在文件開(kāi)始出現(xiàn)一次
EOI = End Of Image = 'FFD9'
JPG 文件都以 FFD9 結(jié)束

RSTi = FFDi ( i = 0..7) [ RST0 = FFD0, RST7=FFD7]
= 復(fù)位標(biāo)記
通常穿插在數(shù)據(jù)流里, 我想是擔(dān)心 JPG 解碼出問(wèn)題吧(應(yīng)該配合 DRI 使用). 不過(guò)很
多 JPG 都不使用它

(SOS --- RST0 --- RST1 -- RST2 --...
...-- RST6 --- RST7 -- RST0 --...)

----
標(biāo)記
----
下面是必須處理的標(biāo)記

SOF0 = Start Of Frame 0 = FFC0
SOS = Start Of Scan = FFDA
APP0 = it's the marker used to identify a JPG file which uses the JFIF
specification = FFE0
COM = Comment = FFFE
DNL = Define Number of Lines = FFDC
DRI = Define Restart Interval = FFDD
DQT = Define Quantization Table = FFDB
DHT = Define Huffman Table = FFC4

JPG 文件中 Haffman 表的儲(chǔ)存
---------------------------
JPEG 里定義了一張表來(lái)描述 Haffman 樹(shù). 定義在 DHT 標(biāo)記后面. 注意: Haffman 
代碼的長(zhǎng)度限制在 16bit 內(nèi).

一般一個(gè) JPG 文件里會(huì)有 2 類 Haffman 表: 一個(gè)用于 DC 一個(gè)用于 AC (實(shí)際有 4
個(gè)表, 亮度的 DC,AC 兩個(gè), 色度的 DC,AC 兩個(gè))

這張表是這樣保存的:
1) 16 字節(jié):
第 i 字節(jié)表示了 i 位長(zhǎng)的 Huffman 代碼的個(gè)數(shù) (i= 1 到 16)

2) 這表的長(zhǎng)度 (字節(jié)數(shù)) = 這 16 個(gè)數(shù)字之和
現(xiàn)在你可以想象這張表怎么存放的吧? 對(duì)應(yīng)字節(jié)就是對(duì)應(yīng) Haffman 代碼等價(jià)數(shù)字. 我
不多解釋, 這需要你先了解 Haffman 算法. 這里只舉一個(gè)例子:

Haffman 表的表頭是 0,2,3,1,1,1,0,1,0,0,0,0,0,0,0,0
就是說(shuō)長(zhǎng)度為 1 的代碼沒(méi)有
長(zhǎng)度為 2 的代碼為 00
01
長(zhǎng)度為 3 的代碼是 100
101
110
長(zhǎng)度為 4 的代碼是 1110
長(zhǎng)度為 5 的代碼是 11110
長(zhǎng)度為 6 的代碼是 111110
長(zhǎng)度為 7 的代碼沒(méi)有 (如果有一個(gè)的話應(yīng)該是 1111110)
長(zhǎng)度為 8 的代碼是 11111100
.....
后面都沒(méi)有了.

如果表下面的數(shù)據(jù)是
45 57 29 17 23 25 34 28

就是說(shuō)
45 = 00
57 = 01
29 = 100
17 = 101
23 = 110
等等...

如果你懂 Haffman 編碼, 這些不難理解

采樣系數(shù)
--------
下面講解的都是真彩 JPG 的解碼, 灰度 JPG 的解碼很簡(jiǎn)單, 因?yàn)閳D形中只有亮度信
息. 而彩色圖形由 (Y, Cr, Cb) 構(gòu)成, 前面提到過(guò), Y 通常是每點(diǎn)采樣一次, 而 Cr,
Cb 一般是 2x2 點(diǎn)采樣一次, 當(dāng)然也有的 JPG 是逐點(diǎn)采樣, 或者每?jī)牲c(diǎn)采樣 (橫向
兩點(diǎn), 縱向一點(diǎn)) 采樣系數(shù)均被定義成對(duì)比最高采樣系數(shù)的相對(duì)值. 

一般情況 (即: Y 逐點(diǎn)采樣, Cr Cb 每 2x2 點(diǎn)一次) 下: Y 有最高的采樣率, 橫向采
樣系數(shù)HY=2 縱向采樣系數(shù) VY=2; Cb 的橫向采樣系數(shù) HCb=1, 縱向采樣系數(shù) VCb=1;
同樣 HCr=1, VCr=1

在 Jpeg 里, 8x8 個(gè)原始數(shù)據(jù), 經(jīng)過(guò) RLC, Huffman 編碼后的一串?dāng)?shù)據(jù)流稱為一個(gè) 
Data Unit (DU) JPG 里按 DU 為單位的編碼次序如下:

1) for (counter_y=1;counter_y<=VY;counter_y++)
for (counter_x=1;counter_x<=HY;counter_x++)
{ 對(duì) Y 的 Data Unit 編碼 }

2) for (counter_y=1;counter_y<=VCb ;counter_y++)
for (counter_x=1;counter_x<=HCb;counter_x++)
{ 對(duì) Cb 的 Data Unit 編碼 }

3) for (counter_y=1;counter_y<=VCr;counter_y++)
for (counter_x=1;counter_x<=HCr;counter_x++)
{ 對(duì) Cr 的 Data Unit 編碼 }

按我上面的例子: (HY=2, VY=2 ; HCb=VCb =1, HCr,VCr=1) 就是這樣一個(gè)次序
YDU,YDU,YDU,YDU,CbDU,CrDU
這些就描述了一塊 16x16 的圖形. 16x16 = (Hmax*8 x Vmax*8) 這里 Hmax=HY=2 
Vmax=VY=2

一個(gè) (Hmax*8,Vmax*8) 的塊被稱作 MCU (Minimun Coded Unix) 前面例子中一個(gè) 
MCU = YDU,YDU,YDU,YDU,CbDU,CrDU

如果 HY =1, VY=1
HCb=1, VCb=1
HCr=1, VCr=1
這樣 (Hmax=1,Vmax=1), MCU 只有 8x8 大, MCU = YDU,CbDU,CrDU

對(duì)于灰度 JPG, MCU 只有一個(gè) DU (MCU = YDU)

JPG 文件里, 圖象的每個(gè)組成部分的采樣系數(shù)定義在 SOF0 (FFC0) 標(biāo)記后

簡(jiǎn)單說(shuō)一下 JPG 文件的解碼
-------------------------
解碼程序閑從 JPG 文件中讀出采樣系數(shù), 這樣就知道了 MCU 的大小, 算出整個(gè)圖象
有幾個(gè) MCU. 解碼程序再循環(huán)逐個(gè)對(duì) MCU 解碼, 一直到檢查到 EOI 標(biāo)記. 對(duì)于每個(gè)
MCU, 按正規(guī)的次序解出每個(gè) DU, 然后組合, 轉(zhuǎn)換成 (R,G,B) 就 OK 了

附:JPEG 文件格式
~~~~~~~~~~~~~~~~

- 文件頭 (2 bytes): $ff, $d8 (SOI) (JPEG 文件標(biāo)識(shí))
- 任意數(shù)量的段 , 見(jiàn)后面
- 文件結(jié)束 (2 bytes): $ff, $d9 (EOI)

段的格式:
~~~~~~~~~

- header (4 bytes):
$ff 段標(biāo)識(shí)
n 段的類型 (1 byte)
sh, sl 該段長(zhǎng)度, 包括這兩個(gè)字節(jié), 但是不包括前面的 $ff 和 n.
注意: 長(zhǎng)度不是 intel 次序, 而是 Motorola 的, 高字節(jié)在前,
低字節(jié)在后!
- 該段的內(nèi)容, 最多 65533 字節(jié)

注意:
- 有一些無(wú)參數(shù)的段 (下面那些前面注明星號(hào)的)
這些段沒(méi)有長(zhǎng)度描述 (而且沒(méi)有內(nèi)容), 只有 $ff 和類型字節(jié).
- 每一個(gè)段結(jié)束到下一個(gè) $ff 間的數(shù)據(jù)都是合法的, 必須被忽略掉.

段的類型:
~~~~~~~~~

*TEM = $01 可以忽略掉

SOF0 = $c0 幀開(kāi)始 (baseline JPEG), 細(xì)節(jié)附后
SOF1 = $c1 dito
SOF2 = $c2 通常不支持
SOF3 = $c3 通常不支持

SOF5 = $c5 通常不支持
SOF6 = $c6 通常不支持
SOF7 = $c7 通常不支持

SOF9 = $c9 arithmetic 編碼(Huffman 的一種擴(kuò)展算法), 通常不支持
SOF10 = $ca 通常不支持
SOF11 = $cb 通常不支持

SOF13 = $cd 通常不支持
SOF14 = $ce 通常不支持
SOF14 = $ce 通常不支持
SOF15 = $cf 通常不支持

DHT = $c4 定義 Huffman Table, 細(xì)節(jié)附后
JPG = $c8 未定義/保留 (引起解碼錯(cuò)誤)
DAC = $cc 定義 Arithmetic Table, 通常不支持

*RST0 = $d0 RSTn 用于 resync, 通常被忽略
*RST1 = $d1
*RST2 = $d2
*RST3 = $d3
*RST4 = $d4
*RST5 = $d5
*RST6 = $d6
*RST7 = $d7

SOI = $d8 圖片開(kāi)始
EOI = $d9 圖片結(jié)束
SOS = $da 掃描行開(kāi)始, 細(xì)節(jié)附后
DQT = $db 定義 Quantization Table, 細(xì)節(jié)附后
DNL = $dc 通常不支持, 忽略
DRI = $dd 定義重新開(kāi)始間隔, 細(xì)節(jié)附后
DHP = $de 忽略 (跳過(guò))
EXP = $df 忽略 (跳過(guò))

APP0 = $e0 JFIF APP0 segment marker (細(xì)節(jié)略)
APP15 = $ef 忽略

JPG0 = $f0 忽略 (跳過(guò))
JPG13 = $fd 忽略 (跳過(guò))
COM = $fe 注釋, 細(xì)節(jié)附后

其它的段類型都保留必須跳過(guò)

SOF0: Start Of Frame 0:
~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $c0 (SOF0)
- 長(zhǎng)度 (高字節(jié), 低字節(jié)), 8+components*3
- 數(shù)據(jù)精度 (1 byte) 每個(gè)樣本位數(shù), 通常是 8 (大多數(shù)軟件不支持 12 和 16)
- 圖片高度 (高字節(jié), 低字節(jié)), 如果不支持 DNL 就必須 >0
- 圖片寬度 (高字節(jié), 低字節(jié)), 如果不支持 DNL 就必須 >0
- components 數(shù)量(1 byte), 灰度圖是 1, YCbCr/YIQ 彩色圖是 3, CMYK 彩色圖
是 4
- 每個(gè) component: 3 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q)
- 采樣系數(shù) (bit 0-3 vert., 4-7 hor.)
- quantization table 數(shù)

DRI: Define Restart Interval:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $dd (DRI)
- 長(zhǎng)度 (高字節(jié), 低字節(jié)), 必須是 4
- MCU 塊的單元中的重新開(kāi)始間隔 (高字節(jié), 低字節(jié)),
意思是說(shuō), 每 n 個(gè) MCU 塊就有一個(gè) RSTn 標(biāo)記.
第一個(gè)標(biāo)記是 RST0, 然后是 RST1 等, RST7 后再?gòu)?RST0 重復(fù) 

DQT: Define Quantization Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $db (DQT)
- 長(zhǎng)度 (高字節(jié), 低字節(jié))
- QT 信息 (1 byte):
bit 0..3: QT 號(hào)(0..3, 否則錯(cuò)誤)
bit 4..7: QT 精度, 0 = 8 bit, 否則 16 bit
- n 字節(jié)的 QT, n = 64*(精度+1)

評(píng)論:
- 一個(gè)單獨(dú)的 DQT 段可以包含多個(gè) QT, 每個(gè)都有自己的信息字節(jié)
- 當(dāng)精度=1 (16 bit), 每個(gè)字都是高位在前低位在后

DAC: Define Arithmetic Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
法律原因, 現(xiàn)在的軟件不支持 arithmetic 編碼.
不能生產(chǎn)使用 arithmetic 編碼的 JPEG 文件

DHT: Define Huffman Table:
~~~~~~~~~~~~~~~~~~~~~~~~~~

- $ff, $c4 (DHT)
- 長(zhǎng)度 (高字節(jié), 低字節(jié))
- HT 信息 (1 byte):
bit 0..3: HT 號(hào) (0..3, 否則錯(cuò)誤)
bit 4 : HT 類型, 0 = DC table, 1 = AC table
bit 5..7: 必須是 0
- 16 bytes: 長(zhǎng)度是 1..16 代碼的符號(hào)數(shù). 這 16 個(gè)數(shù)的和應(yīng)該 <=256
- n bytes: 一個(gè)包含了按遞增次序代碼長(zhǎng)度排列的符號(hào)表
(n = 代碼總數(shù))

評(píng)論:
- 一個(gè)單獨(dú)的 DHT 段可以包含多個(gè) HT, 每個(gè)都有自己的信息字節(jié)

COM: 注釋:
~~~~~~~~~~

- $ff, $fe (COM)
- 注釋長(zhǎng)度 (高字節(jié), 低字節(jié)) = L+2
- 注釋為長(zhǎng)度為 L 的字符流

SOS: Start Of Scan:
~~~~~~~~~~~~~~~~~~~

- $ff, $da (SOS)
- 長(zhǎng)度 (高字節(jié), 低字節(jié)), 必須是 6+2*(掃描行內(nèi)組件的數(shù)量)
- 掃描行內(nèi)組件的數(shù)量 (1 byte), 必須 >= 1 , <=4 (否則是錯(cuò)的) 通常是 3
- 每個(gè)組件(部分): 2 bytes
- component id (1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), 見(jiàn) SOF0
- 使用的 Huffman 表00-1-14:
- bit 0..3: AC table (0..3)
- bit 4..7: DC table (0..3)
- 忽略 3 bytes (???)

評(píng)論:
- 圖片數(shù)據(jù) (一個(gè)個(gè)掃描行) 緊接著 SOS 段.
轉(zhuǎn)自http://dev.gameres.com/Program/Visual/Other/JPEG.htm