Animating My First GIF


The more I surfed the web and compared the pages I saw to my own pages, the more firmly two conflicting views took hold in my mind:

As you can see, there's a bit of conflict here. So as I began thinking about using an animation to liven up my home page I was determined that it not interfere with the page. No long load time, no annoying flashing, no interfering with the browser's access to links on the page. My solution was to combine a GIF animation with a bit of JavaScript stolen borrowed from some kind person's page. To see the animation, move your mouse over the image to the right:

This page describes step by step how to build a GIF image like the one above, how to animate it and how to use JavaScript to switch the animation on and off. The tools I used are all free software that can be downloaded and run on Unix systems. People with other systems can, I imagine, find equivalent tools without having to pay too much of your hardly-earned cash.

Section 1: Creating the text

In the beginning there was the interesting text. This tutorial goes through the steps to take raw text and add color, 3D and shadow effects. I used a wonderful graphics program called GIMP, a free and extensible 2D image manipulator for Unix systems. A lot of the operations supported by GIMP are similar to (based on?) Adobe PhotoShop. I've followed some PhotoShop tutorials using GIMP, so I imagine you could follow this tutorial using PhotoShop.

  1. Start by creating the text. Create a new RGB image canvas (Control-N is the shortcut). Create the text and position it roughly in the center of the window. I used the Rock font, 50 pixels with an antialias setting of 5:
  2. Offset the text (Alt-O) by -3,-2. Gaussian blur (Alt-Shift-B) by 3 pixels. Contrast Autostretch (Filters -> Map -> Contrast Autostretch) the result:
  3. Invert (Alt-I) the colors in the canvas: black to white, white to black, dark to light, etc. Add (Alt-A) this canvas to the canvas from step 1 to create a raised 3D lettering effect:
  4. Create a new canvas (Control-N) that's the same size as our other canvases. Generate a Plasma Cloud (Filters -> Render -> Plasma Clouds) using the default values. Gaussian Blur it (Alt-Shift-B) by 2 pixels to reduce the sharp transitions in the image:
  5. Multiply (Alt-M) the canvas by the raised letter canvas from step 3:
  6. Now we'll create a shadow for the text. Offset the original text from step 1 (Alt-O), this time by +3,+2. Gaussian Blur (Alt-Shift-B) by 3 pixels. The result will look like the canvas from step 2.
  7. Create another new canvas (Control-N). Fill it with some color that won't be used in our final picture. Eventually, we'll make that color represent the transparent parts of the image. (I used gray: 190,190,190.) Multiply (Alt-M) this canvas by the blurred text from step 6:
  8. Composite (Alt-C) the colored text from step 5 (First Image) onto the canvas from step 7 (Second Image) using the text from step 1 as a mask (Mask Image). This means that pixels will be copied only where the mask bits are black:
  9. Now we can either convert the image from RGB to an indexed color file (Alt-Shift-I) and save it as a GIF file or (my preferred approach, since GIMP doesn't do so well with GIF formats) save it as a TIFF file and use a separate utility to convert it to a GIF. Whatever you do, do not save the image as a JPEG file if you ever want to have transparency work. The way JPEG does file compression, you'll end up with a lot of background pixels that are almost but not exactly the same color. Which means that when you convert the JPEG to a GIF and then try to make the background transparent you'll only get a subset of pixels to disappear.

Section 2: Animating The Text

GIF animations are really pretty simple: a single file contains a series of GIF images, with information on when to switch to the next image, where to position it (subsequent images can be smaller than the first) and how to combine the new image with what's already there. Our next step is to create a series of individual image files, which we'll then combine into one big file.

Not having any talent as an animator, I decided to go for a simple lighting effect. Using GIMP again, I chose a small brush and airbrushed a glowing effect onto each letter. I changed the foreground color slightly for each letter to make it a little more interesting:
Next I used the Crop tool to make individual files for each letter in both its lit and unlit state. I recorded the X and Y offset of each clip (we'll need those numbers when we assemble the animation). And I made sure to crop using the same X,Y offset for the lit and unlit versions of a letter. This wasn't strictly necessary, but did make recordkeeping easier. Notice that the clipped letters need to include every pixel where the lit and unlit versions differ; they don't need to include the complete letter-plus-shadow.

There are a variety of tools to make a GIF animation. I used GIFmerge, yet another free utility for Unix and other systems that I discovered while wandering the web. (You can find documentation, source code and even compiled versions here.) GIFmerge supports a variety of options, including transparency, variable delays and repeat counts.

GIFmerge is command-driven. Here's a simple example that turns on each letter in sequence with a one second delay:

  gifmerge -190,190,190 -100 -l100 -d0 \
     shadowText.gif			   \
     -pos9,15   on1.gif                \
     -pos43,26  on2.gif                \
     -pos69,23  on3.gif                \
     -pos100,20 on4.gif                \
     >onSequence.gif

The first argument specifies the color for transparent pixels, those for which the page's background will show through. The next value specifies a delay between frames of one second (measured in .01 second units). That's followed by an iteration count, which controls the number of times the sequence will repeat (zero repeats indefinitely). Next is the disposal mode, which determines how we handle the parts of the image left over from the previous frame. Then come the individual image files, optionally preceded by positioning information and/or unique delay values. The GIF animation gets written to standard output, in this case a file called onSequence.gif.

Of course, we can make the display seem more random and interesting by switching the letters on and off out of sequence, varying the delay and perhaps repeating some of the letters . (The illusion of randomness is easier to pull off if we have more letters to play with.)

Section 3: Stress Reduction

I don't know about you, but I find the animated images above more than a little bit distracting. We might even say annoying. (If you wait long enough they'll stop animating. There, that's better.) So the final part of the job is to give us control over the animation. The process is simple: use a little bit of JavaScript that determines when we move the mouse over the image and switches from the small, peaceful static image to the larger animated one.

The relevant code goes inside the <A> tag and specifies what should happen when the user moves the mouse onto (onMouseOver) and away from (onMouseOut) the image:

  <A HREF="javascript://" 
     onMouseOver="document.images.animate.src='gimp/animate/random.gif';
                  return true" 
     onMouseOut="document.images.animate.src='gimp/animate/allOff.gif'">
    <IMG SRC="gimp/animate/allOff.gif" WIDTH="135" HEIGHT="70"
         HSPACE="10" VSPACE="4" BORDER="0" ALIGN=RIGHT
         NAME="animate">
  </A>
Notice the NAME= item in the <IMG> tag. That lets us refer to the image by name instead of by an ordinal position within the document. Also note that the image is linked to a piece of Javascript that doesn't do anything. You have to have something in the HREF field or Javascript will ignore the onMouseOver and onMouseOut entries.

So that's it. You now know everything I know about making animated GIF files. I hope you'll use your new knowledge for the betterment of webkind and that you won't be seduced into the horror of GIF abuse. If you do, please don't tell anyone who got you started!


Take me home: Show me another:

 Comments to Hank Shiffman, Mountain View, California