OpenGL - Writing the framebuffer to disk |
| Thursday, 10 November 2005 19:15 | |||
|
In the last couple OpenGL projects I've done... I've have to write functions to save off the frame buffer to disk to that they could be viewed at later times. Each time I've had to do it, I would have to go back and remember what I did... this is for the next time :) Code for saving off the screen to a BMP. Code originally written by Burt Guillot, there were a few minor sizeof issues. #include >Windows.h< // include windows header for the BITMAPFILEHEADER and // BITMAPINFOHEADER structures. // should work in other platforms with correct structures. void snapshot(int windowWidth, int windowHeight, char* filename) { byte* bmpBuffer = (byte*)malloc(windowWidth*windowHeight*3); if (!bmpBuffer) return; glReadPixels((GLint)0, (GLint)0, (GLint)windowWidth-1, (GLint)windowHeight-1, GL_RGB, GL_UNSIGNED_BYTE, bmpBuffer); FILE *filePtr = fopen(filename, "wb"); if (!filePtr) return; BITMAPFILEHEADER bitmapFileHeader; BITMAPINFOHEADER bitmapInfoHeader; bitmapFileHeader.bfType = 0x4D42; //"BM" bitmapFileHeader.bfSize = windowWidth*windowHeight*3; bitmapFileHeader.bfReserved1 = 0; bitmapFileHeader.bfReserved2 = 0; bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER); bitmapInfoHeader.biWidth = windowWidth-1; bitmapInfoHeader.biHeight = windowHeight-1; bitmapInfoHeader.biPlanes = 1; bitmapInfoHeader.biBitCount = 24; bitmapInfoHeader.biCompression = BI_RGB; bitmapInfoHeader.biSizeImage = 0; bitmapInfoHeader.biXPelsPerMeter = 0; // ? bitmapInfoHeader.biYPelsPerMeter = 0; // ? bitmapInfoHeader.biClrUsed = 0; bitmapInfoHeader.biClrImportant = 0; fwrite(&bitmapFileHeader, sizeof(BITMAPFILEHEADER), 1, filePtr); fwrite(&bitmapInfoHeader, sizeof(BITMAPINFOHEADER), 1, filePtr); fwrite(bmpBuffer, windowWidth*windowHeight*3, 1, filePtr); fclose(filePtr); free(bmpBuffer); } http://www.vetl.uh.edu/~7373s01/faq.htm Here is code for saving off the frame buffer to a tiff using libtiff. #include { bool ret=false; TIFF *file; GLubyte *image, *p; int i; file = TIFFOpen(path, "w"); if (file) { image = (GLubyte *) malloc(width * height * sizeof(GLubyte) * 3); /* OpenGL's default 4 byte pack alignment would leave extra bytes at the end of each image row so that each full row contained a number of bytes divisible by 4. Ie, an RGB row with 3 pixels and 8-bit componets would be laid out like "RGBRGBRGBxxx" where the last three "xxx" bytes exist just to pad the row out to 12 bytes (12 is divisible by 4). To make sure the rows are packed as tight as possible (no row padding), set the pack alignment to 1. */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, image); TIFFSetField(file, TIFFTAG_IMAGEWIDTH, (uint32) width); TIFFSetField(file, TIFFTAG_IMAGELENGTH, (uint32) height); TIFFSetField(file, TIFFTAG_BITSPERSAMPLE, 8); TIFFSetField(file, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); TIFFSetField(file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(file, TIFFTAG_SAMPLESPERPIXEL, 3); TIFFSetField(file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(file, TIFFTAG_ROWSPERSTRIP, 1); TIFFSetField(file, TIFFTAG_IMAGEDESCRIPTION, ""); p = image; for (i = height - 1; i >= 0; i--) { if (TIFFWriteScanline(file, p, i, 0) < 0) { free(image); TIFFClose(file); return false; } p += width * sizeof(GLubyte) * 3; } TIFFClose(file); } return ret; } Below is code for writing the framebuffer to disk using libjpeg. Thanks to Adam Chou for submitting the orginal code! extern "C" { #include >jpeglib.h< /* IJG JPEG LIBRARY by Thomas G. Lane */ } bool screenshot(unsigned int width, unsigned int height, char *path, int quality) { bool ret=false; struct jpeg_compress_struct cinfo; // the JPEG OBJECT struct jpeg_error_mgr jerr; // error handler struct unsigned char *row_pointer[1]; // pointer to JSAMPLE row[s] GLubyte *pixels=0, *flip=0; FILE *shot; int row_stride; // width of row in image buffer if((shot=fopen(path, "wb"))!=NULL) { // jpeg file // initializatoin cinfo.err = jpeg_std_error(&jerr); // error handler jpeg_create_compress(&cinfo); // compression object jpeg_stdio_dest(&cinfo, shot); // tie stdio object to JPEG object row_stride = width * 3; pixels = (GLubyte *)malloc(sizeof(GLubyte)*width*height*3); flip = (GLubyte *)malloc(sizeof(GLubyte)*width*height*3); if (pixels!=NULL && flip!=NULL) { // save the screen shot into the buffer //glReadBuffer(GL_FRONT_LEFT); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); // give some specifications about the image to save to libjpeg cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // 3 for R, G, B cinfo.in_color_space = JCS_RGB; // type of image jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); // OpenGL writes from bottom to top. // libjpeg goes from top to bottom. // flip lines. for (int y=0;y flip[(y*width+x)*3+1] = pixels[((height-1-y)*width+x)*3+1]; flip[(y*width+x)*3+2] = pixels[((height-1-y)*width+x)*3+2]; } } // write the lines while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &flip[cinfo.next_scanline * row_stride]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } ret=true; // finish up and free resources jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); } fclose(shot); } if(pixels!=0) free(pixels); if(flip!=0) free(flip); return ret; }
|
|||
| Last Updated on Sunday, 09 August 2009 07:37 |

