PNG:使用多个 IDAT-Chunk 有什么好处?

PNG: What is the benefit of using multiple IDAT-Chunks?

我想知道在 PNG 图像中使用多个 IDAT 块的好处是什么。

PNG 文档说

There may be multiple IDAT chunks; if so, they shall appear consecutively with no other intervening chunks. The compressed datastream is then the concatenation of the contents of the data fields of all the IDAT chunks.

我无法想象这是因为块内数据块的最大大小(2^32 字节)。

回想一下,所有 PNG 块(包括 IDAT 块)都有一个带有块长度的前缀。将所有压缩流放在一个巨大的 IDAT 块中会导致以下两个不便:

  • 在编码器端:压缩器在完成压缩之前不知道压缩数据的总大小。然后,在写入块前缀之前,它需要在内存中缓冲完整的压缩数据。

  • 解码端:看chunk decoding是怎么实现的;如果它缓冲内存中的每个块(分配由块长度前缀给出的 space),并且在填充它并检查 CRC 之后,它会将内容传递给解压缩器,然后再次拥有一个巨大的 IDAT 块会是一个记忆猪。

考虑到这一点,我认为应该推荐使用相当小的 IDAT 块(比如 16KB 或 64KB)。开销(每个块 12 字节,如果 len=64KB 则小于 1/5000)可以忽略不计。

似乎在读取 PNG 文件时,libpng limits the chunks of data it buffers to 8192 字节,即使文件中的 IDAT 块大小更大。这对 libpng 读取和解压缩 IDAT 块所需的分配大小设置了上限。但是,在读取整个 IDAT 块之前,仍然无法检测到校验和错误,对于大型 IDAT 块,这可能需要更长的时间。

假设您不关心 CRC 错误的早期检测(如果它们确实发生,它们仍会被检测到,但稍后会被检测到),那么小的 IDAT 块不会为 reader 提供任何好处。事实上,小的 IDAT 块意味着对 zlib 的更多单独调用和 zlib 中更多 preamble/postamble 成本,因此它通常在处理时间和磁盘上 space 方面效率较低。

对于编写者来说,编写有限长度的 IDAT 块很方便,因为您可以在写入之前确定块的长度。如果你想写一个单独的 IDAT 块,那么你必须在开始写任何东西之前完成压缩(需要大量的临时存储),或者你必须在你的输出中寻找更新 IDAT 块的长度,一旦你知道它有多长.

如果您同时压缩图像和流式传输结果,这可能是不可能的。如果您要将图像写入磁盘,那么这可能不是什么大问题。

简而言之,小块用于即时压缩、流式输出用例。在大多数其他情况下,最好只使用一个块。