ImageMagick v6 Examples --
Cutting and Bordering

Index
ImageMagick Examples Preface and Index
Crop (cutting up images in a free form way)
Adding/Removing Image Edges
Adding/Removing Rows, Columns and Edges
Trim or the 'Auto-Crop' Operator

Here we explore the ImageMagick operations which allow you to put your images under the knife, and add frames and borders around the image. That is we look at operations which Changes an image's size, without scaling the image content.

You may think this is a simple operation and it is. So simple, that IM provides a huge number of ways and methods of actually doing this task. So many that I needed to give it its own page of examples just to demonstrate them all.


Crop (cutting images down to size)

Crop and Canvas Page

The "-crop" image operator will simply cut out the part of all the images in the current sequence at the size and position you specify by its geometry argument.

  convert rose:                    rose.gif
  convert rose: -crop 40x30+10+10  crop.gif
  convert rose: -crop 40x30+40+30  crop_br.gif
  convert rose: -crop 40x30-10-10  crop_tl.gif
  convert rose: -crop 90x60-10-10  crop_all.gif
  convert rose: -crop 40x30+90+60  crop_miss.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Just so you can check on exactly what happened here is output from "identify" on the results of the crop above.

  identify rose: crop.gif crop_br.gif crop_tl.gif \
                 crop_all.gif crop_miss.gif
[IM Text]

Notice that the size of the displayed image (its 'virtual canvas' or page size) has not been effected by the "-crop" operation. The actual image itself has been cropped, and may be smaller, but the canvas on which the GIF image is displayed is still the same size as the original canvas.

You will also notice that the size of the actual image produces may not be the actual size you requested from the crop. It could be very much smaller that what you expected, as the crop itself was either partially or fully outside the actual image area being cropped.

You will also notice that the 'offset' of the image on the 'virtual canvas' was in many cases also changed so that the pixels of cropped image is still in exactly the same position as they were in the original image. That is the image contents itself does not move, even though the actual image itself is smaller.

This means if you now modify the smaller image, then overlay the image back over the original, it will fit directly back to where it originally came from.

That is IM retains the 'virtual canvas' or 'page' information so as tp preserve this information for later use. this is especially important for the correct working for GIF animation handling, and layered images. For more information on this see. Deconstruct GIF Animations.

GIF images make active use of the 'page' or 'virtual canvas', size and offset information in images cropped by IM. If you don't want this information remove it with "+repage" immediately after the "-crop".

Note that many image formats don't save this virtual page/canvas information information, so saving to such formats automatically removes it. JPEG is a typical example of a format that removes this info.

The PNG format doesn't make much use of page/canvas info (except in the multi-png (MNG) format) but it does saves the page offset information (even negative offsets). IM will also add a small amount of meta-data to preserve the virtual canvas size for later use by other IM commands.

Because of this preservation, I strongly recommend you still apply a "+repage" even when saving to JPEG or other page-less image format when you will not need that information, as a pre-caution, and to make it obvious you don't what it.

The Missed Image (from a bad crop)

The last image in the above example (EG: "crop_miss.gif") also produced special empty image. Such images can be produced by operations such as Crop, Trim, Layer Comparison, and even GIF Animation Optimizations, generate empty or non-sensible results.

For example in the previous example above, the "-crop" operation missed the actual image it was cropping, so it produced this special 'missed' image, as well as some informational warning messages...

[IM Text]

The output image, or 'missed' image, is a minimal image, one pixel in size at a 0 offset, but with original images page or canvas size, as well as any other meta-data the image may have associated. Here it represents the 'empty' or 'zero sized' image that should have been returned by "-crop", but as no image format can output a image of 'zero' dimensions, a single transparent pixel image is used instead.

Just so you can see more clearly, here is the "identify" output of the missed image, as well as a 'IM pixel enumeration' of that single pixel image, showing that it only contains one single transparent pixel.

  identify crop_miss.gif
[IM Text]

  convert  crop_miss.gif  crop_miss_data.txt
[IM Text]

This 'missed' image is basically same as creating a "null:" image but with the original source images page or virtual canvas size set (but not its offset), and all other image meta-data, such as GIF animation timing delays. The GIF disposal method however may be modified to ensure animations remain correct, after cropping.

Basically you need to keep in mind that "-crop" and other similarly related operators can produce a special 'missed' image. As such you should plan to look for the warning message, or this special 'Missed Image' when writing a script using IM, if such a minimal image is possible and can cause you problems.

If you don't want the warning message (for example you expect and handle, the occasionally 'missed' image), you can add a "-quiet" Operational Control Setting to the command line. This tells IM to not output informational warning messages, only real errors.

At this time there is no method to remove any 'missed', or "null:" images from the current image sequence. However such a method has been proposed for a future release of IM. Mail me if you find you need such a method.

Crop an image with existing page geometry

If a image already has an existing page geometry, (such as from a frame of a GIF animation), then the "-crop" operation will be applied relative to the page geometry, and NOT the actual image.

That is it will try to preserve the page offset of the actual pixel data of the cropped image. That is a specific pixel before the crop should still be located at the offset relative to the page canvas afterward. In this way cropping of GIF animations will continue to work right, even though the 'canvas' itself was not cropped.

Here we create an image centered on a page canvas, and we crop it in various ways. As before the canvas size itself is not modified by the operation.

  convert rose: -shave 12x0 -repage 64x64+9+9  paged.gif
  convert paged.gif -crop 32x32+16+16  crop_page.gif
  convert paged.gif -crop 32x32+0+0    crop_page_tl.gif
  convert paged.gif -crop 32x32+32+32  crop_page_br.gif
  convert paged.gif -crop 60x60+2+2    crop_page_all.gif
  convert paged.gif -quiet -crop 32x32+56+56  crop_page_miss.gif

  identify paged.gif crop_page.gif crop_page_tl.gif crop_page_br.gif \
           crop_page_all.gif crop_page_miss.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Text]

That last example in the above was of course, the special Missed Image. Note that I suppressed the normal warning message from IM using a "-quiet" setting.

Just so you can see just what is going on, lets have a closer look at the paged crop of the lower right corner of the image. Here I have drawn a semi-transparent square over the area that was cropped.

  convert paged.gif -page 64x64+32+32 -size 32x32 xc:'#fff8' \
          -matte  -background none  -mosaic    crop_area_br.png
[IM Output] ==> [IM Output] ==> [IM Output]

From this you can see just what is happening. Even though the crop is contained completely in the page canvas, the crop did not cover the actual image completely. The result is that the actual image is smaller than the user may have intended, but still positioned on a larger canvas or page.

Removing Canvas/Page Geometry

If this canvas and position image information is not wanted, then you can use the special "+repage" operator to reset the page canvas and position to match the actual cropped image.

  convert rose: -crop 40x30+10+10  +repage  repage.gif
  convert rose: -crop 40x30+40+30  +repage  repage_br.gif
  convert rose: -crop 40x30-10-10  +repage  repage_tl.gif
  convert rose: -crop 90x60-10-10  +repage  repage_all.gif
  convert rose: -quiet  -crop 40x30+90+60  +repage  repage_miss.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

This is of course the result new users of IM would normally have expected from the "-crop" operator. It is actually such a common thing to do that you could call it a rule of thumb.

Always use "+repage" after any 'crop' like operation.
Unless you actually need to preserve that info.

The last image in the above is of course the special 'crop missed' error image, and is a single pixel transparent image. An warning error message was also output by the "convert" command, notifying you that the "-crop" operator missed the actual image data.

For IM version 5 and earlier the "+repage" operation was handled by a "-page +0+0" argument sequence, usually just before saving to format that uses virtual canvas and offset information, such as GIF.

With IM version 6, command line restructure, the "-page" option became purely a image read/create setting for use in creating GIF animations and Layers of Images.

Viewport Cropping with Canvas/Page Adjustments

From ImageMagick version 6.2.4-5, you can add a new special flag to the "-crop" argument. This flag '!' will tell crop to adjust the canvas/page information of the returned image so that it is relative to the area cropped.

In other words, regardless of the resulting size of the actual image cropped, the canvas and offset of the image returned will be adjusted to match the area you requested cropped. You can think of this flag as cropping an image to match a 'window' or 'viewport' of the crop area. Even if half the image is not visible in that 'window', the virtual canvas and offset of the part returned will match that 'viewport'.

For example...

  convert rose: -crop 40x30+10+10\!  crop_vp.gif
  convert rose: -crop 40x30+40+30\!  crop_vp_br.gif
  convert rose: -crop 40x30-10-10\!  crop_vp_tl.gif
  convert rose: -crop 90x60-10-10\!  crop_vp_all.gif
  convert rose: -quiet -crop 40x30+90+60\!  crop_vp_miss.gif

  identify rose.gif  crop_vp.gif crop_vp_br.gif crop_vp_tl.gif \
              crop_vp_all.gif  crop_vp_miss.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]
[IM Text]

The '!' character has special significance to some UNIX shells, like "csh", and must be escaped with a backslash, even when placed inside quotes.

Notice how the canvas size of the image returned now matches the area in which the image was cropped.

For crops of images that are completely within the actual image, the result will be equivalent to following the crop with a "+repage". However any partial or missed cropping of the image, the result will a larger canvas and a possible offset to the resulting image. As such this is no substitute for doing a "+repage" after cropping to reset page/canvas information.

However you can follow a 'viewport crop' with a Flatten to 'fill out' the images new virtual canvas with real pixels. That is you will be left with an image that is guaranteed to be the size of the requested crop, with any 'missed' areas filled out with the current "-background" color 'viewport'.

This is particularly useful for viewing an Affine Transformation which preserves the final location of the resulting image using virtual canvas offsets.

  convert rose: -matte -virtual-pixel Transparent \
          -affine .8,-.3,.3,.8,-20,-20 -transform \
          -crop 50x50-30-30\! -background skyblue -flatten \
          crop_viewport.gif
[IM Output]

A 'viewport crop' flag is also very important when cropping GIF animations, as it not only adjusts the canvas size, but also insures all the image frames are still correctly positioned within the cropped area. Without this option cropping a GIF animation is very difficult requiring external correction of the image canvas size and offsets. For and example of this, see Animation Crop, with the canvas too.

The '!' flag can NOT be used for tiled crops.

Crop relative to Gravity

The offset position of the "-crop" by default is relative to the top-left corner of the image. However by setting the "-gravity" setting, you can tell "-crop" to cut the image relative to either the center, corner, or an edge of the image.

The most common use of a gravitated crop, is to crop the 'center' of an image.

  convert rose:  -gravity Center  -crop 32x32+0+0 +repage  crop_center.gif
[IM Output]

The "-gravity" setting does not just effect the initial 'zero' position of the crop but it also effects the direction of the crop offset.

For example if you use a "-gravity" of 'South', and offset of '+0+5' will offset the crop area upward, instead of downward as it normally would.

  convert rose:  -gravity South  -crop 20x20+0+5   crop_south.gif
[IM Output]

Note the position of the crop example above. I purposely left off the "+repage" operation so you can see how the crop area was displaced from the bottom edge of the image.

Also notice that the crop area is not only relative to bottom (southern) edge, but that the area is center 'justified' to be middle of the bottom edge. This is done with all gravity effected operations.

Crop a Percentage of an Image

The "-crop" operator also understands how to crop an image to just a percentage of its original size. For example this will half the size of the image.

  convert rose:   -crop 50%x+0+0      crop_half.gif
[IM Output]

If only one size number is given, then that value is used for both the width and height percentages and the final size of the area that is being cropped will be rounded to nearest integer. The offset is not optional.

Note that while the size can be a percentage the offset will always be in pixels. You can not provide an offset as a percentage of the image size.


  convert rose:   -crop 50%x+30+20      crop_percent.gif
[IM Output]

When a crop is given with an offset you must supply an 'x' symbol in the argument so that the argument can be interpreted correctly. This is especially important when only a single number is provided for both width and height of the crop area.

As such you can not use an argument like '50%+30+20 which is an error, and will result in crop silently doing nothing.

More commonly a percentage crop is done from the center of an image.

  convert rose:  -gravity Center -crop 50x80%+0+0  crop_percent_center.gif
[IM Output]

The percentage symbol '%' can appear anywhere in a argument, and if given will refer to both width and height numbers. It is a flag that just declares that the 'image size' parts are a percentage fraction of the images canvas or page size. Offsets are always given in pixels.

You can also use a 'viewport crop' flag with percentage crops, to automatically set the canvas size and offset of the crop, to the area being cropped.

  convert rose:  -gravity Center -crop 50%\!   crop_percent_vp.gif
[IM Output]

Just remember that this may not always produce the same result as a "+repage", when an offset in pixels is also given.

Tile Cropping, sub-dividing one image into multiple images

One of the more useful aspects of crop is when you don't give a specific position to the crop command. That is you give a size, and not a position within the image to crop. In this case instead of generating just one image, crop generates a whole series of images..

  convert paged.gif  +gravity -crop 32x32  tiles_%d.gif
  identify paged.gif tiles_?.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]
[IM Text]

It is a good idea to make sure gravity is turned off using "+gravity". This is because in one special case (centered percentage crop) the gravity setting can turn off tile cropping. Other effects of gravity on tiled cropping is also undefined.

By using "-mosaic" or "-flatten" (either can be used) you can layer these images all on top of each other, restoring the original image.

  convert tiles_[0-3].gif -background white -mosaic  tiles_mosaic.gif
[IM Output]

However as you can see the the canvas (or page) of the image has been filled with the background color by "-mosaic". A final "-trim" should fix this, restoring the page and offset information. (See the section on trim below).

  convert tiles_mosaic.gif -trim tiles_restored.gif
  identify tiles_restored.gif
[IM Output]
  [IM Text]

Note that if the original image contained some transparency, or a similar "-background" color to that used in the "-mosaic" operation, the "-trim" operator may 'over trim' the image. For this to work properly you need to use a "-background" color which is not present in the original image. (See the warnings about trim below).

Also, to preserve the transparency within the image data, you may need to is a "-compose Copy" setting to preserve it during the "-mosaic" operation. (See the 'Copy' composition setting)

If you had reset the the canvas and offset information using "+repage" then you can re-join all the images together again using the special 'concatenation' mode of "montage". Note that you will need to tell montage how many rows or columns were produced by the original tile cropping.

  convert rose: -crop 20x20  +repage  rose_tiles_%02d.gif
  montage -mode concatenate -tile 4x  rose_tiles_*.gif   rose_rejoined.gif
[IM Output]==> [IM Output][IM Output][IM Output][IM Output]
[IM Output][IM Output][IM Output][IM Output]
[IM Output][IM Output][IM Output][IM Output]
==> [IM Output]

It is currently not possible to sub-divide an image directly into a specified number of tiles, and have it work for all cases.

You could do the maths and work out the tile size for the above Tile Cropping, but that will only work correctly for images that sub-divide exactly by the number of tiles wanted. If it does not then you will be left with a set of small 'reminder' tiles along the bottom and right edges, and probably the wrong number of images as well.

For example try to sub-divide a 100x100 pixel image into 30x30 tiles will not work very well. Using "-crop" with 'best fit' of 3x3 pixels, you will get 33 row/columns of images with a one pixel wide remainder image on the ends. You will never get your requested 30x30 images wanted.

IM really needs an option to subdivide images, as equally as possible. Such an operator will produce some rows and column of tiles that are say one pixel smaller or larger than neighbouring rows and columns, but the tiles will be reasonably equal.

A script that can do this is provided in PerlMagick.. Image::Magick::Tiler.

Strip Cropping, cropping out rows and columns

With IM version 6.1.1, a "-crop" was enhanced so that if one of the size arguments missing, or set to zero, then the missing size argument is set to the size of the image canvas/page. In most cases this is large enough to cover the image located on the canvas, if the related offset is also set to zero.

This small change allows you to easily cut out a single row or column from the image, without needing a huge number like '999999' to cover the size of image.

For example, here we extract a simple row and column from our 'paged' rose image.

  convert paged.gif  -crop 20x0+30+0  strip_column.gif
  convert paged.gif  -crop 0x20+0+30  strip_row.gif
    identify paged.gif strip_column.gif strip_row.gif
[IM Output] ==> [IM Output] [IM Output]
  [IM Text]

If you remove both offsets as well as one size argument, you can divide the image into a series of strips or rows, instead of tiles.

  convert crop.gif -quiet -crop  20x  strips_%d.gif
  identify crop.gif strips_?.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]
  [IM Text]

Notice that tile cropping, strip or otherwise, is across the whole page canvas of the image, and as such is aligned to that canvas, and NOT just the actual image. This is why the first and last actual image generated in the above example is only 10 pixels wide.

Of course if a specific tile, or in this case 'column' misses the actual image on the virtual canvas (such as the last image in the above, then a Missed Image is generated. The warning that IM would have normally produced because of this I suppressed using a "-quiet" setting (this is not recommended unless you are prepared for such an event).

It is possible for an image to be positioned such that it does not even appear on its own page or virtual canvas, or be so large that the page canvas can only contain a small window or portion of that image.

In such rare cases, strip cropping without any size arguments will get the image sub-division wrong, and produce respectively, missed images, or smaller tiles of only the parts within the virtual canvas bounds.

The "-crop" operator however will not be fixed to handle these rare special cases, as doing so will prevent its use in other cases, such as those exampled below.

If this is a problem for you, sanitize the page offsets of the image before cropping it with initial crop to the virtual canvas bounds, or a "+repage" to remove the virtual canvas before attempting to generate the tile images.

As an alternative way of dividing images into separate rows, look at the special script "divide_vert". This program will let you divide up an image according to horizontal 'gaps' of solid single color. For example, if given an image of simple text, it will divide it into alternating images of 'lines' and 'gaps'. A simple option lets you remove those gaps.

Quadrants, cutting around a single point

As any of the crop size numbers are missing then they are replaced with the size of the image canvas of the image you are cropping. This should in most cases result in the whole of the image in that dimension becoming part of the crop result.

This allows, with cautious use of the arguments, is the ability to crop and image into quarters around a specific point (with that specific pixel placed as the top-right pixel of the bottom-left quadrant image). You do not need to know how big the image is to do this.

  convert paged.gif  -crop 30x40+0+0  quadrant_tl.gif
  convert paged.gif  -crop 0x40+30+0  quadrant_tr.gif
  convert paged.gif  -crop 30x0+0+40  quadrant_bl.gif
  convert paged.gif  -crop    +30+40  quadrant_br.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]

Of course if the point you were cropping around missed the actual image, then two or even three of the resulting quadrant images will be the special 'crop missed error' images.

Using Negative Offsets, remove bottom or left edge

Their is no reason that you can not use a negative offset with "-crop". In fact at times it can have very definite benefits.

For example lets take our paged rose image and progressively crop it with larger negative offsets. We will not supply a image size to "-crop" argument, so it will default to the images canvas size.

  convert paged.gif  -crop -10-10  neg_offset_1.gif
  convert paged.gif  -crop -20-20  neg_offset_2.gif
  convert paged.gif  -crop -30-30  neg_offset_3.gif
  convert paged.gif  -crop -40-40  neg_offset_4.gif
  convert paged.gif  -crop -50-50  neg_offset_5.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

As you can see steadily decreasing the offset to a larger negative value slowly results in the bottom and right edges being 'chopped' off, the last example almost missing the actual image. If we took this one step further a Missed Image will be generated. It's a bit like using a "-chop" operator but without a "-gravity" setting. See Chop, Removing Edges.

Of course by using "-crop" you may need to use a "+repage" operator to adjust the canvas/page information, where a "-chop" automatically performs such an adjustment. That's life.


Adding/Removing Image Edges

Border, adding space around the image

Often you simply want to add a little working space around the edge of an image, but you don't want to need or depend on knowing the size of an image to do so.

Now there are many ways to add extra space to an image, outside of direct space additions, including appending blank images or labels, composing 'Src' overlays, or even just positioning the image on a larger canvas. But these methods usually need at least some idea of how big the image you are working with actually is.

One of the simplest form of image space additions is "-border" operation. The color of the space added is "-bordercolor" setting. Here is some straight forward examples..

  convert rose:  -bordercolor SkyBlue    -border 10x10 border.gif
  convert rose:                          -border 15x6  border_default.gif
  convert rose:  -bordercolor LimeGreen  -border 10x0  border_sides.gif
  convert rose:  -bordercolor Tomato     -border  0x10 border_topbot.gif
  convert rose: -matte -bordercolor none -border 10    border_none.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Note last example image above. The border color was set to be the transparent color "none", but for this to work as expected we needed to ensure the image actually contained a 'matte' or 'alpha' channel.

Also note that is the vertical and horizontal border sizes are the same you can omit the second number in the border, using just a single number.

As shown above the default color for border is a light gray as it matches nicely the default grey page color of web pages on the WWW.

You can also use a percentage of the image size...

  convert rose: -border 10%x10%  border_percent.jpg
[IM Output]

Internally what is really happening is that "-border" creates a new image of the right size, then overlays the original source image over this new background.

This is itself a very useful operation in ImageMagick, for setting the background of transparent and semi-transparent images. That is the seemingly useless "-border 0" operation is, in IM version 6, a very useful one. For example...

  convert star.gif -bordercolor LimeGreen -border 0  star_background.gif
[IM Output] ==> [IM Output]

Of course there are lots of other ways to fill-in transparency. The most common method is to use "-flatten" (See Flatten Background Example). However this technique does allow you to 'flatten' a whole list of images onto a specific color, keeping each image separate, where "-flatten" would combine all the images into a single image.

This means you can use this for coalesced GIF animations, as well as in a "mogrify" command. For an example of this, see Solid Colored Background, Animations.

The fact that adding a border to images with transparency, also by default fills the transparent background of the image, has been the cause of some debate amongst IM users and the development team. A summary of this debate is given on Border, Frame and use of BorderColor.

Border and Alpha Composition

The overlay of the image onto the bordercolor canvas is controlled by the "-compose" setting, which by default is set to 'Over' alpha compositing. If it is set to come other setting, the "-border" operation may produce unexpected results.

For example here are some of the more interesting uses of "-compose" with the "-border" image operator, when applied to an image containing some transparent areas.

  convert star.gif -bordercolor LimeGreen \
                   -compose {operation} -border 5  {result}
[IM Output]

The choice between using 'Over' and 'Copy' essentially decides if you want to preserve the transparency in the image or not.

For example here is the same 'star' image with transparency, but this time the border was added without destroying the images transparency.

  convert  star.gif  -bordercolor LimeGreen   -compose Copy \
                     -border 5     star_border_copy.gif
[IM Output]

The 'Src' compose will add a transparent border to an image (if it has an alpha channel), regardless of the current "-bordercolor" setting. Basically the background canvas "-border" generated is ignored.

The 'Dst' may not seem to be very useful, but can be used to generate a canvas the same size (or a little bigger) than the original image. The original image is only used to determine the final size of the canvas. For more examples see Canvases Sized to an Existing Image.

For more information on the various "-compose" methods see the Alpha Compositing Examples.

Frame, adding a 3D-like border

The "-frame" operator is very similar to "-border", and if you look at the first example image generated below, you will find that it will produce exactly the same result, except it used the "-mattecolor" rather than "-bordercolor". Note "-bordercolor" is still used for background of framed images, see below.

To use "-frame" properly you need to supply four arguments to the command, instead of just 2. The extra arguments specify the width of the 'outside' and 'inside' bevels of the frame being produced.

Here are some examples of using the "-frame" operator with various settings.

  convert rose:                     -frame 10x10      frame.gif
  convert rose:                     -frame 15x6+2+2   frame_wierd.gif
  convert rose: -mattecolor SkyBlue -frame 6x6+2+2    frame_blue.gif
  convert rose: -mattecolor Tomato  -frame 10x10+5+5  frame_red.gif

  convert rose:    -frame 10x10+10+0    frame_rasied.gif
  convert rose:    -frame 10x10+6+0     frame_rasied_part.gif
  convert rose:    -frame 10x10+0+6     frame_sunken_part.gif
  convert rose:    -frame 10x10+0+10    frame_sunken.gif
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output] [IM Output]

Using multiple frame operations can also produce weirder framing styles.

  convert rose:       -frame 10x10+3+3                    frame_normal.gif
  convert rose:       -frame 3x3+3+0      -frame 7x7+3+0  frame_popped.gif
  convert rose:       -frame 7x7+0+3      -frame 3x3+0+3  frame_pressed.gif
  convert rose: -frame 3x3+3+0 -frame 4x4 -frame 3x3+0+3  frame_inverted.gif
[IM Output] [IM Output] [IM Output] [IM Output]

The default "-mattecolor" is a slightly darker gray than that of the default setting of "-bordercolor" also allowing it to match the default color of web pages on the WWW.

While "-frame" may actually use the "-mattecolor" color, it also generates four more extra colors from this base for use in drawing the frame. That is five related colors will likely be added to an image, not just one.

With some effort you can even reproduce a "montage"-like framed image complete with text label.

  convert rose:   -mattecolor grey  -background grey  -frame 3x3+0+3 \
          -gravity South -splice 0x15 -annotate 0x0 'A Red Rose' \
          -frame 6x6+3+0    frame_montage.gif
[IM Output]

You can even use a semi-transparent "-mattecolor" for the frame "-frame" and then 'underlay' a interesting pattern (such as a Fractal Plasma Canvas), to produce a more colorful frame.

  convert rose:  -matte -mattecolor '#CCC6' -frame 10x10+3+4 \
          \( -size 100x100 plasma:fractal -normalize -blur 0x1 \) \
          -compose DstOver -composite   frame_plasma.gif
[IM Output]

Alternatively you can color the frame separately, (generated using a special 'Dst' composition setting), then overlay the picture into the frame once you have it colored. But that is getting very tricky indeed.

Frame and Alpha Composition

Frame is closely related to the "-border" operator. Not only is a frame drawn using the "-mattecolor", but this operator will also make use of the "-bordercolor" setting to define the background on which the frame is initially drawn.

Now for images which have no transparency, the "-bordercolor" will not be visible, as it is overlaid by the image itself. But for images that do contain some transparent areas, the background color does become visible.

  convert star.gif  -frame 6x6+2+2  star_framed.gif
[IM Output]

In other words "-frame" acts as if you take your image and overlay it on a picture frame with a solid color background. As such any part of your image that is transparent will be replaced by the "-bordercolor" which by default is a light grey color.

The fact that adding a frame to images with transparency, also by default fills the transparent background of the image with the bordercolor has caused some debate amongst IM users and the development team. A summary of this debate is given on Border, Frame and use of BorderColor.

If you want to preserve the transparency of the image, while framing it, you have two solutions.

The first is to used transparent "-bordercolor" such as 'none'.

  convert star.gif -bordercolor none  -frame 6x6+2+2  star_framed_none.gif
[IM Output]

The other solution and the preferred method is ensure the transparent pixels are preserved when the image is added to the frame. This is done by using a special "-compose" method called 'Copy'.

  convert star.gif -compose Copy  -frame 6x6+2+2  star_framed_copy.gif
[IM Output]

The use of "-bordercolor" as the background image for both "-border" and "-frame" was added to IM with version 6.1.4. Before this the background canvas generated consisted of a black canvas onto which the border, or frame was drawn.

This use of black was especially bad for the "montage" command which makes heavy usage of the internal "-frame" function in its internal processing. (See Montage Background and Transparency Handling)

As you can see the "-frame" operator, like "-border", also uses the "-compose" setting to define how the source image is overlaid onto the background frame.

  convert star.gif -bordercolor LimeGreen \
          -compose {operation} -frame 6x6+2+2  {result}
[IM Output]

The use of a "-compose" setting of 'Copy' becomes very important if you also want to use the "-bordercolor" setting in "montage" frames. See Montage Background and Transparency Handling for more details.

Extent, Direct Image Size Adjustment

After some discussions on the ImageMagick Mailing List, a operator to directly adjust the final size of an image size was added to IM version 6.2.4. The "-extent" operator.

If the image size increases, space will be added to right or bottom edges of the image. If it decreases the image data is just junked or cropped to fit the new image size. In both cases the top left area of the image will likely remain unaffected.

  convert rose: -background skyblue -extent 100x60     extent_enlarge.gif
  convert rose: -background skyblue -extent  40x40     extent_shrink.gif
  convert rose: -background skyblue -extent 100x40     extent_wider.gif
  convert rose: -background skyblue -extent  40x60     extent_taller.gif
[IM Output] [IM Output] [IM Output] [IM Output]

As you can see it will fill any new areas with the "-background" color of any new areas added to the image.

Before IM version v6.3.2, "-extent" just cleared the memory of any new areas to zero, or straight black. It did not fill the areas with "-background" color.

Also after IM v6.3.2, "-extent" will use the "-gravity" to define where the areas added/removed are positioned relative to the original image.


  convert rose:  -gravity north  -extent 100x80 extent_north.gif
  convert rose:  -gravity south  -extent 100x80 extent_south.gif
  convert rose:  -gravity east   -extent 100x80 extent_east.gif
  convert rose:  -gravity west   -extent 100x80 extent_west.gif
  convert rose:  -gravity center -extent 100x80 extent_center.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Remember "-extent" will also crop images according to gravity as well. This makes the operator perfect for padding or cropping an image so that it fits into to a specific sized area, for example see Pad/Fill a Thumbnail to Fit.

Note however that "-extent" works by using the same 'overlay' technique that both the Border and Frame operators uses. As such by default using it with a image containing transparency will replace the transparency with the current "-background" color.

  convert star.gif  -background LimeGreen   -extent 80x80  star_extent.gif
[IM Output]

Again the solution to this is to either set an appropriate "-compose" method, or set the "-background" color to 'None'.

Shave, removing edges from a image

The reverse of the "-border" or "-frame" operators, is "-shave", which if given the same arguments, will remove the space added by these commands.


  convert border.gif -shave 10x10 +repage shave.gif
  convert border.gif -shave 10x0  +repage shave_sides.gif
  convert border.gif -shave  0x20 +repage shave_topbot.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]

The main thing to keep in mind about these three operators is that they add and remove space on opposite sides of the images, not just one side, or adjacent sides.

If you want to only remove one edge of an image, then you will need to use the "-chop" operator instead. (See the Chop Examples below).

When dealing with images containing virtual page or canvas information, the operators only effect the actual image, not the whole canvas. here for example we take a 'paged' image add a "-border", then a "-frame", and lastly remove both using "-shave".

  convert paged.gif         -border 5x5      paged_border.gif
  convert paged_border.gif  -frame  5x5+2+2  paged_frame.gif
  convert paged_frame.gif   -shave  10x10    paged_shave.gif
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]

This of course means you can not use these operators with a typical GIF animation directly.


Adding/Removing Rows, Columns and Edges

Splice, adding rows, columns and edges

The "-splice" operator is new to IM version 6, see Splice, example of the creation of a new image operator.

It basically provides the much needed ability to add a row, column of space into the middle or one edge of an image. The color for the space inserted comes from the "-background" color setting.


  convert  rose:  -background blue  -splice 20x10+40+30  splice.gif
  convert  rose:  -background blue  -splice 20x0+40+0    splice_column.gif
  convert  rose:  -background blue  -splice 0x10+0+30    splice_row.gif
  convert  rose:  -background blue  -splice 20x10        splice_topleft.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]

If the background color is not set, IM will attempt to determine this value from the image itself. This means that for some images it may be white (the normal default), on others it may black, or for the GIF format it could be whatever background color was set to when that image was saved.

What this basically means is that if you don't set "-background" color, its default value depends on the image, and you could get just about anything.

Always set "-background", before using an operator that uses it.

Now while adding a row and column to an image is good, the "-splice" operator is ideal for adding space to just one edge of an image. Which edge is determined by using the "-gravity" option and the splice geometry setting.

  convert  rose: -background blue  -splice 0x10  splice_top.gif
  convert  rose: -gravity south \
                 -background blue  -splice 0x10  splice_bottom.gif
  convert  rose: -background blue  -splice 20x0  splice_left.gif
  convert  rose: -gravity east \
                 -background blue  -splice 20x0  splice_right.gif
  convert  rose: -gravity southeast \
                 -background blue  -splice 20x10  splice_botright.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

One of the most common uses of splice is to add space in which to draw label. (See Labeling Images)

  convert  rose: -gravity South  -background LimeGreen  -splice 0x15 \
           -annotate 0x0 'Rose'    splice_label.gif
[IM Output]

Chop, removing rows, columns and edges

The natural inverse of "-splice" is much older "-chop" operator. Given the same argument as "-splice" and the same "-gravity" setting, "-chop" will restore the image to its original form.

  convert  splice.gif       -chop  20x10+40+30   splice_chop.gif
  convert  splice_chop.gif  -chop  20x10+30+20   chop.gif
  convert  chop.gif -background grey \
                           -splice 20x10+30+20   chop_splice.gif
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]

I continued processing the last example to show how you can reverse the order of the "-splice" and "-chop" so as to 'clear' a row or column (or both) from the middle of an image without using draws or overlays.

Chop is more commonly used to cut of a single edge from an image, using gravity to select that edge. For example...

  convert  frame_red.gif                 -chop  0x10  chop_top.gif
  convert  frame_red.gif                 -chop 10x0   chop_left.gif
  convert  frame_red.gif -gravity East   -chop 10x0   chop_right.gif
  convert  frame_red.gif -gravity South  -chop  0x10  chop_bottom.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]

As an alternative to using "-chop" for removing a single edge, you can in fact use the more universal "-crop" operator instead. This does not require the use of "-gravity" to get the bottom or right edges, however does require you to "+repage" the canvas of the image afterward.

  convert  frame_red.gif  -crop +0+10 +repage  crop_edge_top.gif
  convert  frame_red.gif  -crop +10+0 +repage  crop_edge_left.gif
  convert  frame_red.gif  -crop -10+0 +repage  crop_edge_right.gif
  convert  frame_red.gif  -crop +0-10 +repage  crop_edge_bottom.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output] [IM Output]

This relies on the fact that if "-crop" is not given a image area to remove, it will default to the size of the image canvas (not the actual image but the images virtual canvas). This means you can (for simple images) remove image edges by just offsetting the crop area being cut.

The method of using "-crop" to 'chop' image edges, was discovered and published by Don Sheythe on the IM Mailing List, and after some discussion was deemed to be a 'feature' of IM, and thus included here.


Trim or the 'Auto-Crop' Operator

The "-trim" operator is a very close relation to the highly versatile "-crop" operator discussed above. However instead of supplying an argument, this operator attempts to remove any borders or edges of an image which did does not change in color or transparency. In other words it removes the 'boring' bits surrounding an image.

Note that in ImageMagick version 5 and before, an auto-crop operation was achieved by using a '0x0' argument to the "-crop" operator. This is no longer the case, as 'zero' size arguments in crop now denote 'infinite' or 'to the limit of the image size'.

As such a '0x0' argument to crop now effectively means to crop the image into tiles, the size of the original image canvas. In other words, with IM v6, the result will be the same as the original image, or a 'no-op'.

For example here we take the IM logo, which we resize, and 'trim' or 'auto-crop' all the surrounding extra space in the logo.

    convert  logo: -resize 30%    -trim     trim.gif

Two things should be noted from the above. First is like "-crop", "-trim" will retain the canvas size of the image. This means that the numerical arguments of the trim can be extracted, to allow for further processing, or adjustment of the of the image processing (see Trimming "Noisy" Images for an example of doing this).

[IM Output]

Here we trim the image, but only to list the result on what part of the image was trimmed, not the actual trimmed image.

  convert  logo: -resize 30%   -trim  info:-
[IM Text]

However if you don't care about this information, just junk it by resetting the page information of the image either using a "+repage" operator, or saving to a format that does not save canvas information (such as the JPEG format). Here we do both, to make it clear, that we are junking the canvas information.

  convert  logo: -resize 30%    -trim +repage    trim_repage.jpg
[IM Output]

The second thing to note, is that trim did not actually trim right up to the very edge of the final image. This is especially noticeable in the lower right corner of the logo image, where we can see a distinct gap between the foot and its shadow and the trimmed edge.

In this corner, the colors here became numerically different to the background color of the image. So even though we can't see any real change in the image, the "-trim" operator sees a minor color change, so it did not trim as close to the image as we would have expected.

If the image is all one color, then "-trim" will trim the image down to a minimal single pixel transparent Missed Image. This is logical and prevents more serious problems if the image was left as is.

Trimming with a Specific Color

One of the most worrisome problems with "-trim", especially in automated image processing scripts, is that trim can be a little unpredictable. It does not for example limit itself to just a specific color, or even one color. As such you should easily trim much more than you expect.

For example lets do a simple trim of a simple image of striped colors.

  convert -size 32x32 xc:red xc:green xc:blue +append stripes.gif
  convert stripes.gif  -trim +repage   stripes_trimmed.gif
[IM Output] ==> [IM Output]

As you can see, "-trim" trimmed not just one color but two colors! In a automatic script, this can be very bad and produce unexpected results.

If you know what color you want to trim from an image, then the better way is to add a small one pixel wide "-border" of that color to the image. Lets take 'red' in this case.

  convert stripes.gif -bordercolor red -border 1x1 \
          -trim +repage   stripes_trim_red.gif
[IM Output] ==> [IM Output]

Of course using "-border" like this also will change the canvas offset that "-trim" took great pains to preserve. In the above example it didn't matter as we just junk the virtual canvas page information (using "+repage"), but if the offset of the resulting trimmed image is important in your image processing, say for GIF images, or image masking, then you can adjust the offset added by the border operator, either before, or after the trim operation.

So lets try preserving and correcting the virtual canvas offset when trimming a specific color.

  convert  stripes.gif -bordercolor red -border 1x1 \
           -trim   -repage -1-1\!   stripes_trim_red_fix.gif
[IM Output]

At the moment their is no simple way to also restore the canvas page size, as well as the offset of the trimmed image. Though it is a rare thing to also need to preserve that information.

Trimming just One Side of an Image

As you saw above "-trim" will trim as many sides as it can. Even going so far as removing two different colors from different sides (or if very carefully arranged, four colours could have been removed). This makes it a little more difficult when you want to restrict the trimming to just one side.

To guarantee that we only trim one side (say the bottom) we need to add some color stripes to the other side to protect the other three sides.

Here is the process step-by-step for protecting the 'left' or 'west' side of the 'border' image we created previously. I used much thicker stripes than is necessary so you can see them better in this example.

  convert border.gif  -gravity East \
                      -background white -splice 5x0 \
                      -background black -splice 5x0  trim_protect.gif
  convert trim_protect.gif     -trim +repage         trim_oneside.gif
  convert trim_oneside.gif  -gravity East -chop 5x0  trim_west.gif
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]

Note that we add two different colors in case one of them matched the color surrounding the image, and one of the colors will also be trimmed, leaving just one color stripe to be cleaned up.

Here is the whole one side trim as a single command, but for trimming the top edge.

  convert border.gif -gravity South \
          -background white -splice 0x1  -background black -splice 0x1 \
          -trim  +repage -chop 0x1   trim_north.gif
[IM Output]

And here is a bottom edge only trim. Of course the "-gravity" settings used in the previous example is not needed and the setting defaults to a 'North-West' setting for images.

  convert border.gif \
          -background white -splice 0x1  -background black -splice 0x1 \
          -trim  +repage -chop 0x1   trim_south.gif
[IM Output]

Trimming 'Fuzzy' Images -- Low Quality JPEG Images

Under Construction

FUTURE EXPANSION:

Adding a fuzz factor...

JPEG, or blurry images require the use of fuzzy color matching to trim close
to the image.

Because JPEG is 'lossy' the colors in the image is generally not a single
color but slightly varying band of different colors.

A very small "-fuzz" setting
will solve most of these problems.

  convert image.jpg  -fuzz 1% -trim  new_image.jpg

It is also a very good idea to specify the specific color you want that fuzz
factor to be relative to, by using the "-border" option, as we did above.

Trimming 'Noisy' Images -- Scanned or Video Images

A similar problem is faced with scanned images, where scanners often produce small single pixel errors, caused by dust, dirt, slight variations in the scanner, or just electronic noise picked up by the reader. The pixels errors however this case is usually too big for a small fuzz factor to overcome, so different technique is needed to trim such images.

The simplest solution, though often least practical is to take multiple scans of the same image, or multiple frames in a still sequence of video), then averaging the results to reduce the interference. However this will not remove dust specks on the scanner or help when only a single image or frame is available, making this method impractical in most cases.

A practical solution is a two step one. With a copy of the image, process it in some way to de-emphasize single pixel errors, or scanner dust, while enhancing the effect of large blocks of highly contrasting colors. By then using "-trim" on this copy, and examining exactly what it did, you can then "-crop" the original unmodified image by the same amount.

Their are two main methods of de-emphasizing single pixel errors. One is to use "-blur", the other is "-median". Either of which will to a reasonable job.

This gives two controls:
  • The "-blur" sigma radius, or the "-median" convolution radius, which determines the size of dust specks you want to ignore. Note that both these values can be a floating point number so you have a fine control over the amount of the blur applied.

    For more information on blurring see Blurring Images.

  • The second control is the "-fuzz" color factor that controls the amount of color change matched by the "-trim" operator. That is how close to the desired image you want the trim to get.

  • For example lets use a smaller "logo:" image.
    
      convert logo:   -resize 30%   noisy.jpg
    
    In this small image we could regard the stars and title in the image as noise which we want trim to ignore. The stars in the above is about 5 pixels across, so we want to use a value of about double that to get trim to basically ignore them.

    [IM Output]

    Here is the result. Note in this case we do not want an image, just the canvas information from the image.

    
      convert noisy.jpg  -virtual-pixel edge -blur 0x10 -fuzz 15% -trim  info:
    
    [IM Text]

    You need ensure "-virtual-pixel" to 'edge' (which is the default), to prevent "-blur" from blurring the wizards feet across the edge to the top, and preventing the "-trim" correctly vertically trimming the image.

    Alternatively you can add a wide border of the same background color to image before blurring and adjusting the offset results appropriately. This may be better for more accurate results from both "-blur" and "-trim" operators.

    From the above result we can determine that "-trim" had internally used a "-crop" argument of '88x123+78+21'. This is the actual size of the trimmed image, and its offset image canvas, and presumably the location of the major (single) object we are looking for within the image.

    This can then be used on the original image, which has not been blurred.
    
      convert noisy.jpg   -crop 88x123+78+21 +repage   noisy_trimmed.jpg
    

    And here we have trimmed our image to just the wizard!
    [IM Output]

    Note that while the hand is of the wizard is fully visible, the point of the hat isn't. This is the drawback of this method, it will ignore sharp points and fine details. But then that is what we were asking it to ignore in the first place.

    This can be done all in a single command with a small amount of data re-formatting...
    
      convert noisy.jpg -crop \
        `convert noisy.jpg -virtual-pixel edge -blur 0x10 -fuzz 15% \
                 -trim -format '%wx%h%O' info:`   +repage   noisy_trimmed_2.jpg
    

    [IM Output]

    The above uses a UNIX command line shell feature for 'command-substitution' method using back-quotes '`...`' to insert the generated "-crop" argument into the outer "convert" command.

    You can do this in a Windows Batch Script, using a special FOR..DO construct. Follow the above link for details.

    See Image Property Escapes for more information on the "-format" setting used to control the output of "info:".

    Of course the method could be improved by expanding the area trimmed by a small amount (generally the blur amount), but then you need to apply some extra mathematics to the geometry of the blurred image trim, and that may require more API script work on the initial fuzzy trim results.

    FUTURE EXPANSION:
    
    Is there is a way to grab the color that was (or will be) trimmed from an
    image?
    
    Note that, as shown above  trim could be either top-left, or bottom-right
    or even both, with two different colors (a three color trim is not possible).
    
    The typical reason for wanting to know the trim color, is so you can
    specific that color as the "-bordercolor" to re-add a smaller, more consistent
    border to the image after trimming.
    
    There is currently no way to do this in the same command, at this time, though
    there is some proposals that could allow you to do this.  None of these
    have been ratified, or even attempted to be programmed into IM at this point
    in time.
    
    ---
    Future Examples  (can you help?)
    
    Using multiple trim's to remove a framed image
    
    Trimming images containing a background pattern
      tile image, difference to with the background pattern, blur-trim, get info,
      trim original image using that info.
    
    

    Created: 15 March 2004
    Updated: 3 January 2007
    Author: Anthony Thyssen, <A.Thyssen@griffith.edu.au>
    Examples Generated with: [version image]
    URL: http://www.imagemagick.org/Usage/crop/

    a