解释PNG像素数据

4
看一下 PNG规范,可以看到PNG像素数据块以 IDAT 开始,以 IEND 结束(稍微更清晰的解释在这里)。中间有些值对我来说没有意义。

如何从中得到可用的RGB值,而不使用任何库(即从原始二进制文件中)?

作为示例,我在Photoshop中制作了一个2x2px的图像,其中有4个黑色rgb(0,0,0)像素:
Just four black pixels...

以下是生成的数据(原始二进制输入中的十六进制值和可读的ASCII码表示):

BINARY      HEX ASCII
01001001    49  'I'
01000100    44  'D'
01000001    41  'A'
01010100    54  'T'
01111000    78  'x'
11011010    DA  '\xda'
01100010    62  'b'
01100000    60  '`'
01000000    40  '@'
00000110    06  '\x06'
00000000    00  '\x00'
00000000    00  '\x00'
00000000    00  '\x00'
00000000    00  '\x00'
11111111    FF  '\xff'
11111111    FF  '\xff'
00000011    03  '\x03'
00000000    00  '\x00'
00000000    00  '\x00'
00001110    0E  '\x0e'
00000000    00  '\x00'
00000001    01  '\x01'
10000011    83  '\x83'
11010100    D4  '\xd4'
11101100    EC  '\xec'
10001110    8E  '\x8e'
00000000    00  '\x00'
00000000    00  '\x00'
00000000    00  '\x00'
00000000    00  '\x00'
01001001    49  'I'
01000101    45  'E'
01001110    4E  'N'
01000100    44  'D'
1个回答

6
你在两个规范中都遗漏了一个非常关键的细节:
官方规范如下:
IDAT块包含压缩算法的输出流,即实际图像数据。 [...] PNG内的Deflate压缩数据流以“zlib”格式存储。
维基百科如下:
IDAT包含图像,可能分为多个IDAT块。这种分割会稍微增加文件大小,但可以以流方式生成PNG。IDAT块包含压缩算法的输出流,即实际图像数据。
两者都指出原始图像数据是经过压缩的。看着你的数据,前两个字节
78 DA

包含在RFC1950中指定的压缩标志。其余数据已经被压缩。

使用通用的zlib兼容程序对其进行解压缩,显示14个字节的输出:

00 00 00 00 00 00 00
00 00 00 00 00 00 00

每个字节的第一个字节是PNG行过滤器(两行都为0),然后是2个RGB三元组(0,0,0),用于您图像的2行。
“不使用任何库”,您需要3个单独的程序来:
1. 读取和解析PNG超结构;这提供了IDAT压缩数据以及基本信息,如宽度,高度和颜色深度; 2. 将zlib部分解压缩为原始二进制数据; 3. 解析解压缩的数据,如果需要,处理Adam-7交错,并应用行过滤器。
只有在完成这三个步骤后,您才能访问原始图像数据。其中,您似乎对步骤(1)有很好的掌握。步骤(2)要自己“做”起来要困难得多;就我个人而言,我在自己的PNG处理程序中作弊并使用了miniz。第3步仅仅是一个决心问题。所有必要的信息都可以在网上找到,但需要一段时间将所有内容整理好。(最近我发现在执行很少使用的Paeth行过滤器时出现错误-它之所以没有被注意到是因为在“现实世界”中很少使用。)
请参见构建快速PNG编码器问题进行类似的讨论,以及尝试理解PNG文件中的zlib/deflate进行深入研究Deflate方案。

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