快速写png

Posted

技术标签:

【中文标题】快速写png【英文标题】:write png quickly 【发布时间】:2011-12-18 01:30:46 【问题描述】:

总结

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

动机

我正在制作一个基于 Web 的地图应用程序,在客户端使用 OpenLayers,在后端使用 python/C++。当用户在地图上移动时,应用程序需要能够快速绘制动态内容。我有基于瓦片(256x256 瓦片)和基于单个图像(“单个瓦片”)的版本,但在这两种情况下,后端渲染的最慢部分实际上是将图像保存为 png 文件(无论是-磁盘或内存)。例如,我可能能够在大约 200 毫秒内生成某个视图的“raw”、“tga”或“tiff”版本,但生成 .png 版本需要更多的时间,因为 .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 格式也很快。

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

【问题讨论】:

你的磁盘有一个固定的/最大的写入速度,它通常会比你的处理器做数学的能力慢。 +1 主要是因为这可能是我一段时间以来看到的第一个“做这个 FAST”的问题,(1) 有充分的理由关心速度,(2) 包括硬数字和(3) 实际上在被张贴在这里之前已经看到了一个诚实的尝试。 @Brian Roach:不。请再次阅读帖子。磁盘速度不是这里的限制因素。我可以在 100 毫秒内编写一个 2.5 MB 的 .raw 文件。当我编写一个小五倍的 .png 文件时,需要整整一秒钟。另外,我是否将其实际写入磁盘或将其写入内存文件并不重要。由于实际构建/压缩数据的速度,速度相同。 如果你已经禁用了压缩,然后文件变大了,还是和以前一样慢,你有没有考虑过压缩不是这里的罪魁祸首? @Pascal Cuoq:嗯,它本身可能不是压缩。但我也不相信它的绝对字节数。我需要了解更多关于 .png 的信息,但我知道还有“过滤”和其他一些东西。我相信这是 libpng 花时间安排字节的过程,无论是“压缩”还是其他。 【参考方案1】:

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

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

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


格式由chunks组成。 块结构:

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

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

magic number ("signature") header chunk data chunk end chunk

详细布局:

137, 80, 78, 71, 13, 10, 26, 10 (幻数),8 个字节 IHDR块的字节长度,4字节(值:13) 73, 72, 68, 82 (“IHDR”),4 个字节 宽度,4 个字节 高度,4 个字节 bit depth (per color),1 字节(8 = 24/32 位颜色) color type,1 字节 (2 = RGB) compression method,1 字节(0 = DEFLATE 算法,不允许压缩) filter method,1 字节(0 = 无过滤器) 隔行扫描方法,1 个字节(0 = 无隔行扫描) CRC of IHDR chunk,4 个字节 IDAT 块内容的字节长度,4 字节 73, 68, 65, 84 (“IDAT”),4 个字节 使用 DEFLATE 算法包装的原始图像数据,“IDAT 块内容的字节长度”字节 CRC of IDAT chunk,4 个字节 IEND块的字节长度,4字节(值:0) 73, 69, 78, 68 (“IEND”),4 个字节 CRC of IEND chunk,4 字节(可预计算)

DEFLATE data encoding 无压缩

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

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

就是这样


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

【讨论】:

感谢您提供详细信息。这正是我所需要的。 当我需要同样的东西时的一些细节: IDAT 内容如下所示:字节 0x78、字节 0x01、块、图像数据的 Adler32 校验和。块有一个 5 字节的 little-endian 标头:字节(1=最终块,否则为 0)、2 个字节的 chunk_size、2 个字节的 chunk_size 补码。 另外,每个图像行首先需要以字节 0 为前缀(=无过滤器)。 crc32("IEND") == 0xAE426082【参考方案2】:

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

    ZLIB 压缩的压缩级别。将其设置为 0,png_set_compression_level 实质上相当于禁用此压缩。

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

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

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

【讨论】:

还有 3. png_set_compression_strategy 到 HUFFMAN_ONLY。

以上是关于快速写png的主要内容,如果未能解决你的问题,请参考以下文章

JavaCV开发详解之26补充篇:视频连续截图并按日期格式生成图片文件名称,支持png,jpg,bmp等格式快速连续截图

快速转换操作,CAD转PNG

CAD转PNG,快速转换操作演示

使用 libpng 将位图缓冲区快速编码为 png

快速排序的多种思路实现

算法 快速排序