gpt4 book ai didi

c++ - 使用 C++、libpng 和 OpenMP 并行创建 PNG 文件

转载 作者:可可西里 更新时间:2023-11-01 18:20:47 60 4
gpt4 key购买 nike

我目前正尝试在基于 libpng 的 C++ 中实现一个 PNG 编码器,它使用 OpenMP 来加速压缩过程。该工具已经能够从各种图像格式生成 PNG 文件。我将完整的源代码上传到 pastebin.com,这样你就可以看到我到目前为止做了什么:http://pastebin.com/8wiFzcgV

到目前为止,还不错!现在,我的问题是找到一种方法来并行生成包含压缩图像数据的 IDAT block 。通常,libpng 函数 png_write_row 在 for 循环中被调用,它带有指向包含有关 PNG 文件的所有信息的结构的指针和带有单个图像行的像素数据的行指针。

(Pastebin 文件中的第 114-117 行)

//Loop through image
for (i = 0, rp = info_ptr->row_pointers; i < png_ptr->height; i++, rp++) {
png_write_row(png_ptr, *rp);
}

然后,Libpng 逐行压缩,并用压缩后的数据填充内部缓冲区。一旦缓冲区已满,压缩数据就会以 IDAT block 的形式刷新到图像文件中。

我的方法是将图像分成多个部分,让一个线程将第 1 行压缩到第 10 行,另一个线程将第 11 行压缩到第 20 行,依此类推。但是由于 libpng 使用内部缓冲区,它并不像我最初想的那么容易 :) 我不得不以某种方式让 libpng 将压缩数据写入每个线程的单独缓冲区。之后我需要一种方法以正确的顺序连接缓冲区,以便我可以将它们一起写入输出图像文件。

那么,有人知道我如何使用 OpenMP 和对 libpng 进行一些调整吗?非常感谢!

最佳答案

这对于评论来说太长了,但也不是真正的答案--

我不确定您是否可以在不修改 libpng(或编写自己的编码器)的情况下执行此操作。无论如何,如果您了解 PNG 压缩的实现方式,将会有所帮助:

在高层次上,图像是一组像素行(通常是表示 RGBA 元组的 32 位值)。

每一行可以独立有一个filter应用于它——过滤器的唯一目的是使行更“可压缩”。例如,“子”过滤器使每个像素的值与其左侧的值之差。这种增量编码乍一看似乎很愚蠢,但如果相邻像素之间的颜色相似(往往是这种情况),那么无论它们代表的实际颜色如何,结果值都非常小。压缩此类数据更容易,因为它具有更高的重复性。

往下一层,图像数据可以看成字节流(不再区分行)。这些字节被压缩,产生另一个字节流。压缩数据被任意分解成段(任何你想要的!),每个段写入一个 IDAT block (每个 block 还有一些簿记开销,包括 CRC 校验和)。

最底层将我们带到了有趣的部分,即压缩步骤本身。 PNG 格式使用 zlib压缩数据格式。 zlib 本身只是一个真正的压缩数据格式的包装器(有更多的簿记,包括 Adler-32 校验和),deflate (zip 文件也使用它)。 deflate 支持两种压缩技术:Huffman 编码(考虑到每个不同字节在字符串中出现的频率,它将表示某些字节串所需的位数减少到最佳数量)和 LZ77 编码(它允许重复的字符串已经发生被引用而不是写入输出两次)。

关于并行 deflate 压缩的棘手部分是,通常,压缩输入流的一部分要求前一部分也可用,以防需要引用它。 但是,就像 PNG 可以有多个 IDAT block 一样,deflate 被分解成多个“ block ”。一个 block 中的数据可以引用另一个 block 中先前编码的数据,但它必须(当然,如果不这样做,它可能会影响压缩率)。

因此,并行化 deflate 的一般策略是将输入分成多个 部分(以便压缩率保持高),将每个部分压缩成一系列 block ,然后粘合 block 放在一起(这实际上很棘手,因为 block 并不总是以字节边界结束——但您可以放置​​一个空的非压缩 block (类型 00),它将与字节边界对齐,在部分之间)。然而,这并非微不足道,并且需要控制最低级别的压缩(手动创建压缩 block ),创建跨越所有 block 的适当 zlib 包装器,并将所有这些填充到 IDAT block 中。

如果您想使用自己的实现,我建议您阅读 my own zlib/deflate implementation (和 how I use it ),这是我专门为压缩 PNG 而创建的(它是用 Haxe for Flash 编写的,但应该相对容易移植到 C++)。由于 Flash 是单线程的,我没有进行任何并行化,但我确实将编码拆分为多个帧上几乎独立的部分(“虚拟”是因为部分之间保留了小数字节状态),这在很大程度上相当于同样的事情。

祝你好运!

关于c++ - 使用 C++、libpng 和 OpenMP 并行创建 PNG 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10827247/

60 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com