iDevGames Forums
Save GIF file... - Printable Version

+- iDevGames Forums (http://www.idevgames.com/forums)
+-- Forum: Development Zone (/forum-3.html)
+--- Forum: Graphics & Audio Programming (/forum-9.html)
+--- Thread: Save GIF file... (/thread-5980.html)



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... Ninja


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