The power and flexibility of the ImageMagick suite of software never fails to amaze me. Not only does ImageMagick provide several command-line tools capable of meeting all your image editing/conversion needs, there are also APIs for over a dozen languages, including Python, Ruby, and Perl. I should preface this post by declaring that I am not an expert on the use of ImageMagick, but I have used it successfully to script solutions for many of my image-editing needs. One recent task for which it spared me from having to resort to using a GUI-based image editor was converting a series of PDF slides into an animation for one of my recent posts. I wanted to document how I did this for my own memory, and in case someone else might find it useful.
If you want to follow along, create a directory and download the PDF slides:
My first step was to use the convert
tool to convert the slides into separate
PNG files:
The -density
option determines the resolution (in dots per inch) at which
to rasterize the PDF.
The -strip
option removes any comments or profiles from the output images; I
use this option a lot to reduce the file size of images for the web.
The -resize
option determines the size of the output PNG.
This option is very flexible in the arguments it can
handle;
here I use the @
symbol to specify the area in pixels
(ImageMagick will preserve the
aspect ratio).
To further reduce file size, I specified 8-bit PNG files using the PNG8:
syntax.
Lastly, the slide-%02d.png
syntax in the output file name specifies that I
want the slides to be named slide-00.png
, slide-01.png
, slide-02.png
,
etc.
Next, we can convert the PNGs into an animated GIF:
I have no idea how the -layers OptimizePlus
option works, but it optimizes
the final output to reduce the animated file size.
The -delay
option specifies the number of ticks (the default rate is 100
ticks per second) to pause each image.
The options in the command above specify to spend 3/4 of a second on the first
15 slides, and then 3 seconds on the last three slides.
The -loop
option specifies the number of times the GIF animation should
repeat;
setting it to zero will cause the GIF to repeat indefinitely.
We can use the same command (minus the loop
option) to create a movie out of
the PNG images:
Here, we specified an MP4, but other output formats are supported. I think ImageMagick uses ffmpeg in the background to make the video, so you might have to install it. You can also use ffmpeg directly:
Either way, you should end up with a video like the following:
NOTE: The video is not displaying for some OS/browser combinations. If it’s not working for you, check out the animated GIF below.
Pretty slick; with just a few simple command lines, we went from a PDF to an animated GIF and movie. Ok, let’s clean up all those intermediate PNGs:
Next, we can make a faux play-button image, which, when used with a little javascript, will make the GIF appear controllable. To make the “play button,” we’ll start with a simple blue triangle, which you can download:
We can use convert
to add a shadow to the triangle to make it stand out a bit:
This command was taken, almost verbatim, from the fantastic ImageMagick documentation.
Next, we will parse the GIF frames into individual PNG files in order to overlay the play button onto the first frame.
NOTE: I realize we could have avoided this step by simply using the PNG files we just deleted above, but I often have a GIF as the starting point for this task, and so I wanted to document how to convert the GIF into separate frames.
Next, let’s overlay the shadowed play button:
Now, slides.png
is the first frame of the GIF and looks like it has a “play”
button on it.
Notice that I named the output “play-button” as slides.png
such that the
prefix matches the slides.gif
file we made above.
That was intentional, because now we can use some javascript sleight-of-hand to
make the GIF appear controllable on the web.
Here’s the javascript magic that I found on
codepen:
Adding this javascript to our page allows us to use the gif-hover
class when
embedding the PNG/GIF as an image:
The result is the following GIF that will “play” when moused over.
If we prefer to “control” the GIF with mouse clicks, we can modify the javascript a bit:
Now, we can use the gif-click
class for the image:
The result is the following GIF that will start/stop with mouse clicks.
Notice, the javascript functions work by simply changing the path from the “play-button” PNG file to the GIF, and vice versa. For this to work, the files need to be in the same directory and share the same prefix. A little hacky, no doubt, but it works.