Script-Fu: (Image)Magickal Powers

ImageMagick is the Swiss army knife of the command-line image-processing world. The array of tools it provides, combined with the amount of options each can take, is nothing short of staggering. Due to the fact it is also very shell-friendly, ImageMagick is ideal for batch processing whole directories full of images.

Individual ImageMagick tools are useful by themselves, but combining several instructions with some shell-fu will allow you to save hours of image processing.

Starting simple, let’s say you want to convert one image from one format to another, say from JPEG to PNG:

convert original_image.jpg target_image.png

That was painless. But now imagine you want to convert all the JPEGs in your working directory to PNGs. Still very easy!:

for i in ./*.jpg; do convert "$i" "${i%jpg}png"; done

To make that clear, allow me to lay that single line out as a script, with each instruction on its own line. This is what it would look like:

for i in ./*.jpg
 do
  convert "$i" "${i%jpg}png"
 done

Even if you are only vaguely familiar with Bash scripting, the above shouldn’t be hard to follow. There is only one bit of slightly obscure code. It occurs on line 3, at "${i%jpg}png" where we grab the name of the file stored in the i variable, delete the jpg extension at the end of it (that’s what %jpg does), and then tack the png extension on in its stead. Variables are enclosed in double quotes ("$i") so things don’t go south if the file name they refer to contains a space.

Modifications

We can add modifiers to a base instruction to, for example, change the size, resolution, colour space and so on of any image.

To make a perfectly square 100×100 pixel thumbnail of all your JPEGs, you can do

for i in ./*.jpg; do convert "$i" -resize '100x100' "${i%jpg}thumbnail.png"; done

Unfortunately, it is unlikely all your original images are square and many thumbnails will be distorted. The line

for i in ./*.jpg; do convert "$i" -resize '100' "${i%jpg}thumbnail.png"; done

solves this problem since it creates thumbnails of all your JPEGs, making them 100 pixels wide, but adapting the height accordingly.

Conversely,

for i in ./*.jpg; do convert "$i" -resize 'x100' "${i%jpg}thumbnail.png"; done

creates thumbnails of all your JPEGs by creating PNG files which are 100 pixels high and adapting the width proportionately.

You can create thumbnails for all the pics in one directory with one line of code.

You can create thumbnails for all the pics in one directory with one line of code.

Even cooler,

for i in ./*.jpg; do convert "$i" -resize '100>' "${i%jpg}thumbnail.png"; done

will only downsize images that are wider than 100 pixels. The > symbol avoids blowing up images that are smaller.

If you wanted to do the opposite, i.e., blow up to a certain size images that are smaller than, for example, 480 pixels high, you use

for i in ./*.jpg; do convert "$i" -resize 'x480<' "${i%jpg}big.png"; done

Just in case you’re wondering, if the image is already larger than 480 pixels high, the convert instruction will just create a PNG with the same size of the original JPEG image, no resizing.

Marking

Let’s do something a bit niftier. Say you want to put all the images you have saved in a certain directory online. Although you’re good open content citizen and publish all your work under a CC By-SA license, before you upload all your precious photos, you want to make sure that no evil media corporation takes your work and uses it without properly attributing you or, worse, claiming the content is their own.

One way to avoid this is to watermark your work. However, plunking your big-ass logo with an opaque background in the middle of the picture is not the way to go, so you should probably avoid doing this:

composite top_image.jpg bottom_image.jpg composite_image.png
Compositing two images is easy... to do wrong.

Compositing two images is easy… to do wrong.

It would be much better to put a discrete, semi-transparent logo at the bottom. Visitors would still be able to enjoy your work and it would still be a good way to deter license-breakers.

To do this, for simplicity’s sake, it is better if the top image, the one you are going to overlay onto your photos, has what’s called an alpha channel, i.e. has transparent pixels. Ideal formats for this are PNG or GIF images. Then you can do something like this:

composite top_image.png bottom_image.jpg composite_image.png

And you’ll get something like this:

Using an image with an alpha channel (i.e., a transparent background) makes life much simpler.

Using an image with an alpha channel (i.e., a transparent background) makes life much simpler.

Compositing a JPEG

You can, of course, try to use an image with a single coloured background (ideally white or, as in the case above, black), but you will have to get creative with Bash pipes to get what you want.

For the black image above, for example, you could use the -transparent option to try and cut out the logo from the background, ands then composite both pictures, as shown in the image below. You would do this as follows:

convert -transparent black top_image.jpg png:- | composite - bottom_image.jpg composite_image.png

If you are familiar with pipes, you will recognise this line as actually two independent instructions. The first instruction,

convert -transparent black top_image.jpg png:-

passes its output on via the pipe (|). It is a regular convert instruction that makes your top image’s black pixels transparent (-transparent black top_image.jpg). You then place the image data (without actually creating the pic) into a placeholder that will be passed onto the next instruction as if it were a PNG image (png:-).

You then move onto the second instruction placed after the pipe that does the compositing proper by taking the data in the place holder (-) and compositing it in with the background image.

The problem with this method is that, due to JPEG’s tendency to try and soften sharp edges, the pixels around the side of the logo are not perfectly black, but a mixture of mostly black from the background with some cyan of the logo itself that has bled out. This leaves an ugly jagged edge of seemingly black pixels (but which are really a mixture of black and cyan) around the logo as seen below.

Cutting out the black leaves a jagged edge around the sides of our cyan coloured logo.

Cutting out the black leaves a jagged edge around the sides of our cyan coloured logo.

Another alternative is to experiment with the -compose option combined with, for example, the lighten or screen modifiers:

composite top_image.jpg -compose lighten bottom_image.jpg composite_image.png

Both of these modifiers give interesting, although not exactly correct, results without the jagged edges seen above.

Using the -compose option you can get interesting results.

Using the -compose option you can get interesting results.

To shrink and move the logo to the bottom right hand corner, you could do something like this:

composite \( top_image.png -resize 20% \) -gravity SouthEast -geometry +20+20 -dissolve 60% bottom_image.jpg composite_image.png

Now, this may look complicated, but it’s not. Let’s break it down, piece by piece:

1.- To manipulate each image in such a way so that the changes do no affect the other image, you enclose it and its options and modifiers within brackets (\( ... \)). The spaces between the opening and closing brackets and the contents ARE IMPORTANT, so don’t forget to include them.

In the example shown above, \( top_image.png -resize 20% \), you resize the overlaying image (i.e., the watermark) to 20% of its size. Note that this worked for the images I used, but you may have to change this figure to get it right for your own photos.

2.- You use the gravity and geometry options on the top image to indicate where to place it within bottom image. In this case, you push it to the lower right side of the image (-gravity SouthEast). To push the top image to the center you would use -gravity Center, to push it to the upper left hand corner, you would use -gravity NorthWest, and so on. SouthEast is the bottom (South) right hand (East) corner.

You then use the -geometry +20+20 option to displace the image 20 pixels from the reference point. As we are are using SouthEast, the reference point is at the bottom right hand corner of the image. Hence, the top image is pushed to the left and up 20 pixels from the right and bottom of the underlying image.

3.- Finally, you -dissolve 60% the top image to make it semi-transparent and overlay it over the bottom image.

The final result will look something like what is shown below.

A correctly watermarked image.

A correctly watermarked image.

This command line within a loop that watermarks all your JPEG images will look like this:

for i in ./*.jpg; do composite \( top_image.png -resize 20% \) -gravity SouthEast -geometry +20+20 -dissolve 60% "$i" "${i%jpg}wm.png"; done

or, in a script, like this:

for i in ./*.jpg
 do
  composite \( top_image.png -resize 20% \) -gravity SouthEast -geometry +20+20 -dissolve 60% "$i" "${i%jpg}wm.png"
 done

All the watermarked images will have the double extension *.wm.png.

With a Bash loop you can batch watermark all the images in a directory in a few seconds.

With a Bash loop you can batch watermark all the images in a directory in a few seconds.

With a Bash loop you can batch watermark all the images in a directory in a few seconds.

Conclusion

ImageMagick is amazingly powerful. By combining tools, options, modifiers and pipes, the amount of damage you can do to your photos is just shy of endless. Anything that you have to do with your graphics on a regular basis, and that does not involve actual drawing, is worth considering for the Magick treatment.

So check out the vast online documentation [http://www.imagemagick.org/script/command-line-tools.php] to see what ImageMagick can do for you.

Are you an ImageMagick wizard or witch? Share your tips & tricks in the comments below!

Cove Photo: Wizard by the ImageMagick team.

[sharedaddy]

7 thoughts on “Script-Fu: (Image)Magickal Powers

      • Porque puede usar Imagemagick para procesar scripts en un server en que Gimp no se ha instalado. Además, este script esta portable y puede ser usado en muchas mas servers. Copía su script, ejecuté su script. Aprénde lo que quiere—pero también, sepa cuando usar el martillo y cuando usar el destornillador.

    • Me parece que no has entendido el artículo: Con ImageMagick puedes procesar centenares de imágenes en unos pocos minutos. Si lo que tienes que hacer es realizar una tarea repetitiva, una tarea que es igual para cada imagen en tu galería, usar GIMP es muy contraproducente. Tendrías que cargar cada imagen en GIMP, realizar la modificación y guardarla. Con ImageMagick puedes automatizarlo. Con ImageMagick lo puedes realizar cambios en tus imágenes automáticamente, en el fondo, mientras haces otra cosa.

    • Porque puede usar Imagemagick para procesar scripts en un server en que Gimp no se ha instalado. Además, este script esta portable y puede ser usado en muchas mas servers. Copía su script, ejecuté su script. Aprénde lo que quiere — pero también, sepa cuando usar el martillo y cuando usar el destornillador.

  1. Just curious, have you ever heard of G’MIC ? It’s a similar tool, but more recent, and it has plenty of other interfaces than the CLI available, including a great plug-in for GIMP and Krita, a web-service, and others.
    It’s like having all the ImageMagick tools into a single executable ‘gmic’, which eases the communication between the different commands and the creation of custom pipelines. And you can even integrate your custom scripts directly into the G’MIC script language itself as it has some “include” mechanisms
    (and so it is more convenient and portable than a stand-alone bash script).
    Here is a great introduction to this tool here : http://gmic.eu/tutorial/index.shtml
    And of course, it is free and open-source as well.

    • I am aware of G’MIC and have used it extensively with GIMP. I admit I have not played with it from the CLI, but I will definitely look into it.

Leave a Reply