如何从DEFLATE重建动态霍夫曼树

时间:2018-11-04 19:07:27

标签: huffman-code deflate

该问题与RFC-1951的3.2.7节有关,是重建动态霍夫曼树。

每个代码都由一系列代码长度定义,这样,给定位长的所有代码都具有按字典顺序连续的值。

例如,这是一个rgb(255,0,0)50x50 png,其中IDAT是DEFLATE中的动态霍夫曼树。

0000024: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx  CIDATx
000002a: xxxxxxxx 11101101 11001111 00110001 00010001 00000000  ...1..
0000030: 00000000 00001000 00000000 10100001 11101111 01011111  ....._
0000036: 01011010 00110011 10111000 01111010 00001100 00000100  Z3.z..
000003c: 10100000 10101001 11111001 00100000 00010001 00010001  ... ..
0000042: 00010001 00010001 00010001 00010001 00010001 00010001  ......
0000048: 00010001 00010001 00010001 00010001 00010001 00010001  ......
000004e: 00010001 00010001 00010001 00010001 00010001 00010001  ......
0000054: 00010001 00010001 00010001 00010001 00010001 00010001  ......
000005a: 00010001 00010001 00010001 00010001 00010001 00010001  ......
0000060: 00010001 00010001 00010001 00010001 00010001 10010001  ......
0000066: 10001011 00000101 10110000 00110011 01110101 10010110  ...3u.
000006c: 01111001 11000101 00011100 10110001 00000000 00000000  y.....
0000072: 00000000 00000000 01001001 01000101 01001110 01000100  ..

infgen产生以下标头:

last
dynamic
litlen 0 2
litlen 255 4
litlen 256 4
litlen 274 4
litlen 283 4
litlen 285 1
dist 3 1
dist 15 1

...目标是了解重建动态树的位和过程...


前三位描述DEFLATE头。

101 <- last block bit, tree type is dynamic. 

接下来的14位描述HLIT,HDIST和HCLEN。

11101 <- HLIT,  29 + 257 = 286 
01111 <- HDIST, 15 + 1 = 16
1110 <- HCLEAN, 14 + 4 = 18

这些值对动态霍夫曼树有何描述?


接下来,一次读取三位并遵循置换表...发现长度为...

Lengths: [4, 2, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 2]puff.c的第697行)

这些长度是否用于定义文字?

3 个答案:

答案 0 :(得分:0)

  

这些值对动态霍夫曼树有何描述?

它们并没有真正告诉您有关树的更多信息,而是在动态标头的后续位中描述了每种类型的代码有多少个符号。

接下来提供十八个编码长度的代码长度(每个三位),然后是286个文字/长度编码,然后是十六个距离编码,所有编码都使用该编码进行编码长度代码。

  

这些长度用于定义文字吗?

不。三位长度用于代码长度代码。您只需构建该代码即可读取以下文字/长度和距离代码长度,这些长度本身就是使用该代码压缩的。

这在RFC 1951的3.2.7节中进行了描述:

“为获得更大的紧凑性,使用霍夫曼码对代码长度序列本身进行压缩。”

答案 1 :(得分:0)

标题包含Deflate Literal(0-255),Length(256-285)和Distance码(0-29)的位长。如果知道它们的位长,则可以按照RFC1951第3.2.2节中的算法重建树。寻找以“计算每个代码长度的代码数量...”开头的步骤

但是,位长度值也使用0到7位通过霍夫曼编码。您需要首先使用与上述相同的算法在开始时打开HCLEN表。第3.2.7节对此进行了说明。

为什么要对标题进行两次这样的编码?使动态Huffman标头变小。

答案 2 :(得分:0)

更多信息...接下来的14位是...

5 Bits of HLIT, the Literal/Length codes - 257 (257 - 286)
5 Bits of HDIST, the Distance codes - 1        (1 - 32)
4 Bits of HCLEN, the Code Length codes - 4     (4 - 19)

From the example:
  HLIT => 29 + 257 = 286, HDIST => 15 + 1 = 16, HCLEN => 14 + 4 = 18

现在收集3位值HCLEN次。遵循排列表的顺序(RFC-1951中的第13页。)

permuted ordering: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]

From the example: 
   HCLEN is 18 => 18*3 = 54-bits.
   lengths: [ 4 2 4 0 2 0 0 0 0 0 0 0 0 0 0 0 0 3 2 ]

接下来解压缩那些三位值。此解压缩过程提供了有关如何构造动态霍夫曼树的说明……“为获得更大的紧凑性,使用霍夫曼代码压缩了代码长度序列本身。”

To unpack the triple-bit values: (examples below)
  1. Count the number occurrences of the values.
  2. Determine the offset, the count plus the previous offset.
  3. Determine the symbols. 
     A symbol is placed at the offset value, which is found at a length value. 
     After placing a symbol, increment the offset.


From the example: 
    LENGTHS: [ 4 2 4 0 2 0 0 0 0 0 0 0 0 0 0 0 0 3 2 ] //the three-bits from HCLEN
    COUNT: [ 13 0 3 1 2 0 0 0 0 0 0 0 0 0 0 0 ] //the occurrences of lengths.
      i.e, 0 occurs 13 times, 1 occurs 0 times, 2 occurs 3 times...
    OFFSET: [ x 0 0 3 4 6 6 6 6 6 6 6 6 6 6 6 ] //the count plus the previous offset.
      i.e, o[2] = 0 + 3, o[3] = 3 + 1, o[4] = 4 + 0...
    SYMBOL: [ 1 4 18 17 0 2 ] //use length to index offset to place symbol
      i.e, if i=1, s[off[len[i]]] = s[off[len[2]]] => s[off[0]] => s[0] = 1, increment off[0]...

...现在定义了符号。接下来解码位以构建动态霍夫曼树……