PNG文件格式中的IDAT块

3
我目前正在开发一种基于png文件格式的专有文件格式。到目前为止,我已经完成了所有工作,但它不起作用:-p。我实现的deflate解压器运行良好,但png解码器不想表现出良好的性能,因此我查看了原始的png文件。
标准规定,在IDAT头之后,紧接着就是压缩数据。因此,由于数据是一个deflate流,所以在IDAT之后的第一个字符是0x78 == 01111000,这意味着一个模式一块(未压缩)且不是最终块。
奇怪的是 - 对我来说很难想象PNG编码器不使用动态哈夫曼编码来压缩过滤后的原始图像数据。deflate标准规定,在模式1中跳过当前字节的其余部分。
因此,接下来的四个字节表示未压缩块的大小及其补数。但0x59FD不是0xECDA的补数。即使我搞错了字节顺序:0xFD59也不是0xDAEC的补数。
嗯,下一个无用的字节就会出现。0x97被认为是未压缩但仍然经过滤波的原始png图像数据的第一个字节,因此必须是过滤器类型。但是0x97 == 10010111不是有效的过滤器类型。即使我搞错了位打包顺序11101001 == 0xe9也不是有效的过滤器类型。
我不再太关注RFC 1951,因为到目前为止,我能够使用我的deflate解压器实现所有类型的文件的解压缩,因此我怀疑我在PNG标准方面有所误解。
我一遍又一遍地阅读RFC 2083,但我看到的数据与RFC不匹配,这对我来说毫无意义,一定有一个缺失的部分!
当我查看以下字节时,实际上无法看到附近任何有效的过滤器类型字节,这使我认为经过过滤的png数据流仍然被压缩了。
如果从MSB到LSB读取0x78(IDAT之后的第一个字节),那么这将是有意义的,但RFC 1951表示相反。另一个想法(对我来说更有可能)是,在IDAT字符串和压缩的deflate流开始之间存在一些数据,但RFC 2083表示相反。布局很清晰。
4个字节大小 4个字节块名称(IDAT) [大小]字节(压缩的deflate流) 4个字节CRC校验和
因此,IDAT之后的第一个字节必须是压缩的deflate流的第一个字节 - 这表示模式1未压缩数据块。这意味着0x97必须是未压缩但经过滤波的png图像数据的第一个字节 - 这意味着0x97是第一行的过滤器类型 - 这是无效的...
我就是不明白,我是傻还是怎么了?

总结: 可能性1: 在IDAT和压缩deflate流有效开始之间存在其他数据,如果这些数据是真实的,则未在RFC2083或我所读过的任何关于图像压缩的书中提及。

可能性2: 数字0x78被解释为MSB -> LSB,这将表明是模式3块(动态霍夫曼编码),但这与RF1951相矛盾,后者对位打包非常清楚:(LSB -> MSB)

我已经知道了,缺失的部分一定是很愚蠢的东西,如果Stack Overflow只有一个删除按钮,我会感到非常紧急地需要出售我的灵魂 :-p

enter image description here

1个回答

10

两个更正可能会帮助你开展工作:

  1. 标志中 zlib 字节数是2,而不是1 -- 参见RFC 1950。第一个是 CMF,下一个是FLG

在你的数据中:

78 DA

---CMF---  ---FLG---
0111.1000  1101.0101
CINF -CM-  +-||
           | |+- FCHECK
           | +-- FDICT
           +---- FLEVEL

CINF为7,表示标准的32Kb压缩窗口。
CM为8,表示压缩算法确实是DEFLATE。
FCHECK只是一个校验和;我没有检查它是否正确(但我敢打赌是正确的)。
FDICT清晰,表示没有预设存储的字典。
FLEVEL为3,表示最大压缩。

另请参见尝试理解PNG文件中的zlib/deflate,尤其是Adler博士的答案。

  1. LENNLEN仅针对未压缩块设置;这就是你找不到它们的原因之一(另一个原因是你看错了字节位置)。

流中的下一个字节EC;按位来看,它是1110 1100,但要记得从低位读取位。因此,读取的下一位是0,表示不是FINAL,接下来读取的2个位是10(按顺序!),表示常规的动态哈夫曼编码数据块。


1
我没有意识到deflate流被包装在zlib容器中。我以为它是一个纯的deflate流。所以现在我只是跳过了两个字节,然后哇 - png导入程序就可以工作了! :-) 非常感谢! - Silverdust

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接