Victor Image Processing Library How-to Tips

Load and Display an Animation

(To see how this animation was created visit rotate.html.)
  
An animated gif file consists of multiple frames. In this example, all the frames are loaded into a single image with transparency and frame replacement parameters. The image is then ready to be displayed. (To just load the frames as they exist in the file visit loadgif.html.)

The load sequence is:

  • determine how many frames are in the file
  • get the information describing each frame
  • allocate an image buffer to hold all the frames top to bottom
  • set the background color
  • load each frame into the correct position in the buffer.
    • If the frame has a transparent color
        load it into a disposable buffer
        use coverclear to copy the transparent frame into position as an overlay
    • Determine how the frame is to be disposed of after display and place the appropriate background in the next frame
        frame left in place: copy current frame to next frame
        frame replaced by background: do nothing (background has already been set)
        frame replaced by previous image: copy previous frame to next frame

After the file is loaded we place the information describing the animation into a global variable of type ANIMATOR created for this example:
      typedef struct tagAnimator {
         int frames;               // number of frames in the animation
         int height;               // maximum frame height
         GifGlobalData *gdata;     // global data from the gif file
         GifFrameData *fdataarray; // array of frame data structures
         } ANIMATOR;

The display sequence is:

  • create a memory device context
  • select the entire image containing all frames into the memory DC
  • for each frame
    • bitblt the frame to the screen
    • pause for the delay time

The DoPaint function below is the WM_PAINT message handler and displays the long image with the frames top to bottom at the (0,0) position in the window using the Victor viewimageex function. Then DoPaint places the animation on the screen to the right side of the long image using the display_animation function defined below.


Load an Animated GIF - the C Source Code

Requires Victor Image Processing Library v 5.3 or higher.

// Global variable
ANIMATOR Anima;
// Load a GIF file 
int load_gif(LPTSTR fname, imgdes *image)
{
   int rcode;
   imgdes tempimage;
   int totalFrames;
   GifGlobalData *gdata;
   GifFrameData *fdatarray;
   int gdsize, fdsize;
                        // Loading all frames from a gif into a single vertical image
   rcode = gifframecount(fname, &totalFrames);
   gdsize = sizeof(GifGlobalData);
   gdata = (GifGlobalData *)calloc(1, gdsize);
   fdsize = sizeof(GifFrameData);
   fdatarray = (GifFrameData *)calloc(totalFrames, fdsize);
   rcode = gifinfoallframes(fname, gdata, fdatarray, totalFrames);
   if(rcode == NO_ERROR) {
      int j;
      imgdes prevframe;
      imgdes nextframe;
      imgdes transimage;
                        // Size the image buffer to load all frames
      if((rcode = allocimage(&tempimage, gdata->saveData.scrwidth, 
         gdata->saveData.scrlength * totalFrames, fdatarray[0].vbitcount)) == NO_ERROR) {
         zeroimage(gdata->saveData.bckColor, &tempimage);
         tempimage.imgtype = 0;  // color palette image
         copyimgdes(&tempimage, &prevframe);
         copyimgdes(&tempimage, &nextframe);
         for(j=0; j < totalFrames; j++) {
            tempimage.stx = fdatarray[j].saveData.startx ;
            tempimage.sty = j * gdata->saveData.scrlength + fdatarray[j].saveData.starty ;
                        // Handle transparency
            if(fdatarray[j].saveData.transColor > 0 && fdatarray[j].saveData.transColor < 256) {
               rcode = allocimage(&transimage, fdatarray[j].width, 
                  fdatarray[j].length, fdatarray[j].vbitcount);
               if(rcode == NO_ERROR) {
                        // Load transparent-color image into a special disposable buffer
                  rcode = loadgifframe(fname, &transimage, gdata, &fdatarray[j]);
                        // Overlay the transparent-color image onto the frame
                        // Use pixel values, not palette entries
                  if(rcode == NO_ERROR) {  
                     tempimage.imgtype = 1; transimage.imgtype = 1;  
                     coverclear(fdatarray[j].saveData.transColor, &tempimage, 
                        &transimage, &tempimage);
                     tempimage.imgtype = 0; transimage.imgtype = 0;
                     }
                  freeimage(&transimage);
                  }
               }
            else   // No transparency
               rcode = loadgifframe(fname, &tempimage, gdata, &fdatarray[j]);
         tempimage.stx = 0;        // Set starting position to beginning of frame in image
         tempimage.sty = j * gdata->saveData.scrlength;
                        // Prepare the background of the next frame
         if (j < totalFrames - 1)
            nextframe.sty = (j + 1) * gdata->saveData.scrlength;
         else
            nextframe.sty = (j    ) * gdata->saveData.scrlength;
         if (j != 0)
            prevframe.sty = (j - 1) * gdata->saveData.scrlength;
         else
            prevframe.sty = (j    ) * gdata->saveData.scrlength;
         switch(fdatarray[j].saveData.removeBy) {
            case 0:              // 0  The image is left unremoved
            case 1:              // 1  The image is left unremoved
               {
                copyimagebits(&tempimage, &nextframe);
                break;
               }
            case 2:              // 2  The image is replaced by the background
               break;
            case 3:              // 3  The image is replaced by the previous image
               {
               copyimagebits(&prevframe, &nextframe);
               break;
               }
            }
         }
      }
      loadgifpalette(fname, tempimage.palette);   // In case the palette was overwritten
      updatebitmapcolortable(&tempimage);
      tempimage.sty = 0;
      freeimage(image);
      copyimgdes(&tempimage, image);
      }
                        // Set rcode to NO_ERROR, even if file contained invalid data
   if(rcode == NO_ERROR || rcode == BAD_DATA) {
      rcode = NO_ERROR; 
                        // Set global data for display of animation
      Anima.frames = totalFrames;
      Anima.height = gdata->saveData.scrlength;
      Anima.gdata = gdata;
      Anima.fdataarray = fdatarray;
      }
   return(rcode);
}
//................................................................
// Helper function: a delay routine that counts milliseconds
static void delayTime(int count) // Number of millisecs to delay
{
   if(count) {
      // Calc finish time
      DWORD dwTarget = GetTickCount() + (DWORD)count;
      // Waste time until we're done
      while(GetTickCount() < dwTarget)
         ;
      }
}
int display_animation(HWND hwnd, HDC hdc,
   HPALETTE far *hPal, // Variable to receive logical palette handle
   imgdes far *image,  // Address of image descriptor for buffer containing all frames 
   int scrx, int scry, // Position on client rect to display image
   ANIMATOR *myanimation) 
{
   int rcode, rows2disp, cols2disp;
   HPALETTE hOldPal;
   HDC hMemDC; 
                        // Create a logical palette from a Victor palette
   if((rcode = victowinpal(image, hPal)) == NO_ERROR && *hPal) {
                        // Select and realize the palette
      hOldPal = SelectPalette(hdc, *hPal, 0);
      RealizePalette(hdc);
      }
   cols2disp = myanimation->gdata->saveData.scrwidth;
   rows2disp = myanimation->gdata->saveData.scrlength;
                        // Create a memory DC
   hMemDC = CreateCompatibleDC(hdc);
   if(hMemDC == 0)
      rcode = BAD_MEM;
   else {
      HPALETTE hOldPal1;
      HBITMAP hOldBitmap;
      if(*hPal)
         hOldPal1 = SelectPalette(hMemDC, *hPal, 0);
                        // Select bitmap into the memory DC
      hOldBitmap = SelectObject(hMemDC, image->hBitmap);
      if (myanimation->frames > 0) {  // the animation takes place here .................
         int k, j, waitInMs;
         for(k=0; k < 3; k++) {   // For this example do three loops through all frames
            for(j=0; j < myanimation->frames; j++) {
                        // Convert hunredths of a sec to ms
               waitInMs = myanimation->fdataarray[j].saveData.delay * 10; 
               if(waitInMs < (1000 / 30) ) // 30 frames per sec
                  waitInMs = (1000 / 30);
                        // BitBlt the bits of a frame to the screen
               if(BitBlt(hdc,
                  scrx, scry,   // X,Y of dest rect
                  cols2disp, rows2disp, // Width and height of rectangle to display
                  hMemDC, 
                  0, j * rows2disp,    // X,Y coords of source rectangle in image buffer
                  SRCCOPY) == FALSE) {
                  rcode = BAD_MEM;
                  }
               delayTime(waitInMs);   // delay in millisecs
               }
            }
         myanimation->frames = 0;  // Done displaying animation
         }  // end of the animation  ....................................................
                        // Clean up
      if(*hPal)
         SelectPalette(hMemDC, hOldPal1, 0);
      SelectObject(hMemDC, hOldBitmap);
      DeleteDC(hMemDC);
      }
                        // Restore original palette to screen DC
   if(*hPal)
      SelectPalette(hdc, hOldPal, 0);
   return(rcode);
}
// Repaint a portion or all of the window.
void DoPaint(HWND hWnd)
{
   PAINTSTRUCT ps;   // Holds PAINT info
   HDC hdc;
   int rcode, xpos, ypos;
   hdc = BeginPaint(hWnd, &ps);
   if(HPalette)   // Delete global palette object previously allocated by viewimageex()
      DeletePalette(HPalette);
                        // Display the long image with all frames top to bottom
   rcode = viewimageex(hWnd, hdc, &HPalette, xpos, ypos, &Image, 0, 0, ColorRednMode);
   if(HPalette)   // Delete palette object allocated by viewimageex()
      DeletePalette(HPalette);
                        // Display the animation alongside the image
   if (Anima.frames > 0) {
      int scrnx, scrny;
      scrnx = Image.bmh->biWidth + 1;
      scrny = 0;
      rcode = display_animation(hWnd, hdc, &HPalette, &Image, scrnx, scrny, &Anima);
    }
   EndPaint(hWnd, &ps);
                        // Handle any errors
   if(rcode != NO_ERROR)
      error_handler(hWnd, rcode);  // Your own 
}

  
Victor Image Processing Library

Victor Image Processing Library homepage | Victor Product Summary | more source code




Copyright © 2001 Catenary Systems Inc. All rights reserved. Victor Image Processing Library is a trademark of Catenary Systems.