24

概括

我想尽快写一个 .png 文件,而不用担心压缩。也就是说,我不太关心文件大小,但我确实关心写操作是否发生得越快越好。

动机

我正在使用客户端的 OpenLayers 和后端的 python/C++ 制作基于 Web 的地图应用程序。当用户在地图上移动时,应用程序需要能够快速绘制动态内容。我有基于瓦片(256x256 瓦片)和基于单个图像(“单个瓦片”)的版本,但在这两种情况下,后端渲染的最慢部分实际上是将图像保存为 png 文件(无论是-磁盘或内存)。例如,我可能能够在大约 200 毫秒内生成某个视图的“raw”、“tga”或“tiff”版本,但生成 .png 版本需要 1.2 秒,因为 .png保存几乎需要一秒钟,而实际保存其他格式的时间为 100 毫秒或更短(即使“原始”文件的大小是 .png 文件的五倍)。而且这个文件保存时间也大大超过了将结果图像从服务器传输到客户端的时间。(我的应用程序的一个重要属性是,通常“后端”将与浏览器在同一台机器上运行,因此传输时间可以忽略不计,即使对于大文件也是如此。)

我想我可以通过调用使 .png 快速写入(当使用 C++ 中的 libpng 时)

    png_set_compression_level( png_ptr, 0 );

在调用任何png_write_...函数之前。然而,虽然该调用似乎确实阻止了 libpng 压缩文件(生成的文件与 .raw 文件的大小大致相同),但它并没有明显加快保存 .png 的速度。

请帮忙

我需要为这些图像使用 .png,因为我需要它们成为基本地图顶部的透明叠加层,而且我需要的不仅仅是 GIF 提供的 256 种颜色。OpenLayers 只是简单地使用 html img 标签,所以我的理解是我只能使用有效的 img 格式。

我认为有一种方法可以通过不进行任何实际压缩来快速编写 .png 文件(我知道 .png 是“始终压缩的”,但我想这可能包括“空压缩”)。看起来您应该能够编写一个简单的固定页眉,然后是未压缩的数据,然后是一些固定的页脚。或者也许是同样的想法,但是以逐行的方式。关键是我可以非常快速地在 C++ 内存中对这 2.5 MB 的原始数据进行各种循环,并且可以非常快速地将其转储为各种文件格式,所以看起来我应该能够以固定的方式转储它, 未压缩的 .png 格式也很快。

听起来对吗?你知道我在哪里可以找到这样做的代码示例吗?

4

2 回答 2

32

您想要的是专门针对您的目的的实现;您将不得不编写自己的编码器。它实际上并不太难,而且规格是免费的。

格式不太复杂,应该很容易实现编码器

注意:所有值都是无符号的。多字节整数采用“网络字节顺序”(最高有效字节在前)。


格式由组成。块结构:

  • 块内容的长度,4字节
  • 块标识符 (ASCII),4 个字节
  • 块内容,“块内容的长度”字节
  • 标识符和内容的CRC(即不包括长度),4字节

您的实现应该只需要幻数和三个


详细布局:

  • { 137, 80, 78, 71, 13, 10, 26, 10 }(幻数),8字节
  • IHDR 块的字节长度,4 字节(值:13)
  • { 73, 72, 68, 82 } ("IHDR"), 4 字节
  • 宽度,4 字节
  • 高度,4 个字节
  • 位深度(每种颜色),1 字节(8 = 24/32 位颜色)
  • 颜色类型,1 个字节(2 = RGB)
  • 压缩方法,1 字节(0 = DEFLATE算法,不允许压缩)
  • 过滤方法,1 个字节(0 = 无过滤器)
  • 隔行扫描方法,1 个字节(0 = 无隔行扫描)
  • IHDR块的CRC,4字节
  • IDAT 块内容的字节长度,4 字节
  • { 73, 68, 65, 84 } ("IDAT"), 4 字节
  • 带有 DEFLATE 算法包装的原始图像数据,“IDAT 块内容的字节长度”字节
  • IDAT块的CRC,4字节
  • IEND 块的字节长度,4 个字节(值:0)
  • { 73, 69, 78, 68 } ("IEND"), 4 字节
  • IEND 块的 CRC,4 个字节(可以预先计算)

不压缩的DEFLATE 数据编码

您的数据将被分成 65535 字节的块,格式很简单:

  • 前 X 块
    • 标头,1 个字节(值:0)
    • 数据,65535 字节
  • 最后一块
    • 标头,1 个字节(值:1)
    • 数据,65535 字节或更少

就是这样


这就是你如何制作一个快速的 png 文件

于 2011-11-13T18:46:25.333 回答
15

PNG的压缩速度主要受两个参数的影响:

  1. ZLIB 压缩的压缩级别。将其设置为 0,png_set_compression_level基本上相当于禁用此压缩。

  2. 像素过滤。这可能因每条线而异,并且通常通过一些启发式方法进行选择,这对于大小而言可能是有效的,但可能会很耗时。看看如果速度是主要问题(更重要的是png_set_filterpng_set_filter_heuristics如果 ZLIB 压缩被禁用)你应该选择一个过滤器:PNG_FILTER_NONE

我认为,优化速度几乎没有什么可做的。与 BMP 或 TGA 等“原始”格式相比,未压缩的 PNG 仍然需要为每个块计算 CRC32 以及 ZLIB 的内部 Adler CRC 的(小)负担。这几乎就是全部。

(作为记录,我编写了一个完整的纯 Java 编码器/编码器,它致力于提高内存和 CPU 效率:PNGJ

于 2013-07-05T13:38:22.890 回答