The Alphabet of Nations
How to create an animated GIF from a sequence of scanned JPG images in the Linux Terminal
Elizabeth Wotawa
Before we get into the technical details of this article, I need to tell you one thing: I am a They Might be Giants fan.
A t-shirt wearing, concert-going, lyric-memorizing, cubicle-dance-party-throwing fan. Jumping around to The Guitar is a great way to blow off steam after a few hours of overtime. Be careful not to scare the cleaning crew, though.
So, naturally, when KMSU 89.7 FM announced their annual They Might be Playing They Might be Giants marathon, I got excited. Even better, there was a coloring contest:
The #TheyMightBeColoring contest is back! Go to https://t.co/zX9mJb7ir2 for details! Show off your creativity and love for @tmbg and you could win fabulous prizes! * pic.twitter.com/2Q5hcP6BPq
— They Might Be Playing TMBG (@TMBGdotLOVE) October 24, 2019
WITH PRIZES:
* It's buttons. You could win buttons. pic.twitter.com/K3aq6Fc7WF
— They Might Be Playing TMBG (@TMBGdotLOVE) October 24, 2019
As I looked at the two templates, I worked my way through the TMBG songbook for inspiration. John Linnell came out with a great album called State Songs when I was in college, but I couldn't quite figure out how to get the melodies to fit with the map of the United States. I then thought of another TMBG song from Here Come the ABCs: The Alphabet of Nations.
I hope you like the song. If you're anything like me, you'll be singing it to yourself for the next month.
Now this song had potential. I had the option of a world map template. I started to identify the countries and to incorporate their names into the design. As I was going, I realized that the design would be a lot more fun for the viewer if he or she could follow along with the melody. Hence the purpose of this article: how to use ImageMagick and Gifsicle on the Linux command line to create an animated GIF from scanned JPG images.
The Setup
I really did want to color the template for the contest, but I also wanted to honor the tech theme of my Twitter handle. I settled on a hybrid approach:
- Color the image by hand.
- Scan the document as I complete each colored component.
- Animate the series of scans as an animated GIF.
I started with JPG images due to a hardware limitation: my scanner can only save to PDF or to JPG.
Image Reformatting
The first step is to convert the images into a GIF format so that they can be consolidated into the animation. I decided to use ImageMagick, an open-source software suite for working with image files, to convert my JPG scans into the GIF format. I recently purchased a new computer and thus was working with a fresh install of ImageMagick. You can follow along with my install process in the TecMint article, How to Install ImageMagick 7 on Debian and Ubuntu.
After opening a new terminal, I used the cd
command to navigate into the folder where I stored my images.
I used the ls
command to confirm that I was working in the correct folder.
~/Documents/alphabet$ ls 00_the.JPG 13_japan.JPG 26_w_xylophone.JPG 01_alphabet.JPG 14_kazakhstan.JPG 27_yemen.JPG 02_of.JPG 15_libya.JPG 28_zimbabwe.JPG 03_nations.JPG 16_mongolia.JPG 29_tmbp_outline.JPG 04_algeria.JPG 17_norway.JPG 30_tmbg_outline.JPG 05_bulgaria.JPG 18_oman.JPG 31_kmsu.JPG 06_cambodia.JPG 19_pakistan.JPG 32_spirals.JPG 07_dominica.JPG 20_qatar.JPG 33_tmbp_fill.JPG 08_egypt.JPG 21_russia.JPG 34_tmbg_fill.JPG 09_france.JPG 22_suriname.JPG 35_final.JPG 10_the_gambia.JPG 23_turkey.JPG 11_hungary.JPG 24_uruguay.JPG 12_iran.JPG 25_vietnam.JPG
I then entered ImageMagick's convert
command to iterate through each JPG image in the folder and create a copy in GIF format:
~/Documents/alphabet$ convert *.jpg %d.gif
*
is a wildcard that will read all files with the JPG extension in the path referenced on the command line. %d
is a wildcard that will assign a unique name to each new GIF file.
The Error
Unfortunately, there was a small wrinkle in my process. Rather than returning a series of GIF files, my terminal returned the following error message:
convert: unable to open image '*.jpg': No such file or directory @ error/blob.c/OpenBlob/3497. convert: no decode delegate for this image format `JPG' @ error/constitute.c/ReadImage/561. convert: no images defined `*.gif' @ error/convert.c/ConvertImageCommand/3273.
After some digging, Googling, and sifting through Stack Overflow, I stumbled upon the following command:
~/Documents/alphabet$ convert -list format
The command returns a list of the file formats that ImageMagick supports. I have included a copy of the table at the end of the article for reference.
I was impressed at how thorough the list was. However, when I scrolled down to the J section, I realized why ImageMagick was throwing the error. ImageMagick does not support JPG file formats out of the box. Their supported formats page offered some insight. To use files in a JPG format, I would need to install an additional package, jpegsrc.v8c.tar.gz
, then reinstall ImageMagick.
The format of the tarball for JPG format support looked very similar to the one I had just used to install ImageMagick. I decided to try the same install method for JPG image support as I had for ImageMagick itself.
JPG Format Support Package for ImageMagick
I used the following process to install JPG format support for ImageMagick on my machine. More information about the package is available on its Web site.
Get to the correct directory location
I had been working in the folder with my images when I encountered the error, so I needed to get back to base directory before I could continue with the install. cd ..
is a common terminal command for this task, and one I use when I don't want to open a new terminal window.
Install updates
I next executed the following steps to ensure that my version of build-essential
was up-to-date:
$ sudo apt update $ sudo apt-get install build-essential
Download and decompress the tarball
I downloaded a copy of the tarball to my machine:
$ wget http://www.ijg.org/files/jpegsrc.v8c.tar.gz
A tarball is a compressed file format, similar to a ZIP file. I therefore needed to decompress the tarball before installing the package:
$ tar xvzf jpegsrc.v8c.tar.gz
Configure the package
The ls
command on my working directory showed a new folder, jpeg-8c
. I used the cd
command to move into this directory:
$ cd jpeg-8c
I then ran the configure, make, and install commands shown below:
~/jpeg-8c$ ./configure ~/jpeg-8c$ make ~/jpeg-8c$ sudo make install ~/jpeg-8c$ sudo ldconfig /usr/local/lib
Reinstall ImageMagick
Now that I had JPG format support, I needed to re-install ImageMagick so that the program would recognize the new package. Again, I'd recommend the TecMint article I referenced above.
I can haz JPG?
Before I went any further, I wanted to make sure that ImageMagick would now understand the JPG file format. I ran the ImageMagick command again to show the supported format list.
$ convert -list format
I found a few updates.
Format Mode Description ------------------------------------------------------------------------------- JNX* r-- Garmin tile format JPE* rw- Joint Photographic Experts Group JFIF format (libjpeg 80) JPEG* rw- Joint Photographic Experts Group JFIF format (libjpeg 80) JPG* rw- Joint Photographic Experts Group JFIF format (libjpeg 80) JPS* rw- Joint Photographic Experts Group JFIF format (libjpeg 80) JSON -w+ The image format and characteristics
Now I could continue with my image format conversion exercise.
Image Reformatting, Take 2
I navigated back to the folder where I had stored my JPG scans, and I attempted to run the convert
command again.
~/Documents/alphabet$ convert *.jpg %d.gif
This time the command ran without error. A quick look at the directory revealed twice as many files as I had previously: the original list of JPG files and an enumerated list of GIF files. I moved each file type into its own directory before continuing forward. For the next step of the process, I'd be working with just the GIF images.
~/Documents/alphabet/gif$ ls 0.gif 13.gif 17.gif 20.gif 24.gif 28.gif 31.gif 35.gif 6.gif 10.gif 14.gif 18.gif 21.gif 25.gif 29.gif 32.gif 3.gif 7.gif 11.gif 15.gif 19.gif 22.gif 26.gif 2.gif 33.gif 4.gif 8.gif 12.gif 16.gif 1.gif 23.gif 27.gif 30.gif 34.gif 5.gif 9.gif
Animate the GIF
Now that I had a sequence of GIF files, I could use the Gifsicle application to merge them into an animated GIF.
GIF Animation in ImageMagick
I realized by accident that ImageMagick also can create animated GIFs. If you want a quick preview of how the animated GIF will look, you can use the convert
command to merge the images into a single file:
~/Documents/alphabet$ convert *.jpg animation.gif
However, I wanted more control over several details in the animation. I found an article by Himanshu Arora, How to Create and Edit Animated GIFs from the Command Line in Ubuntu. I will walk you through the steps relevant to my project below, but I recommend Arora's work for a more comprehensive introduction.
Getting Started with Gifsicle
Gifsicle is a command-line tool for creating, editing, and getting information about GIF images and animations.
I returned to my root directory using the cd ..
command. I entered the following command to install the program:
$ sudo apt-get install gifsicle
Prep the GIF files
I navigated to the directory where I had stored my GIF images. I made a few final edits before I began working with Gifsicle:
- Ordered my images. I prefixed all of the ordinal numbers so that they were the same length: represent
1
as01
if your largest number is 99 or lower,001
if your largest number is 100 or higher, e.g. - Duplicated a few images. If you listen to The Alphabet of Nations, some of the country names receive two beats while others receive one. I wanted folks to be able to sing along to the rhythm of the GIF, so I made copies of the appropriate country images to match the rhythm of the song.
Create the Animated GIF
I used the command below to generate my first animated GIF file.
~/Documents/alphabet/gif$ gifsicle --delay=100 loopcount=forever *.gif>alphabet_of_nations.gif
The command breaks down into a few components:
gifsicle
initiates the command.--delay
tells Gifsicle how many hundredths of a second each image in the animated GIF should appear.loopcount=forever
tells Gifsicle that I want the images to loop continuously rather than stopping at the end of one or more sequences.*.gif
tells Gifsicle that I want to include all files with the.gif
extension in my working directory in the animated GIF.alphabet_of_nations.gif
is the name of the animated GIF file.
You can read more about these options on Gifsicle's man (manual) page. You can access the man pages one of two ways:
- On the web. The author of Gifsicle included the man pages on Gifsicle's Web page.
- In the terminal. Enter the command
man gifsicle
to return the same information in the terminal.
Fine-Tune the Animated GIF
The first refinement I made to the animated GIF involved the --delay
option: I wanted the pace of the GIF to approximate the tempo of the song. I settled on a delay of 80
.
Satisfied with the outcome, I tried to upload the file to Twitter to submit my image for the #TheyMightBeColoring competition. That's when I found out that Twitter has a file size limit. Animated GIFs can be up to 5MB on mobile and up to 15MB on web. Yeah, that animated GIF was HUGE since I had started with so many scanned images.
Fortnuately, Gifsicle has a few options that facilitate file compression. I chose to work with scale
, optimize
, and colors
.
scale
adjusts the size of the image. I decided to reduce mine by half.optimize
optimizes the animated GIF for space.colors
reduces the number of colors in the output GIF to no more than the number specified in the command. Because I had scaled down the image, I had space for 256 colors.
After these adjustments, my final Gifsicle command looked as follows:
~/Documents/alphabet/gif$ gifsicle --delay=80 --colors 256 --scale 0.5 --optimize *.gif > alphabet_of_nations_opt_256.gif
The final file size was 5.8MB, which meant that I could upload it to Twitter.
I Might be Coloring
The last step was to submit my animated GIF to the coloring contest.
In the spirit of my Twitter account's tech theme, I created a sing-along @tmbg @tmbgdotlove coloring contest entry: The Alphabet of Nations!
— Elizabeth W (@PenguinPhoenixE) November 4, 2019
May you enjoy this earworm as much as I have.
Stay tuned for a how-to article.#TheyMightBeColoring pic.twitter.com/L5SjvZwt2f
You're singing along, aren't you? So am I.
Additional Resources
Below are a few additional resources you can consult if you'd like to make your own animated GIF.
- Himanshu Arora, How to Create and Edit Animated GIFs from the Command Line in Ubuntu
- ImageMagick
- How to add support for the JPEG image format
- Aaron Kili, How to Install ImageMagick 7 on Debian and Ubuntu
- Gifsicle
- How to post photos or GIFs on Twitter
- ImageMagick - Formats
ImageMagick Supported Image Formats
Format Mode Description ------------------------------------------------------------------------------- 3FR r-- Hasselblad CFV/H3D39II 3G2 r-- Media Container 3GP r-- Media Container A* rw+ Raw alpha samples AAI* rw+ AAI Dune image AI rw- Adobe Illustrator CS2 ART* rw- PFS: 1st Publisher Clip Art ARW r-- Sony Alpha Raw Image Format AVI r-- Microsoft Audio/Visual Interleaved AVS* rw+ AVS X image B* rw+ Raw blue samples BGR* rw+ Raw blue, green, and red samples BGRA* rw+ Raw blue, green, red, and alpha samples BGRO* rw+ Raw blue, green, red, and opacity samples BMP* rw- Microsoft Windows bitmap image BMP2* rw- Microsoft Windows bitmap image (V2) BMP3* rw- Microsoft Windows bitmap image (V3) BRF* -w- BRF ASCII Braille format C* rw+ Raw cyan samples CAL* r-- Continuous Acquisition and Life-cycle Support Type 1 Specified in MIL-R-28002 and MIL-PRF-28002 CALS* r-- Continuous Acquisition and Life-cycle Support Type 1 Specified in MIL-R-28002 and MIL-PRF-28002 CANVAS* r-- Constant image uniform color CAPTION* r-- Caption CIN* rw- Cineon Image File CIP* -w- Cisco IP phone image format CLIP* rw+ Image Clip Mask CMYK* rw+ Raw cyan, magenta, yellow, and black samples CMYKA* rw+ Raw cyan, magenta, yellow, black, and alpha samples CR2 r-- Canon Digital Camera Raw Image Format CRW r-- Canon Digital Camera Raw Image Format CUBE* r-- Cube LUT CUR* rw- Microsoft icon CUT* r-- DR Halo DATA* rw+ Base64-encoded inline images DCM* r-- Digital Imaging and Communications in Medicine image DICOM is used by the medical community for images like X-rays. The specification, "Digital Imaging and Communications in Medicine (DICOM)", is available at http://medical.nema.org/. In particular, see part 5 which describes the image encoding (RLE, JPEG, JPEG-LS), and supplement 61 which adds JPEG-2000 encoding. DCR r-- Kodak Digital Camera Raw Image File DCRAW r-- Raw Photo Decoder (dcraw) DCX* rw+ ZSoft IBM PC multi-page Paintbrush DDS* rw+ Microsoft DirectDraw Surface DNG r-- Digital Negative DPX* rw- SMPTE 268M-2003 (DPX 2.0) Digital Moving Picture Exchange Bitmap, Version 2.0. See SMPTE 268M-2003 specification at http://www.smtpe.org DXT1* rw+ Microsoft DirectDraw Surface DXT5* rw+ Microsoft DirectDraw Surface EPDF rw- Encapsulated Portable Document Format EPI rw- Encapsulated PostScript Interchange format EPS rw- Encapsulated PostScript EPS2 -w- Level II Encapsulated PostScript EPS3 -w+ Level III Encapsulated PostScript EPSF rw- Encapsulated PostScript EPSI rw- Encapsulated PostScript Interchange format ERF r-- Epson RAW Format FAX* rw+ Group 3 FAX FAX machines use non-square pixels which are 1.5 times wider than they are tall but computer displays use square pixels, therefore FAX images may appear to be narrow unless they are explicitly resized using a geometry of "150x100%". FILE* r-- Uniform Resource Locator (file://) FITS* rw- Flexible Image Transport System FLV rw+ Flash Video Stream FRACTAL* r-- Plasma fractal image FTP* --- Uniform Resource Locator (ftp://) FTS* rw- Flexible Image Transport System G* rw+ Raw green samples G3* rw- Group 3 FAX G4* rw- Group 4 FAX GIF* rw+ CompuServe graphics interchange format GIF87* rw- CompuServe graphics interchange format (version 87a) GRADIENT* r-- Gradual linear passing from one shade to another GRAY* rw+ Raw gray samples GRAYA* rw+ Raw gray and alpha samples HALD* r-- Identity Hald color lookup table image HDR* rw+ Radiance RGBE image format HISTOGRAM* -w- Histogram of the image HRZ* rw- Slow Scan TeleVision HTM* -w- Hypertext Markup Language and a client-side image map HTML* -w- Hypertext Markup Language and a client-side image map HTTP* --- Uniform Resource Locator (http://) HTTPS* r-- Uniform Resource Locator (https://) ICB* rw- Truevision Targa image ICO* rw+ Microsoft icon ICON* rw- Microsoft icon IIQ r-- Phase One Raw Image Format INFO -w+ The image format and characteristics INLINE* rw+ Base64-encoded inline images IPL* rw+ IPL Image Sequence ISOBRL* -w- ISO/TR 11548-1 format ISOBRL6* -w- ISO/TR 11548-1 format 6dot JNX* r-- Garmin tile format JSON -w+ The image format and characteristics K* rw+ Raw black samples K25 r-- Kodak Digital Camera Raw Image Format KDC r-- Kodak Digital Camera Raw Image Format LABEL* r-- Image label M* rw+ Raw magenta samples M2V rw+ MPEG Video Stream M4V rw+ Raw MPEG-4 Video MAC* r-- MAC Paint MAP* rw- Colormap intensities and indices MASK* rw+ Image Clip Mask MAT rw+ MATLAB level 5 image format MATTE* -w+ MATTE format MEF r-- Mamiya Raw Image File MIFF* rw+ Magick Image File Format MKV rw+ Multimedia Container MONO* rw- Raw bi-level bitmap MOV rw+ MPEG Video Stream MP4 rw+ MPEG-4 Video Stream MPC* rw+ Magick Persistent Cache image format MPEG rw+ MPEG Video Stream MPG rw+ MPEG Video Stream MRW r-- Sony (Minolta) Raw Image File MSL* --- Magick Scripting Language MSVG -w+ ImageMagick's own SVG internal renderer MTV* rw+ MTV Raytracing image format MVG* rw- Magick Vector Graphics NEF r-- Nikon Digital SLR Camera Raw Image File NRW r-- Nikon Digital SLR Camera Raw Image File NULL* rw- Constant image of uniform color O* rw+ Raw opacity samples ORF r-- Olympus Digital Camera Raw Image File OTB* rw- On-the-air bitmap PAL* rw- 16bit/pixel interleaved YUV PALM* rw+ Palm pixmap PAM* rw+ Common 2-dimensional bitmap format PANGO* --- Pango Markup Language PATTERN* r-- Predefined pattern PBM* rw+ Portable bitmap format (black and white) PCD* rw- Photo CD PCDS* rw- Photo CD PCL rw+ Printer Control Language PCT* rw- Apple Macintosh QuickDraw/PICT PCX* rw- ZSoft IBM PC Paintbrush PDB* rw+ Palm Database ImageViewer Format PDF rw+ Portable Document Format PDFA rw+ Portable Document Archive Format PEF r-- Pentax Electronic File PES* r-- Embrid Embroidery Format PFM* rw+ Portable float format PGM* rw+ Portable graymap format (gray scale) PGX* rw- JPEG 2000 uncompressed format PICON* rw- Personal Icon PICT* rw- Apple Macintosh QuickDraw/PICT PIX* r-- Alias/Wavefront RLE image format PLASMA* r-- Plasma fractal image PNM* rw+ Portable anymap PPM* rw+ Portable pixmap format (color) PS rw+ PostScript PS2 -w+ Level II PostScript PS3 -w+ Level III PostScript PSB* rw+ Adobe Large Document Format PSD* rw+ Adobe Photoshop bitmap PWP* r-- Seattle Film Works R* rw+ Raw red samples RADIAL-GRADIENT* r-- Gradual radial passing from one shade to another RAF r-- Fuji CCD-RAW Graphic File RAS* rw+ SUN Rasterfile RAW r-- Raw RGB* rw+ Raw red, green, and blue samples RGB565* r-- Raw red, green, blue samples in 565 format RGBA* rw+ Raw red, green, blue, and alpha samples RGBO* rw+ Raw red, green, blue, and opacity samples RGF* rw- LEGO Mindstorms EV3 Robot Graphic Format (black and white) RLA* r-- Alias/Wavefront image RLE* r-- Utah Run length encoded image RMF r-- Raw Media Format RW2 r-- Panasonic Lumix Raw Image SCR* r-- ZX-Spectrum SCREEN$ SCREENSHOT* r-- Screen shot SCT* r-- Scitex HandShake SFW* r-- Seattle Film Works SGI* rw+ Irix RGB image SHTML* -w- Hypertext Markup Language and a client-side image map SIX* rw- DEC SIXEL Graphics Format SIXEL* rw- DEC SIXEL Graphics Format SPARSE-COLOR* -w+ Sparse Color SR2 r-- Sony Raw Format 2 SRF r-- Sony Raw Format STEGANO* r-- Steganographic image SUN* rw+ SUN Rasterfile SVG rw+ Scalable Vector Graphics SVGZ -w+ Compressed Scalable Vector Graphics TEXT* r-- Text TGA* rw- Truevision Targa image THUMBNAIL* -w+ EXIF Profile Thumbnail TILE* r-- Tile image with a texture TIM* r-- PSX TIM TM2* r-- PS2 TIM2 TXT* rw+ Text UBRL* -w- Unicode Text format UBRL6* -w- Unicode Text format 6dot UIL* -w- X-Motif UIL table UYVY* rw- 16bit/pixel interleaved YUV VDA* rw- Truevision Targa image VICAR* rw- VICAR rasterfile format VID* rw+ Visual Image Directory VIFF* rw+ Khoros Visualization image VIPS* rw+ VIPS image VST* rw- Truevision Targa image WBMP* rw- Wireless Bitmap (level 0) image WMV rw+ Windows Media Video WPG* r-- Word Perfect Graphics X3F r-- Sigma Camera RAW Picture File XBM* rw- X Windows system bitmap (black and white) XC* r-- Constant image uniform color XCF* r-- GIMP image XPM* rw- X Windows system pixmap (color) XPS r-- Microsoft XML Paper Specification XV* rw+ Khoros Visualization image Y* rw+ Raw yellow samples YCbCr* rw+ Raw Y, Cb, and Cr samples YCbCrA* rw+ Raw Y, Cb, Cr, and alpha samples YUV* rw- CCIR 601 4:1:1 or 4:2:2 * native blob support r read support w write support + support for multiple images