Making Animated GIFs from the Linux Command Line

Posted by Doug Haber on 2013-08-04

Introduction

There are a lot of different tools available for making animated GIFs in Linux. This post discusses my approach at converting videos into animated GIFs from the command line in Linux. I will also provide a wrapper script that I've created for making this process easier.

In figuring this out I came across a lot of incorrect information. I'm still not sure I've got it all perfectly right, but I think I have improved on suggestions I've seen elsewhere. If you have any better techniques or improvements, please mention it in the comments.

My main purpose in using animated GIFs is to demonstrate a very brief clip from a game or tool. Animated GIFs come in handy when there is a very small animated clip that doesn't require audio. Unlike video, they embed on pages just like images and are fairly painless to view on any platform without plugins. If the size is small enough they can also be uploaded to sites like Imgur.

Technique

My approach at this uses two tools. The ffmpeg program is used to take a video file and break it down into individual GIF files for each frame at a given frame rate. This is a great utility that can read from a very wide variety of file formats. It also can do things like cutting clips out of large videos, which can be very useful when making animated GIFs.

Once I have the image files for the frames I use ImageMagick's convert utility to take each frame and build an animated GIF. ImageMagick is a swiss army knife tool for image manipulation and generation, and using it here makes a lot of other changes possible as well.

Here is an example of the basic technique:
# Create a GIF for each from $INPUT_FILE at the framerate $FPS
ffmpeg -i $INPUT_FILE -r $FPS frameTemp.%05d.gif

# Take each of the frame GIFs and make an animated GIF out of them
# $DELAY is in hundredths of a second, so 100 / fps
convert  -layers removeDups -layers Optimize -delay $DELAY \
         -loop 0 frameTemp.*.gif $OUTPUT_FILE

# And here is a real example, without the variable place holders.
# Create individual frame image files from input.mpg at 8 frames per second
ffmpeg -i input.mpg -r 8 frameTemp.%05d.gif

# Delay is 100 / 8 which is 12.5, which rounds up to 13
convert -delay 13 -loop 0 frameTemp.*.gif output.gif

It is important to note that the delay for convert is in hundredths of a second and must be an integer. This means that the correct speed is not possible to maintain accurately at high FPS values. For example, 60 FPS is 1.6666 hundredths of a seconds (100 divided by 60.) So, if we round that up to 2, then the animation will run 20% faster than it should. Generally animated GIFs have much lower frame rates due to file size, so this isn't much of an issue.

The "-layers" arguments are used to enable various optimizations on the GIF being created. They do make the conversion take longer, but when used the resulting GIF may have a far lower file size. These can effect quality. For more details, see ImageMagick's Optimization Examples.

Automating with GifMaker

While the steps in the above section can be done by hand to do the conversion, they are a little bulky. Lots of temporary files are created for the frames and the delay needs to be calculated in order to get accurate timing. To make this easier I've written a little Perl wrapper called gifmaker.

The gifmaker tool is a simple approach at automating this process. It cleanly handles all the validation and tempfiles along the way. The tool itself is available on github and is under a BSD license.

The dependencies are Perl, ImageMagick, and FFmpeg. In Ubuntu, those can be installed via apt-get:
apt-get install perl imagemagick ffmpeg

Usage Examples

USAGE: gifmaker [input_file] ([output_file] [frames_per_second])
     input_file - The input video file to convert (Required)
     output_file - The GIF file to be created (Default=out.gif)
     frames_per_second - The GIF's frame rate. (Default=10)

The only required parameter is the input file. This can be any format supported by ffmpeg. When the extra parameters are not provided, defaults that are specified in the configuration are used.

Here are some examples of how this works:
# Convert input.avi to an animated GIF with the default output file and FPS
gifmaker input.avi

# Convert input.mpg to a GIF named demo.gif at 5 FPS
gifmaker input.mpg demo.gif 5

# Convert input.mpg to a GIF named demo.gif at the default (10) FPS
gifmaker input.mpg demo.gif

Advanced Usage

That is the basics of how it works, but both ffmpeg and convert are very powerful tools. I chose to use them over others because of their advanced capabilities.

The environment variables "FFMPEG_ARGS" and "CONVERT_ARGS" allow extra arguments to be passed to those commands. This is where the real magic happens.

Below I will provide a few examples of how to do some useful things. The possibilities go well beyond this. For more details on what types of things can be done, see the manuals for ffmpeg and imagemagick.

Cutting a Clip Out of a Larger Video File

With ffmpeg it is easy to take a clip out of a video by specifying the start time and duration.
# Create a 3 second clip starting at 1 minute and 35 seconds
FFMPEG_ARGS="-ss 00:01:35 -t 3" gifmaker input.mp4

# Create a 5 second clip starting 1 hour 10 minute and 7.25 seconds
FFMPEG_ARGS="-ss 01:10:07.250 -t 5" gifmaker input.mp4

Scaling & Resizing

The convert command makes it very easy to resize the animation.
# Resize the output GIF to 50% of its current size
CONVERT_ARGS="-resize 50%" gifmaker input.ogv

# Resize the output GIF to 320x200
CONVERT_ARGS="-resize 320x200" gifmaker input.ogv

Drawing an Overlay

The convert command has a lot of drawing capabilities. You can easily draw shapes, images, and text on top of each frame. Here is an example where we write text into the image:
# Write the text 'Sample Text' at 10,100 in a 72pt font
CONVERT_ARGS="-pointsize 72 -draw \"text 10,100 'Sample Text'\"" gifmaker input.avi
Here is an example where we draw a logo over the image in each frame from an image file.
# Draw a logo found in logo.png at 300,200 sized to 150x100 onto each frame
CONVERT_ARGS="-draw \"image over 300,200 150,100 logo.png\"" gifmaker input.avi

Cropping an Area from the Video File

If you want to crop the section of the image being made, that can be done with filters in FFMPEG. The format is "-vf crop=width:height:x:y"
# Crop a section of 150x150 with an upper left corner at 100x100
FFMPEG_ARGS="-vf crop=150:150:100:100" gifmaker input.mp4

Configuration

Towards the beginning of the gifmaker script there is a configuration section. This is available so that default settings and preferences can easily be changed.
my $CONFIG = {
    ffmpeg => 'ffmpeg',       # ffmpeg binary
    convert => 'convert',     # ImageMagick convert binary
    output_file => 'out.gif', # Default file to write to
    default_fps => 10,        # Default frames per second
    ffmpeg_args => '',        # Extra arguments for ffmpeg
    convert_args => '-layers removeDups -layers Optimize', # Extra arguments for convert
};
The "ffmpeg" and "convert" options allow the binaries to be specified. If you prefer an alternate binary the name or full path can be provided.

The "args" options allow for extra parameters to be provided for the convert and ffmpeg commands. This is useful if you want to always specify something, such as a default quality setting. The convert command does have some optimizations enabled by default which can help greatly reduce the final file size, but may also effect quality. For full details on those options, see here.

The "output_file" lets you specify the name of the default file for when no output file is specified. The "default_fps" lets you configure your preferred default FPS value for when none is provided.

Download

The gifmaker script is available HERE on github. To download a raw copy, use THIS link. It is distributed under a BSD license that is included within the script.

See Also

Updates

2013-08-09
  • This document and the gifmaker script have been updated to enable ImageMagick optimizations by default
  • A "See Also" section has been added to this document
  • Added an example of how to crop the video input file



  • comments powered by Disqus

    Featured Apps


  • Leshy SpriteSheet Tool
  • Sprite Sheet Packer, Mapper, and Editor
  • Leshy SFMaker
    Sound FX Generator
  • Leshy Tuner
    HTML5 Chromatic Instrument Tuner
  • Leshy Fractal Explorer
    Web Based Fractal Browser
  • Leshy SpriteSheet Animator
    SpriteSheet Animation Manager

  •