一个简单的PNG封装器,有人有代码片段可以分享吗?

4

我正在寻找一种将图像数据缓冲区保存为PNG文件的方法,以及将PNG文件读入缓冲区的方法。

我只想要做这两件事情。

这将是一个非常简单的包装器,使用png.h。虽然由于可怕复杂的libpng API,它并不完全简单,但其概念是简单的。

我之前尝试了DevIL。它比libpng容易使用。但我遇到了问题。此外,DevIL功能太过强大。我只需要基本的、精简的PNG格式支持,而不是其他20种格式。

然后我发现了这个页面。我感谢Pixel Fairy和万能的Google给我提供了一个实现方式......然后结果是在处理后的图像中,每个扫描线中的第四个像素都会消失。我相当确定从阅读源代码来看,这不应该发生!它应该将红色清零,并将绿色设置为蓝色。这也没有发生。

我还尝试过png ++。 我遇到的问题是,我无法以兼容OpenGL加载的格式从PNG中获取数据,我必须构建另一个缓冲区。 它看起来很丑,但在我甚至考虑再次尝试DevIL之前,我肯定会再试一次png ++。 因为png ++ 起作用了,至少如此。 它还具有仅标头方面的优势。 不过,它确实产生了许多编译器警告。
还有其他竞争者吗? 任何直接使用libpng的人都知道如何制作我所要求的内容:一个函数,它需要一个文件名并填充32 bpp缓冲区,并设置两个分辨率整数; 一个函数,它需要一个32 bpp缓冲区,两个分辨率整数和一个文件名。
更新编辑:我发现this。 可能有一些东西。

1
是的,lodePNG可能是你想要的。 - Gigi
我现在不太确定了。它不依赖于libpng,因此似乎没有使用它。所有这些人自己实现图像表示格式是怎么回事?编程练习吗? - Steven Lu
libpng并不难直接使用,而lodePNG是一个自包含的单文件PNG解析器,与libpng相比具有许多限制和较差的速度。根据您的需求进行选择。 - Gigi
2
我只是觉得很烦人的是libpng不太容易使用,而像png++这样的包装器并没有让它变得更容易... 是的,你可以做所有这些事情,但一些实用函数怎么样? - Steven Lu
3个回答

2
这个教程似乎有你想要的内容。
来自链接的内容:
 //Here's one of the pointers we've defined in the error handler section:
    //Array of row pointers. One for every row.
    rowPtrs = new png_bytep[imgHeight];

    //Alocate a buffer with enough space.
    //(Don't use the stack, these blocks get big easilly)
    //This pointer was also defined in the error handling section, so we can clean it up on error.
    data = new char[imgWidth * imgHeight * bitdepth * channels / 8];
    //This is the length in bytes, of one row.
    const unsigned int stride = imgWidth * bitdepth * channels / 8;

    //A little for-loop here to set all the row pointers to the starting
    //Adresses for every row in the buffer

    for (size_t i = 0; i < imgHeight; i++) {
        //Set the pointer to the data pointer + i times the row stride.
        //Notice that the row order is reversed with q.
        //This is how at least OpenGL expects it,
        //and how many other image loaders present the data.
        png_uint_32 q = (imgHeight- i - 1) * stride;
        rowPtrs[i] = (png_bytep)data + q;
    }

    //And here it is! The actuall reading of the image!
    //Read the imagedata and write it to the adresses pointed to
    //by rowptrs (in other words: our image databuffer)
    png_read_image(pngPtr, rowPtrs);

这可能会帮助我理解得足够好,以找出zarb.org示例代码出了什么问题。谢谢。 - Steven Lu
我衷心建议在这里使用一些向量。 - Matthieu M.
Steven,你能修复zarg.org的示例代码吗?我和你一样,想要一个一站式函数来读取png并将rgba数据传递给OpenGL。 - Shammi
就我个人而言,我通常使用通过原始zlib流馈送的PPM二进制格式,我称之为ppmz格式。比PNG少得多的头疼... - Steven Lu

2
我会尽力帮助您翻译以下内容,涉及it技术:

我将在选项列表中添加CImg。虽然它是一个图像库,但API并不像大多数高层次的库那样(devil/imagemagick/freeimage/GIL)。它还只包含头文件。

图像类具有简单的宽度、高度和数据成员,并具有公共访问权限。在底层,它使用libpng(如果您使用预处理器指令告诉它)。数据被强制转换为您选择的模板化图像对象类型。

CImg<uint8_t>myRGBA("fname.png");
myRGBA._data[0] = 255; //set red value of first pixel

不错,这是一个仅有头文件的库,大小为112K。看一眼里面,他们开始了深入的研究……这是由一位明显知道自己在做什么的研究人员编写的。肯定可以节省时间,并且似乎具有许多有趣的低级特性,包括内置字体和其他花哨的东西。现在它可能对于“libPNG的包装器”来说有点多余,但它确实可以胜任… - Steven Lu
这是相当C风格的C++代码。虽然我考虑过重构一些部分,但它有太多的宏。也缺少注释。 - jiggunjer
是的,大量的宏可能会成为一种可怕的东西,也可能是非常棒的。在我得出结论之前,我需要仔细研究一下。但是我暂时不会回到图像处理代码的工作中。 - Steven Lu

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接