So I have this script which reads the display data into a character array pixels
:
typedef unsigned char uchar;
// we will store the image data here
uchar *pixels;
// the thingy we use to write files
FILE * shot;
// we get the width/height of the screen into this array
int screenStats[4];
// get the width/height of the window
glGetIntegerv(GL_VIEWPORT, screenStats);
// generate an array large enough to hold the pixel data
// (width*height*bytesPerPixel)
pixels = new unsigned char[screenStats[2]*screenStats[3]*3];
// read in the pixel data, TGA's pixels are BGR aligned
glReadPixels(0, 0, screenStats[2], screenStats[3], 0x80E0,
GL_UNSIGNED_BYTE, pixels);
Normally, I save this to a TGA file, but since these get monstrously large I was hoping to use PNG instead as I quickly run out of hard drive space doing it this way (my images are highly monotonous and easily compressible, so the potential gain is huge). So I'm looking at PNG writer but I'm open to other suggestions. The usage example they give at their website is this:
#include <pngwriter.h>
int main()
{
pngwriter image(200, 300, 1.0, "out.png");
image.plot(30, 40, 1.0, 0.0, 0.0); // print a red dot
image.close();
return 0;
}
As I'm somewhat new to image processing I'm a little confused about the form of my pixels
array and how I would convert this to a form representable in the above format. As a reference, I've been using the following script to convert my files to TGA:
//////////////////////////////////////////////////
// Grab the OpenGL screen and save it as a .tga //
// Copyright (C) Marius Andra 2001 //
// http://cone3d.gz.ee EMAIL: [email protected] //
//////////////////////////////////////////////////
// (modified by me a little)
int screenShot(int const num)
{
typedef unsigned char uchar;
// we will store the image data here
uchar *pixels;
// the thingy we use to write files
FILE * shot;
// we get the width/height of the screen into this array
int screenStats[4];
// get the width/height of the window
glGetIntegerv(GL_VIEWPORT, screenStats);
// generate an array large enough to hold the pixel data
// (width*height*bytesPerPixel)
pixels = new unsigned char[screenStats[2]*screenStats[3]*3];
// read in the pixel data, TGA's pixels are BGR aligned
glReadPixels(0, 0, screenStats[2], screenStats[3], 0x80E0,
GL_UNSIGNED_BYTE, pixels);
// open the file for writing. If unsucessful, return 1
std::string filename = kScreenShotFileNamePrefix + Function::Num2Str(num) + ".tga";
shot=fopen(filename.c_str(), "wb");
if (shot == NULL)
return 1;
// this is the tga header it must be in the beginning of
// every (uncompressed) .tga
uchar TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
// the header that is used to get the dimensions of the .tga
// header[1]*256+header[0] - width
// header[3]*256+header[2] - height
// header[4] - bits per pixel
// header[5] - ?
uchar header[6]={((int)(screenStats[2]%256)),
((int)(screenStats[2]/256)),
((int)(screenStats[3]%256)),
((int)(screenStats[3]/256)),24,0};
// write out the TGA header
fwrite(TGAheader, sizeof(uchar), 12, shot);
// write out the header
fwrite(header, sizeof(uchar), 6, shot);
// write the pixels
fwrite(pixels, sizeof(uchar),
screenStats[2]*screenStats[3]*3, shot);
// close the file
fclose(shot);
// free the memory
delete [] pixels;
// return success
return 0;
}
I don't normally like to just dump and bail on these forums but in this instance I'm simply stuck. I'm sure the conversion is close to trivial I just don't understand enough about image processing to get it done. If someone could provide a simple example for how to convert the pixels
array into image.plot()
in the PNG writer library, or provide a way of achieving this using a different library that would be great! Thanks.
Your current implementation does almost all the work. All you have to do is to write into the PNG file the pixel colors returned by OpenGL. Since there is no method in PNG Writer to pass an array of colors, you will have to write the pixels one by one.
Your call to glReadPixels()
hides the requested color format. You should use one of the predefined constants (see the format argument) instead of 0x80E0
. According to how you build the pixel array, I guess you are requesting red/green/blue components.
Thus, your pixel-to-png code may look like this:
const std::size_t image_width( screenStats[2] );
const std::size_t image_height( screenStats[3] );
pngwriter image( image_width, image_height, /*…*/ );
for ( std::size_t y(0); y != image_height; ++y )
for ( std::size_t x(0); x != image_width; ++x )
{
unsigned char* rgb( pixels + 3 * (y * image_width + x) );
image.plot( x, y, rgb[0], rgb[1], rgb[2] );
}
image.close()
As an alternative to PNGwriter, you may have a look at libclaw or use libpng as is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With