![]() |
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:
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:
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 CodeRequires 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 homepage | Victor Product Summary | more source code