DHT Huffuman表格式
--------------------------------------------------------------------------
名称 字节数 值 说明
--------------------------------------------------------------------------
段标识 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个数的和
--------------------------------------------------------------------------
读取Huffman表
FF C4 01 A2 00 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B
FF C4:Huffman表识别码
01 A2:DHT表长度(01~0B的字节数)
00:4bit=0,为DC表;低3bit=0,HT号为0;表示DC直流0号表
00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00:DHT不同bits位数的码字数量,数据之和表示叶子节点数目:1+5+1+1+1+1+1+1 = 12;
00 01 02 03 04 05 06 07 08 09 0A 0B:编码内容,即每个叶子节点下的编码值
构建Huffman树
读取到Huffman表的数据之后,就需要构建Huffman树了。其具体规则如下:
(a)第一个编码的数字必定为0;如果第一个编码的位数为1,就被编码为0;如果第一个编码的位数为2,就被编码为00;如果第一个编码的位数为3,就被编码为000。。。
(b)从第二个编码开始,如果它和它前面编码具有相同的位数,则当前编码是它前面的编码加1;如果它的编码位数比它前面的编码位数大,则当前编码时它前面的编码加1之后再在后面添加若干个0,直到满足编码位数的长度为止。
还是以上面的数据00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00为例:
第1个字节00表示没有位数为1的编码;
第2个字节01表示位数为2的编码有2个;由于没有位数为1的编码,因此这里位数为2的编码中的第一个为00;
第3个字节05表示位数为3的编码有5个;因此,这里位数为3的编码中的第一个为00+1=01,然后添加1个“0”,得到010;位数为3的编码中的第二个为010+1=011;第三个为011+1=100;第四个为100+1=101;第五个为101+1=110;
第4个字节01表示位数为4的编码有1个;因此,这里位数为4的编码中的第一个为110+1=111,然后添加1个“0”,得到1110;
第5个字节01表示位数为5的编码有1个;因此,这里位数为5的编码中的第一个为1110+1=1111,然后添加1个“0”,得到11110;
依次类推,得到如下Huffman树,表1:
Y(luminance亮度)-DC
|
||||||||||||||||
序号(bits位数) |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
相同Bits位的个数 |
0 |
1 |
5 |
1 |
1 |
1 |
1 |
1 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
说明 |
没有位数为1的编码 | 1个2bits |
5个3bits |
1个4bits |
1个5bits |
1个6bits |
1个7bits |
1个8bits |
1个9bits |
没有位数为10的编码 |
没有位数为11的编码 |
没有位数为12的编码 |
没有位数为13的编码 |
没有位数为14的编码 |
没有位数为15的编码 |
没有位数为16的编码 |
码字(二进制) |
无 |
00 |
(00+1)<<1 ==> 010 011 100 101 110 |
(110+1)<<1 ==> 1110 |
(1110+1)<<1 ==> 1111 0 |
(11110+1)<<1 ==> 1111 10 |
(111110+1)<<1 ==> 1111 110 |
(1111110+1)<<1 ==> 1111 1110 |
(11111110+1)<<1 ==> 1111 1111 0 |
无 |
无 |
无 |
无 |
无 |
无 |
无 |
根据Huffman树,建立DHT权值与实际保存数据与DCT量化后数据 表2,查此表可以对jpeg做解码:
序号 |
Bits位数 |
码字长度 |
码字 |
DHT权值 |
Size(数值bits宽度) |
Additionnal Bits (实际保存的数据) |
DC-value(DCT量化后的数据) |
|||
1 |
2bits |
2 |
00 |
0x0 |
0x00 |
0 |
0 |
|||
2 |
3bits |
3 |
010 |
0x2 |
0x01 |
1 |
0 |
1 |
-1 |
1 |
3 |
3 |
011 |
0x3 |
0x02 |
2 |
00,01 |
10,11 |
-3,-2 |
2,3 |
|
4 |
3 |
100 |
0x4 |
0x03 |
3 |
000,001,010,011 |
100,101,110,111 |
-7,-6,-5,-4 |
4,5,6,7 |
|
5 |
3 |
101 |
0x5 |
0x04 |
4 |
0000,…,0111 |
1000,…,1111 |
-15,…,-8 |
8,…,15 |
|
6 |
3 |
110 |
0x6 |
0x05 |
5 |
0000 0,…,01111 |
1000 0,…,11111 |
-31,…,-16 |
16,…,31 |
|
7 |
4bits |
4 |
1110 |
0xE |
0x06 |
6 |
0000 00,…,011111 |
1000 00,…,111111 |
-64,…,-32 |
32,…,64 |
8 |
5bits |
5 |
1111 0 |
0x1E |
0x07 |
7 |
0000 000,… |
…,1111 111 |
-127,…,-64 |
64,…,127 |
9 |
6bits |
6 |
1111 10 |
0x3E |
0x08 |
8 |
0000 0000,… |
…,1111 1111 |
-255,…,-128 |
128,…,255 |
A |
7bits |
7 |
1111 110 |
0x7E |
0x09 |
9 |
0000 0000 0,… |
…,1111 1111 1 |
-511,…,-256 |
256,…,511 |
B |
8bits |
8 |
1111 1111 |
0xFE |
0x0A |
A |
0000 0000 00,… |
…,1111 1111 11 |
-1023,…,-512 |
512,…,1023 |
C |
9bits |
9 |
1111 1111 0 |
0x1FE |
0x0B |
B |
0000 0000 000,… |
…,1111 1111 111 |
-2047,…,-1024 |
1024,…,2047 |
高4bits:保留零的个数 低4bits:接着的数据位长 |
0n |
负数 |
正数 |
-(1<<(n+1)-1) ~ -(1< |
(1< |
|||||
DHT权值表中,高4bit表示零保留的个数,低4bit表示接着的数据位长。 |
||||||||||
Huffman:DC实际值 -> Size[编码长度] -> 权值 -> bitstring{.Len; .value;} Encode: DC实际值 -> DQT量化 -> ZigZag扫描 ->(Y:DPCM编码,CbCr)-> huffman -> write |
根据Huffman系数,或者读取Huffman系数,重建Huffman表:
static BYTE std_dc_luminance_nrcodes[17]={0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};
static BYTE std_dc_luminance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static BYTE std_dc_chrominance_nrcodes[17]={0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};
static BYTE std_dc_chrominance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
static BYTE std_ac_luminance_nrcodes[17]={0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
static BYTE std_ac_luminance_values[162]=
{ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
static BYTE std_ac_chrominance_nrcodes[17]={0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};
static BYTE std_ac_chrominance_values[162]=
{ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
依照上述重建Huffman表的方法,可得:
DHT-Y-DC |
DHT-Y-AC |
DHT-CbCr-DC |
DHT-CbCr-AC |
|||||||||
序号 |
相同Bits位数的:码字个数 |
相同bits位数:码字起始 |
相同bits位数:码字结束 |
相同Bits位数的:码字个数 |
相同bits位数:码字起始 |
相同bits位数:码字结束 |
相同Bits位数的:码字个数 |
相同bits位数:码字起始 |
相同bits位数:码字结束 |
相同Bits位数的:码字个数 |
相同bits位数:码字起始 |
相同bits位数:码字结束 |
1 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
2 |
1 |
0 |
0 |
2 |
0 |
0x1 |
3 |
0 |
0x2 |
2 |
0 |
0x1 |
3 |
5 |
0x2 |
0x6 |
1 |
0x4 |
0x4 |
1 |
0x6 |
0x6 |
1 |
0x4 |
0x4 |
4 |
1 |
0xE |
0xE |
3 |
0xA |
0xC |
1 |
0xE |
0xE |
2 |
0xA |
0xB |
5 |
1 |
0x1E |
0x1E |
3 |
0x1A |
0x1C |
1 |
0x1E |
0x1E |
4 |
0x18 |
0x1B |
6 |
1 |
0x3E |
0x3E |
2 |
0x3A |
0x3B |
1 |
0x3E |
0x3E |
4 |
0x38 |
0x3B |
7 |
1 |
0x7E |
0x7E |
4 |
0x78 |
0x7B |
1 |
0x7E |
0x7E |
3 |
0x78 |
0x7A |
8 |
1 |
0xFE |
0xFE |
3 |
0xF8 |
0xFA |
1 |
0xFE |
0xFE |
4 |
0xF6 |
0xF9 |
9 |
1 |
0x1FE |
0x1FE |
5 |
0x1F6 |
0x1FA |
1 |
0x1FE |
0x1FE |
7 |
0x1F4 |
0x1FA |
10 |
0 |
0 |
0 |
5 |
0x3F6 |
0x3FA |
1 |
0x3FE |
0x3FE |
5 |
0x3F6 |
0x3FA |
11 |
0 |
0 |
0 |
4 |
0x7F6 |
0x7F9 |
1 |
0x7FE |
0x7FE |
4 |
0x7F6 |
0x7F9 |
12 |
0 |
0 |
0 |
4 |
0xFF4 |
0xFF7 |
0 |
0 |
0 |
4 |
0xFF4 |
0xFF7 |
13 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
14 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0x3FE0 |
0x3FE0 |
15 |
0 |
0 |
0 |
1 |
0x7FC0 |
0x7FC0 |
0 |
0 |
0 |
2 |
0x7FC2 |
0x7FC3 |
1) 将待解码数据转换成二进制的数据流;
2) 遍历表Huffman_size、Huffman_code,从待解码二进制数据流中寻找到长度与Huffman_size相等,内容与Huffman_code相等的二进制数据段,并记录下表的ID(即:是在表的第几个数据中寻找到的);
3) 将此ID 值除以16,其商为cnt(指之前有cnt个0),其余数即为取数长度Len;
4) 在二进制的数据流中,从与Huffman_code相同的数据流后,开始取数,取数长度为第3步得到的Len,假设取得的数据为data;
5) 根据data的值,转换得到相应的解码数据de_data。(根据最高位,为1则为相应的数,为0则取反后的负值。例,data=100,则解码后数据de_data值为4;data=010,解码后数据de_data为-5;
6) 写上de_data的值,并在前面添加上cnt个0。至此,解码完成。
示例数据讲解:
长度01 A2后面的字节: 00 表示Y-DC, tablenum=0; 10表示Y-AC, tablenum=1;01表示Cb-DC,tablenum=2;11表示Cb-AC,tablenum=3;
后面的数据依次是bits位数的个数表,bits位数表(码表);
根据这个重建Huffman表,得到size与code表;
DHT后面是SOS数据,实际的数据流从E2 E8 A2 8A F9 93 F7 开始
Huffman解码时,每次读取32bit数据,此次前4字节数据为E2 E8 A2 8A,转换城二进制数据为:
1110 0010 1110 1000 1010 0010 10000 1010
首次编码的数据一定是Y-DC,所以这里可跟表2匹配:匹配二进制数据的长度与Huffman_size相等,内容与Huffman_code相等的二进制数据段,记录下Huffman的ID号,此时匹配上的1110, 码字长度为4,对应的DHT权值为6,即后面需要读取6 bits数据(001011)作为该组数据,对应的实际DCT量化后的数据值为-53。【(001011对应10进制数据为11) 故数据为:11- (1<<6) ==> -53 】,此次计算共用的bit位数为4+6 = 10,所以下一组数据从偏移10bits开始,依次类推,可得出下如下数据:
1110 0010 11 101 0001 010 0 010 1 0000 1010
二进制数据 | 1110 0010 11 | 101 0001 | 010 0 | 010 1 | 00 | 00 | 1010 后面读byte数据,补足32bit,再做Huffman解码,如: 1010 (F9)(93) (F7) |
... |
实际数值 | -53 | -14 | -1 | 1 | 0 | 0 | ... | |
说明 | 4bits码字,6bits数据 | 3bits码字,4bits数据 | 3bits码字,1bits数据 | 3bits码字,1bits数据 | 2bits数据 | ... |
当数据长度不够时,可从后面读取byte的数据以填充,以补足32 bits数据做Huffman解码。
Y-AC,Cb-DC,Cb-AC也依次类推得到相应的数据值。