用 C++ 编写 PNG

Writing a PNG in C++

提问人:Dan 提问时间:3/23/2014 更新时间:1/26/2023 访问量:26653

问:

我正在尝试在 Windows 7 64 位上使用 C++ 和 Visual Studio Express 2013 将一些数据写入 PNG 文件。我知道要做到这一点,我需要使用外部库,但这是我遇到一些困难的地方。

我尝试使用 LodePNG - 它看起来简单、轻巧且易于使用。问题是,它太简单了,似乎需要与我所拥有的不匹配的某种像素格式的数据。我可以修改我的数据以使其与 LodePNG 兼容,但我更愿意使用像 libpng 这样的库,具有更大的灵活性。

但是,我不明白关于构建或链接库的第一件事,libpng 已被证明是这方面的绝对噩梦。我尝试遵循本指南,并设法生成“libpng.lib”和“png.h”,但是当我尝试将它们包含在我的项目中时(我将这两个文件都放在我的项目目录中,将“png.h”添加到我的头文件中,并将“libpng.lib”添加到链接器的“附加依赖项”字段),我遇到了大量构建错误,特别是:

error C1083: Cannot open include file: 'pnglibconf.h': No such file or directory

任何人都可以指导我如何安装 libpng,指导我找到有关该主题的好指南(我对缺乏指南感到惊讶......),或推荐一个不同的(轻量级、易于安装)PNG 库?我在这里发疯了。

C++ PNG libPNG

评论

1赞 Cubic 3/23/2014
你真的,真的不想直接使用 libpng。试试,它很容易使用。你可能想看看,也许它已经有你正在尝试做的事情的功能。FreeImageImageMagick
0赞 Hans Passant 3/23/2014
msdn.microsoft.com/en-us/library/windows/desktop/......
5赞 Ivarpoiss 3/23/2014
您可以从 libpng 源代码中的脚本目录获取 pnglibconf.h。在那里命名为 pnglibconf.h.prebuilt。
0赞 Dan 3/26/2014
谢谢,我会看看 FreeImage、ImageMagick 和 GDI+。@Ivarpoiss我相信我试过了,它抱怨了另一个文件(pngconf.h,可能)
1赞 Peter Parker 5/18/2014
Ivarpoiss:谢谢你指出这一点!!这对我来说是正确的答案!

答:

0赞 capturesteve 3/23/2014 #1

缺少头文件可能是因为您还需要指定 addition include 目录以指向 libpng 的头文件。看起来您可能链接正确。

我已经有一段时间没有在 Visual Studio 中执行此操作了,但是在项目配置中应该有一个字段。

4赞 Mark Setchell 3/23/2014 #2

请考虑按照此处指定的 NetPBM/PBMplus 格式编写文件。这非常简单,您不需要库,因为文件非常简单。维基百科文章在这里显示了格式。

下面是一个简单的示例:

#include <stdio.h>
#include <stdlib.h>

int main(){

   FILE *imageFile;
   int x,y,pixel,height=100,width=256;

   imageFile=fopen("image.pgm","wb");
   if(imageFile==NULL){
      perror("ERROR: Cannot open output file");
      exit(EXIT_FAILURE);
   }

   fprintf(imageFile,"P5\n");           // P5 filetype
   fprintf(imageFile,"%d %d\n",width,height);   // dimensions
   fprintf(imageFile,"255\n");          // Max pixel

   /* Now write a greyscale ramp */
   for(x=0;x<height;x++){
      for(y=0;y<width;y++){
         pixel=y;
         fputc(pixel,imageFile);
      }
   }

   fclose(imageFile);
}

将文件作为 PBM/PGM frmat 后,使用 ImageMagick(此处)通过简单的命令转换为 PNG,如下所示:

convert file.pgm file.png
10赞 Brandon 3/23/2014 #3

LodePNG就像你说的一样简单。我以前也用过它。以防万一您改变主意并决定将您拥有的数据编码为正确的格式(假设它是)。下面将根据 lodepng 的要求将 BGRA 格式转换为 RGBA。BGRA

std::vector<std::uint8_t> PngBuffer(ImageData.size());

for(std::int32_t I = 0; I < Height; ++I)
{
    for(std::int32_t J = 0; J < Width; ++J)
    {
        std::size_t OldPos = (Height - I - 1) * (Width * 4) + 4 * J;
        std::size_t NewPos = I * (Width * 4) + 4 * J;
        PngBuffer[NewPos + 0] = ImageData[OldPos + 2]; //B is offset 2
        PngBuffer[NewPos + 1] = ImageData[OldPos + 1]; //G is offset 1
        PngBuffer[NewPos + 2] = ImageData[OldPos + 0]; //R is offset 0
        PngBuffer[NewPos + 3] = ImageData[OldPos + 3]; //A is offset 3
    }
}

std::vector<std::uint8_t> ImageBuffer;
lodepng::encode(ImageBuffer, PngBuffer, Width, Height);
lodepng::save_file(ImageBuffer, "SomeImage.png");

您也可以就地执行:

for(std::int32_t I = 0; I < Height; ++I)
{
    for(std::int32_t J = 0; J < Width; ++J)
    {
        std::size_t OldPos = (Height - I - 1) * (Width * 4) + 4 * J;
        std::size_t NewPos = I * (Width * 4) + 4 * J;
        std::swap(ImageData[NewPos + 0], ImageData[ImageData + 2]);
    }
}

评论

0赞 jiggunjer 7/29/2015
奇怪的是,lodepng 文档没有提到这一点。它给人的印象是它可以加载任何 png 支持的格式。
1赞 orion elenzil 11/20/2021
Lodepng 对于我的简单用例来说效果非常好。