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 FileWith 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 & ResizingThe 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 OverlayThe 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 FileIf 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-09This document and the gifmaker script have been updated to
enable ImageMagick optimizations by defaultA "See Also" section has been added to this documentAdded an example of how to crop the video input file