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

Raf*_*uay 8 implementation encoding png deflate

我目前正在为了学习目的而自己编写一个小的PNG图像I/O库.我的问题如下:

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

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

一个二乘二像素的黑色,红色,蓝色和绿色像素.

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

00 00 00 FF 00 00 00 00 FF 00 FF 00
Run Code Online (Sandbox Code Playgroud)

存储时没有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
Run Code Online (Sandbox Code Playgroud)

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

这最终让我得到以下字节:

05 C1 01 01 00 00 00 80 10 FF 4F 17 10 48 06
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

为了更好地理解DEFLATE,我尝试至少在我理解它以便编写一个小工具之前用手"解包"这个序列.但我很快被卡住了.

RFC 1951("DEFLATE压缩数据格式规范")规定每个编码块以三位头开始.一位指示这是否是最后一个块以及另外两个指示压缩方法的块.因为我假设编码器在这里只使用了一个块(意思是第一个块自动是最后一个)并且使用了非静态霍夫曼树,我正在寻找比特序列"101"但我找不到它(我也找不到其他的标题"100"或"110").

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

我阅读了RFC 1951和1950("ZLIB压缩数据格式规范"以及关于zlib,DEFLATE,LZ77和Huffman编码的维基百科文章,以及网上的一些小而无用的文章和Stack Overflow上的一些答案,但没有人能帮助我理解我的不足.

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

leo*_*loy 7

我认为您缺少位在字节中的打包方式(参见例如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.
Run Code Online (Sandbox Code Playgroud)

因此,如果第一个字节是 05 = 0000 0101,那么第一位是 1。

(顺便说一句,查看如此多的细节肯定很有启发性,但我想知道如果您的意图是了解 PNG,您是否会走得太远。)

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

  • 对你来说,那是 Adler 博士。 (3认同)
  • 我不确定,我不是 deflate 专家,也许您应该为此提出一个新问题(请记住:这不是聊天论坛)。在这里你可以从真正的专家那里得到答案,就像阿德勒先生本人一样 :-) http://stackoverflow.com/users/1180620/mark-adler (2认同)

Mar*_*ler 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
Run Code Online (Sandbox Code Playgroud)

您可以在此处获取infgen源代码.

  • 这不是确认,而只是声明 Adler-32 应该在那里有四个字节。`infgen` 不会计算未压缩数据的校验值以查看它是否正确。 (2认同)