试图了解PNG文件中的zlib / deflate

时间:2014-09-24 13:58:08

标签: encoding png implementation deflate

我目前正在编写一个小型PNG图像I / O库,用于学习目的。我的问题如下:

我创建了一个尺寸仅为2 x 2的小PNG,并在十六进制编辑器中打开它以研究其内容。这是我使用GIMP创建的图像,并以" 9"的压缩方式存储。

(请注意,这是原始2 x 2像素图像的放大图像;))

a black, red, blue and green pixel in a two by two array of pixels.

所以我猜没有压缩,这在内存中看起来像这样:

00 00 00 FF 00 00 00 00 FF 00 FF 00

在没有Alpha通道的情况下存储。

(为清楚起见,我在此仅说明了这一点。我知道压缩,并且不希望在文件中看到这个字节模式。)

我解压缩了IDAT块并剥离了块ID(" IDAT")和尾随CRC值并得到了这个字节序列:

08 D7 05 C1 01 01 00 00 00 80 10 FF 4F 17 10 48 06 0F FE 02 FE

现在前两个字节08 D7包含有关编码块的信息。 最后四个字节0F FE 02 FE必须是ADLER32校验和。

这最终给我留下了以下字节:

05 C1 01 01 00 00 00 80 10 FF 4F 17 10 48 06

以二进制表示形式写入这些字节:

0000 0101  1100 0001  0000 0001  0000 0001
0000 0000  0000 0000  0000 0000  1000 0000
0001 0000  1111 1111  0100 1111  0001 0111
0001 0000  0100 1000  0000 0110

为了更好地理解DEFLATE,我试图解开"解包"这个序列至少在我理解它之前就已经写好了一个小工具。但是我很快被卡住了。

RFC 1951("DEFLATE Compressed Data Format Specification")指出每个编码块都以三位头开头。一位指示这是否是最后一个块以及另外两个指示压缩方法的块。由于我假设编码器在这里只使用了一个块(意思是第一个块自动是最后一个)并且使用了非静态霍夫曼树,我正在寻找比特序列" 101"但我找不到它(我也找不到其他可能的标题" 100"或" 110")。

RFC也说必须有两个两个字节值LEN和NLEN存储块的长度,其中NLEN是LEN的一个补码但是我再也找不到满足这个条件的四个这样的字节。我甚至没有找到任何可以代表两个赫夫曼树的东西。

我阅读了RFC 1951和1950("ZLIB Compressed Data Format Specification"以及有关zlib,DEFLATE,LZ77和Huffman编码的维基百科文章,以及网上的一些小而无用的文章以及Stack Overflow上的一些答案但是没有人能帮助我理解我。

我真的很感激任何帮助或提示!

2 个答案:

答案 0 :(得分:7)

如果这有帮助,这里是IDAT块内容的反汇编:

! infgen 2.2 output
!
zlib
!
last
dynamic
count 257 2 18
code 1 1
code 2 2
code 18 2
lens 1
zeros 138
zeros 116
lens 2 2 1 1
! litlen 0 1
! litlen 255 2
! litlen 256 2
! dist 0 1
! dist 1 1
literal 0 0 0 0 255 0 0 0 0 0 255 0 255 0
end
!
adler

您可以获取infgen源代码here

答案 1 :(得分:3)

我认为你错过了如何在字节内填充比特(参见RFC的3.1.1节)

 Data elements are packed into bytes in order of
 increasing bit number within the byte, i.e., starting
 with the least-significant bit of the byte.

因此,如果第一个字节是05 = 0000 0101,则第一个比特是1.

(顺便说一下,看看这么多细节肯定很有启发性,但我想知道如果你的目的是了解PNG,你是不是会走得太远。)

此外,当您找到未压缩的IDAT流时,请记住像素使用每行filters中的一个进行编码,并且在开始时有一个额外的字节每一行都表示过滤器类型。所以,你不会真正找到原始的12个字节00 00 00 FF 00 00 00 00 FF 00 FF 00,而是12 + 2 = 14个字节。