Question

I am trying to write some data to a PNG file using C++ with Visual Studio Express 2013 on Windows 7 64-bit. I understand that to do this, I need to use an external library, but here is where I'm having some difficulty.

I tried using LodePNG - it looked simple, lightweight, and easy to use. The problem is, it was TOO simple, and seems to require data in a certain pixel format that doesn't match what I have. I could modify my data to make it compatible with LodePNG, but I'd much rather use a library such as libpng with a bit more flexibility.

However, I don't understand the first thing about building or linking libraries, and libpng has proved to be an absolute nightmare in this. I tried following this guide, and managed to produce "libpng.lib" and "png.h", but when I try to include these in my project (I placed both files in my project directory, added "png.h" to my header files and added "libpng.lib" to the Linker's "Additional Dependencies" field), I got a ton of build errors, notably:

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

Can anyone please instruct me as to how to install libpng, direct me to a good guide on the subject (I'm amazed by the lack of guides out there...), or recommend a different (lightweight, easy to install) PNG library? I'm going crazy here.

Was it helpful?

Solution

LodePNG is as easy as you say. I've used it before as well. Just in case you change your mind and decide to encode the data you have into the right format (assuming it is BGRA).. The following will convert the BGRA format to RGBA as required by lodepng..

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");

You can also just do it in-place:

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]);
    }
}

OTHER TIPS

Consider writing your file in NetPBM/PBMplus format as specified here. It is very easy and you don't need a library as the file is so straightforward. The Wikipedia article shows the format here.

Here is a simple example:

#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);
}

Once you have the file as PBM/PGM frmat, use ImageMagick (here) to convert to PNG with a simple command like:

convert file.pgm file.png

The missing header file may be because you need to specify addition include directories as well to point to libpng's header files. It looks like you are probably linking correctly.

It's been a while since I've done this in visual studios, but there should be a field for this in the projects configuration.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top