首页 > 解决方案 > PNG编码器生成的无效放气流

问题描述

我在 VHDL 中实现了 deflate 算法作为 PNG 编码器的一部分。大多数测试输入都正确放气,但是两个特定输入有问题,我找不到原因。

第一个输入是五行内容:0 1 1 1 1 1 1 1 1 1. IE。它是一个 3x5 RGB 图像,全为零,过滤器类型 (=0) 前置。

第二个输入是三行内容:0 1 1 1 1 1 1 1 1 1 1. IE。它是一个 5x3 灰度 + alpha 图像,带有全零和前置过滤器类型 (=0)。

模拟的输出是

['0x78', '0x1', '0x63', '0x60', '0x84', '0x1', '0x24', '0x26', '0x12', '0x13', '0x89', '0x9', '0x5', '0x0', '0x4', '0x97', '0x0', '0x2e']对于第一个输入,分别

['0x78', '0x1', '0x63', '0x60', '0x84', '0x3', '0x24', '0x16', '0x12', '0xb', '0x0', '0x2', '0x10', '0x0', '0x1f']对于第二个输入。

为了验证,我正在使用 pythons zlib 模块:

>>> zlib.adler32(bytes(([0] + [1]*9)*5)).to_bytes(4, "big")
b'\x04\x97\x00.'
>>> deflated_data = bytes([int(b, 16) for b in ['0x78', '0x1', '0x63', '0x60', '0x84', '0x1', '0x38', '0x13', '0xce', '0x84', '0x33', '0xe1', '0x4c', '0x10', '0x0', '0x0', '0x4', '0x97', '0x0', '0x2e']])
>>> zlib.decompress(deflated_data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
zlib.error: Error -3 while decompressing data: invalid distance too far back
>>> zlib.adler32(bytes(([0] + [1]*10)*3)).to_bytes(4, "big")
b'\x02\x10\x00\x1f'
>>> deflated_data = bytes([int(b, 16) for b in ['0x78', '0x1', '0x63', '0x60', '0x84', '0x3', '0x24', '0x16', '0x12', '0xb', '0x0', '0x2', '0x10', '0x0', '0x1f']])>>> zlib.decompress(deflated_data)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
zlib.error: Error -3 while decompressing data: incorrect data check

所以阿德勒校验和是正确的,但两者似乎都是无效的放气流。接下来,我尝试自己解码流。起点是流的二进制和反转表示,可以从左到右读取。Zlib 标头和 adler 校验和被删除。霍夫曼表取自https://www.ietf.org/rfc/rfc1951.txt

['11000110', '00000110', '00100001', '10000000', '00100100', '01100100', '01001000', '11001000', '10010001', '10010000', '10100000', '00000000']

110      - block header (last block and fixed huffman code)
00110000 - literal 0  -> 0
00110001 - literal 1  -> 1
0000110  - match length 8
00000    - match distance 1  -> 11111111
--------------------------------
0001001  - match length 11/12
0        - match length 11
00110    - match distance 9-12
01       - match distance 10
-------------------------------- repeat two times  -> 01111111110, 11111111101, 11111111011
0000101  - match length 7
0        - match distance 1  -> 1111111
0000000  - end of block
00000    - will be discarded

This yields the original data:
0 1 11111111
01111111110
11111111101
11111111011
1111111
['11000110', '00000110', '00100001', '11000000', '00100100', '01101000', '01001000', '11010000', '00000000']

110      - block header (last block and fixed huffman code)
00110000 - literal 0  -> 0
00110001 - literal 1  -> 1
0000111  - match length 9
00000    - match distance 1  -> 111111111
--------------------------------
0001001  - match length 11/12
0        - match length 11
00110    - match distance 9-12
10       - match distance 11
-------------------------------- repeat one time  -> 01111111111, 01111111111
0000000  - end of block
0000     - will be discarded

This yields the original data:
0 1 111111111
01111111111
01111111111

我看不到无效的距离或任何无效/不正确的数据。有人能指出我的错误在哪里吗?是否有一个(python)库,它可以用详细的输出进行膨胀?

标签: pythonalgorithmpngzlib

解决方案


第一个距离太远了。第二个有一个 Adler-32 不匹配。

第一个的infgen输出:

! infgen 2.4 output
!
zlib
!
last
fixed
literal 0 1
match 8 1
match 11 11
infgen warning: distance too far back (11/10)
match 11 11
match 11 11
match 7 1
end
!
adler

您认为距离 10 实际上是距离 11。那是因为额外的位没有反转。额外的位有10,没有01。因此距离为 11,而不是 10。

对于第二个, infgen 给出:

! infgen 2.4 output
!
zlib
!
last
fixed
literal 0 1
match 9 1
match 11 10
match 11 10
end
!
adler

同样的问题,而是认为10它是真的01。现在距离不是太远,而是不够远,无法生成您想要的数据。因此,不正确的 Adler-32 检查。


推荐阅读