Graphics from the command line

Flip, size, rotate, and more with ImageMagick

There's nothing quite like command-line tools for handling large batches of tasks, and image manipulations are no exception. Web developers and administrators will appreciate the ability to handle large numbers of files easily, either at the command line or in scripts. Programmer Michael Still presents the ImageMagick suite, a Linux toolkit for sizing, rotating, converting, and otherwise manipulating images, in a huge number of formats, whether one or a hundred at a time.

Michael Still (mikal@stillhq.com), Senior software engineer, Tower Software

Michael StillMichael has been working in the image processing field for several years, including a couple of years managing and developing large image databases for an Australian government department. He currently works for Tower Software, which manufactures a world-leading EDMS and records management package called TRIM. Michael is also the developer of an open source PDF generation API called Panda, as well as a bunch of other open source code. You can contact Michael at mikal@stillhq.com



16 July 2003

Also available in Japanese

This article shows how to perform image manipulation using command-line tools. I do this job quite often, since I've picked up a some digital cameras and now manage a library of several thousand happy snaps. For Web developers and administrators who frequently have to batch-process large numbers of images, command line tools are an especially attractive option, because the developer can incorporate them into scripts. But even if you only want to perform a manipulation once or twice, a command-line alternative can save time.

The command line tools discussed in this article are part of the excellent ImageMagick suite, which ships with Red Hat Linux and is freely available online (see Resources). ImageMagick can also be accessed via C, C++, Perl, Python, Java, and several other languages, which Linux programmers will appreciate.

How ImageMagick works

ImageMagick is implemented as a wrapper around a bunch of different imaging libraries, including libtiff and libpng (see Resources for links to my earlier articles on libtiff). In ImageMagick terminology, these are called delegates. This is one reason ImageMagick is not as fast as a custom application would be; it has to be written in a generic manner that can deal with the different ways these libraries represent image data.

Note that there are many ways to do the things discussed in this article. I discuss the methods I use and that work for me. That doesn't mean the other tools out there are broken; it just means that I'm happy with what I am using now.

This article takes the form of discussing specific problems as examples, but the concepts should be applicable to other problem spaces as well.

Generating thumbnails

The first thing I did with my picture collection was generate thumbnails. I also wanted to reduce the size of the images for the Web site version, as many people don't really want to see a 1920-pixel by 1440-pixel picture of my sons.

I used the convert tool, which is part of the ImageMagick suite. Convert is really cool. Besides image resizing, it also anti-aliases, averages a set of images, blurs, converts between image formats, crops, despeckles, dithers, draws borders, flips, joins, re-samples, resizes, and much more. Check out the man page for more information on its various command-line options. Many of the more visually interesting effects offered by convert are also discussed later in this article.

Let's assume I want to make a thumbnail of this rather nice image of a rose:

Figure 1. A picture of a rose
A picture of a rose

To resize the image with convert, just use the -sample command-line option. For example, let's say I want the thumbnail to be 80 x 40 pixels. The command line would be:

# convert -sample 80x40 input.jpg output.jpg

This produces a thumbnail that looks like this:

Figure 2. A first attempt at a thumbnail
A thumbnail of a rose

ImageMagick will automatically respect the ratio created by the two sides of the image when it is resizing. This means that the aspect ratio of the new image will be the same as that of the previous image. In the example above, this means that the resized image is actually 53 by 40, instead of the requested 80 by 40. Another way of specifying the size of the output image is to use percentages. This can be convenient if you're not sure of the size of the input image, or if you're not concerned with having the new image be an exact size. Here's an example of how to use percentages:

# convert -sample 25%x25% input.jpg output.jpg

Now we have a thumbnail that looks like this:

Figure 3. A second attempt at a thumbnail
A thumbnail of a rose

With this command, you can generate thumbnails for images within a directory. While this article isn't about shell scripting, I'll quickly show you an example of how to generate a thumbnail of each JPEG in the current directory:

Listing 1. Thumbnailing all the JPEGs in the current directory
for img in `ls *.jpg`
do
  convert -sample 25%x25% $img thumb-$img
done

This will produce a series of thumbnails 25% the size of the real image, with a filename that is the name of the JPEG file with a thumb- prepended.


Getting information about an image file

Another common task is to determine the dimensions of an image file. You might need to know how big to make the thumbnail from the previous example, for example.

Many imaging libraries come with excellent tools for this purpose. For example, libtiff (a TIFF library I've written about previously; see Resources) ships with tiffinfo, which display the following sort of information about TIFF files:

# tiffinfo sample.tif
Listing 2. Sample output from tiffinfo
TIFF Directory at offset 0x146
  Image Width: 352 Image Length: 288
  Bits/Sample: 8
  Compression Scheme: Deflate
  Photometric Interpretation: RGB color
  Samples/Pixel: 3
  Planar Configuration: single image plane

This isn't an exhaustive example of how to use tiffinfo, but you can see that it returns useful information such as the size of the image, the pixel depth (a combination of the number of bits per sample and the number of samples per pixel), and the compression scheme used.

Similarly, there is a pnginfo command that returns similar information for PNG files:

# pnginfo sample.png
Listing 3. Sample output from pnginfo
sample.png...
  Image Width: 640 Image Length: 480
  Bitdepth (Bits/Sample): 8
  Channels (Samples/Pixel): 3
  Pixel depth (Pixel Depth): 24
  Colour Type (Photometric Interpretation): RGB 
  Image filter: Single row per byte filter 
  Interlacing: No interlacing 
  Compression Scheme: Deflate method 8, 32k window
  Resolution: 0, 0 (unit unknown)
  FillOrder: msb-to-lsb
  Byte Order: Network (Big Endian)
  Number of text strings: 0 of 0

I am not aware of equivalent individual tools for other formats such as BMP, GIF, and JPEG. However, ImageMagick comes to the rescue once more, this time with a tool called identify.

# identify -verbose sample.png
Listing 4. Sample output from identify
Image: sample.png
  Format: PNG (Portable Network Graphics)
  Geometry: 640x480
  Class: DirectClass
  Type: true color
  Depth: 8 bits-per-pixel component
  Colors: 142360
  Filesize: 555.6k
  Interlace: None
  Background Color: grey100
  Border Color: #DFDFDF
  Matte Color: grey74
  Dispose: Undefined
  Iterations: 0
  Compression: Zip
  signature: 361fe70ae623ef6f1fca44e0d29d157c2d701039fcf0f8625862925d881e13a4
  Tainted: False
  User Time: 0.190u
  Elapsed Time: 0:01

You can see that identify displays a bunch of useful information about the image file, such as the size of the image in pixels, the color depth of the image, and the image format.

pnginfo

I'd been a user of libtiff for quite some time when I started using PNG. At the time, there was no tiffinfo equivalent for PNG files, which is why I wrote pnginfo. (You can download pnginfo from the link in Resources).

identify also has a -format command-line flag that allows you to specify only the information you want to output. For example, if you were only interested in the image dimensions, you might use a command like this:

# identify -format "%wx%h" sample.png

The output would be something like:

640x480

Here, %w means image width, and %h means image height. Check out the identify man page for more information on the formatting characters that can be used with the option.


Rotating images

Another commonly needed image manipulation is the rotation of images. For example, many of the photos I take with my digital cameras are rotated ninety degrees, as they are taken as portraits. My camera doesn't rotate these for me, so I have a script that does it once I've downloaded the images from the camera.

For example, this is a photo I took on a recent trip to Port Arthur in Tasmania:

Figure 4. Port Arthur on its side
A sideways picture of Port Arthur

To rotate this picture, we again turn to the convert command:

# convert -rotate 90 input.jpg output.jpg

This produces an image that looks like this:

Figure 5. Port Arthur
A picture of Port Arthur

Note that the argument to the -rotate option is the number of degrees to the right to rotate the image. To rotate to the left, use a negative number.


Changing the format of an image

The convert command is also capable of converting the formatting of the image files. This includes converting between image formats, such as converting a JPEG image to PNG, as well as converting from color to gray scale, dithering, and similar operations.

convert knows what image format the input and output are, based on the file extensions given on the command line. So, to convert a JPEG to a PNG, use a command line like the following:

# convert input.jpg output.png

ImageMagick supports 89 image formats at the time of writing this article. Check out the ImageMagick Web site (see Resources) for more information.


Adding textual annotations to an image

Sometimes you need to add textual annotations to an image. For example, imagine that your company has a standard business card image and wants to put each employee's details onto the card before sending it to the printer. Another example is generating presentation certificates for users who pass an online course on your Web site.

Let's say you start with this image:

Figure 6. A picture from Floriade 2002
Floriade 2002

You could annotate the image with some identifying information using the following command line:

# convert -font helvetica -fill white -pointsize 36 \
-draw 'text 10,50 "Floriade 2002, Canberra, Australia"' \
floriade.jpg comment.jpg

And here is the result:

Figure 7. An annotated picture from Floriade 2002
Floriade 2002 after annotation

This is by far the most complex convert command line I have shown so far in the article, so I'll take some time to explain it.

-font helvetica sets the annotation's font to Helvetica. It is possible here to specify a path to a font file as well. This example badges the image so it can't be reused by other Web sites without permission, but it does so using a font that is in a non-standard location:

# convert -font fonts/1900805.ttf -fill white -pointsize 36 \
-draw 'text 10,475 "stillhq.com"' \
floriade.jpg stillhq.jpg

This is the result:

Figure 8. A badged image
Floriade after badging

-fill white fills the letters with white instead of the standard black.

-pointsize 36 specifies the size of the letters, in points. There are 72 points to an inch.

-draw 'text 10,50 "..."' is a set of drawing commands, in this case to move to the position 10, 50 and then draw the text in the double quotes. The single quotes are used because the double quotes are needed within the drawing command if more than one word is to be drawn, and you cannot have double quotes within double quotes.


Other, more artistic, conversions

convert also implements a series of quite artistic conversions. I'll demonstrate some of the more visually interesting ones here. If you're interested in this, you should check out the ImageMagick man page and Web site for more information. This is the input image I will use for the demonstrations:

Figure 9. Uluru at sunset
Uluru

This photo of Uluru, formerly known as Ayer's Rock, was taken at sunset.

Charcoal

The charcoal effect simulates a charcoal artist's impression of the image.

# convert -charcoal 2 input.jpg output.jpg

And the result looks like this:

Figure 10. Uluru at sunset after a charcoal effect is applied
Uluru after a charcoal effect

Increasing the magnitude of the argument to the -charcoal option increases the amount of "charcoal" applied to the image, but also slows down the generation of the image. Here's an example with a little more charcoal.

# convert -charcoal 10 input.jpg output.jpg

Which yields:

Figure 11. Uluru at sunset after more charcoal effect is applied
Uluru after more charcoal effect

If you really want to go wild with the charcoal:

# convert -charcoal 200 input.jpg output.jpg

You get this:

Figure 12. Uluru at sunset after excessive charcoal effect
Uluru after even more charcoal effect

Specifying three values

To specify three values, one for each of the red, green, and blue samples, use an argument of the form red/green/blue. For example, 10/20/30 would mean red has a value of 10, green a value of 20, and blue a value of 30. You can also use percentages within this construct.

Colorize

Colorizing is the process of blending the color of each pixel with a specified color. The argument to the effect is the color to blend with. This can either be specified as a percentage (which will be used for each of red, green, and blue) or as three percentages. It is also possible to provide either one of three actual values.

# convert -colorize 255 input.jpg output.jpg

Here's Uluru after being colorized:

Figure 13. Uluru at sunset after a colorizing effect is applied
Uluru after a colorizing effect

Implode

The implode effect simulates the center of your image being sucked into a virtual black hole. The argument is the amount of implosion effect you desire.

# convert -implode 4 input.jpg output.jpg

Imploding Uluru looks like this:

Figure 14. Uluru at sunset after imploding
Uluru after an implosion effect

The solarize argument

The ImageMagick documentation states that the argument to solarize is always a percentage. This is not strictly true. If the argument has a percentage sign at the end of it, then it will be treated as a percentage. Otherwise, it is treated as a literal value.

Solarize

Solarizing is an effect that occurs when a negative is exposed to light part way through the photographic development process. Here, the input argument is the intensity above which to apply the effect, either specified as an absolute value, or as a percentage of the maximum possible value for the pixel. If a pixel is above the threshold, then it is negated.

# convert -solarize 42 input.jpg output.jpg

After solarizing, our image looks like this:

Figure 15. Uluru at sunset after solarizing
Uluru after a solarization effect

Spread

Spread moves pixels by a random amount within the image. The argument is the size of the area around the pixel from which to select the new location. It therefore specifies how closely the output resembles the input:

# convert -spread 5 input.jpg output.jpg

Here's Uluru once again, after spreading:

Figure 16. Uluru at sunset after spreading
Uluru after a spreading effect

Multiple commands in one ImageMagick invocation

You have already seen an example of chaining commands with the annotation examples. It is possible, however, to chain any of the ImageMagick commands mentioned in this article. For example, perhaps we want to make a thumbnail of an image, and then apply a spread to it. Once the spread has occurred, we'll apply the charcoal effect:

# convert -sample 25%x25% -spread 4 \ -charcoal 4 input.jpg output.jpg

This produces:

Figure 17. Uluru after chained effects
Uluru after a chain of effects

Tips for image manipulation

There are some things you should remember about image manipulation before you rush out and start modifying every image you own. First, you should give some thought to what image format you are going to use long term, before you end up with many images in a format that you later regret. This is made especially easy, as you can use convert to change the format of the images, as discussed earlier in this article.

JPEG compression is great for large images such as photos. However, the compression is normally lossy (in other words, image data is thrown away as part of the compression process). This makes JPEG very poor for compressing text that needs to remain readable. The other thing to bear in mind is that the loss is cumulative.

PNG is normally a good choice for color images where you don't want accumulating loss to affect the quality of the image after a series of manipulations.

See my "Graphics programming with libtiff, Part 2" article on color imaging with libtiff for more information on this topic (see the link in Resources below).

You should also remember that most of the manipulations shown in this article are one way. For example, once you've shrunk an image, that image data is gone. If you blow up the image again later, the output will be quite pixelated. For example, let's take a picture, make a thumbnail, and then expand the image again. To save some space, I'll just include the before and after images here, and skip the intervening thumbnail.

Figure 18. A waterfall in Cairns
A waterfall

Now, we'll chain a reduction together with an enlargement:

# convert -sample 10% -sample 1000% input.jpg output.jpg

This produces an image that looks like:

Figure 19. A blocky waterfall
A blocky waterfall

It's quite hard to see the waterfall in the finished picture, although unfocusing your eyes seems to help.


Conclusion

In this article we've discussed some of the interesting things that ImageMagick can do to meet your command-line imaging needs. The tools described here are not the answer to every problem, and sometimes you'll need a custom piece of code, but generic command-line imaging tools can often save a lot of work.

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Linux on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Linux
ArticleID=11326
ArticleTitle=Graphics from the command line
publish-date=07162003