ImageMagick v6 Examples --
Creating Thumbnails and Framing

Index
ImageMagick Examples Preface and Index
Thumbnail Storage
General Thumbnail Creation
Other Non-IM Techniques
Further Processing -- Adding Fluff
Advanced Framing Techniques
Framing using Edge Images
Further Ideas
One of the biggest uses ImageMagick is put to is the creation of thumbnails for family photo albums, sports and hobby pages, catalogs, and so on. Typically for use on the world wide web or in photo CDs.

This page provides examples and techniques used to generate thumbnails.


Thumbnail Storage

I would like to first start with one very important point.

The original image from video cameras and photo scanning should be kept in a safe place in the original format, preferably a non-lossy format (not the JPEG image format), without any modification resizing or other change, except possibly a file name change. Of course a scanned image can be re-scanned, but it is simpler to re-use your original scanning than to re-do it again later.

This is VERY important as any form of modification will mean a loss of some information in the image, and provides a source from which you can re-work your image for other uses. The original image does not have to be your working image, which may be resized or color adjusted for display, just be sure to have your image saved and backed up somewhere safe for future use.

The next thing to do, even before you create any thumbnails, is to decide how you want to save your thumbnail relative to your normal sized image format, then stick to that scheme. This is especially important for web pages.

Schemes include... The first scheme can use "mogrify" to generate all your thumbnails, without destroying the original image, by using a "-format" setting to specify the output image format.

As of IM v3.2.0, the second scheme is now also possible to do with "mogrify" thanks to the addition of a special "-path" setting that specifies a different directory in which to save the modified images.

For example, this converts JPG images into GIF thumbnails in a "thumbs" sub-directory that was just created.

  mkdir thumbs
  mogrify  -format gif -path thumbs -thumbnail 100x100 *.jpg

The other methods will require you to either, first make a copy of the original image, before running "mogrify", create a special script to process the images, or some other DIY method. A number of the simpler non-IM techniques are detailed at the end of the example section for Batch Processing - Without using "mogrify".

Whatever method you choose the important thing is to choose a scheme for thumbnail storage, and then stick with it. By using the same scheme for all your thumbnails you can then write shell or Perl scripts to make thumbnail generation and even generation of the HTML links easy. More on this later.

Selection of the Thumbnail format

The format in which you save a thumbnail can make a big difference to its final size on disk and download speed for web pages. In this regard I recommend you study the summary of the various Common File Formats.

Specifically you should note...
JPEG compresses well and is lossy, but is designed for large real world images, not small thumbnails. It also does NOT allow any form of transparency. In summary, the format is good for large images, bad for thumbnails. Watch out for profiles (see next section).

While JPG is not recommended for thumbnails, for viewing images on the WWW it is recommended you use smaller 800x600 pixel image, at a much lower "-quality" percentage (say 50 or even 30%), though it will not look very good.

It has also been suggested that using "-sampling-factor 2x1" will also produce a smaller JPEG image size.

I do not recommend the full original image never be placed directly on the web, unless temporarily (at a referenced location) for a friend to download. Remember do not link to it, (even by directory indexing), and never for more than a day, or it may be Googled.

GIF works for simple small images, and compresses okay. It has a color limit of 256, but for small images this is rarely noticeable. It can also do cartoon like animations of images, not that that is needed for thumbnails, unless you really what to get fancy.

What is a problem is that the format only has Boolean (on/off) transparency, which makes for horrible looking borders on shaped images. The solutions to that is to design the thumbnail to only use Boolean transparency, or arrange it so it can only be used on a specific background color. For details see the examples on GIF's on a background color or pattern.

PNG is the modern ideal format for thumbnails. It has a good compression, and internal format styles. It is non-lossy, and can display all colors, and these days it is understood by almost all browsers, (though for Microsoft Internet Explorer, before v7, needs some java scripting added to web pages).

More importunately this format understands semi-transparent color, making shadows and edges sharp and clear, or faded and blurry as you wish. This format however does not do animations, though the related MNG format does. Very few browsers seem to support that format however.

For thumbnails you can reduce the size of the final image by reducing the depth and number of colors, as well as setting a higher "bzip" compression quality (first digit in "-quality") for your final thumbnail image.

For example, the following is suggested for small PNG thumbnails that does not involve transparency.

        -strip  -quality 95  PNG8:thumbnail.png
    

Which uses a smaller, 8 bit, or 256 color limited, PNG format.

You can also re-process the final image though secondary applications (See Non-IM PNG Processing) which can automatically find the best PNG compression for that specific image. There are also programs to do that color reduction to the smaller internal PNG format, while preserving semi-transparent colors. This is something IM currently does not handle. .

One final word about formats... No matter what format you use for your thumbnails, if you must save an intermediate unfinished image, use a PNG (without any color reduction) or MIFF image format. Doing this will preserve as much color information about the image as possible in the intermediate stage. Only do color reduction, or save to GIF or JPEG formats as a absolute final step.

This is important, so I repeat...
Do NOT use JPEG, PNG8, or GIF for intermediate working images!
Better to use PNG or MIFF.

Profiles, Stripping, and JPEG Handling

Many images from digital cameras, scanning software, and some paint programs (photoshop is notorious for this), save extra information about the image in the form of profiles. This includes image formats such a JPEG, PNG, TIFF and as of IM v6.2.4-1 GIF. Of course the IM specific format, MIFF also does this. (See Image Profiles for more detailed information).

These profiles can be up to 60 Kb in size, so can make a big difference to your file size, and by default IM will preserve this profile information. Thumbnails have no need for this data and often not even the main image needs it.

You can also remove the profiles from your images with the IM commands...

  convert input.jpg  -strip output.jpg

  mogrify -strip  *.jpg

You can also use the option "-profile '*' " to remove the profiles.

It is however recommended you only strip profiles when you modify an image, especially if reducing it in size for web displays, or thumbnail images.

Stripping profiles while resizing, particularly for generating smaller thumbnail images, is so common that both "-resize" and "-strip" were combined into a new operation, just for this very purpose. Naturally enough this resize operation is called "-thumbnail".

For example...

  convert -size 240x180 image.jpg -thumbnail 120x90 thumbs/image.gif

  mogrify -path thumbs -format gif -size 240x180 -thumbnail 120x90 '*.jpg'

The "mogrify" will of course generate thumbnails for a whole directory of JPEG images, but be careful it does not overwrite any thumbnails you want to keep. For a number of other non-IM methods for looping over a large number of images see the example section for Batch Processing - Without using Mogrify.

For very large images the "-thumbnail" resize operator goes further and first scales the image down to 5 times the final thumbnail size first, before doing the actual resize operation. This speeds up the thumbnail generation further.

However for thumbnailing JPEG images, a even better method of limiting the initial image size can be used, by just not reading the whole image into memory in the first place.

The "-size" setting (as shown in the above example) is a special hint to the JPEG image library to reduce the amount data that is read in from VERY BIG JPEG images. See Reading JPEG Files. Caution is however needed if you are also using this setting for other purposes, such as canvas creation.

From IM version 6.2.6-2, a new image input option was added, which lets you resize the input image immediately after it is read in. This option will work with ANY image format, not just JPEG image. It is however no substitute for using a "-size" with JPEG images.

As such the recommended way of resizing ANY input image format is now...


  convert -size 240x180 input.img'[120x90]' -strip  output_thumbnail.gif

Well on with the practical IM thumbnail examples...


General Thumbnail Creation

Generate Thumbnails in General (specific height)

Lets convert a large sample JPEG image to a GIF thumbnail 90 pixels high with the width automatically adjusted (within the 250 pixel width limit) preserve the aspect ratio of the image.

  convert -size 500x180  hatching_orig.jpg  -auto-orient \
          -thumbnail 250x90   -unsharp 0x.5  thumbnail.gif
[IM Output]

Note that I used the "-thumbnail" option above. This not only resizes the image, but strips any and all profile and comment information that may be present in the original JPEG image. Also as it uses the "-sample" resize operator for the initial downsizing of the image, it is reasonably fast, and produces good results for small thumbnails.

I also set a minimum "-size" for the image being read in. This is passed to the JPEG library, which will return an image somewhere between this size and double this size (if possible), rather that the whole very large original image. Basically don't overflow the computers memory with an huge image when it isn't needed.

The "-size" value I use is double that of the final thumbnail so that resize will still generate a reasonable result.

The "-auto-orient" operator ensures that the image, if from a digital camera, is rotated correctly according to the camera's orientation. This is not needed for the 'desktop' image I am using, but I included it in the above for digital camera users.

The result is a thumbnail of a specific height, but variable width. I use this thumbnail for my own web pages so that a series of image in a row, will all match up height wise, forming a neat look.

The 250 pixel width limit in the above is important. If left unset, I would give IM complete width freedom (EG: using "-thumbnail x90" ). This could result in problems when generating thumbnails of long thin images such as though shown in Web Line Images. The result in that case would be very very long, enlargement of the image, instead of the desired small thumbnail.

Some people (including myself) find that while IM's resize is one of the best implementations (See IM Resize vs other Programs), the result is still a little blurry. As such you can improve the above result by sharpening the image slightly (using "-unsharp") after the "-thumbnail" resize operation.


The "mogrify" version is the same as the "convert" command (with no initial input images), but will but will generate automatic thumbnails of every JPEG image in the current directory. The image argument is quoted so that IM itself will scan the directory, and not the command line shell. This prevents 'line limit overflow errors' on directories containing a huge number of images.

  mogrify  -format gif -size 500x180 -auto-orient \
                -thumbnail 250x90 -unsharp 0x.5  '*.jpg'

Note that "mogrify" will blindly create thumbnails, replacing any existing images of the same name. GIF images in this case. Extreme caution is always advised when using this command.

Backup copies are always recommended before doing any processing.

Instead of specifying a different format (using "-format") so as to prevent "mogrify" from overwriting the original source images, you can use a "-path" setting to define a separate thumbnail directory. You can use both output options.

While "mogrify" can output the new images with a different suffix ("-format") or directory ("-path"), they are your only options using this command.

If you are also wanting to change the name of the image, such as adding a "_tn" or "_sm" to denote thumbnail or small versions of the image, then I recommend you create a shell script to do the job for you, processing them one at a time using "convert".     I wrote such a script to do this, while simultaneously generating HTML indexes at the same time.

Resize to fit a rectangular box

Another form of automatic thumbnail generation is shrink image to fit a fixed sized box, say "100x100" but keeping the images aspect ratio. Well that is the default meaning for a resize geometry setting.

However I prefer not to enlarge images which already fit such a box. For that you need to add a ">" to the geometry string.

  convert -size 200x200 hatching_orig.jpg -thumbnail '100x100>' rectangle.gif
[IM Output]

As before the aspect ratio of the image is preserved, as such the thumbnail is unlikely to be exact 100 pixels square. However at least one of the images dimensions will be 100 pixels.

Pad Out the Image

The next most common request is to generate thumbnails that fill out the image with borders of a specific color (usually 'black', or 'transparent' but for these examples I will use 'skyblue') so the thumbnail is exact the size you wanted.

For example: An image which is 400x300 pixels shrunk to fit a 100x100 pixel box will normal (with the above) have a size of 100x75 pixels. We want to add some padding borders to the top and bottom of the image (and to the sides to be sure) to make the final thumbnail image always 100x100 pixels in size.

There are a number of ways to do this, and as of IM v6.3.2 the best way is using the "-extent" option.

  convert -size 200x200 hatching_orig.jpg -thumbnail '100x100>' \
          -background skyblue -gravity center -extent 100x100 pad_extent.gif
[IM Output]

Before IM v6.3.2 the best way was to add extra borders and do a centered "-crop" on the image after adding a large border around the image.

  convert -size 200x200 hatching_orig.jpg -thumbnail '100x100>' \
          -bordercolor skyblue  -border 50 \
          -gravity center  -crop 100x100+0+0 +repage pad_crop.gif
[IM Output]

The "+repage" operator is important to remove any 'virtual canvas' or 'page' information that crop preserves. IM v5 users need to use "-page +0+0" instead.

As of IM version 6.2.5, you can also use a Viewport Crop, and flatten the result onto a background color.

  convert -size 200x200 hatching_orig.jpg -thumbnail '100x100>' \
          -gravity center  -crop 120x120+0+0\! \
          -background skyblue  -flatten    pad_view.gif
[IM Output]

Another method to pad out an image is to overlay the thumbnail onto a background image (actual image, solid color or tiled canvas) that is the right size, in this case the 128x128 "granite:" built-in image.


  convert -size 200x200 hatching_orig.jpg -thumbnail '100x100>' \
          granite: +swap -gravity center -composite pad_compose.gif
[IM Output]

This method is probably the best method to use with older versions of IM (such as IM v5), though the "-composite" operation will need to be done by the separate "composite" command, rather than the above single command method.

Cut the Image to Fit

An alternative, is rather than pad out the image to fit the specific thumbnail size we want, is to instead cut off the parts of the image that does not fit the final size.

Of course this means you actually lose some parts of the original image, particularly the edges of the image, but the result is a enlarged thumbnail of the center part of the image. This is usually (but not always) the main subject of the image, so it is a practical method of thumbnail creation.

As of IM v6.3.8-3 the special resize option flag '^' was added to make this easier. We just resize using this flag then crop off the parts of the image that overflows the desired size.

  convert -size 300x300 hatching_orig.jpg  -thumbnail 100x100^ \
          -gravity center -extent 100x100  cut_to_fit.gif
[IM Output]

As you can see the thumbnail of the image is much larger and more detailed, but at a cost of cutting off the sides off the original image.

For more information on this option see Resize to Fill Given Area.

Before IM v6.3.8-3 when this special flag was added, you would have needed some very complex trickiness to achieve the same result. See Resizing to Fill a Given Space for details.

Area Fit Image Size

The last two methods will often make an image very small with a lot of extra padding, or, it will cut off a lot of the image so as to completely fill the space. However by using a different resize flag, it is possible to get a thumbnail that is between these to extremes.

For example a 100x100 pixel thumbnail has 10,000 pixels. Now if we ask resize to size out image to something around that many pixels in size (using the resize '@' flag), you will have an image that will need both a little padding and a little cutting. This maximizes the size of the resulting thumbnail, while not cutting away too much.

For example...

  convert -size 300x300 hatching_orig.jpg  -thumbnail 10000@ \
          -gravity center -background skyblue -extent 100x100  area_fit.gif
[IM Output]

As you can see the thumbnail has some padding, and the image has some cropping, but the result is probably about the best fit of image to a given thumbnail space.

Fit to Given Space summary

In summary, here are the results of the three methods for thumbnailing an image to a specific sized area. All use exactly the same code, just with a different resize flag (and the argument to match).

[IM Output]
Padded Fit
resize, no flag
[IM Output]
Area Fit
resize, '@' flag
[IM Output]
Cut to Fit
resize, '^' flag


Manual Cropping

The normal way I generate thumbnail images for use on my web pages, is a mix of automatic and manual scripts. The final setup of my images are..

I first generate the web viewable JPEG image using "mogrify" from the original scanned image. This is reduces the download time and viewing size of the image to something that is practical for the typical web user (who could be logged in via modem).

From these images I generate thumbnails, again using "mogrify". However I often find in typical photos that the subject of the thumbnails becomes too small to make an effective thumbnail, when viewed.

To fix this I examine the automatically generated thumbnails, and in about half the cases manually create my own 'zoomed in on subject' thumbnail.

I read in the JPEG image, and crop it down the main subject of the image effectively 'zooming in' on the subject of the photo, and removing bulk of the background context of the image. This is then smoothed and thumbnailed, either using a "convert -thumbnail", or more often in the same graphic program (usually "XV", see below), I used to manually crop the image.

So instead of a thumbnail where the people in the photo are hardly visible (left), I have manually zoomed in on the subject, highlighting the main point of the photo (right). That allows users to see the image content more clearly and thus better decide if they actually want to download and look at the larger JPEG version of the image.

Queensland KiteFlyers, Ron and Val Field
[IM Output]
Automatically
Generated
Thumbnail
[IM Output]
Manually Cropped
and Resized
Thumbnail
(Click on either image for original scanned photo)

This is of course more manually intensive, but only needs to be done once per image, and only on images that have a lot of space such as in the above example.

Of course as "mogrify" will overwrite any existing, possibly hand generated thumbnails, you cannot use it again after you perform any manual thumbnail generation. "Mogrify" is useful, but also very dangerous as it overwrites lots of images. Always think before you run "mogrify" globally across all your images.

HTML Thumbnail Pages

Once I have all the thumbnail images sorted out in the directory I use a special perl script called "thumblinks" I wrote that look for the images (JPEG photos and GIF thumbnails), and generate HTML links, and even full HTML photo pages.

The script will read and include size of the GIF thumbnail size in the HTML, and attach pre-prepared header and footer files around the thumbnail links. The script will also remove any thumbnail links from the list it generates, if it finds an existing link in the header or footer file itself.

This may sound complex, but it makes my HTML page generation very fast and flexible, and ensures ALL image thumbnailed images in a directory have been added to that directories index page, while still letting me comment on specific images in the index header. It also makes the page independent of the users window size, automatically adjusting to suit.

For a simple example of my "thumblinks" script output see Tomb of Castle Artworks.

For a quick example and starting point for generating such links look at the examples of using the identify command.


Other Non-IM Techniques

The "XV" program I use for manual image processing also generates thumbnail images, in a sub-directory called ".xvpics". The format of the images in this directory is its own thumbnail format (ignore the filename suffix). These thumbnails are limited to 80x60 pixels so are a little on the "small" size (unless you hack "xv" to use larger thumbnails -- see link below).

IM understands the "xv" thumbnail format (which is based on the "NetPBM" image format), so you can generate thumbnails using XV, then convert the XV thumbnails of the JPEG images, into GIF thumbnail images...
   xv -vsmap &               # generate thumbs with the "Update" button
   rm .xvpics/*.gif          # delete XV thumbs of existing "gif" thumbnails
   mogrify -format gif .xvpics/*.jpg
   mv .xvpics/*.gif .        # move the new "gif" thumbnails to original dir
If you are sick of the small size of XV thumbnails, particularly with larger modern displays, you can hack the XV code. See my XV modification notes, which allows you to get XV to use a larger thumbnail size, 120x90 pixels in my own case.


Further Processing -- Adding Fluff

The above is only the beginning of what you can to to make your thumbnails more interesting. Beyond the basic thumbnail image you can add borders, rotations even with some random selection of style to make your thumbnail gallery that much more interesting.

Additions to thumbnails like this, is what I term 'fluff' (as in the extra lint you find covering your clothes after you wash your clothes). That is unnecessary extras added to the thumbnail, but which can make web pages and index images that much more interesting.

Be warned that many of the following methods and processing is very complex and my require a deeper knowledge of the various image processing options options of ImageMagick.

Adding image labels

During your thumbnail creation you can also add labels either above, below or even on top of your thumbnail.

This sort of image processing is however covered more thoroughly in Annotating Images with Labels. Just remember to use the "-thumbnail" or "-strip" rather than a "-resize" in those examples.

Here is probably the best type of overlay of a compound font annotation (Specifically the Denser Soft Outline font) showing the complexity that can be achieved by this method.

  convert -size 400x180  hatching_orig.jpg  -resize '120x200>' \
      \( +clone -matte -fill transparent -draw 'color 0,0 reset' \
         -resize 1000x200\!  -font SheerBeauty -pointsize 72 -gravity Center \
         -strokewidth 8 -stroke black  -fill black  -annotate 0,0 '%c' \
         -channel RGBA -blur 0x8 \
         -strokewidth 1 -stroke white  -fill white  -annotate 0,0 '%c' \
         -fuzz 1% -trim +repage -resize 115x \
      \) -gravity North -composite  -strip +repage  annotated.gif
[IM Output]

Note how I do not use the pre-generated "thumbnail.gif" image, or use the Thumbnail Resize Operator to strip the profiles and comments from the image, as I want to preserve the images 'comment' string for use by the "-annotate" operator. Also note how I use "+clone" to generate a working canvas, again to preserve the images 'comment' string. Only at the end do I "-strip" that information.

A Raised Button

The "-raise" operator was basically created with the one purpose of highlighting the edges of rectangular images to form a raised button. It is a simple, fast, and effective thumbnail transformation.

  convert thumbnail.gif  -raise 8   raised_button.gif
[IM Output]

The same operator has a 'plus' form that can be used to make a sunken highlighting effect.

  convert thumbnail.gif  +raise 8   sunken_button.gif
[IM Output]

Adding a 3D frame

In a similar way the "-frame" operator make it easy to add a frame around the image

  convert thumbnail.gif   -mattecolor peru  -frame 9x9+3+3  framed.gif
[IM Output]

This operator also has a lot more options to create a dozen or so different styles of frames. You can see examples of the possibilities in Frame, adding a 3D-like border.

Using Montage

The montage command provides a much easier way of doing all the above, and much more. It cannot only generate thumbnails (or whole pages of thumbnails), but it can label the thumbnails to include information like filenames, disk size, and dimensions, or a user specified string.

Here is a simple use of "montage" to generate a framed thumbnail.

  montage -size 240x200  -label '%c'  hatching_orig.jpg \
          -frame 6  -geometry '120x100>'  montage_simple.gif
The label comes from JPEG image file comment, which was added long ago to the image using the Non-IM command "wrjpgcom". See Non-IM JPEG Processing for more details.
[IM Output]

Even with just "montage" you can get really fancy with your thumbnail generation.

  montage -size 400x180  -label '%c' hatching_orig.jpg -thumbnail '200x90>' \
          -geometry '130x100>'  -mattecolor peru  -frame 6 \
          -bordercolor skyblue  -font LokiCola  -pointsize 18 \
          montage_fancy.gif
[IM Output]

See the "Montage, Arrays of Images" for more details.

You may be especially interesting in the Montage HTML Thumbnail Image Maps example. This creates a HTML index page of thumbnails in which clicking on the thumbnail will bring up the original image, in the same directory.

Self Framing

Rather than framing a thumbnail image with a specific frame you can use the image itself to generate a interesting frame around the image.

This is similar to the simple Raised Button technique shown above, but surrounds the image with the frame, rather than converting part of the image itself into a frame.

For example, If we enlarge the image and dim it, before overlaying the original image on top, we get a very nice looking frame.

  convert thumbnail.gif \
          \( -clone 0 -resize 130% +level 20%x100% \) \
          \( -clone 0 -bordercolor black -border 1x1 \) \
          -delete 0 -gravity center -composite  self_bordered.gif
[IM Output]

Rather than just 'dimming' the image for the frame, you can use a semi-transparent frame on top of the enlarged image. However this requires you to know the size of the thumbnail so as to resize it by exactly 20 pixels in both height and width.

  convert thumbnail.gif \
          \( -clone 0 -resize 140x110\! \) \
          \( -clone 0 -bordercolor black -border 1x1 \
                      -mattecolor '#8884' -frame 9x9+0+9 \) \
          -delete 0 -composite  self_framed.gif
[IM Output]

And here is a much more complex example which rather than enlarging the image to add the new border, it converts parts of the image itself into a border.

Basically it creates a lighter blurred version of the original image which his than overlaid using a mask also generated from the original image. A white edge is then overlaid to separate that lighter blured version from the center un-modified part of the image.

  convert thumbnail.gif \( +clone -blur 0x3 +level 20%,100% \) \
          \( +clone -gamma 0 -shave 10x10 \
             -bordercolor white -border 10x10 \) \
          -composite \
          \( +clone -gamma 0 -shave 10x10 \
             -bordercolor white -border 1x1 \
             -bordercolor black -border 9x9 \) \
          -compose screen -composite \
          self_blurred_border.gif
[IM Output]

Note that in all cases the frames are generated from the same image, which is then combined together to produce a frame based on the colors coming from the original image. The framing border is thus unique to the thumbnail image itself.

Soft Edges

The "-vignette" operator provides a simple means to add a blurry edge around an image.

  convert thumbnail.gif -matte   -background none -vignette 0x4  vignette.png
[IM Output]

Of course as this thumbnail uses semi-transparent color so it needs to be saved in the PNG format.

If you don't really like a circular type edging you can use some trickiness involving Edge Effects and Virtual Pixels to blur a transparent color at the edge of the image.

  convert thumbnail.gif -matte -virtual-pixel transparent \
          -channel A -blur 0x8  -level 0,50% +channel  soft_edge.png
[IM Output]

The extra "-level" operation (adjusting just the 'matte' channel) ensures the edge becomes fully transparent, rather than only half transparent.

You can see another example of using 'soft edges' in Examples of Image Layering.

If instead of doing a level adjustment, you can threshold the blurred matte channel at 50%, generating rounded corners from the above thumbnail image.

  convert thumbnail.gif -matte -virtual-pixel transparent -channel A \
          -blur 0x8  -threshold 50% +channel rounded_corner_blur.gif
[IM Output]

While very simple, the result is not a really nice way to round off the corners of the image. First the corners are not actually circular, but a 'hyperbolic' curve. Also the curve is not smoothly anti-aliased, showing 'jaggies' or steps in the resulting pixels. But that is always the case with the GIF file format.

Also note that the "-blur" operation can become very slow when you work with a large argument for generating a larger rounded corner.

Rounded Corners

The proper way to generate an image with rounded corners, which is properly anti-aliased, requires you to actually cut out each corner using a mask.

The following method from Leif Åstrand <leif@sitelogic.fi> is the simplest I have see to date.

  convert thumbnail.gif \
     \( +clone  -threshold -1 \
        -draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \
        \( +clone -flip \) -compose Multiply -composite \
        \( +clone -flop \) -compose Multiply -composite \
     \) +matte -compose CopyOpacity -composite  rounded_corners.png
[IM Output]

Basically generates a white mask from the original image, with just one black rounded corner. This is then flipped and flopped to produce a mask with all four corners rounded. And finally that mask is applied to the original image.

For much larger images, you may be better off applying a much smaller mask to each individual corner to reduce the amount of processing needed. (Example anyone?)

Torn Paper Edge

Leif Åstrand <leif@sitelogic.fi>, contributed the following IM code to generate a edge that looks like it was torn from a fibrous paper (like newspaper)...

  convert thumbnail.gif \
          \( +clone -threshold -1 -virtual-pixel black \
             -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \
          +matte -compose Copy_Opacity -composite torn_paper.png
[IM Output]

One improvement may be to make it look like you ripped it from a newspaper corner.

  convert thumbnail.gif -bordercolor linen -border 8x8 \
          -background Linen  -gravity SouthEast -splice 10x10+0+0 \
          \( +clone -threshold -1 -virtual-pixel black \
             -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \
          +matte -compose Copy_Opacity -composite \
          -gravity SouthEast -chop 10x10   torn_paper_corner.png
[IM Output]

This could be improved by adding 'paper' colored borders and a curved shaped mask, so that it looks like the image was ripped roughly by hand. Adding a 'soft shadow' (see next) will also 'lift' the resulting image from the background, making it look like it was a separate piece.

As always, suggestions and contributions are welcome.

Adding a Shadow

The "-shadow" operator makes the Generation of Shadows of any shaped image easy.

For example here a I add a semi-transparent colored shadow, to the thumbnail.

  convert thumbnail.gif -matte \
          \( +clone -background navy -shadow 60x0+4+4 \) +swap \
          -background none -mosaic   shadow_hard.gif
[IM Output]

But you can just as easily create soft fuzzy shadows, too.

  convert -page +4+4 thumbnail.gif -matte \
          \( +clone -background navy -shadow 60x4+4+4 \) +swap \
          -background none -mosaic     shadow_soft.png
[IM Output]

Note that I again used a PNG format image for the thumbnails output. That is because the shadowed image will contain a lot of semi-transparent pixels, which GIF cannot handle. (Yes I am repeating myself but it is important).

If you do plan to use GIF or JPG format you will need to use a more appropriate "-background" color for the web page or larger canvas on which you plan to display your thumbnail, as these formats do not handle semi-transparent colors.

Adding Some Thickness

Adding a thickness to a image or a shape looks a little like a hard shadow (see above), but isn't quite the same, and needs some extra work to get right.

This is actually very tricky as we create a colored, mask of the image which is then replicated multiple times and layered under the original image (using 'DstOver' composition) with increasing offsets to give the image thickness.


  convert thumbnail.gif -matte \
          \( +clone -fill DarkSlateGrey -colorize 100% -repage +0+1 \) \
          \( +clone -repage +1+2 \) \
          \( +clone -repage +1+3 \) \
          \( +clone -repage +2+4 \) \
          \( +clone -repage +2+5 \) \
          \( +clone -repage +3+6 \) \
          -background none -compose DstOver -mosaic  thickness.gif
[IM Output]

You get the idea. Each '\( +clone ... \)' line adds one extra pixel to the image in a south by south-easterly direction.

Also as no semi-transparent pixels are involved (at least for a rectangular image) you can use the GIF image format for the result.

The major problem with this technique is that it is hard to specify a thickness as a variable argument or at different angles, unless you write a specific script to add thickness. Also the edge of the angled parts of the thickness is not anti-aliased, so there is lots of room for improvement.

ASIDE: This may be a good operator to add to a future version of IM.

Polaroid-like Thumbnails

You can make your thumbnail image look like a polaroid photo, give it a shadow, and even rotate it a little so as to appear to be just sitting on a table.


  convert thumbnail.gif \
          -bordercolor white  -border 6 \
          -bordercolor grey60 -border 1 \
          -background  none   -rotate 6 \
          -background  black  \( +clone -shadow 60x4+4+4 \) +swap \
          -background  none   -flatten \
          poloroid.png
[IM Output]

A more complex version of the above was added to IM v6.3.1-6 as a "-polaroid" transformation operator. For example...

  convert thumbnail.gif -bordercolor snow -background black +polaroid \
          poloroid_operator.png
[IM Output]

Note that the image not only has the polaroid frame, but the photo has also been given a bit of a 'curl' with appropriate shadow adjustments, giving the resulting image more depth. The plus (+) form uses a randomized angle, while the normal minus (-) form lets you provide the angle of rotation. Special thanks to Timothy Hunter for the idea behind this technique.

You can even add a "-caption", set your own shadow color, specify your own rotation (or none at all).

  convert -caption '%c' hatching_orig.jpg -thumbnail '120x120>' \
          -font Ravie -gravity center -bordercolor Lavender \
          -background navy  -polaroid -0     poloroid_caption.png
[IM Output]

For more information on using this operator see Complex Polaroid Transformation.

For these examples though, I'll continue to use a DIY creation method, as I need finer control of the borders and shadowing effects to demonstrate proper photo 'stacking'.

And here we go... By making multiple copies of the photograph, (or using other images), and adding polaroid borders, you can then randomly rotate and stack them up to produce a nice looking pile of photos.

  convert thumbnail.gif \
          -bordercolor white  -border 6 \
          -bordercolor grey60 -border 1 \
          -bordercolor none  -background  none \
          \( -clone 0  -rotate `perl -e 'print rand() * 30 - 15'` \) \
          \( -clone 0  -rotate `perl -e 'print rand() * 30 - 15'` \) \
          \( -clone 0  -rotate `perl -e 'print rand() * 30 - 15'` \) \
          \( -clone 0  -rotate `perl -e 'print rand() * 30 - 15'` \) \
          -delete 0  -border 100x80  -gravity center \
          -crop 200x160+0+0  +repage  -flatten  -trim +repage \
          -background black \( +clone -shadow 60x4+4+4 \) +swap \
          -background none  -flatten \
          poloroid_stack.png
[IM Output]

The " `perl ...` " argument generates a random floating point number from -15 to +15. Substitute specific numbers for the back-quoted expression if the above does not work for you.

Of course you could substitute a set of different images rather than repeating the same image when creating the stack. Or select a set of rotates angles so they are all reasonably different, or are more pleasing to look at. If you are really good you can even offset the rotated images (jitter their position a little) so they are not all stacked up perfectly centered. But you get the basic idea.

If you really want to avoid the use of the PNG format, due to its current problems with some browsers, you can use the GIF image format. To do this you must be willing to accept some color limitations, and know the exact background color on which the image will be displayed. The 'LightSteelBlue' color in the case of these pages.

  convert thumbnail.gif \
          -bordercolor white  -border 6 \
          -bordercolor grey60 -border 1 \
          -background  none   -rotate -9 \
          -background  black  \( +clone -shadow 60x4+4+4 \) +swap \
          -background  LightSteelBlue  -flatten    poloroid.gif
[IM Output]

For details about this technique (and more) see GIF images on a solid color background.

The above 'stacked polaroid' technique graciously provided by Ally of Ally's Trip and Stefan Nagtegaal for Muziekvereniging Sempre Crescendo, both of which use Polaroid-like thumbnails extensively on their web sites.

In the IM User Forum, the user grazzman went a little further by overlaying images onto a rotating canvas to create a photo spread.

  convert -size 150x150 xc:none -background none \
          -fill white -stroke grey60 \
          -draw "rectangle 0,0 130,100" thumbnail.gif \
                -geometry +5+5 -composite -rotate -10 \
          -draw "rectangle 0,0 130,100" thumbnail.gif \
                -geometry +5+5 -composite -rotate -10 \
          -draw "rectangle 0,0 130,100" thumbnail.gif \
                -geometry +5+5 -composite -rotate +10 \
          -trim +repage -background LightSteelBlue -flatten \
          poloroid_spread.gif
[IM Output]

Of course for a photo spread like this you really need to use a set of different photos rather using the same image over and over as I did here.

There are a few caveats you may like to consider with this technique.

A similar randomized stacking of photos over a larger area was developed for Stas Bekman's Photography, but with a different bordering technique.

A more generalized method for creating some sort of ordered or programmed layout of photos and images, is shown and described in Examples of Image Layering, as well as in Overlapping Photos.

Problems with Shadow Effects

Note that correctly handling semi-transparent shadow effects in a set of overlapping images is actually a lot more difficult that it seems. Just overlaying photos with shadows, cause the shadows to add together which they would not do in real life. That is two overlapping shadows become very dark, where in reality they do not add together in the same way that overlaying images do.

Basically the various parts of the final image will be either shadowed or not shadowed. You will not get two shadows, unless you have two separate light sources. If you are really serious about getting shadowing correct, you make like to consider layering the photos using a raytracer, rather than using a composition method. That way all shadowing effects are correctly determined by the interactions with the lighting that is being used.

If you come up with a method of laying images while still getting shadows correct, both on the background and lower image layers, then please let me and the rest of the IM community know. You will be worshipped as a great graphics designer by all (especially me) :-)

If that is going too far you will need to figure out some sort of top down layering approach is recommended. Basically the top layer casts a shadow onto the next layer's opacity mask, which in turn produces changes the opacity mask for the next layer. That is, intermediate layers will have shadow effects added to image part of that layer and a separate 'shadow producing' image for later layers.

Anyone like to give it a go, say with a stack or sequence of photos? Mail Me.


Advanced Framing Techniques

Here we will look at some advanced framing techniques that use some very advanced knowledge of how IM works to achieve the desired results.

Simple Border Overlay

One simple type of framing is to create a fancy frame, or shaped image into which you can place your image, under the frame.

For example here we generate a simple frame slightly larger than our image with a fancy shaped hole. The shape was extracted from the 'WebDings' font (character 'Y'), but there are a lot of possible sources for fancy shapes that could be used for picture framing.

  convert -size 120x140 -gravity center -font WebDings label:Y \
          -negate -channel A -combine +channel -fill LightCoral -colorize 100% \
          -background none -fill none -stroke firebrick -strokewidth 3 label:Y \
          -flatten +gravity -chop 0x10+0+0 -shave 0x10 +repage border_heart.png
[IM Output]

For other ways of generating a edge on an existing shaped image see the Edge Transform.

You can also optionally give the frame a little depth by using a Shadow Effect.

  convert border_heart.png  \( +clone -background black -shadow 60x3+3+3 \) \
          -background none -compose DstOver -flatten   border_overlay.png
[IM Output]

Now that we have a simple overlay frame, we can underlay the image in the center, underneath the frame by using a 'DstOver' composition.

  convert border_overlay.png  thumbnail.gif \
          -gravity center -compose DstOver -composite   border_overlaid.jpg
[IM Output]

Now you can generate a library of pre-prepared frames to use with your images, such as this Autumn Leaves Image.

    convert thumbnail.gif  autumn_leaves.png +swap \
            -gravity center -compose DstOver -composite \
            border_leaves.gif
[IM Text]  + [IM Text] ==> [IM Text]

Double Masking Technique

In many cases you don't just want to overlay a square border around an image, but also want to cut out the image edges. For this you need at least two images. One is the masked overlay containing the colors, shadows and highlights you want to add to the existing image. And a second image containing the parts you want to remove from the original image.

For example lets create more complex shaped border but this time don't worry about setting the background.

  convert -size 120x100 xc:none -fill none -stroke black -strokewidth 3 \
          -draw 'ellipse 60,50 30,45 0,360  ellipse 60,50 55,30 0,360' \
          -strokewidth 3  -draw 'ellipse 60,50 57,47 0,360' \
          -channel RGBA  -blur 2x1    border_ellipse.png
[IM Output]

Now I purposely made this border blurry, to make the edge components much more semi-transparent. Even without that extra fuzziness, a border also contains a lot of semi-transparent anti-aliasing pixels, that make the edge look smoother and less jagged looking. It is vital when image processing that you consider these semi-transparent pixels, an preserve them as much as possible.

To make it more interesting give this 'fuzzy' border a random bit of coloring.

  convert border_ellipse.png \
          \( -size 120x100 plasma:Tomato-FireBrick -alpha set -blur 0x1 \) \
          -compose SrcIn -composite     border_ellipse_red.png
[IM Output]

Okay we have a border, but we still need some way of defining what should represent the outside and inside of the border. Basically we need a mask to define these two areas.

  convert -size 120x100  xc:none -fill black \
          -draw 'ellipse 60,50 30,45 0,360  ellipse 60,50 55,30 0,360' \
          border_ellipse_mask.png
[IM Output]

The color of this image is not important, just its shape. It can even be a greyscale mask, or the outside shape rather than the inside shape. It just does not matter. All that will change is how the mask is applied to the image later. Though I find a transparent shape mask such as the above (or its inverse) the most versatile.

Also note that some areas enclosed by this border are defined to be inside while other areas are defined as outside. To perform Double Masking, you would first erase the unwanted parts using the transparency masking image and then overlay the color overlay masking image. That is two masking operations are required, thus what I mean by this being a 'Double Masking Technique'.

  convert thumbnail.gif -gravity center -extent 120x100 \
          border_ellipse_mask.png  -alpha set -compose DstIn -composite \
          border_ellipse_red.png   -compose Over -composite \
          border_double_masked.png
[IM Output]

And there we have not only a fuzzy border but and a shaped image with proper semi-transparent (or even just sharp anti-aliased) edges.

Now unlike the previous Simple Border Overlay or 'heart' example, the two images are kept separate. However that does not mean you can't combine the two images to create a simple single overlay framing image.

  convert border_ellipse_mask.png -alpha extract -negate \
          -background DodgerBlue -alpha shape \
          border_ellipse_red.png   -compose Over -composite \
          border_ellipse_overlay.png
[IM Output]

Or just underlay a solid color or some other background image under the previously generate double masked image...

  convert border_double_masked.png \
          \( -size 120x100 plasma:Green-Green -blur 0x1 \) \
          +swap  -compose Over  -composite     border_background.png
[IM Output]

The point is with a separate mask image you have a lot more freedom in how you add the border to the image. You could even define other masks and effects to color the other 'windows' in the border, or add optional highlights and shadows, rather than hard coding them into a single overlay framing image.

Now for a important caveat. The edges of the masking image must not coincide with the edges of the overlay image. This is vital. Otherwise you will not get the correct handling of the edges. If this is not done you will either get invalid edge colors or transparency. Make sure the mask edges fall somewhere within the fully-opaque region of the overlay image.

An alternative double masking technique is two define the border not as a border image, but as separate inside and outside border masks.

That is you would take your image, and overlay the border which sets not only all the border colors, but also masks and colors all the parts outside parts the original image. You then use a separate 'outside' or 'clipping' mask to either overlay or cut out the outside areas of the image.

Note that each masking image defines a different set of borders, one defines the inside edges, while the other defines the outside edges. As a result one image does not completely define the whole border, like it does in the previous examples. The second masking image must be applied to complete the task and clip or color the outside regions as well.

The advantage of this technique is that the two masks should not have any problem with coinciding edges, which I warned about above. As such, very thin borders or even a border which completely disappears with a direct blurring of the inside to outside regions is possible. This is something imposible to achieve without problems using the previous method.

This method of double masking is used in the Fancy Borders example below.


Border with Rounded Corner

As you saw above Double Masking can be used to both add extra colors or 'fluff' to an image, but also remove parts, so as to shape the final image. This presents us with an alternative way of adding rounded corners to an image.

The IM "-draw" operator comes with a 'roundrectangle' method that can be used to provide an interesting frame around the image. However you need to size the dimensions of this draw method to match the image. IM does provide methods to extract and even do mathematical calculations based on the image size.

The draw commands that are needed will be created using fancy FX escapes. This is will then be saved as a Magick Vector Graphics File that can be directly used by draw in later commands.

  convert thumbnail.gif -border 2 \
          -format 'roundrectangle 1,1 %[fx:w-2],%[fx:h-2] 15,15'\
          info: > rounded_corner.mvg
[IM Text]

Note that the image was enlarged slightly, before the calculations were done, to provide some extra space in the final thumbnail for the added border. That same amount of space is also needed in the next steps.

If you can figure out the image size in a different way (using the shell, or other API language wrapper) you can substitute the appropriate draw parameters directly into the next examples, rather then use an FX mathematical expression. Basically the above makes this whole process independent of the actual size of the thumbnail. Any other way, including direct hard coding is also acceptable.

Now we can use this to generate overlay and a mask image. As part of this we create a transparent canvas using the original image (which is first enlarged), to get the size right.

  convert thumbnail.gif -border 2 -alpha transparent \
          -background none -fill white -stroke none -strokewidth 0 \
          -draw "@rounded_corner.mvg"    rounded_corner_mask.png
  convert thumbnail.gif -border 2 -alpha transparent \
          -background none -fill none -stroke black -strokewidth 3 \
          -draw "@rounded_corner.mvg"    rounded_corner_overlay.png
[IM Text] [IM Text]

And there we have the overlay border image, and transparency mask image, we need for the double masking technique.

So lets do it...

  convert thumbnail.gif -matte -bordercolor none -border 2  \
          rounded_corner_mask.png -compose DstIn -composite \
          rounded_corner_overlay.png -compose Over -composite \
          rounded_border.png
[IM Output]

And there we have have a bordered our image with rounded corners.

The following is how you can do the above all in a single command with a little extra fanciness. However this all-in-one command will still generate a temporary file holding the generated draw commands needed for an image of the size given.

  convert thumbnail.gif -matte -bordercolor none -border 2 \
      -format 'roundrectangle 1,1 %[fx:w-2],%[fx:h-2] 15,15' \
      -write info:tmp.mvg \
      \( +clone -alpha transparent -background none \
         -fill white -stroke none -strokewidth 0 -draw @tmp.mvg \) \
      -compose DstIn -composite \
      \( +clone -alpha transparent -background none \
         -fill none -stroke black -strokewidth 3 -draw @tmp.mvg \
         -fill none -stroke white -strokewidth 1 -draw @tmp.mvg \) \
      -compose Over -composite               rounded_border_in_one.png
  rm -f tmp.mvg      # Cleanup of temporary file
[IM Output]

A better way for doing rounded corners, especially with very large images will be to use a separate corner masking image technique, which we will look at in the next set of examples. In many ways this is an extention of the previous Rounded Corners method, but with an extra overlay.

Fancy Corner Overlay Masking

[IM Output] Here we look a bit deeper into used this 'double masking' technique to Cange an image only specific areas, rather than applying it to the whole image. In this case we will only double mask the corners of a prepared thumbnail image with matching borders.

The corner images I will use was generated from the original source (shown right) which I found in the DIY section of Anthony's Icon Library. There are others in this section, so you may like to have a look. If you find something on the net, please let me know as I like to collect interesting corners, and edging techniques.

[IM Output] [IM Output] A color overlay and masking image was generated, though this time I decided to so the masking AFTER the overlay to simplify things...

Notice that the images, being completely rectangular, did not use any semi-transparent pixels. As such this fancy border can be used to produce clean looking 'GIF' thumbnails.

The complication with using corner masks, is that they only mask the corners of the original image. Because of this the original image first needs to be given the appropriate set of border layers. After that the two corner masks, must be composited onto each of the corners of the expanded image, requiring a total of 8 image compositions.

  convert thumbnail.gif   -matte  -compose Copy \
          -bordercolor Black  -border 2 \
          -bordercolor Sienna -border 3 \
          -bordercolor Black  -border 1 \
          -bordercolor None   -border 2 \
          -bordercolor Black  -border 2 \
          -bordercolor Peru   -border 3 \
          -bordercolor Black  -border 1 \
          \
          -compose Over \
          \( fancy_add.gif             \) -gravity NorthWest -composite \
          \( fancy_add.gif -flip       \) -gravity SouthWest -composite \
          \( fancy_add.gif       -flop \) -gravity NorthEast -composite \
          \( fancy_add.gif -flip -flop \) -gravity SouthEast -composite \
          -compose DstOut \
          \( fancy_sub.gif             \) -gravity NorthWest -composite \
          \( fancy_sub.gif -flip       \) -gravity SouthWest -composite \
          \( fancy_sub.gif       -flop \) -gravity NorthEast -composite \
          \( fancy_sub.gif -flip -flop \) -gravity SouthEast -composite \
          fancy_border.gif
[IM Output]

Note that to preserve the transparent border that is being added, you must set "-compose" setting to 'Copy' rather than the default of 'Over'. If you don't then the transparency will be filled by the next border color added, in this case with 'Black'.

The beauty of only using corner masks is that any size image can be framed using this technique, as long as it large enough for the corner masks being added. That is you are not limited by the size of the framing images you have available.

The problem is it is more complex, though not as complex as using tiled framing pieces which is what we will look at next.


Framing using Edge Images

[IM Image] One way to add a complex border to an image is to use a pre-prepared framing images, to produce a frame such as the example shown (right).

However you also need to be careful with generating frames. If you look at the given example carefully you will notice that it is not quite right. The shading of the generated frame is actually incorrect. The left and bottom frame edges should be swapped to produce a correctly shaded frame for a typical top-left light source.

As such before we even begin, I would like to stress the importance of using the correct image, or the correctly modified image for each edge while framing your thumbnail or photo. It is very easy to get wrong, so double check your results when you think you have it right.

The Frame Edge Images

There are may types of images that can be used to frame a image.

For example here is 'thin black with gold trim' frame that was modified from images provided by Michael Slate <slatem_AT_posters2prints.com>.
[IM Image] [IM Image]

There are two images, to provide two different lighting effects, one for the top and left edges, the other for the bottom and right edges. However the colors along the length of the image does not vary. As such you can either tile or stretch this frame to produce the length needed. Also as the colors do not vary, you can use separate pre-prepared corner image when adding frames (more on this later).

A similar set of framing pieces are this 'thin ornate gold' tileable border images.
[IM Image] [IM Image]

As these images has some fine detail you cannot just simply stretch the image to the desired length. Nor can you just Rectangular Rotate these pieces to produce the other edge pieces, as doing so will get the shading of the fine detail wrong. A Diagonal Transpose simple distortion should however get the correct shading for the other edges. Extra caution is advised when reviewing your results, to be sure the both the overall shading and the fine detail shading is correct on all four sides of the image.

Finally a framing image may only consist of a single image that can be used to generate all the framing edges, such as this 'bamboo' tiling frame image.
[IM Image]

The reason only one image is needed is that the frame has no specific 'inside' or 'outside' to it. Though the frame does have both overall and fine detail lighting effects that requires you to again be careful of how you rotate/flip/transpose the image for the other edges.

As you can see framing images can come in a variety of styles, and care must be taken to handle the chosen edging images in the correct way (with regard to lighting image), when generating the other missing edging images.

Lengthening Framing Pieces

Now in any use of these framing images, we will need to create a longer piece, and you have two way in which this can be done.

You can simply stretch the frame image using resize (without aspect preservation) so as to get the right lengths. This works for the first set of pieces shown above, which have no internal detail, but is not appropriate for any of the other framing images presented. Basically it will distort the result, and make become distracting in the final result.

However the other lengthening method, tiling, can be used for any framing image that has a repeating pattern or detail, which is the case with all the above images presented. If you are creating your own framing pieces, I recommend caution in ensuring you have a uniform color and proper cycling of the detail in your framing images, or you will get artificial looking joints between the tiles.

In the real world picture framers also have a problem in 'tiled' joints, generally when two different shades of wood are 'dove-tailed' together to form a longer or larger piece of wood. So your not alone in this problem.

The 'bamboo' framing images, will need to be tiled. Though as the detail is restricted to a small area on the image, you can some interesting random tiling effects. I would not go into this however, and will leave it as a exercise for those that are.

For our examples, and because it works for just about all framing images I will use a simple constant tiling method to make longer pieces.

Over-simplistic Append

Here we just lengthen the simple 'bamboo' frame above, by tiling it to the right length, then append the images together.

The tiling is done simply by the special Tiled Canvas image generator "tile:" to tile a image that is being read in.

  convert thumbnail.gif \
          \( -size 90x14  tile:bamboo.gif -transpose \) \
          \( -size 90x14  tile:bamboo.gif -transpose \) -swap 0,1 +append \
          \( -size 148x14 tile:bamboo.gif \) \
          \( -size 148x14 tile:bamboo.gif \) -swap 0,1 -append \
          frame_append.gif
[IM Output]

Note that the sizes used in the above two examples were calculated based on the known width (10 pixels) of the framing image, and the size of the image being framed (120x100 pixels). You will need to adjust the resize arguments appropriately for your images.

One problem with tiling framing pieces (like bamboo) is that all the edges look like they are exact copies of each other! That is the framing looks artificial. In real life the frame will have been cut with pretty much random offsets, from longer pieces of real wood, or in this case bamboo.

To fix that you will need to also give such tiles a slightly different Tile Offset for each edge of the image.

  convert thumbnail.gif \
          \( -size 90x14  -tile-offset +50+0 tile:bamboo.gif -transpose \) \
          \( -size 90x14  -tile-offset +0+0  tile:bamboo.gif -transpose \) \
          -swap 0,1 +append \
          \( -size 148x14 -tile-offset +70+0 tile:bamboo.gif \) \
          \( -size 148x14 -tile-offset +25+0 tile:bamboo.gif \) \
          -swap 0,1 -append       frame_tile_offset.gif
[IM Output]

This method of framing isn't too bad for this specific type of edge image, though for other types of frames it can look very silly. Basically the corners are not correct, and for most frames you really want to have the edge images meet at a 45 degree angle joint, just as you would have in a real picture frame.

One solution to this is to pre-generate by hand appropriate corner images that we can now overlay onto this image to make it correct. This works well for a simple stretchable framing image (like 'black thin' framing image), but it will fail rather badly for a tileable image like 'bamboo' as the corner image will probably not fit the tile image properly.

The better way is to generate corner joints directly from the tiled edge images. And I'll be showing you methods of doing this later.

Extended Overlay Framing

Also you can make this type of edge framing look even better by extending the frames beyond the bounds of the original image. This is often seen for a 'Home-Sweet-Home' type picture.

To do this you will need to first enlarge the original image with lots of extra space into which the longer frame pieces are overlaid.

  convert thumbnail.gif -matte -bordercolor none -border 34 \
          \( -size 144x14 -tile-offset +30+0 tile:bamboo.gif -transpose \) \
          -geometry +20+10 -composite \
          \( -size 144x14 -tile-offset +45+0 tile:bamboo.gif -transpose \) \
          -geometry +154+0 -composite \
          \( -size 178x14 -tile-offset +60+0 tile:bamboo.gif \) \
          -geometry +0+20 -composite \
          \( -size 178x14 -tile-offset +0+0  tile:bamboo.gif \) \
          -geometry +10+124 -composite \
          frame_overlaid.gif
[IM Output]

Note the measurements and positioning for this type of framing is not simple, and could use some randomization such as I provided above. Also you can improve the look further by rounding of the ends of the lengths of frame.

A much better way of framing images in this manner is to generate the framing image as a complete unit, and just overlay it on a fixed size image (see Simple Border Overlay). However doing this means you can no longer slightly randomize the lengths and position of each framing piece.

45 degree corner joints

The better solution is to somehow add the framing images around the thumbnail in such a way as to actually create a 45 degree joint in each of the corners of the frame. This is not easy, and I went though a number of drawing and masking methods until I re-discovered a magical operator called Frame, 3D like Borders.

The solution then was simple. Read in the image, and "-frame" it, to create a template which of the areas to be framed.

  convert thumbnail.gif -matte -bordercolor none \
          -compose Dst -frame 15x15+15  frame_template.gif
[IM Output]

Now note that this template as some interesting features. First it is transparent in the middle, where the main image will sit. Second it has four and only four distinct colors defining each area in which we want to place our framing images. The width of those areas (15 pixels) is the width of the framing pieces we will add to the image.

This is the framing template and by tiling each of our framing pieces into the four areas using Color Fill Primitives, we will get our 45 degree corner joints.

For example...

  convert frame_template.gif \
          -tile blackthin_top.gif -draw 'color 1,0 floodfill' \
          frame_top_filled.gif
[IM Output]

You can repeat this process for the other three edges. Using various image image flips and rotates to fill each edge in turn. When finished you can center compose the thumbnail into the frame and you are done.


  convert frame_template.gif \
          -tile blackthin_top.gif      -draw 'color 1,0 floodfill' \
          -tile-offset +0+105 -tile blackthin_btm.gif \
                                       -draw 'color 15,105 floodfill' \
          -transpose \
          -tile blackthin_top.gif      -draw 'color 1,0 floodfill' \
          -tile-offset +0+135 -tile blackthin_btm.gif \
                                       -draw 'color 15,135 floodfill' \
          -transpose \
          -gravity center thumbnail.gif -composite frame_filled.gif
[IM Output]

If your framing pieces have strong detailing in it (such as in the bamboo edging image) you can modify the -tile-offset", for ALL four drawing operations, with a random value to avoid an artificially tiled look to the image (as discussed previously). That is of course not a problem in this image.

Tile Offset setting was broken before IM version 6.3.9-9 in that the 'X' offset was being used for both 'X' and 'Y' offset values (the given 'Y' value was ignored). This means that the above example will probably incorrectly tile the bottom and right edges, in older releases of IM.

An alternative solution is to use a modified version of the template, so that it can be used as mask for the edge pieces. For example

  convert thumbnail.gif -matte -bordercolor none \
          -compose Dst -frame 15x15+15 \
          -fill none -draw 'matte 15,0 replace' \
          -flip      -draw 'matte 15,0 replace'  -flip \
          frame_template_better.gif
[IM Output]

Now by using Duff-Porter Compose Methods you can cut out the corners of the various edge pieces, in pairs.

  convert -size 150x15 tile:blackthin_top.gif tile:blackthin_btm.gif \
          -append    -background none -splice 0x90+0+15 \
          frame_template_better.gif -compose DstOut -composite \
          frame_horiz_filled.gif
[IM Output]

Note that I lengthened the edge pieces using "tile:", but then add a clear space between the pieces using a Splice, row/column addition, the size of the original image. Lets repeat the process for the sides of the frame.

  convert -size 120x15 tile:blackthin_top.gif tile:blackthin_btm.gif \
          -rotate -90 +append   -background none -splice 120x0+15+0 \
          frame_template_better.gif -compose DstIn -composite \
          frame_vert_filled.gif
[IM Output]

All that is needed now it to layer all three images together, with an appropriate offset for the main image.

  convert frame_horiz_filled.gif frame_vert_filled.gif \
          -page +15+15 thumbnail.gif \
          -background none  -flatten  frame_45joint.gif
[IM Output]

And there we have a very nicely framed thumbnail using the framing edge images with correct shading and 45 degree angle joins in the corners.

The above use of "-size" to tile the edge pieces will fail for JPEG images, as the JPEG reader also makes use of this setting. An alternative is given in the final example below.

Scripted Version

You can of course do all the above in a single command. However lets do it in a scripted way. This version uses some in-line code to generate appropriate edging images from the base images provided using Simple Distorts and some randomized Image Rolls to improve the overall look of the tiled image. These can be adjusted depending on the type of edge framing image that was provided.

The processed edging images are then tiled using an In-Memory Tile Image technique and the frame template (generated) is used to mask those images, as we did above.

  image=thumbnail.gif
     image_w=`convert $image -format %w info:`
     image_h=`convert $image -format %h info:`

  top=goldthin_top.png
  btm=goldthin_btm.png

     width=`convert $top -format %h info:`
     length=`convert $top -format %w info:`

  # Size of the new image ( using BASH integer maths)
  new_size=$(($image_w+$width*2))x$(($image_h+$width*2))

  # IM options to read a 'randomly rolled' version for the edge pieces
  lft="( $top -roll +$(($RANDOM % $length))+0  -transpose )"
  rht="( $btm -roll +$(($RANDOM % $length))+0  -transpose )"

  # IM options to 'randomly rolled' the top and bottom pieces
  top="( $top -roll +$(($RANDOM % $length))+0 )"
  btm="( $btm -roll +$(($RANDOM % $length))+0 )"

  # Frame the image in a single IM command....
  convert -page +$width+$width  $image  +page -matte \
    \( +clone -compose Dst -bordercolor none -frame ${width}x$width+$width \
       -fill none -draw "matte 0,0 replace" \
          -flip   -draw "matte 0,0 replace"   -flip \) \
    \( $top $btm -append -background none -splice 0x${image_h}+0+$width \
       -write mpr:horz +delete -size $new_size tile:mpr:horz +size \
       -clone 1  -compose DstOut -composite \) \
    \( $lft $rht +append -background none -splice ${image_w}x0+$width+0 \
       -write mpr:vert +delete -size $new_size tile:mpr:vert +size \
       -clone 1  -compose DstIn -composite \) \
    -delete 1  -compose Over  -mosaic   framed_script.png
[IM Output]

And there we have a perfectly framed image with 45 degree corner joints, with randomized tiling offsets.

Yes it is a complex example. But that is to allow the using of In-Memory Tile Images to allow for the image pre-processing. This is what makes this much more versatile.

The above code has been built into a shell script, which you can download ("frame_edges.tar.gz" from the IM Example Scripts directory). This tar file includes the script and a set of framing images, that the script understands how to process and use. It also adds a 'cardboard' border between the frame and the image proper.


Further Ideas

The above is only a sampling of what you can do. You are only really limited by your imagination. If you do come up with something interesting, please mail it to me so other can also benefit from your findings.

How about a bubble-like glass overlay effects, as per Blair Art Studios.


Created: 8 February 2004
Updated: 19 March 2008
Author: Anthony Thyssen, <A.Thyssen@griffith.edu.au>
Examples Generated with: [version image]
URL: http://www.imagemagick.org/Usage/thumbnails/

a