Capturing a OpenGL image into a JPEG (or other bitmap)

I’d like to be able to take a screenshot of a scene rendered in OpenGL and save it to a bitmap file, like bmp, jpeg, gif or something. How would I do this?

Thanks,
-Mike Powers

This might help you,

you will also need a bmp writer. If you need one let me know.

Best Regards,

Vanleurth “The matrix has you”

#include <X11/Xlib.h>
#include <GL/glx.h>
#include <stdio.h>
#include “…/molsimu2/templates.h”

/* Functions in writegif.c /
/
extern void writegif(FILE *fp, XImage *image, int width, int height, int numcol, unsigned char rgb[256]); */

/* Functions in writebmp.c */
extern void write_bmp24(FILE *fp, int width, int height, GLvoid *pixels);

/* Local Functions */
void grabber(int height, int width, int framenum);
int getelem2d(int i, int j, int k, int width, int height, int depth, GLubyte *bmpmem);
void putelem2d(int fwdvalue, int i, int j, int k, int width, int height, int depth, GLubyte *array3d);

void grabber(int height, int width, int framenum)
{
int pixelsqty;
int i, j, k;
int x, y;
int fwdvalue;
char bmpfname[20];
char fname = “frame”;
unsigned char *curpix;
FILE *fp_bmp;
GLubyte *pixels;
GLubyte *revpixels;

/* Determine pixels quantity */
pixelsqty = 3 * width * height;

/* Set up Alignment format for bitmaps */
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glPixelStorei (GL_PACK_ALIGNMENT, 1);
glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);

/* Define pixel array for a no extra byte. Mode 1. */
pixels = (GLubyte*) malloc(pixelsqty);
if (pixels == NULL)
{
	printf("No enough memory 

");
exit (0);
}

/* Define revpixel array for a no extra byte. Mode 1. */
revpixels = (GLubyte*) malloc(pixelsqty);
if (revpixels == NULL)
{
	printf("No enough memory 

");
exit (0);
}

/* Store Full Image from the back buffer */
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);

/* Store image in memory */
glReadPixels (0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels);

/* Save pixels' RGB values inverse to an array */
for (i = 0; i &lt; height; i++)
	for (j = 0; j &lt; width; j++)
		for (k = 0; k &lt; 3; k++)
		{
			fwdvalue = getelem2d(i, j, k, width, height, 3, pixels);
			putelem2d(fwdvalue, i, j, (2 - k), width, height, 3, revpixels);
		}				
			
/* Create 24-Bit bitmap filename. */
sprintf (bmpfname, "%s%d.bmp", fname, framenum);
printf("%s 

", bmpfname);

/* Open file */
fp_bmp = fopen(bmpfname, "wb");
if (fp_bmp == NULL)
{
	printf("Unable to open file. 

");
exit(0);
}

/* Write 24-bit BMP file */
write_bmp24(fp_bmp, width, height, revpixels);

/* Close file and free memory */
fclose(fp_bmp);
free (pixels);
free (revpixels);

}

int getelem2d(int i, int j, int k, int width, int height, int depth, GLubyte *array3d)
{
int value;

value = array3d[k + depth * (j + height * i)];
	
return value;

}

void putelem2d(int fwdvalue, int i, int j, int k, int width, int height, int depth, GLubyte *array3d)
{
array3d[k + depth * (j + height * i)] = fwdvalue;
}

Originally posted by mapowers_:
[b]I’d like to be able to take a screenshot of a scene rendered in OpenGL and save it to a bitmap file, like bmp, jpeg, gif or something. How would I do this?

Thanks,
-Mike Powers[/b]

nate.scuzzy.net has something similar with the output being TGA.

Of course you could always just hit printscreen…This dumps an image of the active window to the clipboard…If all you want is a screen shot.

N-

Originally posted by mapowers_:
[b]I’d like to be able to take a screenshot of a scene rendered in OpenGL and save it to a bitmap file, like bmp, jpeg, gif or something. How would I do this?

Thanks,
-Mike Powers[/b]

Another thing you might be aware of… If the openGL window is overlayed by another window you will get black pixels there. If so, you could render the GL output in a bitmap and then save it.

Kilam.

There is another problem:
If you have changed the gamma ramp this won´t make an impact on glReadPixels…The only solution I´ve found so far is applying the gamma ramp afterwards “by hand”…

Greets,XBTC!

How do you do this ?? I have been trying using a Pixmap but it seems to me this drawable doesn’t work. Have you actually suceed with doing this?

Vanleurth (“what is real ?”)

Originally posted by Kilam Malik:
[b]Another thing you might be aware of… If the openGL window is overlayed by another window you will get black pixels there. If so, you could render the GL output in a bitmap and then save it.

Kilam.[/b]

Try this:

HGLRC bmp_hglrc;
HDC bmp_hdc;

HDC memDC = CreateCompatibleDC(NULL);
int bpp = GetDeviceCaps(memDC,BITSPIXEL);
HBITMAP bmp = CreateBitmap(w,h,1,bpp,0);
SelectObject(memDC,(HBITMAP)bmp);
bmp_hdc = memDC;

BITMAP bmInfo;

GetObject(bmp,sizeof(BITMAP),&bmInfo);

PIXELFORMATDESCRIPTOR pfd;
memset(&pfd,0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1; // Version number
pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = (BYTE)bmInfo.bmBitsPixel;
pfd.cDepthBits = 32; // 32-bit depth buffer
pfd.iLayerType = PFD_MAIN_PLANE ; // Layer type

int pixelFormat = ChoosePixelFormat(bmp_hdc,&pfd);
BOOL success = SetPixelFormat(bmp_hdc,pixelFormat,&pfd);

bmp_hglrc=wglCreateContext(bmp_hdc);

wglMakeCurrent(bmp_hdc,bmp_hglrc);

createPalette();

Draw();

glEnable(GL_MAP_COLOR);
dumpColorBufferToFileHelper(fp,w,h,bmpDepth);
glDisable(GL_MAP_COLOR);

wglMakeCurrent(bmp_hdc,NULL);

wglMakeCurrent(NULL,NULL);
wglDeleteContext(bmp_hglrc);

You can also open this render context with shared display lists from your current render context.

Kilam.

Thanks. I would appreciate it if you could direct me to a bmp writer (or the implementation of writegif(), It doesn’t matter to me if the output is BMP or GIF, as long as it works.

Thanks for your help,

-mapowers_

Originally posted by vanleurth:
[b]This might help you,

you will also need a bmp writer. If you need one let me know.

Best Regards,

Vanleurth “The matrix has you”

[/b]

#include “writebmp.h”
#include <stdio.h>
#include <GL/glx.h>

/* Local Functions */
void write_bmp24 (FILE *fp, int width, int height, GLvoid *pixels);
void write_bmpheader (FILE *fp, int width, int height);
void write_bmpimage (FILE *fp, int width, int height, GLvoid *pixels);
unsigned char *int2word(int number);
unsigned char *int2long(unsigned char *longnum, int number);
void checkvalues(int width, int height, GLvoid *pixels);
void write_u_long_int (unsigned long int u_long_int_val, FILE *fp);
void write_u_short_int (unsigned short int u_short_int_val, FILE *fp);

/* Global Variables */
int pad, rasterwidth;
struct template_bmpheader bmpheader;
struct template_bmpfile bmpfile;

void write_bmp24 (FILE *fp, int width, int height, GLvoid pixels)
{
/
Write header */
write_bmpheader(fp, width, height);

/* Write image data */
write_bmpimage(fp, width, height, pixels);

}

/* Support Functions ------------------------------------------------------ */

void write_bmpheader (FILE *fp, int width, int height)
{
int filesize, bfsize;
int bytesperline, bmpnumbytes;

/* Initialize header structure */
bmpheader.reserved[0] = 0;
bmpheader.reserved[1] = 0;
/* WARNING : 	sizeof() function doesn't work well in 64bit computers,
		so in not good for determining the size of a structure.
*/
bmpheader.headersize = 54;
	
/* Determine image width if it is not a multiple of 4. This is, in 
24-bit bitmap files each raster line should be a multiple of 4 bytes */
if ((width % 4) == 0) 
	pad = 0;
else
	pad = 4 - (width % 4);
	
/* Padded new width */
rasterwidth = width + pad;
	
/* Number of bytes in image */
bmpnumbytes = 3 * rasterwidth * height;

/* File size in bytes */	
bmpheader.bfsize = sizeof(struct template_bmpheader) + sizeof(struct template_bmpfile) + bmpnumbytes;

/* Start writing the file ----------------------------------------- */
fputc('B', fp);
fputc('M', fp);
		
/* Write size of file in bytes */
write_u_long_int(bmpheader.bfsize, fp);

/* Write Reserved 1 */
write_u_short_int(bmpheader.reserved[0], fp);

/* Write Reserved 2 */
write_u_short_int(bmpheader.reserved[1], fp);

/* Write header size */
write_u_long_int(bmpheader.headersize, fp);

/* Bitmap Info ---------------------------------------------------- */
bmpfile.bmpsize = 40;
/* WARNING :	sizeof() function doesn't work on 64 bit computers.
		whenever this can be solved then use ;
		sizeof(struct template_bmpfile);
*/

bmpfile.bmpwidth = rasterwidth;
bmpfile.bmpheight = height;
bmpfile.biplanes = 1;
bmpfile.bitcount = 24;
bmpfile.bicompression = 0;
    bmpfile.bisizeimage = 0;
    bmpfile.bixpelspermeter = 0;
    bmpfile.biypelspermeter = 0;
    bmpfile.biclrused = 0;
bmpfile.biclrimportant = 0;

/* Write variables in file */
write_u_long_int(bmpfile.bmpsize, fp);
write_u_long_int(bmpfile.bmpwidth, fp);
write_u_long_int(bmpfile.bmpheight, fp);
write_u_short_int(bmpfile.biplanes, fp);
write_u_short_int(bmpfile.bitcount, fp);
write_u_long_int(bmpfile.bicompression, fp);
write_u_long_int(bmpfile.bisizeimage, fp);
write_u_long_int(bmpfile.bixpelspermeter, fp);
write_u_long_int(bmpfile.biypelspermeter, fp);
write_u_long_int(bmpfile.biclrused, fp);
write_u_long_int(bmpfile.biclrimportant, fp);

}

void write_bmpimage (FILE *fp, int width, int height, GLvoid *pixels)
{
int i, j, k, m, n, size, value, rowcount, rowindex;
int pixnum = 0;
char *linebuf;
unsigned char zero = 0;
unsigned char *curpix;
int numpixels;

/* Assign pointer to memory image */
curpix = (unsigned char *) pixels;

/* Save image */
for (i = 0; i &lt; height; i++)
{
	for (j = 0; j &lt; width; j++)
		/* Position pointer to the end of next pixels */
		for (k = 0; k &lt; 3; k++)
			fwrite(curpix++, 1, 1, fp);
			
	/* Fill out remaining zero */
	if (pad &gt; 0)
		for (m = 0; m &lt; pad; m++)
			for (n = 0; n &lt; 3; n++)
				fwrite(&zero, 1, 1, fp);
}	

}

/* Miscellaneous Functions ------------------------------------------------ */

void checkvalues(int width, int height, GLvoid *pixels)
{
int i, j, numpixels;
unsigned char *curpix;

curpix = (unsigned char *) pixels;

numpixels = width * height;

for (i = 0; i &lt; numpixels; i++)
{
	printf("pixel num : %d 

", i);

	for (j = 0; j &lt; 3; j++)
		printf("%d 

", *curpix++);

	printf("

");
}
}

unsigned char *int2word(int number)
{
unsigned char wordnum[2];

wordnum[0] = (number & 0x00FF);
wordnum[1] = ((number &gt;&gt; 8) & 0x00FF);

return wordnum;

}

unsigned char *int2long(unsigned char *longnum, int number)
{
longnum[0] = (number & 0x00FF);
longnum[1] = ((number >> 8) & 0x000000FF);
longnum[2] = ((number >> 16) & 0x000000FF);
longnum[3] = ((number >> 24) & 0x000000FF);

return longnum;	

}

void write_u_long_int (unsigned long int value, FILE *fp)
{
unsigned short int value_hi;
unsigned short int value_lo;

value_hi = (unsigned short) (value / 65536);
value_lo = (unsigned short) (value % 65536);

write_u_short_int(value_lo, fp);
write_u_short_int(value_hi, fp);

}

void write_u_short_int (unsigned short int value, FILE *fp)
{
unsigned char chi;
unsigned char clo;

chi = (unsigned char) (value / 256);
clo = (unsigned char) (value % 256);

fputc(clo, fp);
fputc(chi, fp);

}

Who can help me to have this code in VB ? ;-(

I’m not sure if the VB has OpenGL libs.
( It’s been created by Microsoft for viruses
(Sorry fo grammar) )

[This message has been edited by FoxDie (edited 10-25-2001).]

http://openquicktime.sourceforge.net/ http://developer.apple.com/quicktime/
or
I have used
jpeg-lib which was easy to implement.

How can I do that?

Originally posted by Kilam Malik:
[b]Try this:

glEnable(GL_MAP_COLOR);
dumpColorBufferToFileHelper(fp,w,h,bmpDepth);
glDisable(GL_MAP_COLOR);

Kilam.

[/b]