Victor Image Processing Library How-to Tips

Create an animated GIF



rotate.gif
Rotating image created with Victor functions rotate and savegifframe.


The animation is contained in a series of frames in a single GIF file. The sequence followed is:


VB Source Code | C/C++ Source Code


Create a Rotating Image Animation - the Visual Basic Source Code

Requires Victor Image Processing Library v 5.3 or higher.

Private Sub mnumakeanimatedgif_Click()
Dim rcode As Long
Dim loadfname As String
Dim tdat As TiffData
Dim frames As Long
Dim srcimg As imgdes
Dim savefname As String
Dim savesegments As Boolean
    loadfname = "victor.tif"
    rcode = tiffinfo(loadfname, tdat)
    If (rcode = NO_ERROR) Then
        rcode = allocimage(srcimg, tdat.width, tdat.length, tdat.vbitcount)
        If (rcode = NO_ERROR) Then
            rcode = loadtif(loadfname, srcimg)
            If (rcode = NO_ERROR) Then
                frames = 10
                savefname = "rotate.gif"
                savesegments = False
                rcode = makespinningGIF(frames, srcimg, savefname, savesegments)
            End If
            freeimage srcimg
        End If
    End If
End Sub
' A helper function to find the white color in the palette.
Private Function findwhite(srcimg As imgdes) As Long
Dim gifPalette(0 To 255) As RGBQUAD
Dim j As Long
Dim r As Long, g As Long, b As Long
Dim maxwhite As Long
Dim maxwhiteindex As Long
  CopyMemory gifPalette(0), srcimg.palette, srcimg.colors * 4
  maxwhiteindex = -1
  
  For j = 0 To srcimg.colors - 1
    r = gifPalette(j).rgbRed
    g = gifPalette(j).rgbGreen
    b = gifPalette(j).rgbBlue
    If r = g And r = b Then
      If r > maxwhite Then
        maxwhiteindex = j
        maxwhite = r
      End If
    End If
  Next
findwhite = maxwhiteindex
End Function
Public Function makespinningGIF(frames As Long, srcimg As imgdes, savefname As String, Optional savesegments As Boolean) As Long
Dim srcimgBMH As BITMAPINFOHEADER
Dim rcode As Long
Dim cols As Long, rows As Long
Dim j As Long
Dim diagonal As Long
Dim ddiagonal As Double
Dim desimg As imgdes
Dim foundwhite As Long
Dim gdata As GifGlobalSaveData
Dim fdata As GifFrameSaveData
  CopyMemory srcimgBMH, srcimg.bmh, 40
  If srcimgBMH.biBitCount <> 8 Then
    makespinningGIF = BAD_BPP: Exit Function
  End If
  
  cols = CALC_WIDTH(srcimg)
  rows = CALC_HEIGHT(srcimg)
  foundwhite = findwhite(srcimg)
  
  ddiagonal = Sqr(cols ^ 2 + rows ^ 2)
  diagonal = ddiagonal + 0.5
  
            ' GIF global data used by savegifframe()
  gdata.scrwidth = diagonal
  gdata.scrlength = diagonal
  gdata.hasColorMap = 1         ' Global color table is present!
  gdata.bckColor = foundwhite   ' Color index of screen backgnd
  gdata.loop = 1000             ' Number of iterations
  
  fdata.startx = 0
  fdata.starty = 0              ' X,Y pixel position with respect to scrwidth, scrlength
  fdata.hasColorMap = 0         ' Local color table present?
  fdata.delay = 1               ' 100ths of a second to display frame
  fdata.transColor = -1         ' Transparent color index, -1 => none
  fdata.waitForUserInput = 0    ' If true, expect user input
  fdata.removeBy = 2            ' How graphic is to be treated after display
            '    0  The image is left unremoved
            '    1  The image is left unremoved
            '    2  The image is replaced by the background
            '    3  The image is replaced by the previous image
  
  rcode = allocimage(desimg, diagonal, diagonal, 8)
  copyimagepalette srcimg, desimg
  
  For j = frames - 1 To 0 Step -1
    Dim angle As Double
    Dim tmpangle As Double
    Dim dx As Long, dy As Long
    
    zeroimage foundwhite, desimg
    angle = 360 / frames * j
    
            ' Calc the width and height of the rotated image area
    tmpangle = angle
    Do While tmpangle > 90: tmpangle = tmpangle - 90: Loop
    If (angle >= 0 And angle <= 90) Or (angle > 180 And angle <= 270) Then
      dx = (Sin(D2R * (tmpangle)) * rows) + (Sin(D2R * (90 - tmpangle)) * cols)
      dy = (Sin(D2R * (tmpangle)) * cols) + (Sin(D2R * (90 - tmpangle)) * rows)
    ElseIf (angle > 90 And angle <= 180) Or (angle > 270 And angle < 360) Then
      dx = (Sin(D2R * (tmpangle)) * cols) + (Sin(D2R * (90 - tmpangle)) * rows)
      dy = (Sin(D2R * (tmpangle)) * rows) + (Sin(D2R * (90 - tmpangle)) * cols)
    End If
    
            ' Set the area into which to place the rotated image
    desimg.stx = (diagonal - dx) / 2
    desimg.sty = (diagonal - dy) / 2
    desimg.endx = desimg.stx + dx - 1
    desimg.endy = desimg.sty + dy - 1
    rotate angle, srcimg, desimg
    
            ' Restore starting position, save whole frame
    desimg.stx = 0
    desimg.sty = 0
    desimg.endx = diagonal - 1
    desimg.endy = diagonal - 1
    
    If savesegments = False Then
      rcode = savegifframe(savefname, desimg, gdata, fdata, GIFNOCOMP)
    Else
      rcode = savegifframe(left(savefname, Len(savefname) - 4) & Format(j, "000") & ".gif", desimg, gdata, fdata, GIFNOCOMP)
    End If
  Next
  
  freeimage desimg
  
  makespinningGIF = rcode
End Function

Create a Rotating Image Animation - the C Source Code

Requires Victor Image Processing Library v 5.3 or higher.
// A helper function to find the white color in the palette.
int findwhite(imgdes *srcimg)
{
   int j;
   int r, g, b;
   int maxwhite = 0;
   int maxwhiteindex = -1;
   for(j = 0; j <= srcimg->colors; j++) {
      r = srcimg->palette[j].rgbRed;
      g = srcimg->palette[j].rgbGreen;
      b = srcimg->palette[j].rgbBlue;
      if(r == g && r == b)
         if (r > maxwhite) {
            maxwhiteindex = j;
            maxwhite = r;
            }
      }
   return maxwhiteindex;
}
/* A helper function that does a fast calculation of
   rotated width =  costheta * cols + sintheta * rows 
   rotated height = sintheta * cols + costheta * rows 
see any graphics (or trig) textbook for details.  */
// Calculate the cols and rows (in pixels) that will contain the rotated image area.  
static void calcMinRotImageArea(double angDeg, imgdes far *image,
   int far *dcols, // Dimensions of image area that can hold the 
   int far *drows) //  rotated source image
{
#define L_MULTIP 15 // Power of 2 to scale doubles to
#define MRD_FACTOR (double)(1L << L_MULTIP)
#define MRL_FACTOR (1L << L_MULTIP)
#define MRSCALE_UPD(dval) ((long)((dval) * MRD_FACTOR))
#define MRSCALE_DNL(lval) ((int)((lval + (MRL_FACTOR - 1)) / MRL_FACTOR))
#define PI 3.141592654
#define DEGTORAD(ang) ((ang) * PI / 180.0)
   unsigned cols, rows;
   long sintheta, costheta;
   double angRad;
            // Make sure angle lies between -360 -> +360
   while(angDeg > 360.0)
      angDeg -= 360.0;
   while(angDeg < -360.0)
      angDeg += 360.0;
            // Convert angle to radians
   angRad = DEGTORAD(angDeg);
            // Calc a long int version of our sine and cosine
   sintheta = MRSCALE_UPD( sin(angRad) );
   costheta = MRSCALE_UPD( cos(angRad) );
   
            // Calc absolute values of sine and cosine
   if(sintheta < 0L)
      sintheta = -sintheta;
   if(costheta < 0L)
      costheta = -costheta;
   cols = CALC_WIDTH(image);
   rows = CALC_HEIGHT(image);
   *dcols = MRSCALE_DNL( costheta * cols + sintheta * rows );
   *drows = MRSCALE_DNL( sintheta * cols + costheta * rows );
}
int makespinningGIF(int frames, imgdes *srcimg)
{
   int rcode = NO_ERROR;
   int cols, rows;
   int j;
   int diagonal;
   double ddiagonal;
   imgdes desimg;
   int foundwhite;
   GifGlobalSaveData gdata;
   GifFrameSaveData fdata;
   if(srcimg->bmh->biBitCount != 8)
      return(BAD_BPP);
   
   cols = CALC_WIDTH(srcimg);
   rows = CALC_HEIGHT(srcimg);
   foundwhite = findwhite(srcimg);
   ddiagonal = sqrt( (double) (cols*cols +rows*rows) );
   diagonal = (int)(ddiagonal+.5);
            // GIF global data used by savegifframe()
   gdata.scrwidth = diagonal;
   gdata.scrlength = diagonal;
   gdata.hasColorMap = TRUE;     // Global color table is present!
   gdata.bckColor = foundwhite;  // Color index of screen backgnd
   gdata.loop = 1000;            // Number of iterations
   fdata.startx = 0;
   fdata.starty = 0; // X,Y pixel position with respect to scrwidth, scrlength
   fdata.hasColorMap = FALSE;    // Local color table present?
   fdata.delay = 1;              // 100ths of a second to display frame
   fdata.transColor = -1;        // Transparent color index, -1 => none
   fdata.waitForUserInput = FALSE; // If true, expect user input
   fdata.removeBy = 2;           // How graphic is to be treated after display
            // 0  The image is left unremoved
            // 1  The image is left unremoved
            // 2  The image is replaced by the background
            // 3  The image is replaced by the previous image
   rcode = allocimage(&desimg, diagonal, diagonal, 8);
   copyimagepalette(srcimg, &desimg);
   for(j = frames-1; j >= 0; j--) {
      double angle;
      int dx, dy;
      zeroimage(foundwhite, &desimg);
      angle = (double) (360 / (double)frames * (double)j);
            // Calc the width and height of the rotated image area  
      calcMinRotImageArea(angle, &Image, &dx, &dy);
            // Set the area into which to place the rotated image
      desimg.stx = (diagonal - dx) / 2;
      desimg.sty = (diagonal - dy) / 2;
      desimg.endx = desimg.stx + dx - 1;
      desimg.endy = desimg.sty + dy - 1;
      rotate(angle, srcimg, &desimg);
            // Restore starting position, save whole frame
      desimg.stx = 0;
      desimg.sty = 0;
      desimg.endx = diagonal - 1;
      desimg.endy = diagonal - 1; 
      rcode = savegifframe("rotate.gif", &desimg, &gdata, &fdata, GIFNOCOMP);
      }
   freeimage(&desimg);
   return (rcode);
}
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.