解释PNG像素数据

Jef*_*son 3 binary rgb png hex pixel

看看PNG规范,看起来PNG像素数据块的开头IDAT和结尾IEND(这里稍微清楚一点).中间是对我来说没有意义的价值观.

如何在不使用任何库(即来自原始二进制文件)的情况下从中获取可用的RGB值?

作为一个例子,我rgb(0,0,0)在Photoshop中制作了一个带有4个黑色像素的2x2px图像:
只有四个黑色像素......

这是结果数据(在原始二进制输入中,十六进制值和人类可读的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'
Run Code Online (Sandbox Code Playgroud)

usr*_*301 6

您错过了两个规格中相当重要的细节:

官方一:

.. IDAT块包含实际图像数据,它是压缩算法的输出流.
[...]
PNG中的Deflate压缩数据流以"zlib"格式存储.

维基百科:

IDAT包含图像,可以在多个IDAT块之间进行分割.这种分割会稍微增加文件大小,但可以以流方式生成PNG.IDAT块包含实际图像数据,它是压缩算法的输出流.

两者都表示原始图像数据被压缩.查看您的数据,前2个字节

78 DA
Run Code Online (Sandbox Code Playgroud)

包含RFC1950中指定的压缩标志.其余数据被压缩.

使用通用zlib兼容例程解压缩显示14个字节的输出:

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

其中每个第一个字节是PNG行过滤器(两行为0),后面是2个RGB三元组(0,0,0),用于图像的2行.

"不使用任何库",您需要3个单独的例程来:

  1. 读取和解析PNG上层结构; 这提供了IDAT压缩数据,以及宽度,高度和颜色深度等基本信息;
  2. zlib部分解压缩为原始二进制数据;
  3. 解析解压缩的数据,在需要时处理Adam-7隔行扫描,并应用行过滤器.

只有在执行这三个步骤后,您才能访问原始图像数据.其中,你似乎很好地掌握了步骤(1).步骤(2)更难以"做"自己; 就个人而言,我miniz在自己的PNG处理程序中作弊和使用.再次,步骤3仅仅是一个决定的问题.所有必要的信息都可以在网上找到,但需要一段时间才能按顺序排列所有内容.(就在最近,我在执行极少使用的Paeth行过滤器时发现了一个错误 - 它没有引起注意,因为它在'真实世界'图像中很少使用.)

有关类似讨论,请参阅构建快速PNG编码器问题,并尝试了解PNG文件中的zlib/deflate,以深入了解Deflate方案.