Save GIF file...

Post: #1
How the best way to save a Opengl viewport image to a Gif file?....
Any examples?

Thanks... Ninja
Quote this message in a reply
Posts: 1,199
Joined: 2004.10
Post: #2
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:

// 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
#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);
    glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, pBits);
    // 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__
    // 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
    // Success!
    return 1;
Quote this message in a reply
Posts: 1,234
Joined: 2002.10
Post: #3
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];
Quote this message in a reply
Posts: 131
Joined: 2004.10
Post: #4
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.
Quote this message in a reply
Posts: 1,563
Joined: 2003.10
Post: #5
You can do it with QuickTime. Here's some code from Water Tower 3D:

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,;
  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);
          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 {
      if (error != noErr) SysBeep(1);

If you really need a GIF insterad of a PNG, change kQTFileTypePNG to kQTFileTypeGIF.

- Alex Diener
Quote this message in a reply
Post: #6
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
Quote this message in a reply
Posts: 1,563
Joined: 2003.10
Post: #7
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
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  Drag to save unknown 3 4,368 Mar 11, 2006 07:45 AM
Last Post: unknown
  How would I save an NSView as a JPG? Joseph Duchesne 0 4,253 Sep 30, 2005 07:51 PM
Last Post: Joseph Duchesne
  Where to save sprites in memory in OpenGL? forseti 6 7,070 Aug 6, 2002 10:06 AM
Last Post: DaFalcon