用C++;,libpng和OpenMP 我目前尝试在基于LIPPNG的C++中实现PNG编码器,使用OpenMP加速压缩过程。 该工具已经能够从各种图像格式生成PNG文件。 我已将完整的源代码上载到pastebin.com,以便您可以看到我迄今为止所做的工作:
到目前为止,一切都很好!现在,我的问题是找到一种方法来并行生成包含压缩图像数据的IDAT块。通常,libpng函数png_write_row在for循环中被调用,该循环使用指向包含png文件所有信息的结构的指针和带有单个图像行像素数据的行指针 (Pastebin文件中的第114-117行)用C++;,libpng和OpenMP 我目前尝试在基于LIPPNG的C++中实现PNG编码器,使用OpenMP加速压缩过程。 该工具已经能够从各种图像格式生成PNG文件。 我已将完整的源代码上载到pastebin.com,以便您可以看到我迄今为止所做的工作:,c++,parallel-processing,png,openmp,libpng,C++,Parallel Processing,Png,Openmp,Libpng,到目前为止,一切都很好!现在,我的问题是找到一种方法来并行生成包含压缩图像数据的IDAT块。通常,libpng函数png_write_row在for循环中被调用,该循环使用指向包含png文件所有信息的结构的指针和带有单个图像行像素数据的行指针 (Pastebin文件中的第114-117行) //循环浏览图像 对于(i=0,rp=info\u ptr->行指针;i高度;i++,rp++){ png_写入_行(png_ptr,*rp); } 然后,Libpng压缩一行接一行,并用压缩数据填充内部缓
//循环浏览图像
对于(i=0,rp=info\u ptr->行指针;i高度;i++,rp++){
png_写入_行(png_ptr,*rp);
}
然后,Libpng压缩一行接一行,并用压缩数据填充内部缓冲区。缓冲区一满,压缩数据就会以IDAT块的形式刷新到图像文件中
我的方法是将图像分成多个部分,让一个线程压缩第1到10行,另一个线程压缩第11到20行,依此类推。但由于libpng使用的是内部缓冲区,这并不像我第一次想的那么简单:)我必须让libpng为每个线程将压缩数据写入一个单独的缓冲区。之后,我需要一种方法以正确的顺序连接缓冲区,以便将它们一起写入输出图像文件
那么,有人知道我如何使用OpenMP和一些对libpng的调整来实现这一点吗?多谢各位 这条评论太长,但也不是真正的答案-- 我不确定在不修改libpng(或编写自己的编码器)的情况下是否可以做到这一点。在任何情况下,如果您了解PNG压缩是如何实现的,都会有所帮助: 在高层,图像是一组像素行(通常为代表RGBA元组的32位值) 每一行可以独立地应用一个过滤器——过滤器的唯一目的是使该行更“可压缩”。例如,“子”过滤器使每个像素的值成为其与左侧像素之间的差值。这种增量编码乍一看似乎很愚蠢,但如果相邻像素之间的颜色相似(通常情况下),那么不管它们代表的实际颜色如何,结果值都非常小。压缩这样的数据比较容易,因为它的重复性要大得多 往下看,图像数据可以被看作是字节流(行之间不再区分)。这些字节被压缩,产生另一个字节流。压缩数据被任意分解成段(任意位置!),每个段写入一个IDAT数据块(每个数据块都有一点簿记开销,包括CRC校验和) 最底层让我们进入有趣的部分,即压缩步骤本身。PNG格式使用压缩数据格式。zlib本身只是一个围绕真实压缩数据格式的包装器(具有更多簿记功能,包括Adler-32校验和)(zip文件也使用这种格式)。deflate支持两种压缩技术:Huffman编码(根据字符串中每个不同字节出现的频率,将表示某个字节字符串所需的位数减少到最佳位数)和LZ77编码(这允许引用已经发生的重复字符串,而不是将其写入输出两次) 并行化deflate压缩的棘手之处在于,一般来说,压缩输入流的一部分要求前一部分在需要引用时也可用。但是,就像PNG可以有多个IDAT块一样,deflate被分解为多个“块”。一个块中的数据可以引用另一个块中以前编码的数据,但不一定要引用(当然,如果不引用,可能会影响压缩比) 因此,并行deflate的一般策略是将输入分成多个大部分(以便压缩比保持较高),将每个部分压缩成一系列块,然后将这些块粘合在一起(这实际上很棘手,因为块并不总是以字节边界结束——但您可以在节之间放置一个空的非压缩块(类型00),该块将与字节边界对齐)。然而,这并不简单,需要控制非常低的压缩级别(手动创建deflate块),创建跨越所有块的正确zlib包装器,并将所有这些内容填充到IDAT块中 如果您想使用自己的实现,我建议您阅读(和),这是我专门为压缩PNG而创建的(它是用Haxe for Flash编写的,但应该比较容易移植到C++)。由于Flash是单线程的,我不做任何并行化,但我确实将编码分成了几乎独立的部分(“虚拟”是因为在多个帧上,节之间保留了分数字节状态,这在很大程度上是相同的
祝你好运!我终于让它并行化了压缩过程。 正如Cameron在对其回答的评论中提到的,我必须从zstreams中剥离zlib页眉以合并它们。不需要剥离页脚,因为zlib提供了一个名为Z_SYNC_FLUSH的选项,可用于所有块(最后一个块必须使用Z_FINISH编写除外)写入字节边界。因此,您可以简单地在之后连接流输出。最终,必须在所有线程上计算adler32校验和,并将其复制到组合Z流的末尾
如果你对结果感兴趣,你可以在找到完整的概念证明,好吧,我想对我来说,并行化deflate压缩有点太复杂/太耗时了
//Loop through image
for (i = 0, rp = info_ptr->row_pointers; i < png_ptr->height; i++, rp++) {
png_write_row(png_ptr, *rp);
}