【问题标题】:Understanding PNG file format IDAT segment了解 PNG 文件格式 IDAT 段
【发布时间】:2023-12-20 05:49:01
【问题描述】:

从下面的示例图片中,我有一个黄色边框,仅用于显示目的。

实际的 .png 文件是 3 像素 x 3 像素的简单黑白图像。我最初想尝试作为 2x2,但这无助于解释低/高与高/低绘图流。至少这样,我会有两个黑色,一个白色从顶部,或者一个白色,两个黑色从底部..

所以我读取数据块,获取 IDAT 块,解码 (zlib) 并得出 12 个字节,如下所示

00 20 00 40 00 80

所以,我的问题是,如何将上述内容分解为 3x3 黑白样本...此外,它以调色板格式保存并正确识别 1 的位深度和 2 的调色板...颜色托盘 [0] 是 RGBA 全零。 Palette1 的 RGBA 为 255、255、255、0

稍后我将最终进入多种其他深度格式,只是想从最简单的开始。

第二部分。如果需要考虑任何特殊情况,尤其是关于 Alpha 通道(我已经在调色板中寻找)可能会绊倒我的任何特殊情况,任何有关处理其他深度格式的指导都会有所帮助。

【问题讨论】:

  • 如果你想完全了解IDAT格式,只要阅读标准,很简单:libpng.org/pub/png/spec/iso/index-object.html#11IDAT
  • 感谢您提供的附加文件...我也会调查一下,但下面的那个实际上为我清理了一堆我实际上并没有遵循任何规范...图形不是我的小学,所以我正在尝试学习而不是“在这里......使用这个。”

标签: c++ parsing graphics png


【解决方案1】:

如果你使用libpng会更容易,所以我想这是为了学习目的。

问题是,如果您直接解压缩 IDAT 块,您会得到一些不应该显示的数据和/或可能需要转换(因为应用了过滤器)才能获得实际字节。在 PNG 格式中,每行都以一个额外的字节开始,告诉您哪个过滤器应用于该行,其余字节包含行像素。

顺便说一句,00 20 00 40 00 80 只有 6 个字节(不是你想的 12 个字节)。现在,如果您将此数据视为二进制,您的 3 行将如下所示:

00000000 00100000
00000000 01000000
00000000 10000000

现在,您的图像每像素 1 位,因此需要 1 字节来保存一行 3 像素。实际使用了 3 个最高位(忽略 5 个较低位)。我用x 替换了忽略的位,所以我认为更容易看到实际的像素0 是黑色,1 是白色):

00000000 001xxxxx
00000000 010xxxx
00000000 100xxxx

在这种情况下,没有对任何行应用过滤器,因为每行的第一个字节为零(0 表示未应用过滤器,14 之间的值表示应用了过滤器)。

【讨论】:

  • 阅读libpng 上的规范文件格式是必须。其他位深度不是问题——尽管有很多颜色和 alpha 的组合,但它们的定义非常好。另一方面,过滤需要一些时间才能正确 :-) 再说一次,如果你做到了,你也可以轻松地加入 Adam-7 隔行扫描。自己做这一切确实是一个很好的学习过程——PNG 不再对 me 保密了!
  • 感谢您为审查 libpng 提供的澄清和指导。是的,这更多是为了学习经验。我喜欢更多地了解幕后而不是“只使用它”的心态。我相信它在我尝试处理其他事情时会有所帮助,我可以在我通常处理的其他工作中将类似的原则联系起来。
  • @DRapp:对于真实世界的示例,请参阅我的 pngdefry 实用程序的源代码,了解我对 PNG 的自上而下的直截了当的处理——所有工作都在 process 函数中完成。完全写在我的浏览器屏幕上打开的官方规范。