Save GIF file... - alert - Jan 10, 2005 04:36 AM
hello...
How the best way to save a Opengl viewport image to a Gif file?....
Any examples?
Thanks...
Save GIF file... - TomorrowPlusX - Jan 10, 2005 05:49 AM
Does it *need* to be a Gif? Because UNYSIS owns Gif you'll not find many mechanisms for Gif export.
On the other hand, if you're willing to accept TGA output, it's easy. I got this from the OpenGL Superbible -- even includes screencapture:
Code:
// WriteTGA.c
// Captures the current screen/window from the OpenGL context
// and writes the pixels out as a targa formatted file.
// Richard S. Wright Jr.
// OpenGL SuperBible
#include "GLTools.h"
#include <stdio.h>
// Define targa header.
#pragma pack(1)
typedef struct
{
GLbyte identsize; // Size of ID field that follows header (0)
GLbyte colorMapType; // 0 = None, 1 = paletted
GLbyte imageType; // 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8=rle
unsigned short colorMapStart; // First colour map entry
unsigned short colorMapLength; // Number of colors
unsigned char colorMapBits; // bits per palette entry
unsigned short xstart; // image x origin
unsigned short ystart; // image y origin
unsigned short width; // width in pixels
unsigned short height; // height in pixels
GLbyte bits; // bits per pixel (8 16, 24, 32)
GLbyte descriptor; // image descriptor
} TGAHEADER;
#pragma pack(8)
////////////////////////////////////////////////////////////////////
// Capture the current viewport and save it as a targa file.
// Be sure and call SwapBuffers for double buffered contexts or
// glFinish for single buffered contexts before calling this function.
// Returns 0 if an error occurs, or 1 on success.
GLint gltWriteTGA(const char *szFileName)
{
FILE *pFile; // File pointer
TGAHEADER tgaHeader; // TGA file header
unsigned long lImageSize; // Size in bytes of image
GLbyte *pBits = NULL; // Pointer to bits
GLint iViewport[4]; // Viewport in pixels
GLenum lastBuffer; // Storage for the current read buffer setting
// Get the viewport dimensions
glGetIntegerv(GL_VIEWPORT, iViewport);
// How big is the image going to be (targas are tightly packed)
lImageSize = iViewport[2] * 3 * iViewport[3];
// Allocate block. If this doesn't work, go home
pBits = (GLbyte *)malloc(lImageSize);
if(pBits == NULL)
return 0;
// Read bits from color buffer
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
// Get the current read buffer setting and save it. Switch to
// the front buffer and do the read operation. Finally, restore
// the read buffer state
glGetIntegerv(GL_READ_BUFFER, &lastBuffer);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, pBits);
glReadBuffer(lastBuffer);
// Initialize the Targa header
tgaHeader.identsize = 0;
tgaHeader.colorMapType = 0;
tgaHeader.imageType = 2;
tgaHeader.colorMapStart = 0;
tgaHeader.colorMapLength = 0;
tgaHeader.colorMapBits = 0;
tgaHeader.xstart = 0;
tgaHeader.ystart = 0;
tgaHeader.width = iViewport[2];
tgaHeader.height = iViewport[3];
tgaHeader.bits = 24;
tgaHeader.descriptor = 0;
// Do byte swap for big vs little endian
#ifdef __APPLE__
BYTE_SWAP(tgaHeader.colorMapStart);
BYTE_SWAP(tgaHeader.colorMapLength);
BYTE_SWAP(tgaHeader.xstart);
BYTE_SWAP(tgaHeader.ystart);
BYTE_SWAP(tgaHeader.width);
BYTE_SWAP(tgaHeader.height);
#endif
// Attempt to open the file
pFile = fopen(szFileName, "wb");
if(pFile == NULL)
{
free(pBits); // Free buffer and return error
return 0;
}
// Write the header
fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile);
// Write the image data
fwrite(pBits, lImageSize, 1, pFile);
// Free temporary buffer and close the file
free(pBits);
fclose(pFile);
// Success!
return 1;
}
Save GIF file... - arekkusu - Jan 10, 2005 07:39 AM
In Cocoa is it easy.
First you need to get the GL view contents into an NSBitmapImageRep. See this code.
Then it's just one extra line:
[[yourbitmaprep representationUsingType:NSGIFFileType properties:nil] writeToFile:@"/yourpath/foo.gif" atomically:YES];
Save GIF file... - Zekaric - Jan 10, 2005 10:00 AM
Personnally I'd go with PNG, no color reduction then. Unless of course you are already dealing with an image of only 256 colours then GIF is alright.
Save GIF file... - ThemsAllTook - Jan 10, 2005 12:43 PM
You can do it with QuickTime. Here's some code from Water Tower 3D:
Code:
void OpenGLWindowTakeSnapshot(OpenGLWindow * window, bool withAlpha) {
Rect windowBounds;
void * imageData;
int rowSize;
GraphicsExportComponent component;
GWorldPtr gWorld;
OSStatus error;
windowBounds = OpenGLWindowGetBounds(window);
OffsetRect(&windowBounds, -windowBounds.left, -windowBounds.top);
imageData = malloc(4 * windowBounds.right * windowBounds.bottom);
glReadPixels(0, 0, windowBounds.right, windowBounds.bottom, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, imageData);
rowSize = (4 * windowBounds.right);
flipImageY(imageData, rowSize, windowBounds.bottom);
error = QTNewGWorldFromPtr(&gWorld, k32ARGBPixelFormat, &windowBounds, NULL, NULL, 0, imageData, rowSize);
if (error == noErr) {
error = OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypePNG, &component);
if (error == noErr) {
FSSpec fileSpec;
CFStringRef fileNameCF;
HFSUniStr255 fileNameUnicode;
FSRef parentDir, fileRef;
int pictureNum;
error = FSFindFolder(kOnSystemDisk, kDesktopFolderType, 0, &parentDir);
if (error == noErr) {
for (pictureNum = 1; pictureNum < OPENGL_WINDOW_MAX_NUMBER_OF_SCREENSHOTS; pictureNum++) {
fileNameCF = CFStringCreateWithFormat(NULL, NULL, CFSTR("Picture %d.png"), pictureNum);
fileNameUnicode.length = CFStringGetLength(fileNameCF);
CFStringGetCharacters(fileNameCF, CFRangeMake(0, (fileNameUnicode.length > 255 ? 255 : fileNameUnicode.length)), fileNameUnicode.unicode);
CFRelease(fileNameCF);
error = FSMakeFSRefUnicode(&parentDir, fileNameUnicode.length, fileNameUnicode.unicode, kCFStringEncodingMacRoman, &fileRef);
if (error == fnfErr) break;
}
}
if (error == fnfErr) {
/* Create an empty file and get an FSSpec for it */
error = FSCreateFileUnicode(&parentDir, fileNameUnicode.length, fileNameUnicode.unicode, kFSCatInfoNone, NULL, NULL, &fileSpec);
/* Export the image */
if (error == noErr) error = GraphicsExportSetInputGWorld(component, gWorld);
if (error == noErr) error = GraphicsExportSetOutputFile(component, &fileSpec);
if (error == noErr && !withAlpha) GraphicsExportSetDepth(component, 24);
if (error == noErr) error = GraphicsExportDoExport(component, NULL);
} else {
SysBeep(1);
}
if (error != noErr) SysBeep(1);
CloseComponent(component);
}
DisposeGWorld(gWorld);
}
free(imageData);
}
If you really need a GIF insterad of a PNG, change kQTFileTypePNG to kQTFileTypeGIF.
- Alex Diener
Save GIF file... - alert - Jan 11, 2005 08:18 AM
I can weasy and quicly access to any pixel of the generated image file?..... How?
Another thing...
In your opinion how the best image file (gif, tga, png, jpg?) in compression?...
Thanks all
Save GIF file... - ThemsAllTook - Jan 11, 2005 08:48 AM
PNG and JPEG are definitely the best. Which one compresses tighter depends on the image. Of course, if you need an alpha channel, JPEG is out...
- Alex Diener
|