python - 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)库,它可以用详细的输出进行膨胀?
解决方案
第一个距离太远了。第二个有一个 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 检查。
推荐阅读
- c# - SQL 如何替换一个值
- python - 使用 python 和请求,如何进行正确的 POST 调用以及在哪里找到标头?
- android - FirebaseAppDistribution:appDistributionUpload gradle 命令中缺少应用程序 ID
- mysql - 跨列和行计算值的实例
- javascript - 使用 redux 钩子时使用 redux 操作的最佳选择是什么?
- sql - Impala 2.11:AnalysisException:选择列表中不支持子查询
- swift - 在 SwiftUI 中获取当前的经纬度
- c++ - 是否可以禁止一个类被动态转换为?
- git - Git - 将发布分支合并到主分支
- tensorflow - 任何想法如何解决激活函数的问题?