Using ImageMagick to create a GIF test suite

25 Oct 2020

Tags: GIF ImageMagick WebAssembly


In my endeavours to build a GIF decoder for SerenityOS I soon realised the need for a suite of test GIFs to have reference targets to aim for in my implementation. Initially this involved me browsing r/gifs and the occasional Google Doodle, however it’s quite difficult to find contemporary GIFs that exhibit some of the more obscure GIF functionality. It wasn’t long before a few edge cases and bugs cropped up as people discovered GIFs with as-yet unimplemented features, and as I fixed one, another would break. I needed a better way.

Enter ImageMagick, an extremely powerful open-source platform for creating, converting, manipulating, inspecting, and visualising over 200 image file formats. It turns out that we can use ImageMagick’s command-line interface to conjure animated GIFs out of thin air. Using this we can programmatically and systematically generate a suite of GIFs that exhibit all different kinds of GIF features: perfect for testing a decoder.

You can find the GIF test suite on GitHub1. The rest of this post will give an overview of the ImageMagick command-line interface, driven by examples of GIF generation from the test suite. Each example can be run and modified interactively in the browser using a WebAssembly build of ImageMagick.

Note: the command-line examples use ImageMagick 7 which consolidates all functionality into a single magick command. All of the examples should also work with ImageMagick 6, but you will likely need to use convert instead of magick.

ImageMagick command format

An ImageMagick command is a pipeline of settings and operations that are successively applied to input images to generate an output image. The ordering of command-line parameters is therefore important as they specify this pipeline. A command consists of the following types of parameter:

Let’s explore these via some examples.

Static GIF

The following simple command draws a pale green circle on a dark green background, and saves the output as a static GIF:

magick -size 100x100 xc:DarkSeaGreen \
  -fill PaleGreen -draw "circle 50,50 15,25" \
  "static_nontransparent.gif"

Output

Breaking it down:

Basic animated GIF

To create an animated GIF, new frames can be added using the -page operator:

magick -delay 100 \
  -size 100x100 xc:transparent \
  -fill DarkSeaGreen -draw "circle 50,50 15,25" \
  -dispose previous \
  -page +10+10 -size 30x30 xc:LightSalmon \
  -page +30+30 -size 40x40 xc:SkyBlue \
  -page +60+60 -size 30x30 xc:Khaki \
  -loop 0 \
  "animated_transparent_restoreprev_loop.gif"

Output

Breaking down the differences from the previous example:

Image stacks

If you play around with the above example you may notice that performing any drawing commands on the subimages will actually draw to both the first frame, but also to any subimages that have already been specified. This is because ImageMagick applies operators to all images in its current image stack. We can open and close image stacks using parentheses in order to control which set of images to apply drawing commands to:

Note: in Bash, the parentheses must be escaped with a backslash. This may not be necessary in other shells.

magick -dispose none -delay 100 \
  -size 100x100 xc:transparent \
  -fill DarkSeaGreen -draw "circle 50,50 15,25" \
  -page +10+10 \( -size 30x30 xc:transparent -fill LightSalmon -draw "circle 15,15 5,5" \) \
  -page +20+20 \( -size 40x40 xc:transparent -fill SkyBlue -draw "circle 20,20 10,5" \) \
  -page +30+30 \( -size 30x30 xc:transparent -fill Khaki -draw "circle 15,15 5,5" \) \
  -loop 0 \
  "animated_transparent_frame_restoreprev_loop.gif"

Output

Breaking down the differences from the animated GIF example:

ImageMagick settings applicable to GIFs

Some of the settings that are of particular interest for a GIF test suite include:

Other useful ImageMagick commands

Try it yourself

Step through an ImageMagick command in your browser using the command-runner below.

Note: the initial magick command is not required, nor should you specify an output file.

loading...

References

The ImageMagick documentation is very thorough and highly recommended if you want to dive into this subject in more detail. Particularly relevant pages include:


  1. It’s forked from the original that can be found in SerenityOS. ↩︎

  2. The xc prefix stands for “X Constant”. ↩︎

  3. Old versions of ImageMagick have a bug that ignore the -interlace setting. This was fixed on 11th October 2020. ↩︎