# Table of Contents - [Quantization -- ImageMagick Examples](#quantization-imagemagick-examples) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Examples of ImageMagick Usage](#examples-of-imagemagick-usage) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Ordered Dither Upgrade -- ImageMagick Examples](#ordered-dither-upgrade-imagemagick-examples) - [Unknown](#unknown) - [Montage -- ImageMagick Examples](#montage-imagemagick-examples) - [Basic Usage -- ImageMagick Examples](#basic-usage-imagemagick-examples) - [Font Effects -- ImageMagick Examples](#font-effects-imagemagick-examples) - [Photo Handling -- ImageMagick Examples](#photo-handling-imagemagick-examples) - [Layering -- ImageMagick Examples](#layering-imagemagick-examples) - [Lens Correction -- ImageMagick Examples](#lens-correction-imagemagick-examples) - [Text Handling -- ImageMagick Examples](#text-handling-imagemagick-examples) - [Animation Optimization -- ImageMagick Examples](#animation-optimization-imagemagick-examples) - [Unknown](#unknown) - [File Handling -- ImageMagick Examples](#file-handling-imagemagick-examples) - [Animation Basics -- ImageMagick Examples](#animation-basics-imagemagick-examples) - [Thumbnails -- ImageMagick Examples](#thumbnails-imagemagick-examples) - [Comparing -- ImageMagick Examples](#comparing-imagemagick-examples) - [Animation Modifications -- ImageMagick Examples](#animation-modifications-imagemagick-examples) - [Advanced Techniques -- ImageMagick Examples](#advanced-techniques-imagemagick-examples) - [Video Handling -- ImageMagick Examples](#video-handling-imagemagick-examples) - [Common Formats -- ImageMagick Examples](#common-formats-imagemagick-examples) - [ImageMagick Examples -- Repository Links](#imagemagick-examples-repository-links) - [Backgrounds -- ImageMagick Examples](#backgrounds-imagemagick-examples) - [Color Basics and Channels -- ImageMagick Examples](#color-basics-and-channels-imagemagick-examples) - [Masks -- ImageMagick Examples](#masks-imagemagick-examples) - [Cutting and Bordering -- ImageMagick Examples](#cutting-and-bordering-imagemagick-examples) - [Canvas Creation -- ImageMagick Examples](#canvas-creation-imagemagick-examples) --- # Quantization -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Color Quantization and Dithering ==================================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Color Reduction Introduction](#intro) ![](../img_www/space.gif) (what is involved) [![](../img_www/granitesm_right.gif) The Colors in an Image](#handling) ![](../img_www/space.gif) (what colors are used by an image) * [Extracting Image Colors](#extract) * [Comparing Two Colors](#compare) [![](../img_www/granitesm_right.gif) Color Quantization](#colors) ![](../img_www/space.gif) (reducing the number of colors in an image) * [The Color Quantization Operator](#colors) * [Color Quantization and Colorspace](#quantize) * [Quantization does not Preserve Colors](#quantize_not_exact) * [Color Quantization and Transparency](#color_trans) [![](../img_www/granitesm_right.gif) Error Correction Dithering](#dither_error) ![](../img_www/space.gif) (Or Pseudo-Randomized Dithering) * [E-Dither Methods](#dither) * [How an E-Dither Works](#dither_how) * [E-Dither Change Sensitive](#dither_sensitive) * [E-Dither Pixel Speckling](#dither_speckle) * [Monochrome Dithered Bitmap Images](#monochrome) * [Two Color Quantization](#two_color) * [Dither using Pre-Defined Color Maps](#remap) * [Common or 'Best' Colormap](#remap_common) * [Using Web-Safe Colors](#web_safe) * [Uniform Color Maps](#remap_colormaps) * [Uniform 332 ColorMap](#332_colormap) * [TrueColor 16bit or 556 Colormap](#16bit_colormap) * [Gamma Corrected Uniform ColorMaps](#gamma_colormap) * [Posterize, Recolor Using an Uniform Color Map](#posterize) [![](../img_www/granitesm_right.gif)Threshold Dithering Methods](#threshold) ![](../img_www/space.gif) * [Threshold Images](#threshold) * [Random Dither with Thresholding](#random-threshold) [![](../img_www/granitesm_right.gif) Ordered Pattern Dithers](#ordered-dither) ![](../img_www/space.gif) (Using a tiled threshold map) * [Diffused Pixel Dithering](#diffused) * [Digital Halftone Dithers](#halftone) * [Halftone Offset Dithering](#halftone_offset) * [XML Threshold Maps](#thresholds_xml) * [Ordered Dither with Uniform Color Levels](#od_posterize) * [Better Ordered Dither Results](#od_levels) [![](../img_www/granitesm_right.gif) DIY Dither Patterns and Threshold Maps](#diy_dither) ![](../img_www/space.gif) (dither images in your own way) * [Multi-Image Bitmap Dither Patterns](#diy_multi) * [DIY Ordered Dither Threshold Maps](#diy_threshold) * [DIY Horizontal Line Dither](#diy_hlines) * [Dithering with Symbol Patterns](#diy_symbols) Reducing the number of colors or replacing specific colors is a very complex and difficult step in in Image Processing, and that is the topic covered in this example pages. This includes determining the what colors to use (color quantization), and how to place those colors on the image (dithering, and patterning). It also includes the generation of bitmap or two color images, and even handling Boolean (on/off) transparency. This is so important that color reduction or quantization often happens automatically and behind the scene, just so ImageMagick can perform its original primary task of converting images from one file format to another, less colorful format, such as GIF, XPixmap, and XBitmap formats. Knowing how this works can allow you greater control of the process, so as to improve the resulting image stored in a specific image file formats. * * * Color Reduction Introduction ---------------------------- Color reduction is a very important aspect of ImageMagick. For example to magick a JPEG or PNG image containing millions of colors, into a GIF image containing a maximum of 256 color, you really have to be able to reduce colors in an efficient and effective way. Often during an image format conversion, this happens automatically behind the scenes, but there are other times when you want to do this manually. Reducing the number of colors in image is a typically a three step process, 1. First you typically need to survey the colors an image uses. Not only to see how many colors are actually used, but how often a particular color is used. It is no good preserving one specific color, if only a single pixel is using that color, though sometimes you still need to do that. 2. Next you need to somehow decide on the final color set to which you want to limit your image. You may want IM to try and determine the 'best' set of colors for a specific image. Other times you may want something more general and global that can be used on any image. You may even want to specifically add or remove a color from the set of colors that will be used. 3. And finally you need to modify the image so as to only use the colors you have selected. Preferably you want it so the results will look good, or perhaps you want it so that it will compress, compare, or optimize well. To further complicate matters, these steps are often interlinked, as one method of replacing colors, often can only be applied using specific sets of colors. And if you are using a specific set of colors, doing some sort of color survey is not needed, or perhaps you need to make exceptions for specific colors. Basically while color reduction is often automatically handled behind the scenes, it is good to at least be aware just what it is happening, and what its effects will be. #### Color Survey This is probably the lest important, and while IM provides you with methods to perform a survey, it is rarely done by users for the purposes of color reduction. I will leave further discussion to the relevant section, [Extracting Image Colors](#extract) . #### Color Selection (Quantization) For a good initial overview see [Wikipedia, Color Quantization](http://en.wikipedia.org/wiki/Color_quantization) . There are four basic methods for the selection colors. These four color control methods: [Quantization](#colors) , [Predefined Color Map](#remap) , [Uniform Colors](#posterize) , and [Threshold](#threshold) ; all have their limitations, as you will see. Here is an example of each of these four methods... magick colorwheel.png +dither -colors 32 color\_quantize.gif magick colorwheel.png +dither -remap colortable.gif color\_predefined.gif magick colorwheel.png +dither -posterize 3 color\_uniform.gif magick colorwheel.png \\ -separate -threshold 50% -combine color\_threshold.gif [![[IM Output]](../images/colorwheel.png)](../images/colorwheel.png) ![==>](../img_www/right.gif) [![[IM Output]](color_quantize.gif)](color_quantize.gif) [![[IM Output]](color_predefined.gif)](color_predefined.gif) [![[IM Output]](color_uniform.gif)](color_uniform.gif) [![[IM Output]](color_threshold.gif)](color_threshold.gif) The number of colors in each of the final images is only a representative set, but approximately 32 colors in each case (except for threshold which only has 8). From this you can get an idea of what you can expect from each of them. All the other methods have a fix set of colors (according to the operators argument) regardless of the image that is being color reduced. Only the first method ("`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `") will actually pick colors based on the current image contents. As the test image is predominately white, a lot of lighter colors is selected. It surveys the colors in an image using a technique known as "Adaptive Spatial Subdivision" using oct-trees. Then attempts to choose a specific set of colors to best match a specific image, within the limits given. See the [Color Quantization Operator](#colors) below. The "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" lets you give IM your own set of predefined colors (See [User Defined Color Maps](#remap) ). The color map "`[colortable.gif](../images/colortable.gif) `" used in the above, is a set of 32 colors specifically picked for use in an old [X Window Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) and is designed with cartoon like icons in mind. (See [AIcon Library, X Icon Color Selection](http://www.ict.griffith.edu.au/anthony/icons/docs/colors.html) for details). Using "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" can also mathematically divide up each color channel into a set of color levels or intensities producing a 'uniform color map'. That is, a color map with each channel set to a constant set of values or intensities. And finally can "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" all or specific color channels of the image, essentially making each color channel purely Boolean or on/off. That is, each color channel can be given a value of zero or MaxRGB (IM 'Q' level dependant). This however only produces a minimal set of about about 8 colors. A very limited color set. Threshold is also equivalent to a "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" level '1' which picks 2 colors. #### Applying a Color Set Once you have a set of colors, the next problem is to apply the color to an image so that the existing colors are replaced by the selected set of colors. This is known as 'Dithering', and is named as such because of its, "should I pick this, or should I pick that?", either-or nature. Basically the idea of dithering is to place pixels of different colors near each other in such a way as to fool the eye into seeing more colors in the image than is actually used. That is, the color in that area of the image more closely matches the original color of the image, because of the way the human eye 'merges' neighbouring colors together. One of the best introductions to Dithering is on [Wikipedia](http://en.wikipedia.org/wiki/Dither) though you will need to skip over the 'Audio Dithering' section at the start. This presents an excellent set of examples of the benefits of using a dithered pattern of pixels, when you have a limited set of colors. The basic styles of color replacement include... * Direct Color Mapping (threshold, and posterization) * Random Dither (purely random placement of pixels) * Error Correction Dithers (pseudo-randomized patterns of pixels) * Ordered Diffused Pixel Dither (regular patterns of pixels) * Digital Halftoning (dots of different sizes) **Direct mapping** if the nearest color in a given set is what was shown above. Basically you get distinct areas of solid, unchanging colors. When this is applied to an image of slowing varying color, such as a real life photo of sky, you get bands of colors across the image, especially in what would otherwise be a smooth gradient of colors, such as in sky areas. The result is typically regarded as not being very good. The only time direct color mapping is usually thought of as acceptable is for logos, symbols, icons, and cartoon-like images. It is actually rarely an option. This is why you generally have to turn off the normal dithering method, if you do not want directly map colors in your images. Dither however has its own problem. Once an image is dithered, a pattern of colors becomes part of the image. Once such a pattern is present, it is extremely difficult to remove. Also it is generally a bad idea to re-apply dithering to an image multiple times, as that just degrades the image. Because of this, most of the quantization examples below will generally show you how to create un-dithered versions for each technique. It is done that way so you can see what color selections are being made before dithering hides that information. **Random dithering** is the simplest dithering method created. It is also regarded as the worst possible dithering method. However it has some special uses. Within IM only works with two colors, so it is usually restricted to special case bitmap dithering. For more see [Random Dither with Threshold](#random-threshold) below. **Error Correction Dithering** is generally regarded as being the best general method of dithering colors across images as it will produce the closest approximation to the original color of areas in the image. It is also currently the only method that can dither _any_ set of colors, and as such can be used for all four color reduction techniques. See [How E-Dithers work](#dither_how) below for more detail. However Error Correction Dithering has some serious [problems](#dither_sensitive) , especially with regards to animations of images. The last two dithering techniques **Ordered Diffused Pixel** and **Digital Halftoning** is also regarded as a good method, and one that works well for animations, but currently it cannot use any set of colors, only a fixed set of uniform colors. It does provide a means of coloring an image using patterns, allowing you to produce interesting effects otherwise not easy to produce. All these aspects of color reduction are important techniques, and with understanding you can improve the results of your image operations, beyond the generalised defaults that IM provides. It is well worth the studying. * * * The Colors in an Image ---------------------- Information about images, such as the number of colors used and the overall spread can be very important to programs and scripts that are trying to make decisions about the best techniques to use. Here I look at some of the methods you can use to determine this type of information, and not just for color reduction. ### Extracting Image Colors #### Extracting the color table You extract a color palette from an image using a verbose "`[identify](../basics/#identify) `", using any of these methods which basically all does exactly the same thing. magick identify -verbose image.png magick image.png miff:- | identify -verbose - magick image.png -verbose -identify null: magick image.png -verbose info: | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The output from any of the above verbose identification will not return the color tables or histogram if there are more than 1024 colors! As such for large colorful images this is a hit or miss affair, and not recommended, though it can still be useful._ | The better way however is to generate a "`[histogram:](../files/#histogram) `" of the image and extract the comment that is included in the result. magick tree.gif -format %c -depth 8 histogram:info:- [![[IM Output]](../images/tree.gif)](../images/tree.gif) [![[IM Text]](tree_histogram.txt.gif)](tree_histogram.txt) ![](../img_www/warning.gif)![](../img_www/space.gif)_The "`info:`" output format was added to IM v6.2.4. For IM versions before this use.._ magick tree.gif histogram:- | identify -depth 8 -format %c - The problem with these methods is that you are given a plain text output of the colors, which you will need to parse for your own needs. However as of IM v6.2.8-8, the "`[-unique-colors](https://imagemagick.org/script/command-line-options.php?#unique-colors) `" operator will magick an image into a smaller one containing just one pixel per unique color found in the original image, all in a single row. This means you can magick an image into a simpler color table image, listing each color present. The width of the image returns the number of colors, and if you need to actually list the colors you can output it to a "`[txt:](../files/#txt) `" image format. For example, here is the color table for the tree image. magick tree.gif -unique-colors -scale 1000% tree_colors.gif magick tree.gif -unique-colors -depth 16 txt:- [![[IM Output]](tree_colors.gif)](tree_colors.gif) [![[IM Text]](tree_colors.txt.gif)](tree_colors.txt) This reduced color table is also very important as a way of storing a colormap of generated colors in a very small file. Such maps are particularly important for the "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" color reduction operator. (See [Pre-Defined Color Maps](#remap) below) If you like to get an image containing not just the colors in an image but the color counts, here is one color-histogram solution what was developed from a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?f=1&t=19538&p=76915) . magick rose: -colors 256 -format %c histogram:info:- | sed 's/:.*#/ #/' | while read count color colorname; do magick -size 1x$count xc:$color miff:- done | magick - -alpha set -gravity south -background none +append \ unique_color_histogram.png [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](unique_color_histogram.png)](unique_color_histogram.png) Note that I had to [Color Reduce](#colors) the image, as the built-in "`rose:`" image contains 3020 unique colors, which would take a long time and generate a very long image. The GIF image of the rose shown above contains the same set of color reduction. The resulting image still contains the same number of pixels, though padded with extra transparent pixels, and as you can see shows a predominance of greenish greys, strong reds, as well as a very strong peak of pure white. This may not be the best general color histogram method, but it works well for this image. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The order of the colors for both "`[histogram:](../file/#histogram) `" and "`[-unique-colors](https://imagemagick.org/script/command-line-options.php?#unique-colors) `" operator, is undefined, but appears to be sorted by red, then green, and finally blue channel value. This may not the best way for a specific image, but it is impossible to generally sort 3-dimensional colors into a 1-dimensional order._ | #### Extracting the Average Color The average color of an image can be found very quickly by using "`[-scale](https://imagemagick.org/script/command-line-options.php?#scale) `" to reduce an image to a single pixel. Here for example is the average color of the built-in "`rose:`" image. I output the color using the [FX Escape Format](../transform/#fx_escapes) which returns a color string that can be used directly IM without change. magick rose: -scale 1x1\! -format '%[pixel:s]' info:- [![[IM Text]](rose_average.txt.gif)](rose_average.txt) The problem with using the "`%[pixel:...]`" [FX Escape](../transform/#fx_escapes) is that it may return a color name such as '`white`' or '`silver`' instead of a RGB value. However you can simulate this by using three [FX Escapes](../transform/#fx_escapes) to return the actual RGB values at the bit depth wanted. For example... magick rose: -scale 1x1\! \ -format '%[fx:int(255*r+.5)],%[fx:int(255*g+.5)],%[fx:int(255*b+.5)]' info:- [![[IM Text]](rose_fx_rgb.txt.gif)](rose_fx_rgb.txt) As of IM v6.3.9 there are a number of new "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" escapes that can be useful to extract more specific information about images without needing to parse a verbose "`[identify](../basics/#identify) `" or "`[info:](../files/#info) `" output. For example you can get the average red channel colour by getting the '`%[mean]`' greyscale value from of the images, red channel image. magick rose: -channel R -separate -format '%[mean]' info: [![[IM Text]](rose_red_mean.txt.gif)](rose_red_mean.txt) #### Extracting a Specific Color From the command line there are two basic ways of extracting a specific pixel color from an image. Either use an [FX Escape](../transform/#fx_escapes) such as "`%[pixel:...]`" or "`%[fx:...]`" (see above) on a specific pixel location... magick rose: -format '%[pixel:p{40,30}]' info:- [![[IM Text]](rose_pixel.txt.gif)](rose_pixel.txt) Alternatively you can simplify the image by using "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" to cut out a single pixel that you may be interested in, and use any of the previous methods. For example... magick rose: -crop 1x1+40+30 -depth 8 txt:- [![[IM Text]](rose_pixel_crop.txt.gif)](rose_pixel_crop.txt) #### Counts of a Specific (or near) Color This can be used to get the pixel count or percentage of a specific color. What you do is make anything not that color black, and then make that color white. For example lets get the number of colors in the "`yellow`" sun in the 'tree' image. magick tree.gif -fill black +opaque yellow \ -fill white -opaque yellow \ -print "yellow sun pixels = %[fx:w*h*mean]\n" null: [![[IM Text]](tree_sun_pixels.txt.gif)](tree_sun_pixels.txt) There is one cavat, it will not work if the color under test is itself black. To handle black (or very dark colors) swap the fills to map non-black colors to white and then [Negate](../color_mods/#negate) the results to generate the white mask of all black pixels. Remember the "`[-print](https://imagemagick.org/script/command-line-options.php?#print) `" option is equivalent to using "`-format ... -write info:`" and can be used anywhere within your image processing. I then junked the unwanted image using the special "`[null:](../files/#null) `" file format. You can also save the image to use as a mask for later work too. Note that while this will work fine for small images, with much larger images (like high resolution digital photos) the 'mean' will not be accurate enough to get an exact pixel count! Basically the above use of 'mean' is sutiable for generating a ratio, but not for exact pixel counts. To get an exact pixel count you are better of using a histogram 'comment' output that has exact pixel counts (see above). The above can also used a [Fuzz Factor](../color_basics/#fuzz) option "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" before the "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" operator to specify 'near' colors as well. ### Comparing Two Colors So you have two specific colors and you want to compare them. You can use "**`magick compare`**" get the RMSE (on standard error)... magick compare -metric RMSE xc:Navy xc:blue null: [![[IM Text]](compare_navy.txt.gif)](compare_navy.txt) This is good as it will get you the distance between the two colors, both in terms of values, and as a normalized percentage of the distance from black to white. However this method will not handle transparency properly. For example comparing 'fully-transparent black' vs 'fully-transparent white'. magick compare -metric RMSE xc:'#0000' xc:'#FFF0' null: [![[IM Text]](compare_transparency.txt.gif)](compare_transparency.txt) Transparent colors should actually have a zero distance as fully transparent is the same regardless of the underlying color. Instead we got a 4-d hypercube distance). As such the above method of color distance is only suitable for comparing fully-opaque colors only. Rather than getting an actual distance, you can also use a **[Fuzz Factor](../color_basics/#fuzz) ** to check is two colors are close. magick compare -fuzz 20% -metric AE xc:Navy xc:Blue null: magick compare -fuzz 30% -metric AE xc:Navy xc:Blue null: [![[IM Text]](compare_blue-navy.txt.gif)](compare_blue-navy.txt) Remember however that the result will be '`1`' if the pixels do not match (number of error pixels). To get the actual 'fuzz' factor distance that separates the values you can use the 'FUZZ' metric. magick compare -metric FUZZ xc:Navy xc:Blue null: [![[IM Text]](compare_blue-navy_fuzz.txt.gif)](compare_blue-navy_fuzz.txt) The 'normalized' value shows that the actual distance is 28.7%. Using [Fuzz Factor](../color_basics/#fuzz) , is different to calculating the RMSE when transparency is involved. That is, because the fuzz factor is designed so that any two fully-transparent colors are treated as being equal. As such 'fully-transparent black' and 'fully-transparent white' are exactly equivelent (producing a value of 0 or no error pixels)... magick compare -metric FUZZ xc:'#0000' xc:'#FFF0' null: [![[IM Text]](compare_fuzz_trans.txt.gif)](compare_fuzz_trans.txt) Another method of color comparing is to try and [Replace Colors](../color_basics/#replace) with an appropriate [Fuzz Factor](../color_basics/#fuzz) percentage. For example... magick xc:Navy -fuzz 20% -fill Blue -opaque Blue txt: [![[IM Text]](fuzz_navy.txt.gif)](fuzz_navy.txt) As '`Navy`' did not change to '`Blue`' it is more than 20% different to '`Blue`'. Where as magick xc:Navy -fuzz 30% -fill Blue -opaque Blue txt: [![[IM Text]](fuzz_navy2.txt.gif)](fuzz_navy2.txt) This did change the color to '`Blue`', so we now no know that '`Navy`' is somewhere between 20% and 30% distant from each other. To do this in a script use something like... fuzz=%1 color1="red" color2="#e00" color2=\`magick xc:"$color2" -format '%\[pixel:s\]' info:\` result=\`magick xc:"$color1" -alpha set -channel RGBA -fuzz $fuzz \\ -fill $color2 -opaque $color2 -format '%\[pixel:s\]' info:\` if \[ "$result" = "$color2" \]; then echo "Colors match according to Fuzz Factor" else echo "Colors DO NOT match" fi The special options "`-alpha set -channel RGBA`" are important to allow us to for fuzzy matching of transparent and near transparent colors. * * * Color Quantization ------------------ ### Color Quantization Operator The primary work horse of color quantization, and what is used internally for all automatic color reduction, is the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" operator. This implements a "Adaptive Spatial Subdivision" color reduction algorithm, and is an extremely good color reduction algorithm. Here is a typical example, I have an image of a 'colorwheel' image containing a lot of colors, and we ask IM to reduce the number of colors down to only 64 colors, using various [dither methods](#dither) . magick colorwheel.png -dither None -colors 64 colors\_64\_no.gif magick colorwheel.png -dither Riemersma -colors 64 colors\_64\_rm.gif magick colorwheel.png -dither FloydSteinberg \\ -colors 64 colors\_64\_fs.gif [![[IM Output]](../images/colorwheel.png)](../images/colorwheel.png) ![==>](../img_www/right.gif) [![[IM Output]](colors_64_no.gif)](colors_64_no.gif) [![[IM Output]](colors_64_rm.gif)](colors_64_rm.gif) [![[IM Output]](colors_64_fs.gif)](colors_64_fs.gif) IM will by default use a 'dither' to shade the colors over the image. This prevents the sudden changes in color over smoothly changing gradients. If you turn off dithering (using '`None`' or a "`[+dither](https://imagemagick.org/script/command-line-options.php?#dither) `" setting) you can clearly see what colors were merged together to generate what IM regarded as the best set of colors for this specific image. You can also see the sudden color changes that gradients of color will produce if dithering was not done. Of course this image uses a lot more colors than what most images use. As such while a 64 color limit is often acceptable for many images, it is completely unacceptable for this image. In other words color quantization tries to find the best set of colors for a particular image. Here are example of color quantization for part of IM logo, using an extremely small number of colors. magick logo: -resize 40% -crop 100x100+105+50\\! -normalize logo.png magick logo.png +dither -colors 8 colors\_8\_no.gif magick logo.png -dither Riemersma -colors 8 colors\_8\_rm.gif magick logo.png -dither FloydSteinberg \\ -colors 8 colors\_8\_fs.gif [![[IM Output]](logo.png)](logo.png) ![==>](../img_www/right.gif) [![[IM Output]](colors_8_no.gif)](colors_8_no.gif) [![[IM Output]](colors_8_rm.gif)](colors_8_rm.gif) [![[IM Output]](colors_8_fs.gif)](colors_8_fs.gif) Compare that with some results for the built-in "`rose:`" photo image. magick rose: +dither -colors 16 colors\_16\_no.gif magick rose: -dither Riemersma -colors 16 colors\_16\_rm.gif magick rose: -dither FloydSteinberg \\ -colors 16 colors\_16\_fs.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](colors_16_no.gif)](colors_16_no.gif) [![[IM Output]](colors_16_rm.gif)](colors_16_rm.gif) [![[IM Output]](colors_16_fs.gif)](colors_16_fs.gif) As you can see cartoon-like images require far less colors than a real photograph to produce a reasonable result. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Only one Color Quantization algorithm, "Adaptive Spatial Subdivision", is currently implemented in IM, and as it works very well, there has been little need to add others. However with feedback this algorithm is being steadily improved.

ASIDE: As a reference the "`[Gifsicle](http://www.lcdf.org/gifsicle/) `" program lists a number of other color quantization methods (using it "`--color-method`" option). I have no idea as to how well these color quantization methods compare to IM. If you find a good reference to different methods of color quantization, please mail me._ | ### Color Quantization Internals The process of selecting the limited number of colors to use in an image is called Color Quantization, and is a very complex process involving a number of factors. A full technical description of it is given on the ImageMagick web site [Color Reduction Algorithm](https://imagemagick.org/script/quantize.php) . However I'll try to example some of the more important aspects of this here. Probably the biggest factor is the actual colors used in an image. It is no good picking a particular color for an image if their are very few pixels that are 'close' to that color. As such the color choice depends not only on the colors used in an image, but the number of pixels 'close' to the color. I can demonstrate this quite easily by trying to reduce two different two color images to a single common color. magick -size 4x1 xc:blue -draw 'fill red point 0,0' \\ -scale 20 colors\_rb.gif magick -size 4x1 xc:red -draw 'fill blue point 3,0' \\ -scale 20 colors\_br.gif magick colors\_rb.gif -colors 1 colors\_rb2.gif magick colors\_br.gif -colors 1 colors\_br2.gif [![[IM Output]](colors_rb.gif)](colors_rb.gif) ![==>](../img_www/right.gif) [![[IM Output]](colors_rb2.gif)](colors_rb2.gif) [![[IM Output]](colors_br.gif)](colors_br.gif) ![==>](../img_www/right.gif) [![[IM Output]](colors_br2.gif)](colors_br2.gif) As you can see the single final color depends not only on the colors present, but the amount of each color in the image. magick -size 20x640 gradient: -rotate 90 gradient.png magick gradient.png +dither -colors 5 colors\_gradient.gif [![[IM Output]](colors_gradient.gif)](colors_gradient.gif) Note that the color quantization is uniform, within the current colorspace. FUTURE: Just what are the effects of the "`[-treedepth](https://imagemagick.org/script/command-line-options.php?#treedepth) `" setting? Mail me if you know ### Color Quantization and ColorSpace The other big influence on what colors are selected is defining exactly what we mean by colors that are 'close' or 'nearby'. This is defined by the colorspace used for the quantization (color selection), and is (as of IM v6.2.8-6) controlled by the "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" colorspace setting. The "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" setting becomes particularly important when a very small number of colors are chosen. To demonstrate, lets reduce a standard '[colorwheel](../images/colorwheel.png) ' image using various different color spaces and defining different 'color distances'. for S in RGB CMY sRGB GRAY \ XYZ LAB LUV \ HSL HSB HWB \ YIQ YUV OHTA ; do \ magick colorwheel.png -quantize $S +dither -colors 16 \ -fill black -gravity SouthWest -annotate +2+2 $S \ colors_space_$S.gif; \ done [![[IM Output]](colors_space_sRGB.gif)](colors_space_sRGB.gif) [![[IM Output]](colors_space_CMY.gif)](colors_space_CMY.gif) [![[IM Output]](colors_space_RGB.gif)](colors_space_RGB.gif) [![[IM Output]](colors_space_GRAY.gif)](colors_space_GRAY.gif) [![[IM Output]](colors_space_XYZ.gif)](colors_space_XYZ.gif) [![[IM Output]](colors_space_LAB.gif)](colors_space_LAB.gif) [![[IM Output]](colors_space_LUV.gif)](colors_space_LUV.gif) [![[IM Output]](colors_space_HSL.gif)](colors_space_HSL.gif) [![[IM Output]](colors_space_HSB.gif)](colors_space_HSB.gif) [![[IM Output]](colors_space_HWB.gif)](colors_space_HWB.gif) [![[IM Output]](colors_space_YIQ.gif)](colors_space_YIQ.gif) [![[IM Output]](colors_space_YUV.gif)](colors_space_YUV.gif) [![[IM Output]](colors_space_OHTA.gif)](colors_space_OHTA.gif) As you can see the colors chosen depend heavily on how the colorspace is organized. The sRGB (Red, Green, Blue) color cube will generally result in at least the colors close to the primary color being picked. The sRGB color space is particularly good at picking colors for cartoon like images and icons, but is actually a bad color space for general picture-like photos. The CMY color space is exactly the same as sRGB color space as the color channels are simply negated to magick between sRGB and CMY colorspaces. As such the quantization colors end up with roughly the same solution. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The CMYK colorspace (not shown) also produces the same but for different reasons. Because internal the 'K' channel and an images 'colormap' use the same data pointer (See [Palette Channel](../basics/#palette)
), IM converts it back to CMY before quantization.

_ | The sRGB colorspace as expected produces a simular result as RGB, but is warped to remove the number of near-black colors in the colorspace. As such there is less colors for the center of the colorwheel to select from, producing a larger 'not quite so black' spot. The XYZ colorspace is also very very similar to linear RGB colorspace. The big difference here is that the color axis has shifted so as to better contain ALL the posible colors we can (and even colors we normally cannot) see, as such the color data in the colorwheel are compressed a bit more, and as a result the quantizations seems to become spread out more. The LAB and LUV color spaces are based on a different but simular color axis to each other. That results a different arrangement of color quantizations. The special color spaces involving a 'Hue' channel, such as HSL (Hue Saturation, Lightness), HSL (Hue, Saturation, Brightness), and HWB (Hue, White, Black), all have a cyclic color wheel representation of color as part of its color space. Actually it was using a HSL color space what was used to generate this color wheel. See [Generating a Colorwheel](../color_basics/#colorwheel) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _At the time of writing, the color distance algorithm IM uses does not take into account the cyclic nature of the 'Hue' of the colorspace. The algorithm for this is very different. Because of this a strong discontinuity occurs along the 'red' path, where the 'Hue' wraps around, and results in very few red colors being selected in the color quantization process._ | The YIQ, YUV are designed to produce more natural 'pastel' and 'mid-tone' shades of colors that are much better suited for photographs and images of the real world involving subtle shades of colors, and especially skin tones. Helmut Dersch notes on [his web site](http://www.all-in-one.ee/~dersch/barrel/barrel.html) that you should consider using a LAB colorspace for distortions. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _In older versions of IM (specifically IM version 5) the color space that was used for quantization was set with the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" option. However in IM version 6 this operator is used for modifying how images are stored in memory, and as such is not a setting for color quantization.

As such in IM v6.2.8-6, the "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" setting was provided to do this job. However it is only as setting for the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `", Color Quantization process. It will not do anything for the replacement and dithering of colors using operators such as "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" and "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `", or the various dithering techniques._ | For a complete list of the colorspaces available see the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" operator. You can see more effects of the colorspace on color selection by looking at the examples on [Random Spots of Solid Color](../misc/#spots) . There color quantization is used to reduce the number of colors in a randomized image using various colorspaces. ### Quantization does **NOT** Preserve Colors Note that in all the above images a pure-black color is never actually picked by Color Quantization. Mind you their is only one pure black pixel, and not many near-black colors in the image in any case. As a result the only black that appears in the final image was added later as part of the labeling of the image. Even the '`GRAY`' color space image did not produce a pure-black color. In fact none of the images contains any of the primary or secondary colors, such as: red, blue, green, cyan, magenta! The only exception to this is white, as the images did contain quite an amount of pure white color, making it a 'preferred color' (see below). This situation however is not a bug! First, a '`black`' color was generally not selected in the above examples, usually because as their is very little black in the original image, so the Color Quantization generally did not worry too much about dark colors. In fact it generated more of the lighter colors as these are more common in the image. See the previous section for a specific example. Secondly, as quantization is trying to pick colors that are close to the maximum number of existing color pixels in an image, this is best achieved by NOT matching a 'pure' primary or secondary color as these are the always at the very extremes of the color space being used. An 'off-color' will tend to match more colors than a 'primary' color, so these are more often selected. So let me be clear... **Color Quantization ("** \-colors") will generally avoid picking primary colors! As of IM version 6.3 the Color Quantization function was modified to try to include colors that are very common in the original image. As such if an image contains an area of a single color (such as '`white`' in the above), that color will generally be included in the final color map. This improves the situation somewhat, especially for 'cartoon' like images or images on a solid color background. The 'solid' color will generally be picked so as to help avoid [Dither Speckling](#dither_speckle) which we will look at below. **Specific Color in Colormap Solutions**At the moment there is only a few ways to guarantee a 'specific color' gets included into the selected colors for later dithering. One way is to quantize the image as normal, but then output the generated color map (using "`[-unique-colors](https://imagemagick.org/script/command-line-options.php?#unique-colors) `"). Now you can adjust that color map so your specific color is really that color. Finally you can use the [Remap Colors](#remap) operator to dither the image using the provided color map. The colormap may no longer be the BEST colors for the image, and some other colors probably should also be adjusted, but it will be close to the colormap that you wanted. Alternatively, append (enlarging the image) large patches of the specific colors wanted to be preserved in the image, before using "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `". The addition of the large 'swatch' of a specific color, will make that color more likely to be picked in the final color map. Also all the other colors will then automatically be adjusted to fit that color map better). If this works, the swatches of colors you added should remain unchanged (not dithered). Afterwards you can then [Crop](../crop/#crop) the image to remove the added swatches. If it doesn't work, then IM should have at least added a color close to the wanted 'specific color' so only a slight adjustment of the generated colormap needed before using [Remap Colors](#remap) to the original image. _If you try this, regardless of success or failure, please let me know how it went for you._Ideally, what I would like to see a way to specify a small number of specific colors, that must be part of the final color map, and then somehow ask IM to pick the best colors for rest of the colors in the color map, for a specific image. ### Color Quantization and Transparency ImageMagick by default not only generates fully opaque colors, but also attempts to generate semi-transparent colors. In this way, images containing transparent shadows or other overlay effects will not loose those effects. However as IM v6.2.6, color quantization that involves transparency was modified so as to treat all fully-transparent colors as being the same color. This is a linear modification, so colors which are only half-transparent are also thought to be closer together than if they were fully opaque. Because of this modification IM Color Quantization will still generate semi-transparent colors, but will concentrate more on the opaque colors and less on the fully transparent colors in the image. For example, here I generate a [Rainbow Gradient](../canvas/#gradient_colorspace) of colors, with the image fully-opaque at the top, and fully-transparent at the top. I have displayed the images on a background pattern so that you can see just how transparent the image is. magick xc:red xc:yellow xc:green1 xc:cyan xc:blue \\ +append -filter Cubic -resize 100x100\\! -size 100x100 \\ gradient: -alpha off -compose CopyOpacity -composite alpha\_gradient.png magick alpha\_gradient.png +dither -colors 256 alpha\_colors\_256.png magick alpha\_gradient.png +dither -colors 64 alpha\_colors\_64.png magick alpha\_gradient.png +dither -colors 15 alpha\_colors\_15.png [![[IM Output]](alpha_gradient.png)](alpha_gradient.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_colors_256.png)](alpha_colors_256.png) [![[IM Output]](alpha_colors_64.png)](alpha_colors_64.png) [![[IM Output]](alpha_colors_15.png)](alpha_colors_15.png) As you can see, when we ask IM to reduce the number of colors needed by this image, it created a lot more opaque colors and used fewer highly transparent colors for the more translucent parts. The result is a very good spread of colors selected, especially when the number of colors is very small. However just as I pointed out above, not only do [primary colors not get picked](#quantize_not_exact) , but the fully-transparent color will also not get picked for exactly the same reasons. In actual fact even fully-opaque colors will not get picked! In other words every color in the color quantized images in the previous example is semi-transparent. Let me just make that clear. **When transparency is involved, IM Color Quantization may not select any fully-opaque or even a fully-transparent color!** Of course as of IM v6.3, and the 'common color' bug fix (see [Quantization does NOT Preserve Colors](#quantize_not_exact) above), that is less likely to happen if the image contains a lot of opaque and fully-transparent colors, which is commonly the case. As some images can contain a lot of semi-transparent colors, such as images involving smoke or shadows effects, you may like to do a trial run, to make sure a fully-transparent color is selected for inclusion in the resulting image. You can then map the most-transparent color to fully-transparent, and do the [Remap Colors](#remap) yourself. If you really want to be sure you get both fully-opaque and fully-transparent colors in the resulting image you can [Normalize OR Contrast-Stretch](../color_mods/#normalize) the alpha channel. For example, here I ensure the main color selects are made opaque by using "`[-contrast-stretch](https://imagemagick.org/script/command-line-options.php?#contrast-stretch) `". Though this is probably a little heavy handed for a more normal situation. magick alpha\_gradient.png +dither -colors 15 \\ -channel A -contrast-stretch 10% alpha\_colors\_15n.png [![[IM Output]](alpha_gradient.png)](alpha_gradient.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_colors_15.png)](alpha_colors_15.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_colors_15n.png)](alpha_colors_15n.png) This is NOT a problem for GIF images which do not allow semi-transparent colors, or JPG which does not allow transparency, or even PNG which do not need quantization to save properly. It only becomes a problem in special cases where you may force a color reduction in an image when lots of semi-transparent colors are involved. Remember for the GIF format saving semi-transparent colors is an useless endeavor. As such if you plan to do color quantization yourself for such an image format, you need to tell IM to ignore image transparency when generating its reduced color set. you can do that by using the special "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" color space setting of '`transparent`'. magick alpha\_gradient.png -quantize transparent \\ +dither -colors 15 alpha\_colors\_15qt.png [![[IM Output]](alpha_gradient.png)](alpha_gradient.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_colors_15qt.png)](alpha_colors_15qt.png) Notice how the color quantization completely ignored the transparency of the colors, and did not touch the images alpha channel at all. This means you can process the alpha channel in a more appropriate way for your image, completely separately to the other colors. In fact you can do so either before or after using "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" without problems. It will make no difference in the result. This quantization color space is thus recommended when reducing the number of colors for an image you plan to save to a format with Boolean or no transparency, such as GIF or XPM image formats. If you count up the number of colors generated you will also see that it generated exactly the number of colors requested. As such if you you also need a fully transparent color (likely) then you need to reduce the argument of "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" by at least one, to leave space for it in the images final color table. Thus to handle the GIF file format 256 color color table limit, you will need to reduce colors to 255, and not 256, leaving the extra space for the fully-transparent color index, as defined by the "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#tranparent-color) `" setting. Adjust this for a smaller color table sizes. This quantization behaviour is automatic when IM saves to the GIF file format, but is important when you need to DIY the quantization yourself while generating global or shared color tables. Of course you do still need to handle the semi-transparent pixels, so they are correct for what you want your image to look like. FUTURE: This last part will probably move to a new section on 'Dithering Alpha Channel' to be created in the near future. And a reference to this section added here. Here are some examples of dithering just the alpha channel to just a Boolean or on/off setting, without effecting the rest of the color channels in the image. magick alpha\_gradient.png \\ -channel A -threshold 50% alpha\_dither\_threshold.gif magick alpha\_gradient.png \\ -channel A -ordered-dither checks alpha\_dither\_checks.gif magick alpha\_gradient.png \\ -channel A -ordered-dither o8x8 alpha\_dither\_ordered.gif magick alpha\_gradient.png \\ -channel A -ordered-dither h8x8a alpha\_dither\_halftone.gif magick alpha\_gradient.png -channel RGBA -separate \\ \\( +clone -monochrome \\) \\ +swap +delete -combine alpha\_dither\_monochrome.gif magick alpha\_gradient.png -channel RGBA -separate \\ \\( +clone -dither FloydSteinberg -monochrome \\) \\ +swap +delete -combine alpha\_dither\_monochrome\_fs.gif magick alpha\_gradient.png -channel RGBA -separate \\ \\( +clone -remap pattern:gray50 \\) \\ +swap +delete -combine alpha\_dither\_map.gif magick alpha\_gradient.png -channel RGBA -separate \\ \\( +clone -dither FloydSteinberg -remap pattern:gray50 \\) \\ +swap +delete -combine alpha\_dither\_map\_fs.gif [![[IM Output]](alpha_dither_threshold.gif)](alpha_dither_threshold.gif) [![[IM Output]](alpha_dither_checks.gif)](alpha_dither_checks.gif) [![[IM Output]](alpha_dither_ordered.gif)](alpha_dither_ordered.gif) [![[IM Output]](alpha_dither_halftone.gif)](alpha_dither_halftone.gif) [![[IM Output]](alpha_dither_monochrome.gif)](alpha_dither_monochrome.gif) [![[IM Output]](alpha_dither_monochrome_fs.gif)](alpha_dither_monochrome_fs.gif) [![[IM Output]](alpha_dither_map.gif)](alpha_dither_map.gif) [![[IM Output]](alpha_dither_map_fs.gif)](alpha_dither_map_fs.gif) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _When dithering a copy of the Alpha Channel, so you can dither it using either "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `", or "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `", make sure the image is a pure grayscale image, and not a shape mask containing transparency. If you don't you will probably end up with non-linear effects from the alpha channel still being present.

There are a number of ways of extracting and restoring the alpha channel from an image, as a gray-scale mask so you can dither it. The above uses the [Channel Separation](../channel/#separate)
and [Combine](../channel/#combine)
to do this. Other methods use [Alpha Extraction](../basics/#alpha_extract)
with [CopyOpacity Composition](../compose/#copyopacity)
._ | * * * Error Correction Dithering -------------------------- As discussed in the introduction an error correction dither is generally regarded the best choice for producing the truest representation of the original image with a reduced color set. It also limits itself to any pre-defined palette of colors, whether it was user supplied, or as determined by the IM color quantization routines. Because of this it is the logical default choice for general color reduction as provided by the IM operators, "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `", "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `", "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" and "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `". ### E-Dither Methods As of version 6.4.2-9, IM now provides more than one type of dithering style or method, which can be selected using the "`[-dither](https://imagemagick.org/script/command-line-options.php?#dither) `" setting. Before this IM was limited to a variation of the [Riemersma Dither](http://www.compuphase.com/riemer.htm) , or [Hilbert Curve Dither](http://www.compuphase.com/hilbert.htm) . which you can set using "`-dither Riemersma`". Now you can also select a Floyd-Steiberg Dither using "`-dither FloydSteinberg`". You can see what types of dither methods has been implemented in your version of IM using... magick -list dither [![[IM Text]](dithers.txt.gif)](dithers.txt) For example, here is the color wheel dithered using different dithering methods. magick colorwheel.png -dither Riemersma -colors 16 dither\_riemersma.gif magick colorwheel.png -dither FloydSteinberg -colors 16 dither\_floyd.gif [![[IM Output]](dither_riemersma.gif)](dither_riemersma.gif) [![[IM Output]](dither_floyd.gif)](dither_floyd.gif) As you can see the Floyd-Steinberg dither produces a much more uniform dither pattern than the default Riemersma dither. The biggest difference between them is how each of them distributes the 'color error' between neighbouring pixels. So lets have a look at just how an E-Dither works. ### How an E-Dither Works **![](../img_www/const_barrier.gif) Re-Write In Progress ![](../img_www/const_hole.gif)** The specific method used by IM for general dithering is a variation of the "Hilbert Curve Error Correction Dither". This is actually a very good dithering technique, very well defined and reasonably quick. For a full description (and a very similar variation) see... [Riemersma Dither](http://www.compuphase.com/riemer.htm) . Basically each pixel in the image is looked at in a very complex path known as a '[Hilbert Curve](http://www.compuphase.com/hilbert.htm) '. The pixel is assigned the color closest to that pixels value, and any difference between the pixels original color and the selected color, is saved and added to the next pixels color values (which is always a neighbouring pixel) before a new color is again selected. In this way any color variations between selected colors and the images original color is distributed to the other pixels in the same area. The result is that while only specific colors will be assigned to the final image, the same basic overall color for that area will closely match the original image. For example, here is a small grey image that I asked IM to dither using a set of colors that does not include the original color. The resulting image is magnified so you can see the individual colored pixel assigned. magick -size 10x10 xc:'#999999' -scale 80x80 dither_not.gif magick -size 10x10 xc:'#999999' \ -remap colortable.gif -scale 80x80 dither.gif [![[IM Output]](dither_not.gif)](dither_not.gif) ![==>](../img_www/right.gif) [![[IM Output]](dither.gif)](dither.gif) As you can see the as the original images color was not in the specified color map, the original color is approximated using a pattern of the three nearest colors that were in the given color table. If we were to average the color generated by the above dither pattern, we would get the color [![[IM Text]](dither_avg.txt.gif)](dither_avg.txt) , which is very close to the images original average color of [![[IM Text]](dither_not_avg.txt.gif)](dither_not_avg.txt) and that is the whole point of the dither pattern that was produced. However as the 'path' used to assign colors is complex (though generally remains in the local area), the color assignments produce an essentially random pattern. It isn't technically random however as the same image will produce the same pattern, but the results may as well be random, or at least pseudo-random. The "F-S" dither is actually only one (the first one) of several 'Rasterized E-Dithers' that has been developed since its inception in the early 1970's. It is also probably the most widely implemented, even though it is not regarded as the best one. See the paper, [Dithering Algorithms](http://www.efg2.com/Lab/Library/ImageProcessing/DHALF.TXT) , for a more complete summary of such algorithms. As of IM v6.4.3 it is also directly available in IM, and is implemented so as to follow a 'serpentine' path row-by-row from the top of the image to the bottom. magick -size 10x10 xc:'#999999' -dither FloydSteinberg \ -remap colortable.gif -scale 80x80 dither_fs.gif [![[IM Output]](dither_not.gif)](dither_not.gif) ![==>](../img_www/right.gif) [![[IM Output]](dither_fs.gif)](dither_fs.gif) The "Floyd-Stienberg Dither" in particular I find produces a more 'hash' like pattern of pixels than the "Hilbert Curve Dither", and was in fact designed to do so. Such a regular pattern can make a low level manual clean up of small color icon images, a lot easier. This was something I did a lot of in my past for [Anthony's Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) , but that type of thing is not often needed anymore, except possibly for small monochrome images. ### E-Dither Problem - Change Sensitive One of the biggest problems you face when you use an error correction dither is that you get an essentially random pattern of pixels, that is also highly sensitive to changes. Here for example take the original grey image and replace one pixel with a different color before dithering it again. The result is a complete shift of the dithering pattern in every pixel that is further along the path followed by the Hilbert Curve Dither. magick -size 10x10 xc:'#999999' -draw 'fill #C28 point 2,2' \ -remap colortable.gif -scale 80x80 dither_modified.gif magick compare dither.gif dither_modified.gif dither_difference.gif | | | | | | --- | --- | --- | --- | | [![[IM Output]](dither.gif)](dither.gif)

original dither | [![[IM Output]](dither_modified.gif)](dither_modified.gif)

one pixel change | ![==>](../img_www/right.gif) | [![[IM Output]](dither_difference.gif)](dither_difference.gif)

comparison of changes | As you can see just adding a single pixel to the image resulted in the dither pattern changing dramatically! It only takes a single bit change for the resulting image to become different, even though overall look of an image (when not enlarged) is still basically the same (which is the purpose of a good dither algorithm after all). The "`magick compare`" image also shows the extent of the change in the dither pattern. In this case, approximately 80% of the pixels were assigned a completely different color. In a Hilbert Curve Dither, a single pixel change actually will result in every pixel that comes later being possibly different, which means from 0 to 100% percent of the dither pattern could be different. It just depends on where in the complex Hilbert curve the change occurred. The Floyd-Steinberg dither however only progresses though the image in one direction, and as such a single pixel change will modify the pattern only to one side of the change. magick -size 10x10 xc:'#999999' -draw 'fill #C28 point 2,2' \\ -dither FloydSteinberg -remap colortable.gif \\ -scale 80x80 dither\_fs\_modified.gif magick compare dither\_fs.gif dither\_fs\_modified.gif dither\_fs\_difference.gif | | | | | | --- | --- | --- | --- | | [![[IM Output]](dither_fs.gif)](dither_fs.gif)

FS Dither | [![[IM Output]](dither_fs_modified.gif)](dither_fs_modified.gif)

one pixel change | ![==>](../img_www/right.gif) | [![[IM Output]](dither_fs_difference.gif)](dither_fs_difference.gif)

comparison of changes | As you can see it has exactly the same problem. A single pixel change causing an almost complete change in the dither pattern for the areas of the image processed after that pixel. That is, from that row downward. For a single image the resulting pattern of the dithered colors is unimportant. The average color of the pattern should give the image the appropriate color for that area of the image. But when you have an animation in which one image is followed by other very similar images, with large areas of constant color, the changing dither pattern becomes highly noticeable and irritating as a low level background 'noise'. For example, here I generate a 3 image animation of the same dithered color but with a single pixel change in each frame. I also magnify a central region so you can see this changing pattern more clearly. magick -size 80x80 xc:'#999999' \ \( +clone -draw 'fill #C28 point 2,2' \) \ \( +clone -draw 'fill #28C point 2,2' \) \ -remap colortable.gif -set delay 50 -loop 0 dither_anim.gif magick dither_anim.gif -crop 10x10+40+40 +repage \ -scale 80x80 dither_anim_magnify.gif [![[IM Output]](dither_anim.gif)](dither_anim.gif) ![==>](../img_www/right.gif) [![[IM Output]](dither_anim_magnify.gif)](dither_anim_magnify.gif) As you can see you get a sort of churning background to the image, caused by the pseudo-randomness generate by the E-Dither. In most cases the colors used are close enough together so as not to make this 'dither noise' visible. But when the dithering colors are visibly different (in this case forced by the use of a colormap) it definitely becomes an issue. See [Video Color Optimization](../video/#gif) for a more practical example of an animation showing this 'dither noise'. The change in pattern also cause problems in optimizing animations. That is, a different pattern means that simple [frame optimization](../anim_opt/#frame_opt) fails to reduce the size of frame overlays. For one solution see [fuzzy color optimization](../anim_opt/#color_fuzz) , though that only works when the churn is using very similar colors. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Unlike other dithering methods (such as [threshold](#threshold)
, and [ordered-dither](#ordered-dither)
) the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting does not effect color quantization, or error correction dithers. Basically has it has no place in how these image operation work._ | Ordered dithers do not have any of these problems, containing changes to the immediate local area of the change. Unfortunately are also generally limited to using a mathematically derived color set. (See [Ordered Dither using an Uniform Color Map](#od_posterize) ). ### E-Dither Pixel Speckling Another problem with E-Dithers is that they can produce the occasional odd-colored pixels in areas which would otherwise be fairly uniform in color. For example the occasional green, pixel in a greyscale image. Or as in the examples below, a white pixel in an areas of otherwise plain flat blue color. This is especially the case in large images which containing objects with large numbers of colors, and other areas of plain solid unchanging colors. This is especially typical of colored objects overlaid onto flat colored backgrounds, as you often get in diagrams and drawings. You can see such an odd-colored pixel in the enlargement of the test examples above, where an extra light purple pixel was added quite a distance from the small single pixel change. The odd-colored pixels added to the above is not however readily visible and the color map does cover the image rather well, so the odd pixels are reasonably close to the normal three colors used for dithering the image. For a more extreme example, here I have a blurred gradient background, which I heavily color reduced to 64 colors to really stress the error correction dither. magick -size 100x60 xc:SkyBlue \\ -fill DodgerBlue -draw 'circle 50,70 15,35' \\ -fill RoyalBlue -draw 'circle 50,70 30,45' \\ -blur 0x5 -colors 64 speckle\_gradient.gif [![[IM Output]](speckle_gradient.gif)](speckle_gradient.gif) As you can see with this highly reduced color map, the error correction dither did a reasonably good job of representing the original gradient. But if we add a patch of pure white to the above... magick -size 100x60 xc:SkyBlue \\ -fill DodgerBlue -draw 'circle 50,70 15,35' \\ -fill RoyalBlue -draw 'circle 50,70 30,45' -blur 0x5 \\ -fill white -draw 'rectangle 40,40 60,55' \\ -colors 64 speckle\_problem.gif [![[IM Output]](speckle_problem.gif)](speckle_problem.gif) You can see that the E-dither suddenly started to produce a sprinkling of white pixels in the upper area of the image where we didn't have any before.Here is an enlargement a small section so you can see these pixel more clearly... magick speckle\_problem.gif -crop 15x15+75+0 +repage \\ -scale 90x90 speckle\_prob\_mag.gif [![[IM Output]](speckle_prob_mag.gif)](speckle_prob_mag.gif) The odd colored pixel is caused by two factors. First, the Color Quantization was forced to include a single pure white color (but no other white-blue anti-aliasing colors) into the final colormap for the image, thus allowing the dithering process to use this extra color. But as E-Dithers slowly accumulate errors, especially in areas of extreme colors, such as in the top section of the above image. Eventually the errors will add up to a value that is large enough make the one additional color the closest match. As such, every so often a highly contrasting white pixel is output to 'correct the error', at a pseudo-random location. The result is a very light speckling of white pixels. The slower the accumulation of error, the more spread out those white pixels are and the more, out-of-place, they appear. **The best solution** is to switch to some other image format that does not have a limited color table. For example magick your GIF format image to PNG. This will avoid the need for color quantization (reduction) and hence the need to dither the reduced colors. The next solution is to replace the use of E-dither with some other dithering method, that 'localizes' any errors, such as [Ordered Dithering](#ordered-dither) . However that is currently not easy thing to apply in IM at this time. See [Better Ordered Dither Results](#od_levels) , for one such method until a more general one is found. If switching to another image format, or using a different dithering method is not practical (and often isn't), then you are left with attempting to fix the situation for that specific image. **The best fix**, to this is to somehow insure you have other colors just outside the large group of colors that is causing the E-Dither error accumulation. However normal [Color Quantization](#colors) does not do this. It tends to pick a set of average colors representing color groups. What is needed is extra colors that 'picket fence' the edges of the a large color group, rather than a simple average color. Here for example, I used a circle rather than a square, so that not only is a pure white color added, but a number of white-blue colors also. These were added automatically due to the anti-aliasing of the circle edges, to smooth its look. magick -size 100x60 xc:SkyBlue \\ -fill DodgerBlue -draw 'circle 50,70 15,35' \\ -fill RoyalBlue -draw 'circle 50,70 30,45' -blur 0x5 \\ -fill white -draw 'circle 50,45 40,40' \\ -colors 64 speckle\_fixed.gif [![[IM Output]](speckle_fixed.gif)](speckle_fixed.gif) And a magnification of the same area as before. magick speckle\_fixed.gif -crop 15x15+85+0 +repage \\ -scale 90x90 speckle\_fix\_mag.gif [![[IM Output]](speckle_fix_mag.gif)](speckle_fix_mag.gif) As you can see the additional colors provide the extra colors, just outside the blue-cyan gradient. Now while these extra colors will mean there are fewer colors available for the actual gradient, they do provide other blue-white colors that will allow the E-dither to correct itself sooner and more often, before the accumulated error can grow too large. That is, not to say we have prevented E-dither speckling, just provided better colors for the dither algorithm to work with. If you study the magnified portion of the image you will still see a speckle pattern, but the colors are closer to the background color, and there are a lot more of them producing a more even, spread of speckles. Another way is to generate our own color table, perhaps based on the one IM generated, and add the appropriate colors to prevent the error accumulation. This is however not an easy thing to do, especially with a 3-dimensional color space. For this specific image example, one way to prevent 'speckling' is to generate and dither the background separately, with slightly less colors that is needed, then overlay the white box and its additional color. magick -size 100x60 xc:SkyBlue \\ -fill DodgerBlue -draw 'circle 50,70 15,35' \\ -fill RoyalBlue -draw 'circle 50,70 30,45' -blur 0x5 \\ -colors 63 \\ -fill white -draw 'rectangle 40,40 60,55' speckle\_perfect.gif [![[IM Output]](speckle_perfect.gif)](speckle_perfect.gif) This will add a 'white' color to the image, but the background will not have any speckling effect, as white was not available when the error correction dither was used. The result is an image with exactly 64 colors, and no speckling at all. However this is very dependant on the image and what you are trying to achieve, so is not a general solution to the specking problem. A more general alternative to adding extra colors is try to remove the speckles from the final dithered image. That is, clean up the image in some way. However this is itself a tricky problem, as you do not what to remove pixels which are part of the normal dithering pattern. What we need is to find color pixels which are somehow very different to all the colors surrounding it, but which are also well isolated from all other similar colors, by some distance. _Do you have a better image filter solution?_ **Summary**To me speckling is a very annoying problem, especially for desktop icon images using a very limited color table. I myself often edit smaller 'icon' images to remove speckles or fix some of the other dithering effects, such a vertical banding. If you know of another better solution, please let me know. ### Monochrome Dithered Bitmap Images The "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator is a specialized form of both the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" operator to generate a bitmap image. It is as such an ideal operator to demonstrate not only 'Hilbert Curve Dithering', but also have a closer look at color selection. Here is a typical example. magick logo.png -monochrome monochrome.gif [![[IM Output]](monochrome.gif)](monochrome.gif) The operator dithered the image solely based on their grey-scale brightness 'intensity' or 'level', however it doesn't dither the whole grey-scale range directly but thresholds the most extreme values to their maximum values. We can see this by asking IM to dither a gradient image. magick -size 15x640 gradient: -rotate 90 \\ -monochrome monochrome\_gradient.gif [![[IM Output]](monochrome_gradient.gif)](monochrome_gradient.gif) As you can see the gradient only has about the middle 50% of its colors dithered by the "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator. Special thanks goes to Ivanova for pointing out this interesting fact of the was IM works. If you like to dither using the whole grey-scale range, you can use the "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator using a pure black and white colormap (supplied by a built-in pattern image). magick logo.png -remap pattern:gray50 mono\_remap.gif magick -size 15x640 gradient: -rotate 90 \\ -remap pattern:gray50 mono\_remap\_gradient.gif [![[IM Output]](mono_remap.gif)](mono_remap.gif) [![[IM Output]](mono_remap_gradient.gif)](mono_remap_gradient.gif) By more careful selection of colors using "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" you can effectively produce the same 'threshold' range as used by the "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator, or any other threshold range you like. magick xc:gray20 xc:white +append ctrl\_colors.gif magick logo.png -colorspace Gray \\ -remap ctrl\_colors.gif -normalize mono\_remap\_ctrl.gif magick -size 15x640 gradient: -rotate 90 \\ -remap ctrl\_colors.gif -normalize mono\_remap\_grad\_ctrl.gif [![[IM Output]](mono_remap_ctrl.gif)](mono_remap_ctrl.gif) [![[IM Output]](mono_remap_grad_ctrl.gif)](mono_remap_grad_ctrl.gif) What "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" actually does is to first magick the given image first into a grey scale image, after that it performs a two color '[Color Quantization](#colors) ', to decide the threshold colors to dither the image with. This is what the next section of examples will explore. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "`[+dither](https://imagemagick.org/script/command-line-options.php?#dither) `" setting currently has no effect on the result of "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `". This however may change in the future, so make sure it is not turned off in your scripts when using this operator._ | ### Two Color Quantization Rather than picking the two control colors yourself, you can use color quantization to pick the best two colors in the image by using the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" operator. magick logo.png -colors 2 -colorspace gray -normalize \\ colors\_monochrome.gif [![[IM Output]](colors_monochrome.gif)](colors_monochrome.gif) However the result will not be the same as using "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `", as we didn't magick the image to grey-scale first. Instead the image was dithered directly between the two non-grey color values chosen. That is, the best two colors is selected to dither the image with, rather than two gray-scale brightness levels. Consequently it will produce a better result for say image that only uses colors of about the same gray-scale 'level'. Here for example we use "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `", as well as a "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" bitmap dithering operator, on a red-blue gradient. As you can so you can see that the results are not the same. magick -size 20x640 gradient:red-blue -rotate 90 gradient\_rb.png magick gradient\_rb.png -colors 2 -colorspace gray \\ -normalize colors\_threshold.gif magick gradient\_rb.png -monochrome mono\_threshold.gif [![[IM Output]](gradient_rb.png)](gradient_rb.png) [![[IM Output]](colors_threshold.gif)](colors_threshold.gif) [![[IM Output]](mono_threshold.gif)](mono_threshold.gif) The "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator in the above failed to find any differences to bitmap dither as both blue and red are very nearly the same intensity. Using a "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" quantization method however had no problem in finding acceptable colors to dither between. You can also see that only the middle portion of the colors were dithered. This is due to the color quantization picking colors in the middle of two color 'clusters' it selected. Colors on the 'outside' of the selected colors in is thus effectively threshold directly to that color without dithering. This demonstrates that colors on the outside of the quantization color space does not get dithered, though this fact is difficult to make use of in a practical way.By setting the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" to gray-scale before quantization, you will reproduce the internal operation of the "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator. magick logo.png -colorspace gray -colors 2 -normalize \\ monochrome\_equivelent.gif [![[IM Output]](monochrome_equivelent.gif)](monochrome_equivelent.gif) And finally, by turning off the dithering, you can produce a more automatic separation of the colors in the image than produced by using a fixed "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" setting. magick logo.png -colorspace gray +dither -colors 2 -normalize \\ threshold\_two\_grays.gif [![[IM Output]](threshold_two_grays.gif)](threshold_two_grays.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Remember "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" currently ignores the "`[+dither](https://imagemagick.org/script/command-line-options.php?#dither) `" setting, so you can't just use that operator to do a 'smart threshold'._ | If you remove the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" for the color quantization stage of the image processing, you can threshold an image based on the best color separation (rather than greyscale color separation) possible for that image. magick logo.png +dither -colors 2 -colorspace gray -normalize \\ threshold\_two\_color.gif [![[IM Output]](threshold_two_color.gif)](threshold_two_color.gif) ### Dither using Pre-Defined Color Maps As shown above "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" attempts to choose an optimal limited set of colors with which to represent an image. With "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" you provide IM with the final set of colors you want to use for the image, whether you plan to dither those colors, or just replace the ones with their nearest neighbours. The argument is given as an image containing all the colors you would like to use. If you what to reduce a large image of colors to just its list of colors, you can use "`[-unique-colors](https://imagemagick.org/script/command-line-options.php?#unique-colors) `", before saving, it for later use by "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `". | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that while the "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator will accept any image to use, do not use a JPEG image for this image or you will get a lot of extra colors due to its 'lossy compression' generating extra colors.

On the other hand using JPEG to generate extra colors may help resolve the 'speckling' problem seen previously!_ | For example, here I limit the colors used in the IM logo to a predefined map of named X window colors. The default is the '`Riemersma`' dither, but as of IM v6.4.4 "`[-dither](https://imagemagick.org/script/command-line-options.php?#dither) `" was expanded to allow the selection of other dither methods such as '`FloydSteinberg`'. You can of course still turn off dithering using the "`[+dither](https://imagemagick.org/script/command-line-options.php?#dither) `" option. magick logo.png -dither None -remap colortable.gif remap\_logo\_no.gif magick logo.png -dither Riemersma -remap colortable.gif remap\_logo\_rm.gif magick logo.png -dither FloydSteinberg \\ -remap colortable.gif remap\_logo\_fs.gif [![[IM Output]](logo.png)](logo.png) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/colortable.gif)](../images/colortable.gif) ![](../img_www/right.gif) [![[IM Output]](remap_logo_no.gif)](remap_logo_no.gif) [![[IM Output]](remap_logo_rm.gif)](remap_logo_rm.gif) [![[IM Output]](remap_logo_fs.gif)](remap_logo_fs.gif) As you can see IM attempted to do a reasonable job of representing the image using just the given colors, though the results is nowhere near as good as the image you get if you allowed IM to select the color set to use. Mind you this "`[colortable.gif](../images/colortable.gif) `" image was never designed for dithering images, but as a color set for designing cartoon-like color icons for older more primitive X window color displays (See [Anthony's X Window Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) and [AIcons Color Selection](http://www.ict.griffith.edu.au/anthony/icons/docs/colors.html) for details). Also note that the final image did not use all 32 colors provided by this map, though more of the colors in the map will be used when some form of dithering was enabled ([![](remap_logo_count_rm.txt.gif)](remap_logo_count_rm.txt) and [![](remap_logo_count_fs.txt.gif)](remap_logo_count_fs.txt) respectively), than when it was turned off ([![](remap_logo_count_no.txt.gif)](remap_logo_count_no.txt) ). This last example shows just how important selecting a good colormap is. Because of this I recommend you let IM optimize the color selection used in an image using the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" operator, and modify that to suit your needs, unless you have more pressing reasons not to do so. One final point, while you can specify a color space in which "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" will find the best set of colors, you currently can NOT define a color space for the color mapping or dithering phase. All my experiments seem to show that the color set is applied (both error correction dither and nearest color replacement) based on RGB space. The "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" colorspace setting is only used for the selection of colors, not its mapping. So if using a color map is such a bad idea, why would you want use it? There are a number common reasons, usually because you need more control of the specific palette of colors used in an image. Another user also separated the colormap out so he could use it on a Risograph (A digital printing system). _If you know of another reason to use the "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator which I have not presented below - Mail me._ #### Common or 'Best' Colormap The other technique, when handling multiple images, is to generate a common color table for all the images involved. Basically you append all the images together into one large image, then use the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" operator to figure out a good color map to use that is common to all the images. Once you have that color map image you can use it to re-color each of the original images using this juts generated [Pre-Defined Color Map](#map) . Alternatively, you can use the special "`[+remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator, which does the same thing to a 255 color colormap. It counts up the colors, perform the color quantization to form a good, common colormap, then dithers the images to use that map, if needed. Both "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" and "`[+remap](https://imagemagick.org/script/command-line-options.php?#remap) `" forms however has one very important feature for GIF animations. It converts all the images to an image "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" of '`Palette`' with all the images using the same palette of colors. The reason is that when writing a GIF image, the first images color palette, will be used for the file formats 'global colormap'. Then as each image is written it notes that those images use the same set of colors, so it does NOT create a 'local colormap'. This can save up to 256 × 3, or 768 bytes of colormap space for each and every image the final GIF file. Only the "`[-remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operators can do this. So when handling GIF's and in particular GIF animations, it can be an important point to remember. For more details, and an example see [Gif Animations, Global Color Table](../anim_opt/#colortables) . ### Web Safe Coloring When the WWW was first created, computer displays had a limited range of colors available, and web browsers usually used a simpler set of colors for images. As such it was common to recolor images to this color set, to make them both smaller, and to ensure they will look okay on users browsers. For more detail see [Web Style Guide, Dithering](http://www.webstyleguide.com/graphics/dither.html) . To help with this IM provided a built-in colormap image of this special table of 216 colors, called "`netscape:`". So lets look at how our test image would look on of an old web browser display using these colors. magick logo.png -remap netscape: remap\_netscape.gif magick logo.png +dither -remap netscape: remap\_netscape\_nd.gif [![[IM Output]](logo.png)](logo.png) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/netscape.gif)](../images/netscape.gif) ![](../img_www/right.gif) [![[IM Output]](remap_netscape.gif)](remap_netscape.gif) [![[IM Output]](remap_netscape_nd.gif)](remap_netscape_nd.gif) This color set was a mathematically determined pallet, designed by engineers of displays and computers, not graphic artists, and while it is is general enough that it works reasonably well for real images such as photos, it is very bad for images containing large flat areas of color, such as logos, backgrounds, computer generated images such as graphs, and cartoon-like images. Basically this works in areas of highly variable colors, but for the larger flat areas of constant colors a dithering of three colors (in general) is applied, such as the off-blue shirt of the IM logo test images (above). In other words, if you were designing an image or logo for use on the web, you work generally try to use the colors in this pallet for the large flat areas, and only have dithered colors in areas where your have varying shades of color. The above commands lets you test your images to see how they would look on more primitive computer displays, and to edit image to use these colors, so they will work well. This is particularly important for symbols and navigation images. Of course today, thanks to the demands by game and web users, you can be pretty well assured that most users have a modern computer display that does not have those old color limitations, however the use of this "web safe palette" is still around, as it does have other benefits, such an image compression. For a discussion about the use of Web-safe colors in the modern world see [Death of the Web-safe Color Palette?](http://www.webmonkey.com/00/37/index2a.html) , and probably a more important view from a graphic designer that first identified this color map, [Lynda Weinman](http://www.lynda.com/hex.asp) . ### Generating Color Maps Determining a good color map for any image, or an specific set of images, can be very important. This becomes especially important when you are dealing with a sequence of images that will be used for GIF animation. Basically you want to make it so they only need one color table, to use for all the frames of the animation, rather than a separate color table for each frame. In other words you want one single color map for all the image. You have really only two choices in this case. You can attempt to create a colormap that will work well for any image, or you try to optimize a color map for the specific set of images you are applying it to. #### Web-Safe Colormap [![[IM Output]](../images/netscape.gif)](../images/netscape.gif) The first method is typically a mathematically generated color map, such as the IM built-in "`netscape:`" color map. This provides a set of 216 colors, which will nicely fit into the GIF formats 256 color limit, and still have space for handling image transparency, or even adding some extra colors for special purposes, like shadows, or text overlays. This color map was generated by creating 6 levels of colors for each of the three color channels, producing 6×6×6 colors or 216 colors. The number of the beast. As only 219 color are used it still has space (for GIF images) to add more colors to the color map for specific purposes. For example a transparent color, as well as more grey scale shades. An old Macintosh version of the web-safe map actually did exactly this to try to improve its overall result, but it was only used on Macintosh web clients. This is probably the most common 'uniform' (or mathematically derived) colormap in general use, thanks to its simplicity, and its general use on the the World Wide Web. #### Uniform 332 Colormap Another uniform color mapping that is commonly used is the "332 RGB color map". The number refer to the number of bits used to represent each color within a 8 bit color index. That is, 3 bits (or 8 levels) of red, 3 for green, and 2 bits (or 4 color levels) for blue, seeing as our eyes do not respond well to blue. This gives 3+3+2 bits or an 8 bit color index, or 256 colors. Perfect for the limited GIF color table. However it will not leave any space for a GIF transparency color, or other special use colors. Here is one way to get IM to generate this color map... magick -size 16x16 xc: -channel R -fx '(i%8)/7' \\ -channel G -fx '(j%8)/7' \\ -channel B -fx '((i>>3&1)|(j>>2&2))/3' \\ -scale 600% colormap\_332.png [![[IM Output]](colormap_332.png)](colormap_332.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The bit-shifting operators '`>>`' and '`<<`' was missing from the "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator until IM version 6.2.9-2._ | A simpler way of doing the same thing is to use [Ordered Dither using Uniform Color Levels](#od_posterize) using the operation, "`-ordered-dither threshold,8,8,4`" (see that examples area). A far easier and faster technique than the above [DIY FX method](../transform/#fx) , and even allows you to use other built-in dithering maps for better gradient handling. The only drawback with this map is that it does not actually provide any 'gray' colors at all. However this drawback can be a plus when dithering is used as the slight color differences reduce the effect of color boundary changes in a grey-scale gradient, making it just that little bit smother looking. #### TrueColor 16bit Colormap A similar uniform colormap to the '332 colormap' above is used by X windows in a rarely used 16 bit visual class. In this case, 16 bits are used for the color index which is divided into 5 bits for red, 5 for green, and 6 for blue. In other words, this color map is more like a "556 colormap", and is best achieved using a [Ordered Dither using Uniform Color Levels](#od_posterize) using a 'threshold' dithermap. Specifically the operation "`-ordered-dither threshold,32,32,64`". 16 bit colormaps are however rarely seen as images using colormaps typically need a 8 bit color table. As such I won't mention it further. #### Gamma Corrected Uniform Colormaps At this time IM does not do gamma corrected color maps directly. Instead what you should do is magick your image (assuming you have Q16 or better compile time [quality](../basics/#quality) version of IM), from the sRGB or whatever gamma level the image has to a linear RGB model, before doing your dithering. This also goes for many other image processing operations, such as resize, bluring, etc. See [Resizing with Gamma Correction](../resize/#resize_gamma) for an example. ### Posterize, Recolor using an Uniform Color Map The operators original purpose (using an argument of '2') is to re-color images using just 8 basic colors, as if the image was generated using a simple and cheap poster printing method using just the basic colors. Thus the operator gets its name. The "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operator is actual fact is a special color reduction operator that generates a color map based on the the number of color 'levels' given, for each color channels in the image, dithering the image using an error correction dither. magick netscape: -scale 50% +dither -posterize 2 posterize\_2\_ns.gif magick netscape: -scale 50% +dither -posterize 3 posterize\_3\_ns.gif magick netscape: -scale 50% +dither -posterize 6 posterize\_6\_ns.gif [![[IM Output]](../images/netscape.gif)](../images/netscape.gif) ![](../img_www/right.gif) [![[IM Output]](posterize_2_ns.gif)](posterize_2_ns.gif) [![[IM Output]](posterize_3_ns.gif)](posterize_3_ns.gif) [![[IM Output]](posterize_6_ns.gif)](posterize_6_ns.gif) As you can see a "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" argument on '`2`' means to only provide 2 colors per color channel, producing a map of just 8 colors for a 3 channel RGB image, such as the above. Basically it will recolor images using the threshold set of 8 colors. An argument of '`3`' will map image colors based on a colormap of 27 colors, including mid-tone colors. While an argument of '`4`' will generate a 64 color colortable, and '`5`' generates a 125 color colormap. Of course as mentioned above, an argument of '`6`' will reproduce the same set of 216 colors, as provided by the in the built-in "`netscape:`" image. Please note that a "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" argument of '`0`' or '`1`' is non-sensible, and with the latest IM releases just converts images to pure black (which though logical, is quite useless). The result is that the image has been recolors using a mathematically derived or 'uniform' color map. You can see this more clearly on a gradient image, producing an even distribution of posterized gray levels. #magick -size 20x640 gradient: -rotate 90 gradient.png magick gradient.png +dither -posterize 5 posterize_gradient.gif [![[IM Output]](posterize_gradient.gif)](posterize_gradient.gif) For example lets posterize the IM logo image at various levels... magick logo.png +dither -posterize 2 posterize\_logo.gif magick logo.png -posterize 2 posterize\_logo\_dither.gif magick logo.png -posterize 6 posterize\_6\_logo.gif [![[IM Output]](logo.png)](logo.png) ![==>](../img_www/right.gif) [![[IM Output]](posterize_logo.gif)](posterize_logo.gif) [![[IM Output]](posterize_logo_dither.gif)](posterize_logo_dither.gif) [![[IM Output]](posterize_6_logo.gif)](posterize_6_logo.gif) As a better test lets poserize the shaded "[colorwheel](../images/colorwheel.png) " image. magick colorwheel.png +dither -posterize 2 posterize\_2\_cw.gif magick colorwheel.png +dither -posterize 3 posterize\_3\_cw.gif magick colorwheel.png +dither -posterize 6 posterize\_6\_cw.gif [![[IM Output]](../images/colorwheel.png)](../images/colorwheel.png) ![](../img_www/right.gif) [![[IM Output]](posterize_2_cw.gif)](posterize_2_cw.gif) [![[IM Output]](posterize_3_cw.gif)](posterize_3_cw.gif) [![[IM Output]](posterize_6_cw.gif)](posterize_6_cw.gif) And here is the same thing with dithering enabled... [![[IM Output]](../images/colorwheel.png)](../images/colorwheel.png) ![](../img_www/right.gif) [![[IM Output]](posterize_2_dither.gif)](posterize_2_dither.gif) [![[IM Output]](posterize_3_dither.gif)](posterize_3_dither.gif) [![[IM Output]](posterize_6_dither.gif)](posterize_6_dither.gif) Of course many of the bitmap dithers we look at in the next section can also generate level 2 ordered dithers, using various sorts of dither styles. However few can use a larger number of grey levels. [Ordered Dither](#ordered-dither) as of IM v6.2.9, is also a posterization method, due to its current limitation in dithering using a uniform colormaps. However the dither pattern is more uniform, with a larger selection of styles, than the pseudo-randomized dither produced by "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `". Compare these with the dithered "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" versions above. magick colorwheel.png -ordered-dither o8x8,2 posterize\_2\_od.gif magick colorwheel.png -ordered-dither o8x8,3 posterize\_3\_od.gif magick colorwheel.png -ordered-dither o8x8,6 posterize\_6\_od.gif [![[IM Output]](../images/colorwheel.png)](../images/colorwheel.png) ![](../img_www/right.gif) [![[IM Output]](posterize_2_od.gif)](posterize_2_od.gif) [![[IM Output]](posterize_3_od.gif)](posterize_3_od.gif) [![[IM Output]](posterize_6_od.gif)](posterize_6_od.gif) The '`threshold`' dither map (instead of '`o8x8`' used above) effectively converts "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" into an un-dithered posterization method. Finally the [Ordered Dither](#ordered-dither) does allow you to specify a different number of color levels, for each individual color channel. Something that the "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operator does not currently allow. * * * Threshold Dithering Methods --------------------------- ### Threshold Images The simplest method of converting an image into black and white bitmap (to color) image is to use "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `". This is actually a simple mathematical operator that just provides a cut-off value. Anything equal to or below that value becomes black, while anything larger becomes white. magick logo.png -threshold -1 threshold\_0.gif magick logo.png -threshold 25% threshold\_25.gif magick logo.png -threshold 50% threshold\_50.gif magick logo.png -threshold 75% threshold\_75.gif magick logo.png -threshold 100% threshold\_100.gif [![[IM Output]](threshold_0.gif)](threshold_0.gif) [![[IM Output]](threshold_25.gif)](threshold_25.gif) [![[IM Output]](threshold_50.gif)](threshold_50.gif) [![[IM Output]](threshold_75.gif)](threshold_75.gif) [![[IM Output]](threshold_100.gif)](threshold_100.gif) As you can see a value of '`-1`' will magick all colors white, while '`100%`' converts all colors to black. A '`50%`' is of course the most common value used.A value of '`0`' is a special case which turns all non-pure black colors, white. Of course if the image does not have pure-black colors, then you will only get a solid white image! magick logo.png -threshold 0 threshold\_black.gif [![[IM Output]](threshold_black.gif)](threshold_black.gif) If you actually want to magick all non-pure white colors to black, then I recommend that you threshold the [negated](../color_mods/#negated) image instead of trying to work out the right threshold value to use (one less than IM's current 'MaxRGB'), a value that is dependant on your specific IM's compile time in [Quality, or 'Q'](../basics/#quality) setting. magick logo.png -negate -threshold 0 -negate threshold\_white.gif [![[IM Output]](threshold_white.gif)](threshold_white.gif) The "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" operator can be classed as an ultimate 'contrast' operator, maximizing the differences in colors by the threshold level. It is however a gray-scale operator, meaning that the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting, can be used to adjust which color channel the operator will be applied to. For example you can threshold each of the individual channels of the image to produce the same effect as an un-dithered level 2 "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operation. magick logo.png -channel R -threshold 50% \\ -channel G -threshold 50% \\ -channel B -threshold 50% threshold\_posterize.gif [![[IM Output]](threshold_posterize.gif)](threshold_posterize.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" treats any transparency in an image as a matte channel, not an alpha channel (just as it is stored internally within IM). As such caution is needed if you plan to apply this operator to the alpha channel. See [Matte Channel](../masking/#matte)
for more details._ | For a more automatic thresholding technique, you can use a [Two Color Quantization](#two_color) technique that we showed previously.For example, this will threshold the image based on the best two colors found in the image. These colors may not necessarily be greyscale or even opposites, just the two colors that best represent the whole image. The two colors are then mapped (using "`[-normalize](https://imagemagick.org/script/command-line-options.php?#normalize) `") to pure black and white. magick logo.png +dither -colors 2 -colorspace gray -normalize \ threshold_two_color.gif [![[IM Output]](threshold_two_color.gif)](threshold_two_color.gif) ### Random Dither and Threshold The "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" operator is a special form of bitmap image converter. In this case it uses a very simple "random dither" to determine if a particular pixel is to become a white pixel or a black pixel. Unlike the "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" or the "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operators, or even the variations in the previous section, the selected channels (set with "`[-channels](https://imagemagick.org/script/command-line-options.php?#channels) `") are not merged together into single grey-scale channel and dithered as a single unit. Instead "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" works on each selected channel completely independently of each other.Of course using the operator directly will result in a 2 level posterization of the image using a random dither. magick logo.png -random-threshold 0x100% random_posterize.gif [![[IM Output]](random_posterize.gif)](random_posterize.gif) Converting to gray-scale will equalize all the channels in the image, before they are dithered. But as each channel is dithered independent of each other and in a random way, the result is not a bitmap image as you would expect. Instead you will get a splatter of color pixels, especially for mid-tone colors. magick logo.png -colorspace Gray -random-threshold 0x100% \ random_greyscale.gif [![[IM Output]](random_greyscale.gif)](random_greyscale.gif) Here is the correct way to generate a proper random dithered bitmap image. magick logo.png -colorspace Gray -channel B \ -random-threshold 0x100% -separate random_monochome.gif [![[IM Output]](random_monochome.gif)](random_monochome.gif) Basically what it did was to only dither one channel of the grey-scaled image, and then use the "`[-separate](https://imagemagick.org/script/command-line-options.php?#separate) `" channel operator to extract that channel as the final bitmap image. Tricky but effective.As a special feature for this operator, IM will ensure a bitmap image is generated in the special "`[-channels](https://imagemagick.org/script/command-line-options.php?#channels) `" option of '`All`' is used. magick logo.png -channel All -random-threshold 0x100% random_all.gif [![[IM Output]](random_all.gif)](random_all.gif) However please note that any alpha channel will be ignored and lost using this method, as such it is not normally recommended. I myself only discovered this ancient feature by accident from the source code. Now that you know how to use the operator to correctly generate bitmaps from a color image lets look how the argument effects the range of the dithering. This also shows clearly the 'clumping' of pixels that this dither produces. #magick -size 20x640 gradient: -rotate 90 gradient.png magick gradient.png -channel All \ -random-threshold 0x100% random_grad_0x100.gif magick gradient.png -channel All \ -random-threshold 10x90% random_grad_10x90.gif magick gradient.png -channel All \ -random-threshold 25x75% random_grad_25x75.gif magick gradient.png -channel All \ -random-threshold 50x50% random_grad_50x50.gif [![[IM Output]](random_grad_0x100.gif)](random_grad_0x100.gif) [![[IM Output]](random_grad_10x90.gif)](random_grad_10x90.gif) [![[IM Output]](random_grad_25x75.gif)](random_grad_25x75.gif) [![[IM Output]](random_grad_50x50.gif)](random_grad_50x50.gif) A "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" setting of '`0x100%`' will produce a purely 'Random Dither' of the image. If the two bounds are set to the same value (or even past each other) it will just produce a pure "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" image. Using any other sets of bounds (usually specified using a percentage) will threshold the bitmap outside the given range, while producing a random dither pattern for the values within the given range.The best results can be obtained by using a slightly smaller range, just as you get using the "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator. A value of about '`30x80%`' probably the best result for most cases. magick logo.png -channel All -random-threshold 30x80% random_30x80.gif [![[IM Output]](random_30x80.gif)](random_30x80.gif) Of course the result is still not very good. But then this is the simplest and worst form of dithering you can get. What actually happens is that the randomized dither pattern tends to produce 'clumps' of pixels rather than a smooth dither pattern. this is due to the high frequency 'noise' in the random number generator. However at very high resolutions a random dither has been shown to produce an extremely good result, if random enough. IM uses a cryptographic level of randomness so it will likely be very random, though images are rarely used at a high enough a resolution to make it useful in this way. One 'fix' for this dither, that has been suggested is to use a random 'blue noise' generator (a high frequency filter, as opposed to a low frequency 'pink noise' filter used in sound production). This should remove the clumping of the pixels, but is very difficult to implement digitally. No known implementation of 'blue noise randomized dither' has been found, and unlikely to be ever created. * * * Ordered Dithering ----------------- While a random dither produces random clumps of pixels, and the various error correction dithers produce an essentially random pattern of dots, ordered dithering is basically the opposite. It is designed to be as mathematically deterministic as possible. So deterministic, that you actually need to specify the pattern for it to should use in dithering the image. The "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator will dither each of the selected "`[-channels](https://imagemagick.org/script/command-line-options.php?#channels) `" in the image a given predefined pattern. The argument defines the pattern (known as a threshold map) to use. These threshold maps fall into three basic styles. [Diffused Pixel Dithers](#diffused) where the pixels are placed as far from each other as possible, so as to avoid 'clumping' and tiling artifacts. Or to clump them together into tight dots that makes them easier to mechanically print, in a technique known as [Digital Halftoning](#halftone) . There is also some specialized artistic threshold maps that we will also be looking at, and even designing our own dithering pattern or threshold maps. In each case the number of pixels that is on or off in the threshold map depends on the grey-level intensity of the image (or individual color channel) that is being dithered into a bitmap. The map adds pixel threshold levels in a consistent manner, so that once a pixel turns on at a particular 'threshold' it remains on for any lighter grey color. This consistency is very important, otherwise artifacts are produced along the boundaries of changes the dither pattern. The important point about this is that the result for each pixel in an image is purely mathematically determined independently of any other pixel in the image. As such any small change to the original image will have absolutely no effect on the image in any other area a problem that [Error Correction Dithers](#dither_error) have, as we saw above. This point is vital to consistent dithering of video images and optimized animations. ### Diffused Pixel Dithering The original purpose of ordered dithering, and what most graphic programmers expect to get when you use an ordered dither is sometime more correctly termed, "Diffused Pixel Ordered Dither". What this means is that pixels are added to the tiled map as the threshold intensity increases, so that they are as far away from each other and evenly distributed as possible. This produces a highly consistent pattern that look quite smooth and near invisible on most modern displays.Such patterns have been worked out for tiling sizes that are a power of 2, namely, tile sizes of 2, 4, and 8. Though IM also provides a reasonable threshold pattern for a 3 by 3 threshold map tile. Here is the current set of built-in ordered dithers that IM currently provides. Remember the argument reflects the tile size of the ordered dither. magick logo.png -ordered-dither o2x2 logo\_o2x2.gif magick logo.png -ordered-dither o3x3 logo\_o3x3.gif magick logo.png -ordered-dither o4x4 logo\_o4x4.gif magick logo.png -ordered-dither o8x8 logo\_o8x8.gif [![[IM Output]](logo_o2x2.gif)](logo_o2x2.gif) [![[IM Output]](logo_o3x3.gif)](logo_o3x3.gif) [![[IM Output]](logo_o4x4.gif)](logo_o4x4.gif) [![[IM Output]](logo_o4x4.gif)](logo_o8x8.gif) Note how a larger tile size allows you to simulate more 'color levels', but also generates more noticeable defects or rectangular arrays of pixels at certain levels. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The '`o8x8`' ordered dither was part of the IM core code for a long time, but was not used. It was only added as an option to the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator IM v6.2.9, when IM Examples started to detail the use of this operator.

At this time the maps were given more definitive names to allow further expansion of the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator, though the older backward compatible 'tile size' names, were retained as aliases to the new names.

Also the 'maps' that produced the 'o3x3' and 'o4x4' were completely revised to produce a better 'diffused pixel' dither pattern. Before this the maps produced distinct 'clumps' of pixels.

See [Ordered Dither Upgrade](../bugs/ordered-dither/)
notes page for examples of the old patterns before they were fixed, as well as other changes made during the development for the official release of the upgrades in IM v6.3.0._ | Of course you need to magick the image to grey-scale first to produce a proper bitmap of all the channels in the image, however as the process is not random you don't need to post-process the image as you need to for the [\-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) " operator simplifying things enormously. magick logo.png -colorspace Gray -ordered-dither o2x2 logo\_bw\_o2x2.gif magick logo.png -colorspace Gray -ordered-dither o3x3 logo\_bw\_o3x3.gif magick logo.png -colorspace Gray -ordered-dither o4x4 logo\_bw\_o4x4.gif magick logo.png -colorspace Gray -ordered-dither o8x8 logo\_bw\_o8x8.gif [![[IM Output]](logo_bw_o2x2.gif)](logo_bw_o2x2.gif) [![[IM Output]](logo_bw_o3x3.gif)](logo_bw_o3x3.gif) [![[IM Output]](logo_bw_o4x4.gif)](logo_bw_o4x4.gif) [![[IM Output]](logo_bw_o8x8.gif)](logo_bw_o8x8.gif) As a reference here are each of the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" 'diffused pixel' patterns applied to a grey-scale gradient, so you can see clearly what they look like. # Threshold Non-Dither / Minimal Checkerboard Dither magick gradient.png -ordered-dither threshold od\_threshold.gif magick gradient.png -ordered-dither checks od\_checks.gif # Diffused Pixel Dither magick gradient.png -ordered-dither o2x2 od\_o2x2.gif magick gradient.png -ordered-dither o3x3 od\_o3x3.gif magick gradient.png -ordered-dither o4x4 od\_o4x4.gif magick gradient.png -ordered-dither o8x8 od\_o8x8.gif [![[IM Output]](od_threshold.gif)](od_threshold.gif) [![[IM Output]](od_checks.gif)](od_checks.gif) * * * [![[IM Output]](od_o2x2.gif)](od_o2x2.gif) [![[IM Output]](od_o3x3.gif)](od_o3x3.gif) [![[IM Output]](od_o4x4.gif)](od_o4x4.gif) [![[IM Output]](od_o8x8.gif)](od_o8x8.gif) The number of effective or pseudo-level patterns produced by a specific ordered dither, is typically (by not always) equal to the number of pixels in the pattern plus one. As such a '`o3x3`' ordered dither will produce 3×3+1 or 10 effective grey levels per channel (black, white, and 8 artificial gray patterns) in the resulting image. Also shown above are two special minimal dither threshold maps: 1. a straight '50% threshold' non-dither, which does not produce any extra grey levels and 2. a 'checks' or checkerboard dither pattern, that only inserts a single pattern to add an extra 'pseudo-level' to the resulting gradient. ### Digital Halftone Dithers The "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" was extended in IM v6.2.8-6 with a set of digital-halftone dither patterns (thanks Glenn Randers-Pehrson). All of which were set to produce a simple 45 degree dot pattern. With IM v6.3.0 this was further expanded with a similar set of larger un-angled halftones. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Before the release of IM v6.3.0 halftone screens were selected by using an argument of the form '`{number}x1`'. With the [Re-Development of Ordered Dither](../bugs/ordered-dither/)
this limitation was lifted, better naming selected, and extra halftone screens (orthogonal forms) was added (see example arguments below)._ | Note that digital halftoning is not strictly a true halftone screen, which is designed to handle round dots of ink mechanically deposited onto a medium such as paper, cardboard or even metal. Such dots can overlap, and smear during the printing process, thus requiring some non-linear level adjustment. This is not needed for producing purely digital halftone effects. For more details of the process see the document [Dithering and Halftoning (PDF)](http://www.fho-emden.de/~hoffmann/hilb010101.pdf) . That said the [Ordered Dither](#ordered-dither) digital halftone patterns do provide the same basic effect as seen in newspapers and cheaply printed magazines. # Halftone Screen (45 degree angle) magick logo.png -ordered-dither h4x4a logo\_h4x4a.gif magick logo.png -ordered-dither h6x6a logo\_h6x6a.gif magick logo.png -ordered-dither h8x8a logo\_h8x8a.gif # Halftone Screen (orthogonal) magick logo.png -ordered-dither h4x4o logo\_h4x4o.gif magick logo.png -ordered-dither h6x6o logo\_h6x6o.gif magick logo.png -ordered-dither h8x8o logo\_h8x8o.gif [![[IM Output]](logo_h4x4a.gif)](logo_h4x4a.gif) [![[IM Output]](logo_h6x6a.gif)](logo_h6x6a.gif) [![[IM Output]](logo_h8x8a.gif)](logo_h8x8a.gif)       [![[IM Output]](logo_h4x4o.gif)](logo_h4x4o.gif) [![[IM Output]](logo_h6x6o.gif)](logo_h6x6o.gif) [![[IM Output]](logo_h8x8o.gif)](logo_h8x8o.gif) Again to use the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" operator to generate a true bitmap dither of an image. # Halftone Screen (45 degree angle) magick logo.png -colorspace Gray -ordered-dither h4x4a logo\_bw\_h4x4a.gif magick logo.png -colorspace Gray -ordered-dither h6x6a logo\_bw\_h6x6a.gif magick logo.png -colorspace Gray -ordered-dither h8x8a logo\_bw\_h8x8a.gif # Halftone Screen (orthogonal) magick logo.png -colorspace Gray -ordered-dither h4x4o logo\_bw\_h4x4o.gif magick logo.png -colorspace Gray -ordered-dither h6x6o logo\_bw\_h6x6o.gif magick logo.png -colorspace Gray -ordered-dither h8x8o logo\_bw\_h8x8o.gif [![[IM Output]](logo_bw_h4x4a.gif)](logo_bw_h4x4a.gif) [![[IM Output]](logo_bw_h6x6a.gif)](logo_bw_h6x6a.gif) [![[IM Output]](logo_bw_h8x8a.gif)](logo_bw_h8x8a.gif)       [![[IM Output]](logo_bw_h4x4o.gif)](logo_bw_h4x4o.gif) [![[IM Output]](logo_bw_h6x6o.gif)](logo_bw_h6x6o.gif) [![[IM Output]](logo_bw_h8x8o.gif)](logo_bw_h8x8o.gif) And finally another gradient reference image to clearly show the halftone dither pattern, and how the pixel clumps within the dither pattern grow into each other as the grey-level changes. # Halftone Screen (45 degree angle) magick gradient.png -ordered-dither h4x4a od\_h4x4a.gif magick gradient.png -ordered-dither h6x6a od\_h6x6a.gif magick gradient.png -ordered-dither h8x8a od\_h8x8a.gif # Halftone Screen (orthogonal) magick gradient.png -ordered-dither h4x4o od\_h4x4o.gif magick gradient.png -ordered-dither h6x6o od\_h6x6o.gif magick gradient.png -ordered-dither h8x8o od\_h8x8o.gif magick gradient.png -ordered-dither h16x16o od\_h16x16o.gif # Circle Halftones (black and white) magick gradient.png -ordered-dither c7x7b od\_c7x7b.gif magick gradient.png -ordered-dither c7x7w od\_c7x7w.gif [![[IM Output]](od_h4x4a.gif)](od_h4x4a.gif) [![[IM Output]](od_h6x6a.gif)](od_h6x6a.gif) [![[IM Output]](od_h8x8a.gif)](od_h8x8a.gif) * * * [![[IM Output]](od_h4x4o.gif)](od_h4x4o.gif) [![[IM Output]](od_h6x6o.gif)](od_h6x6o.gif) [![[IM Output]](od_h8x8o.gif)](od_h8x8o.gif) [![[IM Output]](od_h16x16o.gif)](od_h16x16o.gif) * * * [![[IM Output]](od_c7x7b.gif)](od_c7x7b.gif) [![[IM Output]](od_c7x7w.gif)](od_c7x7w.gif) Up until ImageMagick version 6.2.9 all the above threshold ordered dither map were all that was possible with IM. This has now changed, allowing users to add their own patterns, add even contribute them to the IM community. The 'Circle' halftone thresholds were added by Glenn Randers-Pehrson, IM v6.6.5-6. ### Offset HalfTone Dither The only problem with the above halftone dither is that it is that the exact same threshold map (tile) is applied to all the color channels in the same way. That means the same set of primary color is arranged in dots with the same 'center'. To get what is known as 'Offset Printing' the threshold pattern is rotated in a particular pattern such that the colors form small scale 'rosette patterns' that destroyes the more horrible looking interference (moiré) patterns that you could otherwise develop. This diagram basically explains the process, and is explained in great detail on the Wikipedia Page, [Halftone](http://en.wikipedia.org/wiki/Halftone) . ![[IM Output]](../img_diagrams/cmyk_offset.png) Note however that the rotated screens do not tile very well, as such the best idea is to actually generate the rotated pattern directly, rather than use a tiles threshold pattern. Here is one way to give an image an offset-halftone printing look, using small rotated 2x2 pixel checkerboard pattern, which is about the smallest 'screen' that can be used. magick colorwheel.png -set option:distort:viewport '%wx%h+0+0' \\ -colorspace CMYK -separate null: \\ \\( -size 2x2 xc: \\( +clone -negate \\) \\ +append \\( +clone -negate \\) -append \\) \\ -virtual-pixel tile -filter gaussian \\ \\( +clone -distort SRT 60 \\) +swap \\ \\( +clone -distort SRT 30 \\) +swap \\ \\( +clone -distort SRT 45 \\) +swap \\ \\( +clone -distort SRT 0 \\) +swap +delete \\ -compose Overlay -layers composite \\ -set colorspace CMYK -combine -colorspace RGB \\ offset\_colorwheel.png [![[IM Output]](offset_colorwheel.png)](offset_colorwheel.png) Note that the four rotated 'screens' are applied to the image as a whole, it is only the "`-combine`" step in CMYK colorspace, that actually extracts the 4 different color channels from the screened images. Also the 'no-op' distort for the last 'black' channel is important as it will blur the input checker pattern according to the Gaussian filter that was used on the other channels during their rotations, even though that screen itself is not being rotated. And here I use the scaling function of the [SRT Distort](../distorts/#srt) used to generate the rotated tiles to create a slightly larger and more blurry 'screen pattern'. magick parrots\_med.png -set option:distort:viewport '%wx%h+0+0' \\ -colorspace CMYK -separate null: \\ \\( -size 2x2 xc: \\( +clone -negate \\) \\ +append \\( +clone -negate \\) -append \\) \\ -virtual-pixel tile -filter gaussian \\ \\( +clone -distort SRT 2,60 \\) +swap \\ \\( +clone -distort SRT 2,30 \\) +swap \\ \\( +clone -distort SRT 2,45 \\) +swap \\ \\( +clone -distort SRT 2,0 -blur 0x0.7 \\) +swap +delete \\ -compose Overlay -layers composite \\ -set colorspace CMYK -combine -colorspace RGB \\ offset\_parrots.png [![[IM Output]](offset_parrots.png)](offset_parrots.png) Note that the pattern remains very 'square-like' especially the black screen from which all the others are derived. FUTURE POSSIBILITY: Replace the 2 pixel checkboard in the above with "pattern:gray50" pixel level checkerboard pattern. Gaussian filter options can be used to adjust the bluriness of the scaled pattern. Alternatively, you can blurry scale the pattern, and thresholded it, to make rounder dots. This can then be rotated as previously to create the 4 color screens. It also would be better is a larger screen using a pattern of hexagonal dots could be used, rather than the checkerboard pattern I have used above. It is important to note that this is not really generating color dots like true offset printing, but faking it by simply multiplying the color screens against the original image. You can see that this is the case due to the sharp color change along the edges of the red parrot against the green background. True offset printing using only dots of pure color will not have any middle of dot color changes. It is the size of the pure colored dot that should change, depending on the average of the colors in that area reprended by the dot in the source image. To actually generate an true offset printing image only containing round dots in each color channel of appropriate size would require a lot more work. The average color in each dot in each color channel will been to be determined, and from that the appropriate size of colored dot (anti-aliased circle) generated. _Anyone like to give it a go?_ The above was from a discussion in the IM forum discussion [CMYK Halftone Effect](https://magick.imagemagick.org/viewtopic.php?f=1&t=18409&p=70730) which looks at how photoshop 'fakes it', and how ImageMagick could achieve the same effect. This discussion is also related to [B/W Halftone Dither](https://magick.imagemagick.org/viewtopic.php?f=1&t=17389&p=67746) which takes a closer look at generating true halftone screens using actual dots of appropriate sized. That discussion however did not take it to the next step of using offset (rotated) screens. Such screens would probably require rotating the image to generate the dots, then rotating the dot pattern back again for that specific color channel. ### XML Threshold Maps From IM version 6.3.0, rather than using a fixed set of map that were built into the source code of IM (shown previously), the maps are now read in from a set of XML data files external to the program itself. As part of this change you can now list the available 'threshold maps' that "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator can use. magick identify -list threshold [![[IM Output]](tmaps_list.txt.gif)](tmaps_list.txt) The above list shows not only the threshold maps available, but also the aliases provided for backwards compatibility or alternate naming, and those defined in my own personal "`thresholds.xml`" XML data file (saved into the "`.magick`" sub-directory of my home). When "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" is looking for a map, the first map that it finds in the above list, will be used. As such you can not override a system defined threshold pattern. The system file "`thresholds.xml`" (the path of which is given by the above "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" option), contains a complete summary of the format of the XML file. A format that is simple enough (with error checks by IM) to allow users to define and create their own ordered dither threshold maps. For example, here is a copy of the '`diag5x5`' threshold map I defined in my personal "`threshold.xml`" file. [![[IM Output]](tmap_diag.txt.gif)](tmap_diag.txt) If you look it creates a simple 5x5 map of a single diagonal line that becomes thicker as the threshold level increases. The level numbers in the map goes from 0 to 5, one less than the divisor, which declares how many 'grays' it needs to divide the color gradient into. Here is a gradient dithered using this personal threshold map. magick gradient.png -ordered-dither diag od\_diag.gif [![[IM Output]](od_diag.gif)](od_diag.gif) And here is an example of using that threshold to dither the alpha channel of a simple shadowed image, a purpose for which I designed it. magick -size 70x60 xc:none -font Candice -pointsize 50 \\ -fill black -annotate +10+45 'A' -channel RGBA -blur 0x5 \\ -fill white -stroke black -draw "text 5,40 'A'" shadow.png magick shadow.png -channel A -ordered-dither diag shadow\_diag.gif [![[IM Output]](shadow.png)](shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](shadow_diag.gif)](shadow_diag.gif) Pretty cool hey! More on dithering alpha channels later. First I need to also show how to use the coloring abilities of expanded "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator. ### Ordered Dither using Uniform Color Levels With the release of IM v6.3.0, not only was the threshold maps used by "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" changed so as to be read from external files, but the internal operations was enhanced to allow it to use mathematically defined 'posterized' color maps. This means you can generate a more deterministic dithering of images than you can achieve with 'error correction dithering'. This is especially important for color reductions involving animations as you will not get problems from color differences between frames. The posterization levels is passed to the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" argument using an extra comma separated list of numbers appended to the name of the threshold map to use. If no numbers are provided then the operator falls back to the normal 2 color (or posterize level 1) color map. For example and argument of '`checks,6`' will use a classic [Web Safe Color Map](#web_safe) (posterized level 6) color map (also defined by the "`netscape:` built-in colormap image). However as the minimal dither map of '`checks`' is used a single extra level of dithering is added between each of the 6 color levels creating 11 pseudo-levels of colors in each channel of the image. In other words even though only 6 levels of color per channel is being used (producing 6^3 or 216 colors) the single dither pattern between levels increases the dither to and effective 11 levels (producing and effective 11^3 or 1331 colors). For example, here is a gray scale gradient dithered using 6 grey levels and various threshold maps. The first map '`threshold`' is a special non-dithering ordered dither threshold map, showing just the colors used. magick gradient.png -ordered-dither threshold,6 od\_threshold\_6.gif magick gradient.png -ordered-dither checks,6 od\_checks\_6.gif magick gradient.png -ordered-dither o2x2,6 od\_o2x2\_6.gif magick gradient.png -ordered-dither o4x4,6 od\_o4x4\_6.gif magick gradient.png -ordered-dither o8x8,6 od\_o8x8\_6.gif [![[IM Output]](od_threshold_6.gif)](od_threshold_6.gif) [![[IM Output]](od_checks_6.gif)](od_checks_6.gif) [![[IM Output]](od_o2x2_6.gif)](od_o2x2_6.gif) [![[IM Output]](od_o4x4_6.gif)](od_o4x4_6.gif) [![[IM Output]](od_o8x8_6.gif)](od_o8x8_6.gif) As you can see even though only 6 colors are used, with ordered dithering you increase the effective number of colors used to define the gradient, to a point where you can be hard pressed to notice just how few colors were actually used! Not only can you define the number of posterization levels for all channels, but unlike the "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" error correction dither option, you can specify the levels for each channel. The numbers are assigned to the channels as per the "`[-channels](https://imagemagick.org/script/command-line-options.php?#channels) `" setting. For example, here we dithered the gradient using a special 332 color map (8 levels or red and green, 4 of blue) which defines a total of 256 colors. magick gradient.png -ordered-dither o8x8,8,8,4 od\_o8x8\_884.gif [![[IM Output]](od_o8x8_884.gif)](od_o8x8_884.gif) Because of the different number of color levels per channel, the above image does not contain just pure grey colors, but includes some bluish and yellowish pixels which cancels each other out to produce extra levels of greys. Now compare the [O-dithered](#ordered-dither) version against error correction dithered version using a posterization levels of 2, and 6, and a "332 colormap" (8 levels of red and green, 4 of blue). magick logo.png -ordered-dither o8x8 logo\_o8x8\_2.gif magick logo.png -posterize 2 logo\_posterize\_2.gif magick logo.png -ordered-dither o8x8,6 logo\_o8x8\_6.gif magick logo.png -posterize 6 logo\_posterize\_6.gif magick logo.png -ordered-dither o8x8,8,8,4 logo\_o8x8\_332.gif magick logo.png -remap colormap\_332.png logo\_remap\_332.gif [![[IM Output]](logo_o8x8_2.gif)](logo_o8x8_2.gif) [![[IM Output]](logo_posterize_2.gif)](logo_posterize_2.gif)     [![[IM Output]](logo_o8x8_6.gif)](logo_o8x8_6.gif) [![[IM Output]](logo_posterize_6.gif)](logo_posterize_6.gif)     [![[IM Output]](logo_o8x8_332.gif)](logo_o8x8_332.gif) [![[IM Output]](logo_remap_332.gif)](logo_remap_332.gif) The first image of each pair in the above is mathematically ordered dithered, while the second is pseudo-randomly 'error correction' dithered. The last pair uses the special '332 colormap' (See [Generating Color Maps](#remap_colormaps) ), which is regarded as probably the best posterize colormap for general images with a 256 color limit. The odd difference in channel levels producing a slightly better shading of colors for this cartoon like image. It was to allow the production the '332 colormap' that the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator, included the ability to specify separate levels for each color channel. #### Better Ordered Dither Results Lets take a closer look at the level 6 [O-Dither](#ordered-dither) we just generated. magick logo.png -ordered-dither o8x8,6 -format %k info: [![[IM Text]](logo_color_6.txt.gif)](logo_color_6.txt) As you can see for this image we did not even come close to filling the GIF color table (256 limit). Basically as the image generally consists of mostly blue colors, very few shades of red or even green colors from a level 6 uniform colormap was even used. However by increasing the number of posterization level we can fill the GIF color table better, so as to produce a better [O-Dithered](#ordered-dither) Image. magick logo.png -ordered-dither o8x8,13 -format %k info: [![[IM Text]](logo_color_13.txt.gif)](logo_color_13.txt) This produces enough colors to be only slightly smaller than the GIF color table limits. With the increase in the number of colors the result looks a lot better that the results of a simple standard uniform colormap. magick logo.png -ordered-dither o8x8,13 logo\_o8x8\_13.gif [![[IM Output]](logo_o8x8_13.gif)](logo_o8x8_13.gif) As you can see with a high 'levels' value, "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" can produce images that are comparable to color quantized, to the specific color picking generated by color quantization and an error correction dither. The major point about these images, is not that they are of high quality. After all a full [Color Quantization](#colors) can more easily produce better color map for the image. But that the low level dither pattern within the image is fixed, regardless of any small changes that may occur. Only the area changes will be changed in the Ordered Dithered Image. That is, they do not have the [E-Dither Sensitivity](#dither_sensitive) to change that causes problems for [Frame Optimization](../anim_opt/#frame_opt) in GIF animations. (see [Optimization Problem](../anim_opt/#color_fuzz) )Of course for an animation, you will need to "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" all the images together, before checking how many colors is actually used. And you will need to use the special "`[+remap](https://imagemagick.org/script/command-line-options.php?#remap) `" option after using the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" to force IM to generate a 'common global colormap' for ALL the images, even though you have already performed color reduction and dithering. _This method of determining the number of color levels is not simple to determine, but it does works. I hope to work out a way for IM to determine the best level automatically, especially for GIF animations._ * * * DIY Dither Patterns and Threshold Maps -------------------------------------- Previously I show you that the new "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator can accept an user defined dithering pattern. Here I am going to show you how you can create your own dither pattern. Specifically a special pattern I found useful for generating a shadows consisting of horizontal lines. ### Multi-Image Dither Patterns The first thing you need to do is create a set of images defining the pattern you want to create. The pattern should start with a solid black image of the right size as the first image (all pixels off) and a solid white image at the other end (all pixels on). The next image should be the middle 50% grey pattern, defining the the basic style of the dithering you are trying to achieve. For example, here is my initial DIY dither pattern. Which I save into a multi-image GIF file (not a GIF animation)... magick -size 2x2 xc:black \\ \\( +clone -draw 'fill white line 0,0 1,0' \\) \\ xc:white dpat\_hlines2x2.gif montage dpat\_hlines2x2.gif -tile x1 -background none -frame 2 \\ -filter box -geometry 32x32+5+0 dpat\_hlines2x2\_imgs.gif [![[IM Output]](dpat_hlines2x2_imgs.gif)](dpat_hlines2x2.gif) This is about the simplest set of dither pattern images you can get, and is very similar to the 'checks' or 'Checkerboard Dither', but with horizontal lines, rather than a checker pattern. So you can see just what this dither pattern would look like, here is a rather simple DIY ordered dither, that makes direct use of the threshold dithering image set. magick gradient.png dpat\_hlines2x2.gif \\ -virtual-pixel tile -fx 'u\[(floor((n-1)\*u)+1) % n\]' dgrad\_hlines2x2.gif [![[IM Output]](dgrad_hlines2x2.gif)](dgrad_hlines2x2.gif) As you can see the dither pattern is nothing fancy. The "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" function is a variation of the [Color Lookup Tables](../color_mods/#color_lut) function, namely, an IM Dither Lookup Patterns' type function. And with a "`[-virtual-pixel](https://imagemagick.org/script/command-line-options.php?#virtual-pixel) `" setting of '`tile`', the function does not even need to know the size of the dither pattern image you are using. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The use of "`[-virtual-pixel](https://imagemagick.org/script/command-line-options.php?#virtual-pixel) `" by the "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator using calculated indexes like this was broken before IM version 6.2.9-2._ | Lets try this dither pattern set again but using a simple shadowed image... magick shadow.png dpat\_hlines2x2.gif -channel A \\ -virtual-pixel tile -fx 'u\[floor((n-1)\*u)+1\].g' \\ shadow\_dpat\_hlines2x2.gif [![[IM Output]](shadow.png)](shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](shadow_dpat_hlines2x2.gif)](shadow_dpat_hlines2x2.gif) ### DIY Ordered Dither Threshold Maps The above DIY dither pattern is about as simple a dither pattern as you can get, and as such we can magick it directly into a XML threshold map, so that the fast built-in "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator can make use of it. Here is the final XML definition, which I saved in my own personal threshold map file "`~/.magick/thresholds.xml`" of my "$HOME" directory. [![[IM Output]](tmap_hlines2x2.txt.gif)](tmap_hlines2x2.txt) The XML format is very simple, and defines a 2x2 pixel map. The first black image is given a value of zero, and has no pixels, so no zero values is present. The pixels turned on (made white) in the middle image is set to '`1`' and the remaining or second image pixels are given a value of '`2`'. The '`divisor=`' defines the number of images, or pseudo-color levels (fake color levels) this dither pattern represents, so it has a value of '`3`'. It divides the pixel values, to defined the color level at which that pixel is to be turned on. As such the top two pixels are turned on for colors larger than 1/3, while the bottom two are turned on for color values larger that 2/3. That is, each pixel value represents a 'threshold' level, and why dither patterns are also called threshold maps. The rest of the definition defines the names (and optional alias) by which you can refer to the threshold map for the ordered dither operator. So lets try it out... magick gradient.png -ordered-dither hlines2x2 od\_hlines2x2.gif magick shadow.png -channel A \\ -ordered-dither hlines2x2 shadow\_hlines2x2.gif [![[IM Output]](od_hlines2x2.gif)](od_hlines2x2.gif) [![[IM Output]](shadow.png)](shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](shadow_hlines2x2.gif)](shadow_hlines2x2.gif) As you can see the result is reasonably good, but we can do other things to improve the result. By adjusting the threshold values in the map, we can change the boundary's, so it does not divide the color space into 3 equal areas... [![[IM Output]](tmap_hlines2x2a.txt.gif)](tmap_hlines2x2a.txt) Note how I increased the divisor to '`10`', so as to divide the color levels into ten equal sections. I then changed the threshold settings so that the pattern starts at a 30% threshold at the transparent end (black), to 90% for fully opaque (white). And here is the results of changing the threshold map. magick gradient.png -ordered-dither hlines2x2a od\_hlines2x2a.gif magick shadow.png -channel A \\ -ordered-dither hlines2x2a shadow\_hlines2x2a.gif As you can see this widened the range of semi-transparent pixels that use pure horizontal lines as a dither pattern. This gives a better better shadow effect, though it probably should only be used with a less fuzzy shadow than the example used here. Note however that this type of change to a threshold is very uncommon. Though justified for the intended use in this case. Basically it does not properly define a gradient, or allow for lighter and darker shades of patterns. For that we need to make a much more complex threshold map, with more pixels, and more patterns. ### DIY Horizontal Line Dither Here I expanded the simple horizontal lines dither pattern I created above into a set of patterns, to produce a smoother gradient from 'off' to 'on'. This was the result. montage dpat\_hlines.gif -filter box -geometry 60x20+2+0 \\ -tile x1 -background none -frame 2 dpat\_hlines\_images.gif magick gradient.png dpat\_hlines.gif \\ -virtual-pixel tile -fx 'u\[(floor((n-1)\*u)+1) % n\]' \\ dgrad\_dpat\_hlines.gif magick shadow.png dpat\_hlines.gif -channel A \\ -virtual-pixel tile -fx 'u\[floor((n-1)\*u)+1\].g' \\ shadow\_dpat\_hlines.gif [![[IM Output]](dpat_hlines_images.gif)](dpat_hlines_images.gif) [![[IM Output]](dgrad_dpat_hlines.gif)](dgrad_dpat_hlines.gif) [![[IM Output]](shadow.png)](shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](shadow_dpat_hlines.gif)](shadow_dpat_hlines.gif) As you can see it now consists of 9, 12x4 pixel images. It does not represent all the pixel patterns that you could have, but this enhances the effect of the lines. Also I doubled its height so as to jitter the gaps in the lines appropriately. Here is another example of using this dither pattern... magick -size 120x55 xc:white -draw 'fill #777 ellipse 50,43 30,5 0,360' \\ -motion-blur 0x15+180 -blur 0x2 sphere\_shadow.png magick sphere\_shadow.png dpat\_hlines.gif \\ -virtual-pixel tile -fx 'u\[(floor((n-1)\*u)+1) % n\]' \\ sphere\_shadow\_dither.gif magick sphere\_shadow\_dither.gif -fill red -stroke firebrick \\ -draw 'circle 35,25 35,5' sphere\_shadow\_hlines.gif [![[IM Output]](sphere_shadow.png)](sphere_shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](sphere_shadow_dither.gif)](sphere_shadow_dither.gif) ![==>](../img_www/right.gif) [![[IM Output]](sphere_shadow_hlines.gif)](sphere_shadow_hlines.gif) The next step is to magick this set of dither patterns into single threshold map image, rather than a set of multiple images. This is achieved by using some fancy image manipulations to merge all the images together.[![[IM Output]](od_hlines2x2a.gif)](od_hlines2x2a.gif) [![[IM Output]](shadow_hlines2x2a.gif)](shadow_hlines2x2a.gif) magick -size 1x10 gradient: -flip -crop 1x1 +repage -delete 0,-1 \\ -scale 12x4\\! null: \\( dpat\_hlines.gif -delete 0 \\) \\ -alpha off -compose CopyOpacity -layers Composite \\ -reverse -compose Over -flatten -alpha off dmap\_hlines.png [![[IM Output]](dmap_hlines_mag.png)](dmap_hlines.png) The value '`10`' is one more than the number of images in the dither pattern while "`-scale 12x4\!`" is the size of the dither patterns being converted into a threshold map. The result is a grey-scale map, with no pure black or white colors. The grey level used for a pixel means that if the color level is that grey value or higher, then that pixel should be turned on. That is, each grey level is the 'threshold' level at which the color value goes from black to white. If you like to look at the image in another way, dark pixels generally result in those pixels being turn on for more color levels. While light pixels are only turned on when the image color becomes very bright. This is almost a negation of what the image actually looks like, but if you think about it it does make sense. I also used a PNG image rather than a GIF image for the map as only one image needs to be saved, and more importantly, to attempt to preserve 16 bit quality levels for the threshold values. GIF can only handle 8 bit color levels. Now we can dither our images using, just a single image, and a much simpler threshold comparison of each pixel directly against the dithering threshold image (or map). magick gradient.png dmap\_hlines.png \\ -virtual-pixel tile -fx 'u>=v' dgrad\_dmap\_hlines.gif [![[IM Output]](dmap_hlines_mag.png)](dmap_hlines.png) ![==>](../img_www/right.gif) [![[IM Output]](dgrad_dmap_hlines.gif)](dgrad_dmap_hlines.gif) See how much simpler a threshold map is. You have only one image, and one direct comparison to do per pixel, for each channel that is being dithered. This makes dithering using a threshold map very very fast. Much faster that full color quantization. This simplicity is the why ImageMagick and most graphics software use a threshold map to hold various dither patterns. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The greater-then or equal ('`>=`') test was not added to the "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator, until IM version 6.2.9-2. If this is a problem, use the inverted test '`v dmap_hlines.pgm [![[IM Text]](dmap_hlines.pgm.gif)](dmap_hlines.pgm) All the numbers (other than the '`P2`' image magic identifier) in the above are the numbers needed to generate the appropriate 'threshold map', that you can add to your personal "`thresholds.xml`" file. For example here is the resulting threshold map entry created from the above. [![[IM Output]](tmap_hlines.txt.gif)](tmap_hlines.txt) And here is an example of using this threshold map. magick shadow.png -channel A -ordered-dither hlines shadow\_hlines.gif [![[IM Output]](shadow.png)](shadow.png) ![==>](../img_www/right.gif) [![[IM Output]](shadow_hlines.gif)](shadow_hlines.gif) And that is how you can generate a complex threshold map from a progression of images. ### Dithering with Symbol Patterns Now while you can use a single threshold map or threshold image, instead of a multi-image pattern set for most dithering operations, that does not mean that multi-image maps don't have there own uses. You can use a set of lookup image to tile multiple areas all at once, rather than one at a time. For example by scaling a simple image, and then replace each pixel in an image with a particular symbol. For example, here I take the very small 'eyes' image [![[IM Output]](../images/eyes.gif)](../images/eyes.gif) and replace the individual pixels with various symbols, to produce such a pattern for each pixel in the original image. montage dpat\_symbols.gif -geometry +5+0 \\ -tile x1 -background none -mattecolor blue -frame 3 \\ dpat\_syms\_images.gif magick eyes.gif -alpha off -colorspace sRGB -grayscale Average \\ -alpha off -scale 1600% -negate \\ dpat\_symbols.gif -virtual-pixel tile -fx 'u\[floor(15.9999\*u)+1\]' \\ eyes\_syms.gif [![[IM Output]](dpat_syms_images.gif)](dpat_syms_images.gif) [![[IM Output]](eyes_syms.gif)](eyes_syms.gif) The [montage](../montage/) is used to expand the multi-image GIF image so that you can see it's contents, without it being 'animated'. You can adjust which "`[-grayscale](https://imagemagick.org/script/command-line-options.php?#grayscale) `" intensity method you want to use, from the normal '`Rec709Luminance`' to a darker '`Rec709Luma`', or use a '`average`' of either a non-linear '`sRGB` colorspace, or linear '`RGB`' colorspace. You can even adjust the "`[-gamma](https://imagemagick.org/script/command-line-options.php?#gamma) `" scaling of the values to get the best spread of colors. There are a lot of posibilities, and what is good depends more on your symbol arrangement than actual method chosen. The key with the above is to somehow ensure each color in the input image produces an unqiue symbol, and that can be very tricky to achieve. This example can be used for creating cross-stitch or knitting guides that hobbists can follow, generating larger scale artwork from smaller comuter images. You can use this technique to tile greyscale images with a set of tiling color images. The result is a bit like the landscape maps seen in many old computer war games. montage dpat\_map.gif -geometry +5+0 -tile x1 -background none \\ dpat\_map\_images.gif magick -seed 100 \\ -size 200x200 plasma:'gray(50%)-gray(50%)' -blur 0x15 \\ -channel G -auto-level +channel -set colorspace sRGB \\ dpat\_map.gif -virtual-pixel tile -fx 'u\[floor(5.999\*u.g)+1\]' \\ map.gif [![[IM Output]](dpat_map_images.gif)](dpat_map_images.gif) [![[IM Output]](map.gif)](MAP.GIF) Note that I needed to ensure that IM thought of the grayscale image as being already in the final sRGB colorspace (as the tile images are), even though it is actually linear RGB data that is being used for FX index lookups. Without this the resulting 'map' is skewed toward wooded landscapes, with little chance of water areas. As you can see any set of images can be used for the tiles, the images don't even need to line up with each other, or even be the same size tile. Of course if the tiles are the same size and are closely related to each other, as in the case of the 3 blue 'sea' tiles, the tiled pattern can 'flow' from one tiled area into another. By replacing the tile with images of numbers you can also generate a sort of paint by numbers guide. However some extra processing may be needed to border the different areas. This is left as an exercise, mail your solutions to me, and you can have your name in IM examples as the author for this technique. * * * Ordered Dither Random notes and Future possibilities ---------------------------------------------------- **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** ### Ordered Dither with small numbers of colors. When using a small number of colors for a small image a pseudo-random dither like IM's hilbert curve error correction dither, or even a simpler Floyd-Steinberg error correction dither (see [Error Correction Dither](#dither_error) above ) produces a horrible looking result. Ideally an [Ordered Dither](#ordered-dither) should be used with low color and small icon like images to produce a much better looking result. However at the moment ordered dither in IM can only used 'fixed' mathematically generated color tables, and not just a collection of 'best' colors. ### Ordered Dither with a map of any colors There is some algorithm that will allow you to use a set of specific colors for ordered dithering. Basically by adding the 'pseudo-colors' that an ordered dither algorithm can generate (which could involve three color dithering), to the given color map, to 'fill it out'. You can then 'map' the individual pixels of an image to this 'expanded color map'. From that initial mapping to a specific pseudo-color) the actual color can be picked from the threshold map that generates that pseudo-color, and thus order dither areas of that color, and thus the whole image to a given set of colors. Because of my background in icons, and now GIF animations, I definitely would like to see an any color ordered dither implemented, but I have yet to find a practical reference to how to do ordered dithers with a fixed set of colors. * * * --- # Unknown 16: ( 0,128, 0) #008000 green 422: ( 0,255,255) #00FFFF cyan 126: ( 46,139, 87) #2E8B57 SeaGreen 381: ( 50,205, 50) #32CD32 LimeGreen 59: (160, 82, 45) #A0522D sienna 20: (255,255, 0) #FFFF00 yellow --- # Unknown \# ImageMagick pixel enumeration: 6,1,65535,srgb 0,0: (41120,21074,11565) #A0A052522D2D sienna 1,0: ( 0,32896, 0) #000080800000 green 2,0: (12850,52685,12850) #3232CDCD3232 LimeGreen 3,0: (11822,35723,22359) #2E2E8B8B5757 SeaGreen 4,0: (65535,65535, 0) #FFFFFFFF0000 yellow 5,0: ( 0,65535,65535) #0000FFFFFFFF cyan --- # Unknown \# ImageMagick pixel enumeration: 1,1,255,srgb 0,0: (232, 54, 58) #E8363A srgb(232,54,58) --- # Unknown yellow sun pixels = 20 --- # Unknown \# ImageMagick pixel enumeration: 1,1,65535,rgb 0,0: ( 0, 0,32896) #000000008080 navy --- # Examples of ImageMagick Usage Examples of ImageMagick Usage ImageMagick Version 7 ===================================================== These web pages presents a set of examples using [ImageMagick](https://imagemagick.org/) ("IM," for short), version 7, from the command line. However, they often have direct analogs in the legacy release of ImageMagick, [version 6](https://legacy.imagemagick.org) . They also illustrate what can be done using the ImageMagick Application Programming Interface (API). As such, these pages should be the first stop for IM users after reading the terse [Command Line (CLI) Option manuals](https://imagemagick.org/script/command-line-options.php) . Often, the same questions of "_How do I..._" gets asked, over and over again on the network. The examples in these web pages, I hope, will answer most of the common "how-to" questions that arise.  [![[IM Logo]](images/logo.gif)](https://imagemagick.org/Usage/) [![[IM Version]](version.gif)](https://imagemagick.org/) [Download Page](https://imagemagick.org/script/download.php) ,  [CentOS RPM](https://imagemagick.org/download/linux/CentOS/x86_64/) , [Linux SRPM](https://imagemagick.org/download/linux/SRPMS/) ,  [Beta Release](https://imagemagick.org/download/beta/) [Discussion Server](https://github.com/ImageMagick/ImageMagick/discussions) Other related sites... [Fred's ImageMagick Scripts](http://www.fmwconcepts.com/imagemagick/) [RubbleWebs, PHP using IM CLI](http://www.rubblewebs.co.uk/imagemagick/imagemagick.php) [Snibgo's ImageMagick pages](https://im.snibgo.com/)   [![](img_www/granitesm_up.gif) Main ImageMagick Web Site](https://imagemagick.org/) | | | | --- | --- | | | ![ ----- ](img_www/speech_start.gif)   **Practical Examples**   ![ ----- ](img_www/speech_start.gif) ![ ](img_www/space.gif) | | [![](img_www/granitesm_right.gif)](basics/) | [Basic Usage](basics/)
![](img_www/space.gif) Basic command and image handling | | [![](img_www/granitesm_right.gif)](files/) | [Image File Handling](files/)
![](img_www/space.gif) Reading and writing images | | [![](img_www/granitesm_right.gif)](formats/) | [Common Image Formats](formats/)
![](img_www/space.gif) Handling GIF, JPEG, and PNG images | | [![](img_www/granitesm_right.gif)](text/) | [Text to Image Handling](text/)
![](img_www/space.gif) Converting text into images | | [![](img_www/granitesm_right.gif)](fonts/) | [Compound Font Effects](fonts/)
![](img_www/space.gif) Font drawing styles and techniques | | [![](img_www/granitesm_right.gif)](annotating/) | [Annotating Images](annotating/)
![](img_www/space.gif) Labeling and overlaying images | | [![](img_www/granitesm_right.gif)](thumbnails/) | [Thumbnails and Framing](thumbnails/)
![](img_www/space.gif) Small reference images of large photos | | [![](img_www/granitesm_right.gif)](photos/) | [Photo Handling](photos/)
![](img_www/space.gif) Modifying photographs | | [![](img_www/granitesm_right.gif)](lens/) | [Lens Correction](lens/)
![](img_www/space.gif) Correcting photo distortions | | [![](img_www/granitesm_right.gif)](montage/) | [Montage, Arrays of Images](montage/)
![](img_www/space.gif) Image indexes and arrays | | [![](img_www/granitesm_right.gif)](layers/) | [Layers of Multiple Images](layers/)
![](img_www/space.gif) Combining multiple images together | | [![](img_www/granitesm_right.gif)](anim_basics/) | [Animation Basics](anim_basics/)
![](img_www/space.gif) Creation and study of animations | | [![](img_www/granitesm_right.gif)](anim_opt/) | [Animation Optimization](anim_opt/)
![](img_www/space.gif) Making GIF animations smaller | | [![](img_www/granitesm_right.gif)](anim_mods/) | [Animation Modifications](anim_mods/)
![](img_www/space.gif) Changing and merging animations | | [![](img_www/granitesm_right.gif)](video/) | [Video Handling](video/)
![](img_www/space.gif) Handling real life video images | | [![](img_www/granitesm_right.gif)](compare/) | [Image Comparing](compare/)
![](img_www/space.gif) Comparing two or more images | | [![](img_www/granitesm_right.gif)](advanced/) | [Advanced Techniques](advanced/)
![](img_www/space.gif) Complex manipulations of images | | [![](img_www/granitesm_right.gif)](backgrounds/) | [Background Examples](backgrounds/)
![](img_www/space.gif) Examples of creating random backgrounds | | | | [![](img_www/granitesm_right.gif)](repositories.html) | [**Repositories Links**](repositories.html)
![](img_www/space.gif) Links to other IM scripts and info | | [![](img_www/granitesm_right.gif)](reference.html) | [**Reference Index**](reference.html)
![](img_www/space.gif) Quick index for specific options | | [![](img_www/granitesm_right.gif)](scripts/) | [**Support Scripts**](scripts/)
![](img_www/space.gif) Shell scripts used by examples | | | | | --- | --- | | | ![ ----- ](img_www/speech_start.gif)   **Basic Techniques**   ![ ----- ](img_www/speech_start.gif) ![ ](img_www/space.gif) | | [![](img_www/granitesm_right.gif)](canvas/) | [Canvas Creation](canvas/)
![](img_www/space.gif) Creating canvas and background images | | [![](img_www/granitesm_right.gif)](color_basics/) | [Color Basics and Channels](color_basics/)
![](img_www/space.gif) Low level color handling | | [![](img_www/granitesm_right.gif)](color_mods/) | [Color Modifications](color_mods/)
![](img_www/space.gif) General color changes | | [![](img_www/granitesm_right.gif)](masking/) | [Masking and Background Removal](masking/)
![](img_www/space.gif) Alpha channel, and transparency handling | | [![](img_www/granitesm_right.gif)](quantize/) | [Color Quantization and Dithering](quantize/)
![](img_www/space.gif) Reducing the number of colors | | [![](img_www/granitesm_right.gif)](crop/) | [Cutting and Bordering](crop/)
![](img_www/space.gif) Slicing, dicing, framing, trimming | | [![](img_www/granitesm_right.gif)](resize/) | [Resizing or Scaling](resize/)
![](img_www/space.gif) Enlarging and shrinking images | | [![](img_www/granitesm_right.gif)](filter/) | [Resampling Filters](filter/)
![](img_www/space.gif) Controlling image resizing | | [![](img_www/granitesm_right.gif)](compose/) | [Compositing Images](compose/)
![](img_www/space.gif) Overlaying and merging two images | | [![](img_www/granitesm_right.gif)](draw/) | [Drawing on Images](draw/)
![](img_www/space.gif) Vector graphics, MVG and SVG images | | [![](img_www/granitesm_right.gif)](warping/) | [Simple Image Warping](warping/)
![](img_www/space.gif) Flipping, rotating, twisting | | [![](img_www/granitesm_right.gif)](distorts/) | [Distorting Images](distorts/)
![](img_www/space.gif) Carnival house of mirrors | | [![](img_www/granitesm_right.gif)](transform/) | [Image Transformations](transform/)
![](img_www/space.gif) Drastic changes to the look of an image | | [![](img_www/granitesm_right.gif)](mapping/) | [Image Mapping Effects](mapping/)
![](img_www/space.gif) Lens, glass and ripple effects | | [![](img_www/granitesm_right.gif)](blur/) | [Blurring and Sharpening Images](blur/)
![](img_www/space.gif) Blurring, sharpening and shadows | | [![](img_www/granitesm_right.gif)](morphology/) | [Morphology of Shapes](morphology/)
![](img_www/space.gif) Using pixel neighbourhoods | | [![](img_www/granitesm_right.gif)](convolve/) | [Convolution of Images](convolve/)
![](img_www/space.gif) Weighted averaged neighbourhoods | | [![](img_www/granitesm_right.gif)](fourier/) | [Fourier Transforms](fourier/)
![](img_www/space.gif) Modifying images in the frequency domain | | [![](img_www/granitesm_right.gif)](antialiasing/) | [Anti-Aliasing](antialiasing/)
![](img_www/space.gif) Anti-aliasing effects and problems | | [![](img_www/granitesm_right.gif)](misc/) | [Miscellaneous](misc/)
![](img_www/space.gif) Bits and pieces | | [![](img_www/granitesm_right.gif)](api/) | [APIs, Scripting, Building](api/)
![](img_www/space.gif) Usage in other environments | | [![](img_www/granitesm_right.gif)](windows/) | [Usage under Windows](windows/)
![](img_www/space.gif) IM on Windows PC | | [![](img_www/granitesm_right.gif)](bugs/) | [Development and Bugs](bugs/)
![](img_www/space.gif) Development proposals and bugs, new and old | **Legend for symbols used within example pages...** | | | | | | | | | | --- | --- | --- | --- | --- | --- | --- | --- | | ![](img_www/reminder.gif)![](img_www/space.gif) | Hint, tips or extra info | | ![](img_www/expert.gif)![](img_www/space.gif) | For more advanced users | | ![](img_www/warning.gif)![](img_www/space.gif) | Older version warnings | **Test Image Storage Directories...**   [Small Images](images/) ([image display](images/INDEX.html) ),     [Photographs](img_photos/) ([fancy index](img_photos/INDEX.html) ). * * * ImageMagick Examples - Introductory Notes ----------------------------------------- ### What is ImageMagick? A No-Holds-Barred Summary [ImageMagick](https://imagemagick.org/script/index.php) is designed for batch processing of images. That is, it allows you to combine image processing operations in a script (shell, DOS, Perl, PHP, etc.) so the operations can be applied to many images, or as a sub-system of some other tool, such as a Web application, video processing tool, panorama generator, etc. _It is not a GUI image editor_. ImageMagick is, first of all, an image-to-image converter. That is what it was originally designed to do. That is, it will convert an image in just about any image format (tell us if it can't) to any other image format. But it is also a library of _image processing algorithms_. These can be access via the command line and shell/DOS scripts (which these example pages demonstrate), or via a large number of programming languages, such as C, C++, Perl, Ruby, PHP, etc. See: [ImageMagick APIs](https://imagemagick.org/script/develop.php) . Speed was never a major feature of IM, which places more emphasis on the quality of the images it generates. That is not to say that it can't transform images in a reasonable amount of time. It's just not blindingly fast. Because of this, IM can be slow to perform certain processing operations, especially when attempting to compress images into image formats that have limited capabilities. ImageMagick concerns itself mainly with images in the form of a _rectangular array of pixels_, commonly called a "raster." It will handle "vector" image formats like Postscript or PDF, but at the cost of converting those images into a raster when loading them, and generating a vector image wrapper around the raster when saving it. As a result, vector images are often processed badly when using the default settings. However, specific options can be used to improve this situation. See: [A word about vector image formats](formats/#vector) . ### About These Examples of ImageMagick Usage These pages were developed from, and are a continuation of, my [Collection of ImageMagick Hints and Tips](https://antofthy.gitlab.io/info/graphics/imagemagick.txt) page I first started in 1993, and placed on the new fangled world-wide-web making its appearance around the same time. Information on many aspects of IM, and notes not included in these pages, are still present in that document. However, while the present pages were designed for you to look at, the hints and tips document was only for my own edification. So, it may be vague or chaotic in places. You are welcome to look at it, learn, and make comments on it. Other examples were grabbed or developed from answers to users' questions on he [IM Forums](https://magick.imagemagick.org/viewforum.php?f=1) , or contributed to me as solutions to various problems. I look forward to suggestions and e-mail from other IM users. Such e-mail generally results in improvements and expansions to these example pages. ### Command Line Environments All examples are written for use on UNIX, and specifically GNU/Linux systems, using BASH scripting. As a consequence, some examples use shell 'for-do' loops. Most examples use a backslash '`\`' at the end of a line to continue that command on the next line. The longer commands are broken into separate lines to try to further highlight the steps being applied. However, you can still use these examples from **PC Windows batch scripts**, with some changes to the handling of certain characters. With some slight adaptation, the examples can also be run directly from '`system`' calls in **PHP scripts**. See [Windows Usage](windows/) and [APIs and Scripting](api/index.html) for more information on using the ImageMagick commands in these alternative environments. Contributions and test examples are welcome. ### PerlMagick, and Other APIs It should also be possible to adapt any of these examples to use the IM API from languages such as Perl, C, C++, Ruby, PHP, and so on. I recommend trying things out on the command line first, until you get them right, and then converting the operations to the specific API you are using. Although the situation has improved enormously with IM version 6, the command line really only deals with a single image sequence at any one time. However, APIs do not have this limitation, and allow you to manipulate multiple image sequences, separately or together, to perform more complex operations. This ability makes it simpler to implement these examples using the IM API, and removes the need to save images as temporary files, as many of the command line examples require. When using an API, only permanent and semi-permanent images need be saved to disk. Basically, let the example pages give you a start, to let you see what is possible with ImageMagick. Then, formulate what you want to do on the command line, before coding the operations in scripts and API code, where it is harder to make extensive changes. I also recommend that you comment your API code, **heavily**, adding the command line equivalents to what you are trying to do, if possible. That way, you can check and compare the results against those using the command line. This lets you debug problems that you may come across later, especially as improvements are made to image processing in the Core ImageMagick Library. ### Downloading Input Images and Results As much as possible, I try to use images built-into IM (such as "`logo:`" or "`rose:`") as input images for IM example commands, or to generate input images using IM commands. I also often re-use the output of previous commands in later examples. Because of this, you usually don't need to download any 'test' images in order to try out the examples yourself. However, such generated or built-in images are not always convenient. So, when I do use an external image, I tend to re-use that input image, or the results of previous examples, for later examples in that section. Sometimes the original source image will be displayed or for larger images a link to the source image is provided. More commonly only the final resulting image will be shown, as the input is well known or obvious. Almost all the IM example commands shown are executed in the same web directory in which they appear. That is, the command you see is the command that was actually used to generate the image. Because of this you can modify the page's URL to download or view the input image(s) used by an example. Extra copies of the external source images have also been placed in the "[images](images/) " and "[img\_photos](img_photos/) " sub-directories. See also the example of a [Fancy Photo Index](img_photos/INDEX.html) of those images. If text output or image information is produced by an example, it is saved to a text file, and an image of it is generated for display on the Web page. Selecting the text output image will link you to a copy of the actual text output by the command. In all these examples, selecting the output image should let you download the image which was actually created by the example command. But be warned, not all browsers understand all image formats used. ### External Image Sources By the way, most of the source images used in these examples come from [Anthony's Icon Library](https://antofthy.gitlab.io/icons/) , particularly the [background tiles](https://antofthy.gitlab.io/icons/desc/cl-bgnd/Icons.html) , [large clip-art](https://antofthy.gitlab.io/icons/large/Icons.html) , and [dragons](https://antofthy.gitlab.io/icons/dragons/Icons.html) sections of the library. (I like dragons!). ASIDE: these pages may be offline as the web site slowly moves to a new server. This library actually predates the WWW. I created it in 1991, due to the lack of good, clean iconic images for use on the X Window System. The advent of the WWW has of course changed this, but my original library still exists and remains available as a source of images, even though it is not actively growing. Some specific images, and larger images, are contributed by the authors of specific examples. The authors of such examples are listed in the contributed section, or at the bottom of the page. If you are looking for a specific image, I recommend using [Google Image Search](http://images.google.com/imghp) (or similar) to find something appropriate. You can, of course, convert or resize such images using IM for your own purposes. However, you should be careful about copyright if you plan to use such images commercially. ### PNG Images on Web Pages [![[IM Output]](images/test.png)](images/test.png) In many examples, I use an image in PNG format, such as that shown to the right of this text. The PNG image format supports images with semi-transparent pixels, a feature few other image formats provide. It is also a very well-understood image format and, as such, is usable by most of today's image programs and Web browsers. Some Web browsers, however, do NOT handle transparent PNG images correctly (most notably Microsoft Internet Explorer v6). Because of this, I generally use the JPEG and GIF formats for images on the Web, and only use the PNG format when generating images with semi-transparent pixels, or when exact colors are needed for later examples. To allow IE v6 browsers to display PNG images, I use a special 'style sheet' using complex JavaScript. For information on this, see [PNG with transparency for IE](http://www.ict.griffith.edu.au/anthony/wwwlab/pngtest/) . Technically, this is only problem with IE, not ImageMagick. ### Displaying Images on Your Screen Display problems can also occur when displaying images on-screen. Because of this, I recommend using a command like the following to tile a '`checkerboard`' pattern underneath the image, to highlight any transparent or semi-transparent pixels in it. magick composite -compose Dst\_Over -tile pattern:checkerboard image.png x: [![[IM Output]](test_undertile.jpg)](test_undertile.jpg) The image displayed in the above example is a special PNG-format [test image](images/test.png) , which was generated using a shell script. Normally, the command would output the results to your display, not onto a Web page like this. If you look carefully, you can see the checkerboard pattern though the semi-transparent colors. However, the image, as a whole, is fully opaque. So, this technique should work on all displays, Web browsers, and image viewers. As of IM v6.0.2, the "`magick display`" program performs something like this automatically. However, it does not seem to handle images using color tables (i.e., GIF) in this way. Using the "`x:`" output image format (as above) causes an image to be displayed directly to the screen, without having to save it. See [Show Output Display](files/#show) for more information. ### Font Usage The fonts I use in these examples are from a small collection of TrueType fonts I have found over the years, and saved for my own use. Some of these are under copyright, so I cannot publish them online. You are, however, welcome to substitute other fonts that you have available. The examples should work (perhaps with some changes to image size) with any appropriate font you have available on your system. Microsoft "Arial" font, or even "Times-BoldItalic", should work on most systems. To see what fonts are currently available to your version of IM, run the following command... magick -list font WARNING: If the font requested is not found, ImageMagick used to silently substitute a default font, typically Arial or Times. It still does this, but a warning is now given. So, test the font beforehand, to make sure that it is the one you want, and not the default font. On my Linux system, I use a special Perl script, "`[**imagick_type_gen**](scripts/imagick_type_gen) `", to generate a file, "`type.xml`", saved in the "`.magick`" sub-directory of my home directory. ImageMagick uses that file, which contains a font list in XML format, to find fonts. The script "`locate`"s (run "`updatedb`" first, if you have just added new fonts), and describes all the fonts available on my system. With this setup, I only need to specify the name of the font I want to use, and not the full path to a specific font file. For example... # Instead of using the command... magick -font $HOME/lib/font/truetype/favorite/candice.ttf \ -pointsize 72 label:Anthony anthony.gif # I can use the simpler font label... magick -font Candice -pointsize 72 label:Anthony anthony.gif | | | | --- | --- | | ![](img_www/warning.gif)![](img_www/space.gif) | _Before IM v6.1.2-3, the "`type.xml`" file was named "`type.mgk`". If you are using an earlier version of IM._ | The fonts used in these IM examples are listed in a [Montage of Example Fonts Example](montage/#fonts) . My personal favorite is Candice, so it gets used quite a bit. | | | | --- | --- | | ![](img_www/reminder.gif)![](img_www/space.gif) | _If you also like the '`Candice`' font, or any of the other fonts I use, grab them from [Free Fonts](http://www.webpagepublicity.com/free-fonts.html)
or [1001 Fonts .com](http://www.1001fonts.com/)
._ | ### Example Page Updates These example pages are in an on-going cycle of improvement. Generally, I find I stop adding to these pages for long periods of time, when my interests become focused on other things. Often these examples are re-built using the latest beta release of IM, allowing me to see changes and bugs that may appear in each version of IM, before it is generally released. However, the example images shown are what the given IM command produces on **my** system. If you get something different, your IM is probably a much older version (with old bugs), or is not correctly installed. Note that e-mailing me, or discussing some aspect of ImageMagick on the [discussions forum](https://github.com/ImageMagick/ImageMagick/discussions) will generally result in new examples, or whole new sections, being added to these examples. The more discussion there is, the better the examples become. If you are doing anything interesting with IM, please share, and allow me to provide examples of your technique to the rest of the IM community. Some of the biggest advances in IM usage have come from users just like you. ### Special Thanks A special thank you goes to Cristy, who has tirelessly spent months, upgrading, bug-fixing, and putting up with my off-the-wall suggestions... especially with regards to my major suggestions for the command line processing, parenthesis, image sequence operators, and GIF animation processing. He has done a marvelous job making Version 7 the best and most advanced command line image processing program available. While most users will not show appreciation for that, I certainly do appreciate the effort he has put into IM. I also want to thank Gabe Schaffer, who has been most helpful in discussions involving the JPEG format and library, affine matrix operators, and [Magick Vector Graphics](https://imagemagick.org/script/magick-vector-graphics.php) in general. And to Glenn Randers-Pehrson, who wrote the PNG coder module and had an interest in Color Quantization and Dithering. He was the first to add 'halftone' dithering to IM, which I later revised and extended further, to added new dithers to the ordered dither configuration file. And finally, I want to thank the huge number of people with problems, suggestions, and solutions, who generally lurk on the [IM User Forum](https://magick.imagemagick.org/viewforum.php?f=1) . Many now have their names as contributors of ideas and suggestions throughout IM Examples. I also want to thank the people who regularly answer questions on the forums, such as '[Bonzo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=6256) ', and his web site [RubbleWebs](http://www.rubblewebs.co.uk/imagemagick/imagemagick.php) , detailing use of IM commands from PHP scripts. Also '[scri8e](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=143) ' and his Web site, [Moons Stars](http://www.scri8e.com/stars/) , for glitter and star handling. Also a thank you goes to Pete '[el\_supremo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=3499) ' A special thanks goes to [Fred Weinhaus](http://www.fmwconcepts.com/fmw/fmw.html) , a researcher from the early days of image processing, who was a major help in the initial implementation of the [General Image Distortion Operator](distorts/#distort) . You can see Fred's ImageMagick scripts on [Fred's ImageMagick Site](http://www.fmwconcepts.com/imagemagick/) , often as a proof of concept for future IM additions. Also to Nicolas Robidoux, an expert in digital image processing, for reworking the [Elliptical Weighted Average Resampling](distorts/#area_resample) , which vastly improves the output of [General Image Distortion](distorts/#distort) . And finally to the many users of ImageMagick who, had allowed others to see the IM commands they use as part of some project, either on the forums, or on the web. You are all to be commended on your willingness and openness to share your findings. Well enough "Yadda, yadda, yadda."   Go look at some of the examples. * * * --- # Unknown \# ImageMagick pixel enumeration: 1,1,65535,rgb 0,0: ( 0, 0,65535) #00000000FFFF blue --- # Unknown None FloydSteinberg Riemersma --- # Unknown Threshold Maps for Ordered Dither Operations PATH: /etc/ImageMagick/thresholds.xml Map Alias Description ---------------------------------------------------- threshold 1x1 Threshold 1x1 (non-dither) checks 2x1 Checkerboard 2x1 (dither) o2x2 2x2 Ordered 2x2 (dispersed) o3x3 3x3 Ordered 3x3 (dispersed) o4x4 4x4 Ordered 4x4 (dispersed) o8x8 8x8 Ordered 8x8 (dispersed) h4x4a 4x1 Halftone 4x4 (angled) h6x6a 6x1 Halftone 6x6 (angled) h8x8a 8x1 Halftone 8x8 (angled) h4x4o Halftone 4x4 (orthogonal) h6x6o Halftone 6x6 (orthogonal) h8x8o Halftone 8x8 (orthogonal) h16x16o Halftone 16x16 (orthogonal) c5x5b c5x5 Circles 5x5 (black) c5x5w Circles 5x5 (white) c6x6b c6x6 Circles 6x6 (black) c6x6w Circles 6x6 (white) c7x7b c7x7 Circles 7x7 (black) c7x7w Circles 7x7 (white) PATH: /home/anthony/.magick/thresholds.xml Map Alias Description ---------------------------------------------------- diag5x5 diag Simple Diagonal Line Dither hlines2x2 hlines2 Horizontal Lines 2x2 hlines2x2a Horizontal Lines 2x2 (bounds adjusted) hlines6x4 Horizontal Lines 6x4 hlines12x4 hlines Horizontal Lines 12x4 --- # Unknown Simple Diagonal Line Dither 4 2 1 3 5 2 1 3 5 4 1 3 5 4 2 3 5 4 2 1 5 4 2 1 3 --- # Unknown Horizontal Lines 2x2 (bounds adjusted) 3 3 9 9 --- # Unknown P2 12 4 9 7 8 8 8 8 7 6 6 5 5 5 6 2 1 1 1 1 2 3 4 4 4 3 3 6 6 5 5 5 6 7 8 8 8 8 7 3 4 4 4 3 3 2 1 1 1 1 2 --- # Unknown Horizontal Lines 12x4 7 8 8 8 8 7 6 6 5 5 5 6 2 1 1 1 1 2 3 4 4 4 3 3 6 6 5 5 5 6 7 8 8 8 8 7 3 4 4 4 3 3 2 1 1 1 1 2 --- # Ordered Dither Upgrade -- ImageMagick Examples ImageMagick Examples -- ![](../../img_www/space.gif) Ordered Dither Upgrade ============================================================================= **Index** [![](../../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../../) [![](../../img_www/granitesm_left.gif) Known and Fixed Bugs Index](../) The following is a demonstration before and after results and IM Examples development examples of a new or exapnded aspect of ImageMagick. During the creation of the IM Examples for [Quantization and Dithering](../../quantize/) I saw an oppertunity to expand the ordered dither functionality to not only provide more ordered dither patterns, but also expand it to provide an ordered dithered posterization functionality. That is, allow not only bitmap dithering, but dithering between multiple color levels as per the "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operator. See [Posterize, recolor using primary colors](../../quantize/#posterize) for examples. * * * Original Ordered Dither Threshold Maps -------------------------------------- _This is section is a reference and will not be updated._ This is what the IM "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator provided before the expandion of this operators functionality. magick logo: -resize 40% -crop 100x100+105+50\\! logo.png magick logo.png -ordered-dither 2x2 logo\_2x2.gif magick logo.png -ordered-dither 3x3 logo\_3x3.gif magick logo.png -ordered-dither 4x4 logo\_4x4.gif [![[IM Output]](logo.png)](logo.png) ![==>](../../img_www/right.gif) [![[IM Output]](logo_2x2.gif)](logo_2x2.gif) [![[IM Output]](logo_3x3.gif)](logo_3x3.gif) [![[IM Output]](logo_4x4.gif)](logo_4x4.gif) Note that ordered dither was able to, by default so a level 2 posterization of images. This will be the last time I look at this. Notice that it only provided these three ordered dither patterns, and these patterns had to be specified as numbers, representing the patterns tile size. Lets look at these patterns using gradients. magick gradient:'\[640x1\]' -scale 640x30\\! -negate gradient.png magick gradient.png -ordered-dither 2x2 orig\_2x2.gif magick gradient.png -ordered-dither 3x3 orig\_3x3.gif magick gradient.png -ordered-dither 4x4 orig\_4x4.gif magick gradient.png -ordered-dither 8x8 orig\_8x8.gif [![[IM Output]](orig_2x2.gif)](orig_2x2.gif) [![[IM Output]](orig_3x3.gif)](orig_3x3.gif) [![[IM Output]](orig_4x4.gif)](orig_4x4.gif) [![[IM Output]](orig_8x8.gif)](orig_8x8.gif) The extra '`8x8`' ordered dither pattern was an existing ordered dither function that was only linked into the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator with IM v6.2.9-2, under my suggestion. In version IM v6.2.8-6 some digital-halftone dither patterns was added by Glenn Randers-Pehrson. magick gradient.png -ordered-dither 2x1 orig\_2x1.gif magick gradient.png -ordered-dither 4x1 orig\_4x1.gif magick gradient.png -ordered-dither 6x1 orig\_6x1.gif magick gradient.png -ordered-dither 8x1 orig\_8x1.gif [![[IM Output]](orig_2x1.gif)](orig_2x1.gif) [![[IM Output]](orig_4x1.gif)](orig_4x1.gif) [![[IM Output]](orig_6x1.gif)](orig_6x1.gif) [![[IM Output]](orig_8x1.gif)](orig_8x1.gif) Note the 'hack'-like nature using a '`x1`' number to allow the addition of these dithering patterns. Also note that at this time "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" and "`[-random-dither](https://imagemagick.org/script/command-line-options.php?#random-dither) `" operators were aliases for each other, which is why this restriction existed. But it also created a horrible 'fall-back' situation, in that if the arguments for "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" was wrong, IM would do a "`[-random-dither](https://imagemagick.org/script/command-line-options.php?#random-dither) `" using a very bad set of argument, rather than give the user an error. * * * Ordered Dither Threshold Maps Expansion (and naming) ---------------------------------------------------- From IM v6.2.9-7, the above changed, to allow the use of more symbolic selection of the ordered dither threshold maps, with IM returning an error if no map was selected rather than falling back to the disasterious "`[-random-dither](https://imagemagick.org/script/command-line-options.php?#random-dither) `" operator. First of all, all the threshold maps used for the ordered dither patterns were checked and updated to produce a better result for the specified style. For example compare these new "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" threshold map results... magick logo.png -ordered-dither o3x3 logo\_o3x3.gif magick logo.png -ordered-dither o4x4 logo\_o4x4.gif [![[IM Output]](logo_o3x3.gif)](logo_o3x3.gif) [![[IM Output]](logo_o4x4.gif)](logo_o4x4.gif) ...to what the previous threshold maps produced... [![[IM Output]](logo_3x3.gif)](logo_3x3.gif) [![[IM Output]](logo_4x4.gif)](logo_4x4.gif) As you can see the re-developed and checked threshold maps produce a distictly better diffused pixel dither pattern. And here is the new expanded set of built-in ordered dither threshold map arguments, and the new names for selecting the threshold map to use. # Threshold Non-Dither / Minimal Checkerboard Dither magick gradient.png -ordered-dither threshold od\_threshold.gif magick gradient.png -ordered-dither checks od\_checks.gif # Diffused Pixel Dither magick gradient.png -ordered-dither o2x2 od\_o2x2.gif magick gradient.png -ordered-dither o3x3 od\_o3x3.gif magick gradient.png -ordered-dither o4x4 od\_o4x4.gif magick gradient.png -ordered-dither o8x8 od\_o8x8.gif # Halftone Screen (45 degree angle) magick gradient.png -ordered-dither h4x4a od\_h4x4a.gif magick gradient.png -ordered-dither h6x6a od\_h6x6a.gif magick gradient.png -ordered-dither h8x8a od\_h8x8a.gif # Halftone Screen (orthogonal) magick gradient.png -ordered-dither h4x4o od\_h4x4o.gif magick gradient.png -ordered-dither h6x6o od\_h6x6o.gif magick gradient.png -ordered-dither h8x8o od\_h8x8o.gif magick gradient.png -ordered-dither h16x16o od\_h16x16o.gif [![[IM Output]](od_threshold.gif)](od_threshold.gif) [![[IM Output]](od_checks.gif)](od_checks.gif) * * * [![[IM Output]](od_o2x2.gif)](od_o2x2.gif) [![[IM Output]](od_o3x3.gif)](od_o3x3.gif) [![[IM Output]](od_o4x4.gif)](od_o4x4.gif) [![[IM Output]](od_o8x8.gif)](od_o8x8.gif) * * * [![[IM Output]](od_h4x4a.gif)](od_h4x4a.gif) [![[IM Output]](od_h6x6a.gif)](od_h6x6a.gif) [![[IM Output]](od_h8x8a.gif)](od_h8x8a.gif) * * * [![[IM Output]](od_h4x4o.gif)](od_h4x4o.gif) [![[IM Output]](od_h6x6o.gif)](od_h6x6o.gif) [![[IM Output]](od_h8x8o.gif)](od_h8x8o.gif) [![[IM Output]](od_h16x16o.gif)](od_h16x16o.gif) That is, a total of 13 different types of threshold maps. Internally the code was designed to allow simple addition of more such maps in the future, and the development of the use of XML data file to read in such maps in a later stage. Note the "`checks`" used to be called "`2x1`", as a halftone 2x2 pattern, however it is more than that. It represents the most minimal dither pattern posible, for all ordered dither patterns, one that only adds a single dither pattern between any two colors. The "`threshold`" pattern is supplied as an equivelent to using a undithered "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operator, as well as a test map on the posterization aspects of the new "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" function. (See next section) As part of backward compatibility, all the old '`_{number}_x_{number}_`' arguments have been made aliases to the appropriate 'named' threshold map above. They are now depreciated, but will always remain. * * * Posterized Ordered Dither Expansion ----------------------------------- The above consolidation of "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" code and the addition of the extra threshold mappings was not the primary purpose of the re-development of the operator. With some initial 'proof of concept' work using the "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator (see below), I wanted to provide a ordered dithering between multiple levels of colors (as per the "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `"). WHY? Because then you can generate a more deterministic dithering of images than you can achieve with 'error correction dithering'. This is especially important for color reductions involving animations as you will not get problems from color differences between frames. The posterization level is added to "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" argument using commas, making this addition backward compatible with previous usage of the operator. For example 'checks,6' will use a classic "web-safe" color map (see the "netscape:" built-in), but add one extra pseudo-level of color dithering the 'checks' dither map between each level. In other words even though only 6 levels of color per channel is being used (producing 6^3 or 216 colors) the single dither pattern between levels increases the dither to and effective 11 levels (producing and effective 11^3 or 1331 colors). In this I plan to implement the extra levels with the following proprieties. * What channels are operated on is controlled by the "-channels" setting. * A single number is for all channels. EG: '6' for the "web-safe colormap". * Multiple numbers allows you to use different level counts for each channel. EG: '8,8,4' will implement a '332' ordered dithered colormap. * If no numbers are given, fall back to a 2 level bitmap dither. * A value of zero disables posterization of that color channel. For example, here is the same gray scale gradient first dithered using a 6 grey levels. # dithering between 6 grey levels magick gradient.png -ordered-dither threshold,6 od\_threshold\_6.gif magick gradient.png -ordered-dither checks,6 od\_checks\_6.gif magick gradient.png -ordered-dither o2x2,6 od\_o2x2\_6.gif magick gradient.png -ordered-dither o4x4,6 od\_o4x4\_6.gif magick gradient.png -ordered-dither o8x8,6 od\_o8x8\_6.gif [![[IM Output]](od_threshold_6.gif)](od_threshold_6.gif) [![[IM Output]](od_checks_6.gif)](od_checks_6.gif) [![[IM Output]](od_o2x2_6.gif)](od_o2x2_6.gif) [![[IM Output]](od_o4x4_6.gif)](od_o4x4_6.gif) [![[IM Output]](od_o8x8_6.gif)](od_o8x8_6.gif) Compare that to the original gradient... [![[IM Output]](gradient.png)](gradient.png) As you can see even though only 6 colors are used, with ordered dithering you increase the effective number of colors used to define the gradient, to a point where you can be hard pressed to notice just how few colors were used! Not only can you define the number of posterization levels for all channels, but you can specify the levels for each channel (as specified in "`[-channels](https://imagemagick.org/script/command-line-options.php?#channels) `". For example, here we dithered the gradient using a special 332 color map (8 levels or red and green, 4 of blue) which defines a total of 256 colors. magick gradient.png -ordered-dither o8x8,8,8,4 od\_o8x8\_884.gif [![[IM Output]](od_o8x8_884.gif)](od_o8x8_884.gif) Because of the different number of color levels per channel, the above image is not made up of pure grey colors, but includes some bluish and yellowish pixels which cancels each other out to produce extra levels of greys. Now compare a 'error correction dithered' posterization, with an 'ordered dithered' posterization of the IM logo at level 2, and level 6. magick logo.png -posterize 2 logo\_posterize\_2.gif magick logo.png -ordered-dither o8x8 logo\_o8x8\_2.gif magick logo.png -posterize 6 logo\_posterize\_6.gif magick logo.png -ordered-dither o8x8,6 logo\_o8x8\_6.gif [![[IM Output]](logo_posterize_2.gif)](logo_posterize_2.gif) [![[IM Output]](logo_o8x8_2.gif)](logo_o8x8_2.gif)         [![[IM Output]](logo_posterize_6.gif)](logo_posterize_6.gif) [![[IM Output]](logo_o8x8_6.gif)](logo_o8x8_6.gif) Each set of images use the same set of colors, the first pair using the simple threshold set of 8 colors, with the second using the 6 level 'web-safe' color map. The first image in each pair is pseudo-randomly 'error correction' dithered, the second is ordered dithered. That means if a small change occurs the first will have almost the whole pattern of dithered colors within the image will change, while the second will only be modified wherever it was actually changed. In other words an ordered dithered posterization is much better for animations, that rely on finding the areas of change in images to reduce the overall animation size. The 'error correction dithered' version however is generally regarded as better as it is more 'correct' color wise, and there is less patterns to attract the eye. Also at this time you can not use ordered dithering between a random set of colors as you can with an 'error correction dither', but only between mathematically determined 'posterized' colors. Here is the logo ordered dithered against a '332' colormap magick logo.png -ordered-dither o8x8,8,8,4 logo\_o8x8\_332.gif [![[IM Output]](logo_o8x8_332.gif)](logo_o8x8_332.gif) The '332' colormap (8 levels of red and green, 4 levels of blue) is regarded as probably the best posterize colormap for a 256 color limit image. The off difference in channel levels producing a slightly better shading of colors for this cartoon like image. Unfortunately this is not currently reproducible using the error correction dithered "`[-posterize](https://imagemagick.org/script/command-line-options.php?#posterize) `" operator. It was to produce this color map that the expansion of the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator, included the ability to specify separate levels for each color channel. * * * XML data source for threshold maps ---------------------------------- This was a final addition to the Ordered Dither Upgrade, and combined with a revisement of all the XML data handling within IM by Cristy. With this development you can now use a "`[-list](https://imagemagick.org/script/command-line-options.php?#list) threshold`" command to see exactly what maps are available to the "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" operator. as well as use personal "`threshold.xml`" data files to define your own maps. * * * DIY New Othered-Dither Replacement ---------------------------------- _This is provided as a reference to the source and prototyping of the new posterized form of ordered dither functionality that was shown above._ As part of using ImageMagick for my own images, I wanted to be able to design and use my own ordered dither patterns. As such I figured out a equivalent ordered dither method using the extremely slow "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator. For example (repeat of [DIY Horizontal Dither](../../quantize/#diy_horizontal) )... Here I created another set of dither pattern images, specifically to produce a interesting shadow shading effect. montage dpat\_hlines.gif -filter box -geometry 30x20+5+0 \\ -tile x1 -background none -frame 3 dpat\_hlines\_images.gif magick gradient:'\[600x1\]' -scale 600x24\\! -negate \\ dpat\_hlines.gif -virtual-pixel tile -fx 'u\[floor(13\*u)+1\]' \\ dpat\_hlines\_gradient.gif [![[IM Output]](dpat_hlines_images.gif)](dpat_hlines_images.gif) [![[IM Output]](dpat_hlines_gradient.gif)](dpat_hlines_gradient.gif) And here I apply it to generate a shadow pattern. magick -size 120x55 xc:white -draw 'fill #777 ellipse 50,43 30,5 0,360' \\ -motion-blur 0x15+180 -blur 0x2 sphere\_shadow.png magick sphere\_shadow.png \\ dpat\_hlines.gif -virtual-pixel tile -fx 'u\[floor(13\*u)+1\]' \\ sphere\_shadow\_dither.gif magick sphere\_shadow\_dither.gif -fill red -stroke firebrick \\ -draw 'circle 35,25 35,5' sphere\_shadow\_hlines.gif [![[IM Output]](sphere_shadow.png)](sphere_shadow.png) ![==>](../../img_www/right.gif) [![[IM Output]](sphere_shadow_dither.gif)](sphere_shadow_dither.gif) ![==>](../../img_www/right.gif) [![[IM Output]](sphere_shadow_hlines.gif)](sphere_shadow_hlines.gif) Now I converted Multi-Image Dither patterns, into and ordered dither threshold map. Though this only works properly for complete sets of ordered dithered images. montage dpat\_o2x2.gif -filter box -geometry 30x30+5+0 \\ -tile x1 -background none -frame 3 dpat\_o2x2\_images.gif magick dpat\_o2x2.gif -delete 0 +append \\ \\( gradient:'\[6x1\]' -chop 1x0 -flop -chop 1x0 -scale 200% \\) \\ +matte +swap -compose CopyOpacity -composite \\ -background none -crop 2x2 +repage -compose DstOver -flatten \\ +matte dmap\_o2x2.png montage dmap\_o2x2.png -filter box -geometry 30x30 -frame 3 dmap\_o2x2\_mag.png [![[IM Output]](dpat_o2x2_images.gif)](dpat_o2x2.gif) ![==>](../../img_www/right.gif) [![[IM Output]](dmap_o2x2_mag.png)](dmap_o2x2.png) Which can be applied using "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `". Now we can dither our images using, just a single image, and a much simpler threshold comparison for each pixel rather than multiple images. magick gradient:'\[600x1\]' -scale 600x24\\! -negate \\ dmap\_o2x2.png -virtual-pixel tile -fx 'u>=v' \\ dmap\_o2x2\_gradient.gif [![[IM Output]](dmap_o2x2_mag.png)](dmap_o2x2.png) ![==>](../../img_www/right.gif) [![[IM Output]](dmap_o2x2_gradient.gif)](dmap_o2x2_gradient.gif) And an example of applying this map. magick logo.png \\ dmap\_o2x2.png -virtual-pixel tile -fx 'u>=v' \\ diy\_map\_o2x2.gif [![[IM Output]](diy_map_o2x2.gif)](diy_map_o2x2.gif) These were then expanded into posterized forms. montage dpat\_o2x2x6.gif -filter box -geometry 20x20+3+3 \\ -tile x1 -background none -frame 2 dpat\_o2x2x6\_images.gif magick gradient:'\[600x1\]' -scale 600x20\\! -negate \\ dpat\_o2x2x6.gif -virtual-pixel tile -fx 'u\[floor(21\*u)+1\]' \\ dpat\_o2x2x6\_gradient.gif [![[IM Output]](dpat_o2x2x6_images.gif)](dpat_o2x2x6.gif) [![[IM Output]](dpat_o2x2x6_gradient.gif)](dpat_o2x2x6_gradient.gif) And here I apply it to each color channel of IM logo test image. magick logo.png \\ dpat\_o2x2x6.gif -virtual-pixel tile -fx 'u\[floor(21\*u)+1\]' \\ diy\_ordered\_2x2x6.gif [![[IM Output]](diy_ordered_2x2x6.gif)](diy_ordered_2x2x6.gif) And finally I created a posterized form of ordered dither using a single binary threshold map. map=dmap\_o2x2.png; levels=6; \\ g=\`expr $levels - 1\`; \\ p=\`magick $map -unique-colors -format %w info:\`; \\ t=\`expr $p + 1\`; d=\`expr $g \\\* $p + 1\`; \\ magick gradient:'\[600x1\]' -scale 600x20\\! -negate \\ -virtual-pixel tile $map \\ -fx "((((u\*$d-floor(u\*$d/$p)\*$p)/$t)>=v)+floor(u\*$d/$p))/$g" \\ diy\_o2x2\_l6\_gradient.gif [![[IM Output]](dmap_o2x2_mag.png)](dmap_o2x2.png) ![==>](../../img_www/right.gif) [![[IM Output]](diy_o2x2_l6_gradient.gif)](diy_o2x2_l6_gradient.gif) It is the mathematics developed for this final, posterization ordered dither from a single threshold map, that was encoded to produce the new `OrderedPosterizeImage()`, function defined above. * * * Created: 18 September 2006 (from 'quantize' example page) Updated: 24 September 2006 Author: [Anthony Thyssen](https://antofthy.gitlab.io/anthony.html) , Examples Generated with: ![[version image]](version.gif) URL: `https://imagemagick.org/Usage/bug/ordered-dither/` --- # Unknown Horizontal Lines 2x2 1 1 2 2 --- # Montage -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Montage, Arrays of Images ============================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Montage, Introduction and General](#montage) * [Geometry - Tile Size (Image Resize)](#geometry_size) * [Geometry - Tile Spacing](#geometry_spacing) * [Tile Layout Controls](#tile) * [Frame Decoration](#frame) * [Border Decoration](#border) * [Shadow Decoration](#shadow) * [Labeling Montage Images](#label) * [Using Saved Image MetaData](#metadata) * [Leaving Gaps in a Montage](#null) [![](../img_www/granitesm_right.gif) Montage Settings](#settings) * [Montage Color Settings](#color) * [Montage Control Settings](#controls) * [Re-Using Settings for Image Read/Creation](#reuse) * [Montage vs Magick Option Differences](#diff) [![](../img_www/granitesm_right.gif) Indexes of Image Directories](#index) * [HTML Thumbnail Image Maps](#html) (basic index map) * [Smaller HTML Index Maps, using JPEG images](#html_jpeg) * [Visual Index](#vid) (A non-montage solution) * [A Montage of Polaroid Photos](#polaroid) (a fancy index map) [![](../img_www/granitesm_right.gif) Special Techniques in using Monatge](#special_usage) * [Montage into Columns](#columns) * [Overlapped Montage Tiles](#overlap) * [Montage Concatenation Mode](#concatenate) * [Zero Geometry](#zero_geometry) (caution required) * [Background and Transparency Handling](#bg) The original use of "`magick montage`" is to generate tables of image thumbnails, that is, to reference thumbnails of large collections of images, especially photos. And while it still can be used for that purpose, it can also do a lot more. This page examines what you can do with montage, and how you can use it on your own images. * * * Montage, Introduction --------------------- The "`[magick montage](https://imagemagick.org/www/montage.html) `" command is designed to produce an array of thumbnail images. Sort of like a proof sheet of a large collection of images. The default "`[magick montage](https://imagemagick.org/www/montage.html) `" with no options is very plain, with quite large containment squares, no frame, labels, or shadows. magick montage balloon.gif medical.gif present.gif shading.gif montage.jpg [![[IM Output]](montage.jpg)](montage.jpg) ### Geometry - Tile Size and Image Resizing The "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting, is the most important control of "`magick montage`". It defines the size of the individual thumbnail images, and the spacing between them. The size part of the geometry is used as an argument to the [Resize Operator](../resize/#resize) , including all its special purpose flags. The position part of the option is interpreted as the amount of border space to leave around the image, so making this smaller, will make the gaps between the images smaller. The default "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting is '`120x120>+4+3`' which means to fit any image given into a box 120x120 pixel in size. If the image is larger shrink it, but don't resize smaller images (as per the [Only Shrink Larger ('>') Flag](../resize/#larger) . The 'tile' size is then set to the largest dimentions of all the resized images, and the size actually specified. That means you will never get a tile size that is smaller than the specified "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" size. You can remove huge size of the tiles in the previous example space by modifing the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" default. For example by removing the 'size' component, none of the images will be resized, and the 'tile' size will be set to the largest dimensions of all the images given. For example, here I ask montage to tile using the largest image given with a small gap between tiles. This is a very typical setting to use when all the input images are small and roughly same size. magick montage balloon.gif medical.gif present.gif shading.gif \\ -geometry +2+2 montage\_geom.jpg [![[IM Output]](montage_geom.jpg)](montage_geom.jpg) For example, here I replaced one image with a larger 'logo' image, but set a the resize setting to '`48x48`' to resize both smaller and larger images. magick montage balloon.gif medical.gif present.gif logo: \\ -geometry 48x48+2+2 montage\_geom\_size.jpg [![[IM Output]](montage_geom_size.jpg)](montage_geom_size.jpg) And here I again restrict the resize to just images larger than the specified tile size. magick montage balloon.gif medical.gif present.gif logo: \\ -geometry 48x48\\>+2+2 montage\_geom\_larger.jpg [![[IM Output]](montage_geom_larger.jpg)](montage_geom_larger.jpg) As you can see the spacing between images appears to be larger than the requested 2 pixel spacing. But that is not the case. The tiles are still separated by 2 pixels, but the images themselves do not fill the 48x48 tile size requested. The 'logo' image was still resized to fit into the 48x48 pixel tile. If you don't want any resizing, then only define the spacing between the tiles. Alternatively, use a special size such as '`1x1<`' which tells IM to only resize smaller images to the given size. As no image can be smaller that 1 pixel, no image will be resized. The tile size will thus be again the largest dimention of all the images on the page. See [Zero Geometry, caution required](#zero_geometry) for reasons why you may like to do this. ### Geometry - Tile Spacing The positional part of the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting, will add space between the individual 'tiles', by adding a [Border](../crop/#border) of those dimensions around the tiles before [Appending](../layers/#append) them together. That means for the default "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting, of '`+4+3`', the tiles will be spaced from the left and right edges of the final image by 4 pixels, and will have a 8 pixel (twice the size given) spacing horizontally between the tiles. The same goes for the vertical spacing. Note how the space bewteen the tiles when all the images were resized (second last example) is twice the size of the space around the edges. ### Tile Layout Controls The next most important option in "`magick montage`" is the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting. This tells montage what limits you want on how the tiled images are to be laid out on the final result. In ImageMagick version 6 "`magick montage`" will make an educated guess as to how best to tile a given number of images, when you provide no "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" hints. It does however assume that the images being tiled are roughly squarish in nature, as it does not look at the images aspect ratios, when deciding on the tiling to use. magick montage font\_1.gif -geometry 16x16+1+1 tile\_1.gif magick montage font\_\[12\].gif -geometry 16x16+1+1 tile\_2.gif magick montage font\_\[123\].gif -geometry 16x16+1+1 tile\_3.gif magick montage font\_\[1-4\].gif -geometry 16x16+1+1 tile\_4.gif magick montage font\_\[1-5\].gif -geometry 16x16+1+1 tile\_5.gif magick montage font\_\[1-6\].gif -geometry 16x16+1+1 tile\_6.gif magick montage font\_\[1-7\].gif -geometry 16x16+1+1 tile\_7.gif magick montage font\_\[1-8\].gif -geometry 16x16+1+1 tile\_8.gif magick montage font\_\[1-9\].gif -geometry 16x16+1+1 tile\_9.gif magick montage font\_\[0-9\].gif -geometry 16x16+1+1 tile\_0.gif [![[IM Output]](tile_1.gif)](tile_1.gif) [![[IM Output]](tile_2.gif)](tile_2.gif) [![[IM Output]](tile_3.gif)](tile_3.gif) [![[IM Output]](tile_4.gif)](tile_4.gif) [![[IM Output]](tile_5.gif)](tile_5.gif) [![[IM Output]](tile_6.gif)](tile_6.gif) [![[IM Output]](tile_7.gif)](tile_7.gif) [![[IM Output]](tile_8.gif)](tile_8.gif) [![[IM Output]](tile_9.gif)](tile_9.gif) [![[IM Output]](tile_0.gif)](tile_0.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The strange "`[1-5]`" syntax is an UNIX shell shorthand, which is expanded into a list of filenames. The "`magick montage`" command itself does not see these characters, just the resulting list of files._ | ImageMagick is pretty good at figuring out the right "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting to use for a specific number of input images. Here is a table of number of input images and the tile setting IM will used to layout those images. | Num Images | Tile Setting | | --- | --- | | 1 | 1x1 | | 2 | 2x1 | | 3 | 3x1 | | 4 | 2x2 | | 5 - 6 | 3x2 | | 7 - 8 | 4x2 |     | Num Images | Tile Setting | | --- | --- | | 9 | 3x3 | | 10 - 12 | 4x3 | | 13 - 15 | 5x3 | | 16 - 20 | 5x4 | | 21 - 24 | 6x4 | | 25 | 5x5 |     | Num Images | Tile Setting | | --- | --- | | 26 - 30 | 6x5 | | 31 - 36 | 7x5 | | 31 - 35 | 7x5 | | 36 | 6x6 | | 37 - 42 | 7x6 | | 43 - 48 | 8x6 | Note however that IM will not automatically select a 'perfect fit' 6x3 tile setting for 18 images, nor a 7x4 setting for 28 images. However if you specify a specific "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting, montage will always create an image big enough to hold that many 'tiles'. magick montage font\_\[1-7\].gif -tile 9x1 -geometry 16x16+1+1 tile\_9x1.gif magick montage font\_\[1-7\].gif -tile 4x3 -geometry 16x16+1+1 tile\_4x3.gif magick montage font\_\[1-7\].gif -tile 3x3 -geometry 16x16+1+1 tile\_3x3.gif magick montage font\_1.gif -tile 2x3 -geometry 16x16+1+1 tile\_2x3.gif [![[IM Output]](tile_9x1.gif)](tile_9x1.gif) [![[IM Output]](tile_4x3.gif)](tile_4x3.gif) [![[IM Output]](tile_3x3.gif)](tile_3x3.gif) [![[IM Output]](tile_2x3.gif)](tile_2x3.gif) As you can see montage created an image that is large enough to hold the number of tiles specified, regardless of how many images are available to fill the tile space requested, be it 7 images, or just 1 image. It will only fill the space row by row, no option is currently provided to do a column-by-column fill of the tile space. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Before IM v6.1 montage would automatically truncate the extra space if the number of images did not use that space. As such a setting such as the first "`9x1`" image would have been truncated to produce a "`7x1`" tile image._

_Because of this, past users of montage often used large numbers such as "`999x1`" to generate a single row of images. Now such a argument will produce a very long image, and could take a long time for IM to complete. As such..._

**Avoid the use of very large tile numbers in IM montage!** | You can avoid the problems of extra space, and multiple images, especially for an unknown number of input images, by removing either a row, or the column number, from the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting. The missing number will be taken by montage as being variable and montage will only create enough tile space to hold ALL the input images, producing only one image, never multiple images. magick montage font\_\[1-7\].gif -tile x1 -geometry 16x16+1+1 tile\_x1.gif magick montage font\_\[1-7\].gif -tile x2 -geometry 16x16+1+1 tile\_x2.gif magick montage font\_\[1-7\].gif -tile x4 -geometry 16x16+1+1 tile\_x4.gif magick montage font\_\[1-7\].gif -tile 4x -geometry 16x16+1+1 tile\_4x.gif magick montage font\_\[1-7\].gif -tile 5x -geometry 16x16+1+1 tile\_5x.gif magick montage font\_\[1-7\].gif -tile 9x -geometry 16x16+1+1 tile\_9x.gif [![[IM Output]](tile_x1.gif)](tile_x1.gif) [![[IM Output]](tile_x2.gif)](tile_x2.gif) [![[IM Output]](tile_x4.gif)](tile_x4.gif) [![[IM Output]](tile_4x.gif)](tile_4x.gif) [![[IM Output]](tile_5x.gif)](tile_5x.gif) [![[IM Output]](tile_9x.gif)](tile_9x.gif) This is the more typical use of the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting, as it ensures the montage is sized correctly, while still allowing it some control in determining the final array size. Note the last image, in the above where we requested 9 columns of images. IM still generated the requested 9 columns, even though less than 9 images were given. On the other hand the first image (one row requested), is exactly the right length to hold all the images. If you have more input images than montage can tile into the space given by a "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting, then multiple images can be generated by montage, either resulting in image sequence numbers being added to the filename, or some sort of GIF animation, being created. See [Writing Multiple Images](../files/#write_list) for details. For example, here I have asked montage to save separate images for each page generated, by supplying a '`%d`' for the frame/scene/page number of each image filename. magick montage font\_\*.gif -tile 4x1 -geometry +2+2 multi\_%d.gif [![[IM Output]](multi_0.gif)](multi_0.gif) [![[IM Output]](multi_1.gif)](multi_1.gif) [![[IM Output]](multi_2.gif)](multi_2.gif) ### Frame Decoration The best part of using montage to arrange images is that it provides a lot of extra controls to add extra 'fluff' around each image. For example, you can better define the images being displayed by adding a "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" around each image. magick montage balloon.gif medical.gif present.gif shading.gif \\ -tile x1 -frame 5 -geometry +5+5 frame.jpg [![[IM Output]](frame.jpg)](frame.jpg) This is not like the same option in "`magick`" (See [Adding a 3D frame](../crop/#frame) example). The montage frame option will automatically figure out default values for the internal and external bevel of the frame. As such only a single argument number is needed. ### Border Decoration Sometime around IM v6.1.0, "[`-border`](https://imagemagick.org/script/command-line-options.php?#border) " became a new decorative option of montage. It now adds extra 'padding' around each image, after it has been resized according ot the "[`-geometry`](https://imagemagick.org/script/command-line-options.php?#geometry) " setting. magick montage balloon.gif medical.gif present.gif shading.gif \\ -tile x1 -border 5 -geometry +5+5 border.jpg [![[IM Output]](border.jpg)](border.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "[`-border`](https://imagemagick.org/script/command-line-options.php?#border)
" decoration does not currently work when the [Frame Decoration](#frame)
is also applied._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Before IM v6.1.0 (approx) [**\-border**](https://imagemagick.org/script/command-line-options.php?#border)
_ would been applied to images at the point in which it appeared in the "`magick montage`" command line, just like it would have with "`magick`".

That is, border would have been thus added to the image long before the images get resized (according to "[`-geometry`](https://imagemagick.org/script/command-line-options.php?#geometry)
"), which resulted in different border widths around each image depending on the size of the image at that point. It was to remove this inconsistancy that [**\-border**](https://imagemagick.org/script/command-line-options.php?#border)
became a special montage setting. | ### Shadow Decoration Adding a shadow with the frame is also quite good. magick montage balloon.gif medical.gif present.gif shading.gif \\ -tile x1 -frame 5 -shadow -geometry +5+5 frame\_shadow.jpg [![[IM Output]](frame_shadow.jpg)](frame_shadow.jpg) Of course you don't actually need a frame to generate image shadows magick montage balloon.gif medical.gif present.gif shading.gif \\ -tile x1 -shadow -geometry +5+5 -background lightblue \\ shadow\_noframe.jpg [![[IM Output]](shadow_noframe.jpg)](shadow_noframe.jpg) As of IM v6.3.1 when 'soft shadows' were implemented, the shadows will now be shaped according to the transparency of the images being displayed! magick montage font\_1.gif font\_7.gif font\_2.gif font\_0.gif \\ -tile x1 -shadow -geometry +3+5 -background none \\ shadow\_shaped.png [![[IM Output]](shadow_shaped.png)](shadow_shaped.png) As you can see the shadow used by montage is actually a semi-transparent color, allowing the background to affect its final color. This means if you create a montage with textured background, or use a transparent background and overlay it, the shadow will do the right thing. Of course you need to use an image format that can handle semi-transparent colors, like PNG. Remember because of [GIF Boolean Transparency](../formats/#boolean_trans) you can not use GIF image file format for this purpose. Note that shadows do not care about the "[`-geometry`](https://imagemagick.org/script/command-line-options.php?#geometry) " spacing between the images. As such if the images are too close together, the shadow of previous images can be obscured by later images. For example... magick montage balloon.gif medical.gif present.gif shading.gif \\ -tile x1 -shadow -geometry +1+1 -background none \\ shadow\_spacing.png [![[IM Output]](shadow_spacing.png)](shadow_spacing.png) It is thus recommended at a reasonable amount of "[`-geometry`](https://imagemagick.org/script/command-line-options.php?#geometry) " spacing be provided when using shadow. To avoid 'edge clipping' shadows to much, the "[`-shadow`](https://imagemagick.org/script/command-line-options.php?#shadow) " option will add 4 extra edge spacing pixels the right and bottom edges of the final image. This is on top of the normal "[`-geometry`](https://imagemagick.org/script/command-line-options.php?#geometry) " spacing provided. However as you can see above, this is not always enough space. Montage currently also provides no controls for the offset, color or the 'softness' of the generated shadow (at least not yet), but then, you didn't have such control with hard rectangular shadow that was provided by older versions of montage. ### Labeling Montage Images You can also tell montage to label the image with their source filenames, though you probably need to resize the image frames, or the labels may not fit, truncating the text label. In this case we added a "`60x60>`" to the geometry string, which tells IM to shrink larger images to fit into this space, but _not_ to enlarge images if they are smaller. This is probably the most typical use of montage. magick montage -label '%f' balloon.gif medical.gif rose: present.gif shading.gif \\ -tile x1 -frame 5 -geometry '60x60+4+4>' label\_fname.jpg [![[IM Output]](label_fname.jpg)](label_fname.jpg) The '`%f`' is a special format character, which can pull out various details about the images in memory. See [Image Property Escapes](https://imagemagick.org/script/escape.php) for details of other information you can extract from images. You don't have to use a "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" when labeling thumbnails. The labels are not shadowed, so that they remain clearly readable. montage -label '%f' balloon.gif medical.gif logo: present.gif shading.gif \\ -tile x1 -shadow -geometry '60x60+2+2>' label\_shadow.jpg [![[IM Output]](label_shadow.jpg)](label_shadow.jpg) And as of IM v 6.2.1 you can now re-label images after they have been read in using the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" image attribute operator. Lets use the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator to add more information about the images. And also few more montage settings... magick montage balloon.gif medical.gif logo: present.gif shading.gif \\ -tile x1 -geometry '90x32+2+2>' -pointsize 10 \\ -set label '%f\\n%wx%h' -background SkyBlue label\_fname3.jpg [![[IM Output]](label_fname3.jpg)](label_fname3.jpg) As we showed in the examples above you can use the "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" setting to define the default label for an image, as they are read in, or you can re-label the image afterward using the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that '`%wx%h` gives the current pixel width and height of the image as it is in memory. If the image size was modified, such as during input this may be different to the images in disk (or creation) size. Use '`%[width]x%[height]`' instead if you want its in memory pixel size._ | You can also label images differently by setting label of individual images. Either option can be used, though you will need to use of parenthesis to limit what images the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator will be applied to. Here for example we use both forms of labeling. But lets also add a title to the montage, just because we can... magick montage -label Balloon balloon.gif \\ -label Medical medical.gif \\ \\( present.gif -set label Present \\) \\ \\( shading.gif -set label Shading \\) \\ -tile x1 -frame 5 -geometry '60x60+2+2>' \\ -title 'My Images' titled.jpg [![[IM Output]](titled.jpg)](titled.jpg) You can turn off image labeling for the next image(s) by using a "`-label ''` " or "`+label`". However as you will see later these two settings are not quite the same. The same applies for a post reading, label "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operation. magick montage balloon.gif \\ -label 'My Image' medical.gif \\ +label present.gif \\ -label ' ' shading.gif \\ -tile x1 -frame 5 -geometry '60x60+2+2>' labeling.jpg [![[IM Output]](labeling.jpg)](labeling.jpg) The last image shows how using a space for an image label, you can create a image label space, but leave it blank. This presents a good rule of thumb when using montage... **Either label all your images, or none of them!** You don't have to label your images during the montage operation itself. Both the MIFF and PNG formats, can store a label as part of their image format. Montage will automatically label any image read in that already contains a label. This is automatic and does not need to be specified, and I have used this technique to generate some very complex image montages. For example the montage array in [Annotate Angle Examples](../misc/#annotate) was created using this technique. If you do not want this automatic labeling, you must specifically tell montage to reset all the labels being read in or created to the empty string, using "`-label ''`" before reading the image. Or you can just delete the label meta-data using "`+set label`" after reading the images. This is where "`[+label](https://imagemagick.org/script/command-line-options.php?#label) `" differs from using an empty label ("`-label ''`"). The former will reset the default behavior back to automatically using any label meta-data that the image being read-in may have , while the later replaces the label with an empty string, which effectiavvly removes the label. You can also preserve the original label of the image using "`-label '%l'`", which can be usful as a NO-OP labeling option in image processing scripts. Note that "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" cannot restore the original label of an image, once it has been modified or removed, either by using "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" or "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" magick -label 'medical' medical.gif label\_medical.png magick -label 'logo' logo: label\_logo.png magick -label 'rose' rose: label\_rose.png magick montage label\_medical.png \\ -label '' label\_logo.png \\ +label label\_rose.png \\ -tile x1 -frame 5 -geometry '60x60+2+2>' label\_control.jpg [![[IM Output]](label_control.jpg)](label_control.jpg) In the above you can see that the first image was labeled using the label supplied with the image itself. The second had the incoming label removed by a "`-label ''` " setting, while the third also used the images label because we turned-off the label setting with "`[+label](https://imagemagick.org/script/command-line-options.php?#label) `". ### Using Saved Image MetaData When generating images for later use by montage it is important to know what sort of image metadata a specific image file format can save. For example only PNG, and MIFF image file format can actually store '`label`' meta-data in their saved image file format... magick -label 'GIF' balloon.gif label.gif magick -label 'JPG' medical.gif label.jpg magick -label 'PNG' present.gif label.png magick -label 'MIFF' shading.gif label.miff montage label.gif label.jpg label.png label.miff \\ -tile x1 -frame 5 -geometry '60x60+2+2>' label\_files.jpg rm label.\* [![[IM Output]](label_files.jpg)](label_files.jpg) However all the common file cormats allow you to use '`comment`' meta-data, which you can use by specifying a '`%c`' argument to "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `". magick -comment 'GIF' balloon.gif comment.gif magick -comment 'JPG' medical.gif comment.jpg magick -comment 'PNG' present.gif comment.png magick -comment 'MIFF' shading.gif comment.miff magick montage -label '%c' comment.gif comment.jpg comment.png comment.miff \\ -tile x1 -frame 5 -geometry '60x60+2+2>' comment\_files.jpg rm comment.\* [![[IM Output]](comment_files.jpg)](comment_files.jpg) This is often more useful for pictures saved in the JPEG file format, though JPEG image comments generally are too large (often whole paragraphs describing the image), for use as montage labels, as they will not be word wrapped (see [Montage of Polaroid Photos](#polaroid) for an alternative method of labeling using image 'comment' meta-data). Many other programs also automatically add 'made-by' labels and comments to images they save (YUCK) so some caution is recommended. The [GIMP](http://www.gimp.org/) program particularly likes to add such comments and labels, unless you tell it not to, every time you save an image. Note that IM is generally not used to add comments to saved JPEG files, (due to [JPEG Lossy Compression](../formats/#jpg) ) unless processing them for other reasons. Instead they are usually added by some other method in order to avoid reading and re-writing the image data and thereby degrading the JPEG image files in which you are adding comments. See [lossless JPEG Processing](../formats/#jpg_lossless) options, for some such methods. It is also important to note that labeling (and image 'comments') is not specific to montage. Montage just makes automatic use of image labels if present. Labels and comments are attached to images, and the their specific file formats, and is not montage or even IM specific. The PNG and MIFF file format also allow you to use a less commonly used '`caption`' meta-data. magick balloon.gif -set caption 'GIF' caption.gif magick medical.gif -set caption 'JPG' caption.jpg magick present.gif -set caption 'PNG' caption.png magick shading.gif -set caption 'MIFF' caption.miff magick montage -label '%\[caption\]' caption.gif caption.jpg caption.png caption.miff \\ -tile x1 -frame 5 -geometry '60x60+2+2>' caption\_files.jpg rm caption.\* [![[IM Output]](caption_files.jpg)](caption_files.jpg) Actually both these file formats allow you to save ANY [Image property Meta-data](../basics/#property) that may be present in an image when it is saved! magick balloon.gif -set my\_data 'GIF' my\_data.gif magick medical.gif -set my\_data 'JPG' my\_data.jpg magick present.gif -set my\_data 'PNG' my\_data.png magick shading.gif -set my\_data 'MIFF' my\_data.miff magick montage -label '%\[my\_data\]' my\_data.gif my\_data.jpg my\_data.png my\_data.miff \\ -tile x1 -frame 5 -geometry '60x60+2+2>' my\_data\_files.jpg rm my\_data.\* [![[IM Output]](my_data_files.jpg)](my_data_files.jpg) ### Leaving Gaps in a Montage While you can leave extra space in a montage at the bottom by judicious use of the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting and controlling the number of images given, leaving an empty tile space in the middle of a montage requires the use of a special image. The "`null:`" generated image was defined specifically for this purpose. The position in which it appears will not receive any label (even if one is defined), nor will it have any frame or shadow 'fluff' added. The tile is just left completely empty except for the background color (or texture) of the montage drawing canvas itself. magick montage -label 'Image' medical.gif null: present.gif \\ -tile x1 -frame 5 -geometry +2+2 montage\_null.jpg [![[IM Output]](montage_null.jpg)](montage_null.jpg) Note that to other IM commands the "`null:`" image is represented a single pixel transparent image. It is also used as a 'error image' for options like "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" or "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" which could produce a 'zero' or empty image as a result of the operation. This special image cannot be saved and then later used to leave gaps, currently it is only 'special' if given on the command line of "`magick montage`". | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _There is no method, at this time to allow montaged images to span multiple rows or columns, as you can in HTML tables. Nor can you generate variable sized rows and columns to best fit the array of images being generated.

If you really need this sort of ability you will need to develop your own montage type of application. If you do develop something, then please contribute, and we'll see about merging it into the existing montage application.

Some solutions for this includes labeling and framing the image thumbnails yourself and then using either [Append Images](../layers/#append)
or use a more free form [Layering Image](../layers/#layer_examples)
technique.

_ | * * * More Montage Settings --------------------- The "`magick montage`" settings I have shown above are only the basic controls for montage. Their are a lot of other settings you may like to consider for your own needs. ### Montage Color Settings | | | | --- | --- | | `[**-background**](https://imagemagick.org/script/command-line-options.php?#background) ` | The color outside the drawn frame. Often this is set to the '`none`' or '`transparent`', for use on web pages. The [\-texture](https://imagemagick.org/script/command-line-options.php?#texture)
setting will be used instead if given. | | `[**-bordercolor**](https://imagemagick.org/script/command-line-options.php?#bordercolor) ` | The fill color inside the frame for images, or any border padding. Any transparent areas in an image will become this color, unless no such decoration is added. | | `[**-mattecolor**](https://imagemagick.org/script/command-line-options.php?#mattecolor) ` | The color used as the frame color. Note that the color is also made lighter and darker to give the frame a beveled 3D look. So this setting really defines 5 colors. (See also [Framing Images](../crop/#frame_border)
) | | `[**-fill**](https://imagemagick.org/script/command-line-options.php?#fill) ` | The fill color for text labels and titles. | | `[**-stroke**](https://imagemagick.org/script/command-line-options.php?#stroke) ` | The stroke color for text labels and titles. | ### Montage Control Settings > `[**-tile**](https://imagemagick.org/script/command-line-options.php?#tile) {_cols_}x{_rows_}` > > The number of images across and down used to fill a single montage image. If more images were read in or created than fits in a single montage image, then multiple images will be created. (See [Tile Controls](#tile) > above) > > `[**-title**](https://imagemagick.org/script/command-line-options.php?#title) {_string_}` > > Set a title over the whole montage, using the same font (but larger) as that used to label the individual images. > > `[**-frame**](https://imagemagick.org/script/command-line-options.php?#frame) {_width_}` > > Create a frame around the box containing the image, using the _width_ provided (must be at least 2, but 5 or 6 is a good value). If used any transparency in images will also become the border color. > > `[**-border**](https://imagemagick.org/script/command-line-options.php?#frame) {_width_}` > > Create a border around the image, using the _width_ provided. If used any transparency in images will also become the border color. > > `[**-shadow**](https://imagemagick.org/script/command-line-options.php?#shadow) ` > > Generate a shadow of the frame. Note that no argument is required or expected. > > `[**-texture**](https://imagemagick.org/script/command-line-options.php?#texture) {_filename_}` > > Use the given texture (tiled image) for the background instead of a specific color. See the section on [Background and Transparency](#bg) > below for more information. > > `[**-geometry**](https://imagemagick.org/script/command-line-options.php?#geometry) {_W_}x{_H_}+{_X_}+{_Y_}` > > Resize images after they have all been read in before montage overlays them onto its canvas. It also defines the size and the spacing between the tiles into which the images are drawn. If no size is specified the images will not be resized. > > `[**-gravity**](https://imagemagick.org/script/command-line-options.php?#gravity) {_direction_}` > > if the image is smaller than the frame, where in the frame is the image to be placed. By default it is centered. Added to the above are all the font settings that the "`label:`" image creation operator understands (See [Label Image Generator](../text/#label) ). These settings are used for the creation of labels added underneath the displayed image. These include settings such as "`[-font](https://imagemagick.org/script/command-line-options.php?#font) `", "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" (ignored for "`[-title](https://imagemagick.org/script/command-line-options.php?#title) `"), "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `", "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `", "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `", and "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `". As long as any or all of the above setting are defined or reset, before the final 'output filename' argument, montage will use them as you have requested. ### Re-Using Settings for Image Read/Creation Note however that many of these options are also used for other purposes, in either the generation of images or during image processing. But thanks to the 'do things as you see them' command line handling on IM v6, this presents no problem to the "`magick montage`" command. That means you are free to use any of these option settings to read, create, or modify the images being read in, then reset those settings after all the images have been read in or created. The final setting value will be what montage will use for its final processing. This was not the case in versions of IM before version 6, in which it was generally impossible to separate image creation settings, from montage settings, without generating intermediate images (such as in the [Image Labels](#image_labels) example above). Here is a practical example of setting reuse. I wanted to make a table of some of the fonts I have been using in these example pages, then reset the settings to other values for the final processing of the images by montage. magick montage -pointsize 24 -background Lavender \\ -font Candice -label Candice label:Abc-123 \\ -font Corsiva -label Corsiva label:Abc-123 \\ -font SheerBeauty -label SheerBeauty label:Abc-123 \\ -font Ravie -label Ravie label:Abc-123 \\ -font Arial -label Arial label:Abc-123 \\ -font ArialI -label ArialI label:Abc-123 \\ -font ArialB -label ArialB label:Abc-123 \\ -font ArialBk -label ArialBk label:Abc-123 \\ -font CourierNew -label CourierNew label:Abc-123 \\ -font LokiCola -label LokiCola label:Abc-123 \\ -font Gecko -label Gecko label:Abc-123 \\ -font Wedgie -label Wedgie label:Abc-123 \\ -font WebDings -label WebDings label:Abc-123 \\ -font WingDings -label WingDings label:Abc-123 \\ -font WingDings2 -label WingDings2 label:Abc-123 \\ -font Zymbols -label Zymbols label:Abc-123 \\ \\ -frame 5 -geometry +2+2 -font Arial -pointsize 12 \\ -background none -bordercolor SkyBlue -mattecolor DodgerBlue \\ montage\_fonts.gif ![[IM Output]](montage_fonts.gif) Note the two stages to the "`magick montage`" command. Which I clearly marked using an extra almost empty line. The first part is essentially exactly as you would define multiple images using the normal IM "`magick`" command, and is processed in the same, 'do it as you see it' order. The second part, defines _all_ the settings I wanted the "`magick montage`" command itself to use. That is, the framing, image resizing, fonts and colors I wanted to use in the final montage image. I especially take care to reset the "`[-font](https://imagemagick.org/script/command-line-options.php?#font) `" and "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" settings for the labeling underneath the montaged images. While you can separate the options of "`magick montage`" like this, you can actually define the montage settings at any time on the command line. As long as those settings do not interfere with your image creating and processing options, and are still defined correctly when the end of the command line is reached, "`magick montage`" will use them. ASIDE: You may like to look at the shell script I wrote to do something similar to the above (and which works with earlier versions of montage) to display a directory of truetype (.ttf) fonts, called "`[**show_fonts**](../scripts/show_fonts) `". Another shell script example is "`[**show_colors**](../scripts/show_colors) `". ### Montage vs Magick Option Differences Now while "`magick montage`" generally allow you to use any "`magick`" settings and operators in reading and processing its input images, their are a few differences which need to be highlighted. These "`magick`" operators and settings are different when used within "`magick montage`". > `[**-tile**](https://imagemagick.org/script/command-line-options.php?#tile) ` > > In "`magick`" the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting defines an image to use as a texture instead of using the "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color. In "`magick montage`" it defines how to layout the individual image cell 'tiles'. See [Tile Layout Controls](#tile) > above for more detail. > > `[**-frame**](https://imagemagick.org/script/command-line-options.php?#frame) ` > > In "`magick`" this is an operator used to add a 3D frame border around images, and requires 4 arguments to work correctly (See [Convert Frame](../crop/#frame) > examples). See [Frame Decoration](#frame) > for more detail. > > `[**-border**](https://imagemagick.org/script/command-line-options.php?#border) ` > > Sometime around IM v6.1.0 this operator became a special montage option. As such, like the previous frame option it only takes one number as an argument, rather than two arguments as per the [Convert Border](../crop/#border) > . See [Border Decoration](#border) > for more detail. > > `[**-shadow**](https://imagemagick.org/script/command-line-options.php?#shadow) ` > > The "`[-shadow](https://imagemagick.org/script/command-line-options.php?#shadow) `" option in "`magick`" takes an argument which is used to create a soft blurry shadow to which can be place under a second copy of the original image. However in "`magick montage`" this is only a Boolean setting that just turns the rectangular shadowing abilities, on and off. See [Shadow Decoration](#shadow) > for more detail. > > `[**-geometry**](https://imagemagick.org/script/command-line-options.php?#geometry) ` > > The "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" option in "`magick montage`" is simply saved to provide the size of the images within each cell of the final montage, and the spacing between the cells. In "`magick`" it resizes just the last image, and sets the off set for [Image Composition](../compose/#compose) > . If you really need to use the "`magick`" form of these options, then you will need to pre-process your images using "`magick`" before passing them to "`magick montage`". One method using intermediate files was demonstrated in the [Image Labels](#image_labels) example above. Another is to just do your processing in "`magick`" and just pipe the resulting multiple images into "`magick montage`". This separation is easy to do if you always do your image input handling first, then set the "`magick montage`" specific settings afterward, such as I have done in all these examples. This is especially shown in the last font example above. For example lets frame our images using the "`magick`" frame, and then frame them again using the "`magick montage`" labeled frames. magick -label %f balloon.gif medical.gif present.gif shading.gif \\ -mattecolor peru -frame 10x5+3+0 miff:- |\\ magick montage - -tile x1 -frame 5 -geometry '64x56+5+5>' double\_frame.jpg [![[IM Output]](double_frame.jpg)](double_frame.jpg) You can also see the extra arguments required by the "`magick`" form of the "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" operator. * * * Indexes of Image Directories ---------------------------- ### HTML Thumbnail Image Maps Montage is especially designed for generating thumbnail maps of images. For example, here I have created an index of the [Photo Images](../img_photos/) source directory, which holds the digital photos used for examples throughout IM Examples. Click the 'art' image below to view the result. magick montage -label '%t\\n%\[width\]x%\[height\]' \\ -size 512x512 '../img\_photos/\*\_orig.\*\[120x90\]' -auto-orient \\ -geometry +5+5 -tile 5x -frame 5 -shadow photo\_index.html [![[IM Output]](../img_www/doc_html.png) \ IM Examples \ Photo Store](photo_index.html) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note the use of '`%[width]x%[height]`' instead of just '`%wx%h`'. This is important as the image is being resized as it is read in. The former will label the images with their original pixel size as it is on disk, while the latter will use the current resized size of the image. This is something that is easily overlooked by users._ | The result of this command were three files... > | | | > | --- | --- | > | **`[photo_index.png](photo_index.png) `** | The montage of all thumbnails of the images | > | **`[photo_index_map.shtml](photo_index_map.shtml.txt) `** | An HTML 'image map' for the thumbnail image | > | **`[photo_index.html](photo_index.html.txt) `** | The HTML thumbnail index page for the World Wide Web.
This also includes a copy of the previous image map. | Of course you don't have to generate an HTML index file if you only want an index image. In that case just replace "`INDEX.html`" in the command above with the image you want to generate. Note the use of the [Image Property Escape](https://imagemagick.org/script/escape.php) '`%t`' for the image "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `". This is the filename of the image without any 'path' components. Though the HTML link will still contain the appropriate 'path' components allowing you to build the index image in a different directory to the images themselves. The source images "`'*_orig.*'`" in the above examples is quoted, so the "`magick montage`" command does the expansion of '\*' itself, and not the command line shell. This avoids any command line length limits that you may have problems with. Also I do some initial resizing of images '`[120x190]`' as I read them (see [Read Image Modifiers](../files/#read_mod) ). For JPEG images I also specified a smaller "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting so the JPEG library can do some very rough initial scaling, and not read the whole image into memory. If this is not done, then very large JPEG images could use up an enormous amount of memory and CPU cycles when there is no real need. I also "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" any profiles that the images may have. For more info see [Profiles, Stripping, and JPEG Handling](../thumbnails/#profiles) and [Reading JPEG Images](../formats/#jpg_read) . Remember the montage "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" option can also specify a final resize setting, though in this case it is isn't needed as I did it during the read process, so I don't set any 'size' in that setting. Finally the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" option of '`5x`' is used to ensure all images appear in a single image, otherwise "`magick montage` could generate a multi-page HTML files, which are not correctly linked together. This will hopefully change, though HTML generation is not a primary goal of ImageMagick. For other ways of generating thumbnails and HTML index pages, read the [Thumbnail Examples Page](../thumbnails/) . ### Smaller HTML Index Maps, using JPEG images The above index image generated a PNG format index image. This was used because it is a non-lossy format, which can be important when the images being indexed are of wildly different colors. It also enables the use of the new 'soft shadows' features of montage if the background color is set to '`transparent`' or '`none`'. Very very old IM's will have generated a GIF image for the above. However, this has some heavy color reduction on the results as part of the formats limitations. It also did not allow the use of semi-transparent 'soft shadows' as PNG allows. JPEG also does not allow semi-transparency, but that is not a problem if you do not use a transparent background for the image. It is however a lot smaller than PNG, which provides a way to drastically reduce the size of the index image, especially for web use, and still handle a large range of colors. However, HTML output above only generates PNG format images, so you will need to not only magick the PNG to JPEG, but also some extra processing to fix the HTML file. magick montage -label '%t\n%[width]x%[height]' \ -size 512x512 '../img_photos/*_orig.*[120x90]' -auto-orient \ -geometry +5+5 -tile 5x -frame 5 -shadow photo_jpeg.html magick photo_jpeg.png photo_jpeg.jpg perl -i -lpe 's/src="photo_jpeg.png"/src="photo_jpeg.jpg"/' photo_jpeg.html rm -f photo_jpeg.png photo_jpeg_map.shtml [![[IM Output]](../img_www/doc_html.png) \ IM Examples \ Photo Store](photo_jpeg.html) The above commands are rather tricky so here is what happens... * First I generate a montage thumbnail HTML index, as I did previously. This generated the files: "`photo_jpeg.html`" and "`photo_jpeg.png`" * I then converted the PNG image to a smaller, lossy, JPEG image. * Then I used a small '`perl`' one line script to change HTML file to use the JPEG image instead of PNG. * And finally I removed the PNG image, as well as the SHTML map file which I don't need. And hey presto, we have a Thumbnail index using a very small JPEG image for the thumbnail index image. Here are comparisons of the file sizes of the thumbnail index image... [![[IM Text]](photo_index_sizes.txt.gif)](photo_index_sizes.txt) That is, the image used for the index is only about 15% of the size of the original PNG image. A big saving for a downloadable web page of thumbnails! You can make the JPEG image even smaller by using a smaller "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" setting, though the default setting produces a very reasonable result. Other possible options include using "`[-sampling-factor](https://imagemagick.org/script/command-line-options.php?#sampling-factor) 2x1`" to make it even smaller. ### Visual Index Images (a non-montage solution) An alternative to using montage, is to use a special "visual index" input format... magick 'vid:../img\_photos/\*\_orig.\*' vid\_index.gif [![[IM Output]](../img_www/doc_art.png) \ Visual Index of \ Photo Store](vid_index.gif) And can also generate 'clickable' HTML index files. magick 'vid:../img\_photos/\*\_orig.\*' vid\_index.html [![[IM Output]](../img_www/doc_html.png) \ Visual HTML of \ Photo Store](vid_index.html) It is obvious that "`VID:`" uses montage internally to generate the index array. However you do not have the same controls as you do if you had used montage directly. Note that a VID HTML index creates a PNG format thumbnail image. ### A Montage of Polaroid Photos With the advent of a [Complex Polaroid Transform](../transform/#polaroid) it is now possible to generate quite a different style of montage, and montage indexing. magick montage -size 256x256 '../img_photos/*_orig.*' -auto-orient \ -auto-orient -thumbnail 128x128 \ -set caption '%t' -bordercolor AliceBlue -background grey20 \ +polaroid \ +set label -background white -geometry +1+1 -tile 4x \ polaroid_index.html [![[IM Output]](../img_www/doc_html.png) \ Polaroid \ Montage](polaroid_index.html) Note that as I used "`[+polaroid](https://imagemagick.org/script/command-line-options.php?#polaroid) `" to frame and label the images, I needed to resize the image (using "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `") myself, and make sure the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" and image "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" has been reset before actually creating the "`magick montage`" index array. The [Polaroid Transform](../transform/#polaroid) however tends to blur the text during the addition of the 'curl' to the thumbnail image. However you can improve the overall by generating the polaroid images at a larger size then shrinking the result by 50%. The only drawback is the reduced 'shadow' effect. magick montage -size 400x400 '../img_photos/*_orig.*' \ -auto-orient -thumbnail 200x200 \ -set caption '%t' -bordercolor Lavender -background grey40 \ -pointsize 9 -density 144x144 +polaroid -resize 50% \ +set label -background white -geometry +1+1 -tile 5x \ polaroid_index2.html [![[IM Output]](../img_www/doc_html.png) \ Sharper \ Polaroid \ Montage](polaroid_index2.html) This fancy montage, as well as other techniques shown above was used to create a script to generate a montage thumbnail index in the actual "`[photo_store](../img_photos/) `" directory. See [Photograph Store Index](../img_photos/INDEX.html) for the results of this script. * * * Special Techniques using Montage -------------------------------- ### Montage into Columns By default "`magick montage`" can only place the images in the order given (typically sorted order) row by row. However sometimes you would like to have them shown in column order. This can not be done with a single command, but requires a pipe-line of at least two commands. For example, here I generate a page of 5x3 tiles, using two montages. magick montage font_*.gif -tile 1x3 -geometry 16x16+1+1 miff:- |\ magick montage - -geometry +0+0 -tile 5x1 montage_columns.gif [![[IM Output]](montage_columns.gif)](montage_columns.gif) Note that it is the first "`magick montage`" that creates the tiles and performs any of the geometry tile sizing, framing, labeling and spacing needed. It will then output one image for each column of tiles. The second "`magick montage`" then simply contatanates the columns into 'page' images without adding any more space between columns. If you only want a single image of a variable number of columns, then you can replace the second "`magick montage`" with a "`magick`" to concatanate without adding extra space of 'pages'. For example... magick montage font_*.gif -tile 1x3 -geometry 16x16+1+1 miff:- |\ magick - +append montage_columns_2.gif [![[IM Output]](montage_columns_2.gif)](montage_columns_2.gif) ### Overlapped Montage Tiles In the [IM User Forum](https://magick.imagemagick.org/viewforum.php?f=1) , during a discussion between, [Fred Weinhaus](http://www.fmwconcepts.com/fmw/fmw.html) , aka _[fmw42](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=9098) _ and another user _[pooco](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=10889) _, it was discovered that if you set the inter-tile space (set in the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting) to a negative number you can actually overlap the tiled areas into which the images are drawn. For example, here we use a negative horizontal inter-tile spacing, for a single row of images. magick montage null: font\_\*.gif null: \\ -tile x1 -geometry -5+2 montage\_overlap.jpg [![[IM Output]](montage_overlap.jpg)](montage_overlap.jpg) Rotating the images will make the overlapping series even more interesting... magick montage null: font\_\*.gif null: -background none -rotate 30 \\ -background white -tile x1 -geometry -8+2 montage\_rot\_overlap.jpg [![[IM Output]](montage_rot_overlap.jpg)](montage_rot_overlap.jpg) Note that I needed to add a special "`null:`", spacing image at the start and end of the row of images so the images do not overflow the canvas, "`magick montage`" calculates and generates. This presents us with some interesting possibilities. For example you could generate a very interesting row of overlapping thumbnails, by making use of the randomly rotated [Polaroid Transform](../transform/#polaroid) . magick montage -size 400x400 null: ../img_photos/[a-m]*_orig.* null: \ -auto-orient -thumbnail 200x200 \ -bordercolor Lavender -background black +polaroid -resize 30% \ -gravity center -background none -extent 80x80 \ -background SkyBlue -geometry -10+2 -tile x1 polaroid_overlap.jpg [![[IM Output]](polaroid_overlap.jpg)](polaroid_overlap.jpg) The use of [extent](../crop/#extent) in the above is used to remove the randomness of image size that "`[+polaroid](https://imagemagick.org/script/command-line-options.php?#+polaroid) `" can produce on different 'runs', giving more control of the final spacing and overlap between images. This is a very interesting result, though it should actually be classed as a BUG, as this is not the intended purpose of "`magick montage`". I also would not expect any HTML image mapping to work correctly, without some fixing by the user. However a more complex, and user controllable solution for overlapping images is demonstrated using a scripted form of [Layer Merging](../layers/#merge) , which is the recommended and more logical solution. See examples in [Programmed Positioning of Layered Images](../layers/#example) . ### Montage Concatenation Mode As you saw, montage has a special concatenation mode, which can be used to join images together without any extra spaces just like the "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" option. I do however recommend you set the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" option appropriately, so as to direct the appending either horizontally, vertically or in an array. For example, here we use a "`-tile x1`" to append images horizontally. magick montage balloon.gif medical.gif present.gif shading.gif \\ -mode Concatenate -tile x1 montage\_cat.jpg [![[IM Output]](montage_cat.jpg)](montage_cat.jpg) But you can also use it to just as easily create an array of images. Preferably, the images are the same size, so they fit together properly. magick montage balloon.gif medical.gif present.gif shading.gif \\ -mode Concatenate -tile 2x2 montage\_array.jpg [![[IM Output]](montage_array.jpg)](montage_array.jpg) When concatenating images of different sizes, the images are concatenated with 'top' vertical alignment, then 'left' horizontal row alignment. magick montage medical.gif rose: present.gif shading.gif \\ granite: balloon.gif netscape: recycle.gif \\ -mode Concatenate -tile 4x montage\_cat2.jpg [![[IM Output]](montage_cat2.jpg)](montage_cat2.jpg) However vertical alignment goes weird when framing is also added. magick montage medical.gif rose: present.gif shading.gif \\ granite: balloon.gif netscape: recycle.gif \\ -mode Concatenate -tile 4x -frame 5 montage\_cat3.jpg [![[IM Output]](montage_cat3.jpg)](montage_cat3.jpg) Of course, framing is not really part concatenate mode, so if "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" is set before the "`[-mode](https://imagemagick.org/script/command-line-options.php?#mode) `" setting, it will be turned off. As such this quirk is not likely to be seen, except by mistake when you accidentally use a 'zero geometry' (see below). | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Montage Concatenation to the 'HTML' image indexing format, produces incorrect image maps. Basically the resulting image map will be as if the generated montage was a true equally divided 'array' of images, rather than a concatenation of the images in line. In other words it is wrong for lines of 'short' images._ | ### Zero Geometry, caution required With only "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" spacing values (no image resizing specified), all montages image frames are set to the same size, so that both the widest and tallest image will fit, without being resized. This is itself an useful behaviour... magick montage present.gif rose: shading.gif \\ -frame 5 -geometry +1+1 montage\_geom\_1.jpg [![[IM Output]](montage_geom_1.jpg)](montage_geom_1.jpg) However a 1 pixel gap was left around and between the image frames. But if you try to remove those gaps with a position of "`+0+0`", you run into a very unusual problem... magick montage present.gif rose: shading.gif \\ -tile x1 -frame 5 -geometry +0+0 montage\_geom\_0.jpg [![[IM Output]](montage_geom_0.jpg)](montage_geom_0.jpg) The 'zero geometry' you specified (that is "`-geometry 0x0+0+0`" ), has the extra effect of putting montage in a 'concatenation' mode (see above), which is NOT what we were after in the above. For single images it also does not matter if we use a zero "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" (and thus concatenation mode). The desired result is what we want, no extra borders. As such a "`-geometry +0+0`" is fine if you are only using "`magick montage`" to [add a label to an image](../annotating/#labeling) . The concatenation mode will however not be invoked if you specify a non-zero geometry 'size' for your images, even though you used a zero offset. This in turn gives us a tricky solution to our original problem. What we do a set a geometry image size of "`1x1`" but also tell IM, never to shrink images (using a "`<`" character) to this size! In other words, never resize an image ever, just use a zero offset, in a non-zero geometry argument. magick montage present.gif rose: shading.gif \\ -frame 5 -geometry '1x1+0+0<' montage\_geom\_1x1.jpg [![[IM Output]](montage_geom_1x1.jpg)](montage_geom_1x1.jpg) This brings up another good rule of thumb... **Always set a non-zero geometry when using montage** Even if it is only the 'fake' geometry such as I used above. ### Background and Transparency Handling By default images are overlaid onto the montage canvas, which is created using the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color setting, as you can see here. magick montage font\_9.gif \\( recycle.gif -set label recycle \\) medical.gif \\ -tile x1 -geometry +5+5 -background lightblue bg\_lightblue.gif [![[IM Output]](bg_lightblue.gif)](bg_lightblue.gif) Instead of a solid color, you can instead use "`[-texture](https://imagemagick.org/script/command-line-options.php?#texture) `" to define a tile image to use instead of the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color. magick montage font\_9.gif \\( recycle.gif -set label recycle \\) medical.gif \\ -tile x1 -geometry +5+5 -texture bg.gif bg\_texture.gif [![[IM Output]](bg_texture.gif)](bg_texture.gif) Adding frames (which add extra border space into the tiles) just adds more drawn 'fluff' on top of the background canvas. magick montage font\_9.gif \\( recycle.gif -set label recycle \\) medical.gif \\ -tile x1 -frame 5 -geometry '40x40+5+5>' \\ -bordercolor lightblue -texture bg.gif bg\_frame.gif [![[IM Output]](bg_frame.gif)](bg_frame.gif) Note that when framed, the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" setting will be used to fill in the inside the frame, effectively becoming the background color of the image. Also notice that any transparent areas of the image are also set to this color. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Before version 6.1.4 of IM, what was seen in the transparent areas of images was undefined. In some versions you would see through the framed image to the background color or texture. On others you might get black, or white. In still other versions you would be able to see though all the layers and the final image would be transparent where the original image was transparent. Upgrade NOW if this is a problem for you.

_ | Also new to IM version 6.1.4 is the ability to use a special 1 pixel wide frame. This will basically remove the frame around the image cells completely, but retaining the internal "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" padding around (and underneath) the image. For example compare a frame of '`1`' with the minimal frame width of '`2`'. magick montage font\_1.gif \\( recycle.gif -set label recycle \\) medical.gif \\ -tile x1 -frame 1 -geometry '40x40+5+5>' \\ -bordercolor lightblue -texture bg.gif bg\_frame\_1.gif [![[IM Output]](bg_frame_1.gif)](bg_frame_1.gif) magick montage font\_2.gif \\( recycle.gif -set label recycle \\) medical.gif \\ -tile x1 -frame 2 -geometry '40x40+5+5>' \\ -bordercolor lightblue -texture bg.gif bg\_frame\_2.gif [![[IM Output]](bg_frame_2.gif)](bg_frame_2.gif) But what if you want your montage to have a transparent background? Particularly, if you plan to use it on a web page containing a texture mapping. Simple, just use a "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color of '`None`' or '`Transparent`', without any "`[-texture](https://imagemagick.org/script/command-line-options.php?#texture) `" image to override that setting. For example, here we generated a transparent montage. Note that "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" is still used to add space around and between the images. magick montage font\_9.gif recycle.gif medical.gif \\ -tile x1 -geometry +2+2 -background none bg\_none.gif [![[IM Output]](bg_none.gif)](bg_none.gif) Of course if you also use "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `", you need to make the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" transparent too. magick montage font\_9.gif recycle.gif medical.gif \\ -tile x1 -frame 5 -geometry '40x40+5+5>' \\ -bordercolor none -background none bg\_framed\_trans.gif [![[IM Output]](bg_framed_trans.gif)](bg_framed_trans.gif) Note that the montage "[`-shadow`](https://imagemagick.org/script/command-line-options.php?#shadow) " option is completely unaffected by all the above. it is applied according to the final transparent shape of the cells, before it is overlaid onto the background color or texture. magick montage font\_9.gif recycle.gif medical.gif \\ -tile x1 -shadow -geometry '40x40+5+5>' \\ -texture bg.gif bg\_shadow.gif [![[IM Output]](bg_shadow.gif)](bg_shadow.gif) magick montage font\_9.gif recycle.gif medical.gif \\ -tile x1 -frame 5 -shadow -geometry '40x40+5+5>' \\ -bordercolor none -texture bg.gif bg\_shadow\_framed.gif [![[IM Output]](bg_shadow_framed.gif)](bg_shadow_framed.gif) Any suggestions, ideas, or other examples of using "`magick montage`" are of course always welcome. The same goes for anything in these example pages. * * * Montage Image Output Size The mathematics of montage is straight forward... Basically the montage width should be.... (geometry\_size + 2\*frame\_size + 2\*geometry\_offset) \* images\_per\_column That is, each 'cell' of montage has a fixed sized frame and spacing (border) added around it before the cells are appended together. In essence the size of montage is also a multiple of the tile size, which can make it easy to break up montage, or re-arrange the 'cells', if so desired, as they are simple fixed sized tiles in a rectangular array. The height is similar but with tha additional spacing needed for labels and the optional montage title, both of which are much more difficult to calculate, as they depend heavilly on text, font, pointsize, and density settings. There is also an effect of adding a shadow to the montage in this calculation, but that appears to be a simple small fixed addition to the bototm and right edges. It does not appear to effect the tile size used. * * * --- # Basic Usage -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Basic Usage =============================================================== **Index** | | | | --- | --- | | [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) | | | [![](../img_www/granitesm_right.gif) ImageMagick Command Line Processing](#cmdline)

* [Why did Command Line Style Change!](#why)

* [IMv7 command line Syntax](#syntax)

* [Operators and Setting Options](#options)
* [Settings](#option_settings)
:  [operator](#option_ops)
,  [input](#option_in)
,  [output](#option_out)
,  [control](#option_ctrl)

* [Operators](#option_operators)
:  [create](#option_create)
,  [simple](#option_simple)
,  [list](#option_list)
,  [stack](#option_stack)
,  [misc](#option_misc)

* [A Working Example of an IM Command](#example)

* [Legacy Command Line Style](#legacy)

* [Command Line (CLI) vs API](#cmd_vs_api)

* [Argument Handling](#arguments)
[Constant Names](#arg_constant)
,  [Constant List](#arg_const_list)
,  [Geometry Arguments](#arg_geometry)
,
[Floating-Point Lists](#arg_list)
,  [Freeform Strings](#arg_string)
* [Percent Escapes](#arg_percent)

* [Delayed Percent Escapes](#arg_delayed)


[![](../img_www/granitesm_right.gif) ImageMagick Commands](#im_commands)

* [Convert -- magick and modify images](#convert)

* [Identify -- Output information about this image](#identify)
* [Identify, To Ping or not to Ping!](#identify_ping)

* [Identify as a floating point Calculator](#identify_math)

* [Extra Cavats about Identify](#identify_cavats)

* [Identify Alternatives - Text Output Options](#identify_alt)

* [Mogrify -- in-place batch processing](#mogrify)
* [Alpha Composition with Mogrify](#mogrify_compose)

* [Using Convert Instead of Morgify](#mogrify_convert)

* [Batch Processing Alternatives](#mogrify_not)

* [Composite -- overlaying images in special ways](#composite)

* [Montage -- generating arrays of thumbnails](#montage)

* [Display -- Slideshows of Images](#display)

* [Animate -- Show GIF Animations](#animate)

* [Compare -- Look for Differences](#compare)

* [Stream -- Pipelined Image Processor](#stream)

* [Import -- Read Images from On-screen Display](#import)

* [Conjure -- Experimental IM Scripting Language](#conjure) | [![](../img_www/granitesm_right.gif) Image Lists](#image_lists)

* [Parenthesis -- processing images 'on-the-side'](#parenthesis)

* [Parenthesis and Settings](#respect-parentheses)

* [Image List Operators](#list_ops)

[\-delete](#delete)
,  [\-insert](#insert)
,  [\-swap](#swap)
,

[\-reverse](#reverse)
,  [\-clone](#clone)
,  [\-duplicate](#duplicate)

* [Combining Image List Operations](#seq_combine)


[![](../img_www/granitesm_right.gif) Complex Image Processing and Debugging](#complex)

[![](../img_www/granitesm_right.gif) Meta-data: Attributes, Properties and Artifacts](#settings)

* [Setting/Changing Image Atrributes](#attributes)

* [Virtual Canvas, and the Page and Repage Operators](#virtual_canvas)

* [Set Per-Image Properties](#set)

* [Define Global Artifacts](#define)

* [Image Type when Reading and Writing](#type)


[![](../img_www/granitesm_right.gif) Controling the Quality of Images](#image_quality)

* [Depth - File Format Bit Depth](#depth)

* [Quality - In Memory Bit Quality](#quality)

* [HDRI - Floating Point Quality](#hdri)
* [Quantum Effects, HDRI vs non-HDRI](#quantum_effects)

* [Clamp image bounds in HDRI](#clamp)

* [HDRI File Formats](#hdri_formats)

* [What Q-level should I use](#quality_best)

* [Image Density or Resolution](#density)
* [Photoshop and Density](#density_photoshop)

* [Some Speed Tests based on Quality](#speed)


[![](../img_www/granitesm_right.gif) ImageMagick Operational Controls](#controls) | Here we explain in detail the command line processing that IM follows, some of the new image processing abilities, the ideas, philosophy, and methodology, and what is actually going on, internally. With this background knowledge the rest of the examples provided pages becomes much clearer. Even if you only use the Application Program Interface (API), this section is well worth knowing and understanding. * * * ImageMagick Command Line Processing ----------------------------------- ### Why did the command line style change!  or... The problem with previous versions of IM In previous major version of ImageMagick (version 5.5.7 and earlier) the command line interface into the IM library has been prone to problems involving the order in which operations were performed. It was very haphazard, and confusing to anyone trying to make sense of what was actually going on. Also, what worked one time may not work in the same order another time, as the author of IM, constantly battled with the interface to get it to work as people expected. The cause of the problem was that ImageMagick followed a fairly standard UNIX command line style... **command \[options\] input\_image output\_image** As time went on this started to produce problems, as images are complex objects with an enormous number of operations that can be performed on them often involving other images. As a consequence of this the above slowly expanded to become.. **command \[options\] image1 \[options\] image2 \[options\] output\_image** This worked, and is the basic style that was used in version 5.5.7. The various image operations such as "`[-negate](https://imagemagick.org/script/command-line-options.php?#negate) `", "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `", and "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `", etc, could appear either before or after the image it was meant to apply to. For example under version 5.5.7 the following two commands were equally valid and did the same thing. magick -negate image.gif output.gif magick image.gif -negate output.gif The problem was what if you were dealing with two image processing operations! For example... magick -size 40x20 xc:red xc:blue \\ -append -rotate 90 append\_rotate.gif [![[IM Output]](append_rotate_bad.gif)](append_rotate_bad.gif) The result (in IM v5.5.7) was that the two input images were rotated first, then appended together, producing an image like... That is, the "`[-rotate](https://imagemagick.org/script/command-line-options.php?#rotate) `" operator would be applied BEFORE the "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" which is probably not what the user intended. With ImageMagick version 6, the operators will always be applied in the command line order as given by the user. [![[IM Output]](append_rotate.gif)](append_rotate.gif) As such the previous example in IMv7 will result in: the two images being appended together _first_, then that result will be rotated; producing this... If the user actually intended to do the rotations before the append, he can explicitly ask IM v6 to do it in that order. magick -size 40x20 xc:red xc:blue \\ -rotate 90 -append append\_rotate\_bad.gif This sort of fine control was just beyond previous versions of IM, and would probably have required a pipeline, or intermediate save images to achieve it. The solution to the problem, unfortunately required a drastic measure and some incompatibility. On the other hand just about every 'simple' command that worked in IM version 5 work as you would expect IM version 6. In essence command line usage in versions before version 6 was ill-defined and in my thinking broken, producing numerous odd and unexpected results. ### IMv7 command Syntax Note that no 'operation' should be given, before at least one image is either read in or created. In fact you may like to consider a 'image read/create' also as an operation as well. Afetr all it really is image processing operation, that of translate an image in a file to an image in memory. So the correct way to do this in IMv7 is to read the image, process and then use the final 'implicit write' argument to write out the result. That is.. **command "image" { -operation }... "output\_image"** Of course there are some settings that may be need to control the image reading which need to be given before actually reading the image (see below for the meaning of a setting). As such **IMv7 syntax** basically follows the following... **command { \[settings\] \[operation\] }... "implict\_write"** With the part in '`{...}`' being repeated with as many 'reads' or 'operations' you want or need. And '`[operation]`' being either an image read or create, or image processing operation that actually 'does something'. And you would do them in the exact order you want to process the images. ### Types of Options - Operators and Settings... A summary of the following is now also available from the [ImageMagick Website](https://imagemagick.org/) on [The Anatomy of the Command Line](https://imagemagick.org/script/command-line-processing.php) . All command line options will now fall into two basic groups: 'settings' and 'image operators'. Settings set values, Operators actually preform some action. | | | | --- | --- | | **Setting Options** | | | | are command line options that only save information, that will be used later by other 'image operators'. That is, they do not do anything, except set some value, to be used later. Many of the options have both a '`-`' and a '`+`' style. The latter is generally used to turn off the setting, or reset it to its normal default state. This allow you remove the effect of a setting quickly and simply. For example "`[+gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" will return the gravity setting to the initial 'gravity none' state. Settings can be further divided into a number of sub-categories... **Operator Settings** which control how later operators function. They set the colors, and fonts that may be used by an operator, control placement of images and text, the lookup of color from source images, control the method of processing by some of the more complex operators, etc., etc., etc..

> `-dither  -gravity  -fill  -background  -bordercolor  -stroke  -font  -pointsize  -strokewidth  -box  -virtual-pixel  -interpolate` 

Most setting options belong to this category. **Input Settings** are specifically restricted to controlling the creation of images that are created or read in. Typically they are used to assign or override specific meta-data that is to be associated with the image(s) created after that setting was defined. they are created or read in from an external file.

> `-label  -delay  -dispose  -page  -comment  -size` 

Remember, they are ONLY applied when an image is created or read in and are otherwise completely ignored. The special operator, "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" has been provided to change the meta-data of images after they have been read into memory, or processed in some way. See [Meta-Data](#meta-data)
below for more details. **Output Settings** which are only used during the writing or saving of images back to disk. While they can be given anywhere on the command line, they are only applied when the image is written, either as the default last image filename argument operation, or via a "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `", or "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" operation.

> `-quality  -loop  -compression  -format  -path  -transparent-color` 

If not set, or turned off (using their plus '`+`' form), an appropriate default will be used. Generally this default is a saved value from the last image read in. A few 'operation settings' such as the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color, is also assigned to the image, if the file format requires. **Control & Debugging Settings** which control how IM, in general, performs its tasks. These includes...

> `-verbose  -debug  -warnings  -quiet  -monitor  -regard-warnings`

See [IM Operation Controls](#controls)
below, for more information on these special settings. | | | | **Image Operators** | | | | Are command line arguments that will modify the image(s) in some way. They are performed **immediately** when seen, and may use other 'setting options' that have been given previously on the command line. These operators can be grouped into a few sub-categories... **Image Creation Operators** which will read images from a file or pipeline, or generate new images. These include...

> `image.png  xc:  canvas:  logo:  rose:  gradient:  radial-gradient:  plasma:  tile:  pattern:  label:  caption:  text:` 

As 'operators' they are also performed immediately when seen on the command line. They only add new images to those already in memory, but do not touch those previously read. Of course being operators, any previously defined 'settings' will be applied to them. Especially [Input Settings](#option_in)
, used to control the input from the file or file stream. For example "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", which hints at the size of the image you want to create, or setting that define or override image meta-data such as "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `", and "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `". **Simple Image Processing Operators** will modify all images that have already been read into memory. Each image is modified separately to every other image. They include operations such as...

> `-crop  -repage  -border  -frame  -trim  -chop  -draw  -annotate  -resize  -scale  -sample  -thumbnail  -magnify  -adaptive-resize  -liquid-resize  -distort  -morpohology  -sparse-color  -rotate  -swirl  -implode  -wave  -flip  -flop  -transpose  -transverse  -blur  -gaussian-blur  -convolve  -shadow  --radial-blur  -motion-blur  -sharpen  -unsharp  -adaptive-sharpen  -adaptive-blur  -noise  -despeckle  -median  -negate  -level  -level-color  -gamma  -auto-level  -auto-gamma  -sigmoidial-contrast  -normalize  -linear-stretch  -contrast-stretch  -colorize  -tint  -modulate  -contrast  -equalize  -sepia-tone  -solarize  -recolor  -opaque  -transparent  -colors  -map  -ordered-dither  -random-dither  -raise  -paint  -sketch  -charcoal  -edge  -vignette  -emboss  -shade  -poloroid  -encipher  -decipher  -stegano  -evaluate  -function  -alpha  -colorspace  -separate  And probably many other operators I missed! (or have been added)`

Because all image operators are performed immediately when seen on the command line, they must be given _after_ the images for which they are to operate, have been read into memory. If more than one image is present, _all_ images are operated on, one at a time in sequence. As such you will have to be careful about what image(s) you have in the current image list. Note that it is possible that some of these operators can generate multiple images. For example "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" could generate multiple image 'tiles', or "`[-separate](https://imagemagick.org/script/command-line-options.php?#separate) `" which splits images into separate channel images. As such you may end up with more images in memory. But all of them only take one image at a time as input. Note that many API's only apply the equivalent operation to just the first image in the image list given. That is, they may not loop over each image. The "`magick`" and other CLI (command line interface) commands, however apply the operator to each image in the current image list in turn. **Multi-Image List Operators** are special in that they modify the whole current list of images as a single entity. They could replace the whole list with a single combined image, or modify each image depending on the other images found before or after it. They are used for alpha composition, animation handling, color channel handling, etc...

> `-append  -flatten  -mosaic  -layers  -composite  -combine  -fx  -coalesce  -clut  -evaluate-sequence mean  -evaluate-sequence` 

Remember the whole list is treated as a single entity, and some images may be removed, or replaced. Most of the above operators merges all the given multiple images into a final single image. The [Layers Composite](../anim_mods/#composite)
method is currently the only operator that will spilt the current image list into two completely separate image lists, before merging them together to form completely new list of images. It makes the split by looking for the special '`null:`' image somewhere in the current image list. None of these operators can be used in a "`[mogrify](#mogrify) `" command, as that command processes a list of input images (given at the end) as an individual images. **Image Stack Operators** affects the ordering of the list of images currently in memory. Specifically they provide special 'on the side' processing of images. They are in many way similar to the previous [Image List Operator](#option_list)
, but they don't actual modify the images themselves, only how they are arranged in memory.

> `(  )  -delete  -insert  -swap  -reverse  -duplicate  -clone` 

Note that parenthesis '`(`' and '`)`' may require backslashing or quoting, to prevent any special meaning given to it by the Command Line shell Interface (CLI). None of these operators can be used in a "`[mogrify](#mogrify) `" command, as that command processes a list of input images (given at the end) as an individual images. **Miscellaneous Special Operators** are operators that do things in either an unusual or non-standard ways (compared to the above).

> `-geometry  -version  -list  -bench  -concurrent  -preview` 

The "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" operator is special as it is the only operator that only affects one image (the last) in the image list, rather than affecting all of the images in some way. It is only provided for backward compatibility and special alpha composition requirements. See [Geometry, resize just the last image](../resize/#geometry)
for more details. The other two "`[-version](https://imagemagick.org/script/command-line-options.php?#version) `" and "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" are information generating operators, and causes IM to explicitly quit, after returning the requested information. See [IM Special Controls](#controls)
below, for more information on these options. Some options could even cause the whole command to be run multiple times. Basically they are specially handled in some strange and unusual way. Generally these as not used except in special situations or to recover specific global information. | I hope the separation of options into settings and operators is clear as it is vital to the way IM now works. Remember under version 6 of ImageMagick... **Settings are _saved_ in some way for later use, while Operators are applied _immediately_ to the images.** This is what makes version 6 different from every previous version of IM. All options are defined to be a 'setting' or an 'operator' and the order will determine exactly when, and to what images, the option will be applied to. The [IM Examples Options Reference](../reference.html) can be used to identify what is an 'setting' and what is an 'operator'. ### Working Example of an IM Command Let's take a look at an example, and how it will be processed by IM version 6. magick eye.gif news.gif -append storm.gif tree.gif \\ -background skyblue +append result.gif [![[IM Output]](result.gif)](result.gif) Let's break this down and look at what IM v6 does... | | | | | | --- | --- | --- | --- | | **Argument** | | **Action Performed** | **Images** | | * * * | | | | | | | | **`magick`** | Initialize and Create an empty 'image list' | empty seq | | **`eye.gif`** | Read in image and add to end of current image list | 1 image | | **`news.gif`** | Add a second image into list (now with two images) | 2 images | | **`-append`** | Take all images in current list, and append vertically.
All images are replaced by a single image. | 1 (merged) | | **`storm.gif`** | Add another image to the image list | 2 | | **`tree.gif`** | And another | 3 | | **`-background skyblue`** | Set a 'background color' to be used later.
No changes are made to any images. | 3 | | **`+append`** | Join all 3 images in the list horizontally
Current background color is used to fill the empty space | 1 (merged) | | **`result.gif`** | As this is last argument, an implicit **`-write`** operation is performed with this argument. The single image in the current list is written using the given filename which also sets image file format to use. | written | As you can see the processing of the command line in ImageMagick version 6 is very straight forward, and logical, making the result predictable. And that is the point... ### Legacy Command Line Style Due to the fact that a lot of very old IM scripts out there use a command with a single image operator of the form... **command -operator input\_image output\_image** That is, you specified an image operator before you actually read the image to which the operator will be applied. To handle this legacy situation, IM will save up all the image operators it sees, and apply them to the first image when it is finally seen on the command line. That is, the above will work as if you wrote the operation in the IMv7 way... **command input\_image -operator output\_image** For example, this IMv5 legacy (UNIX option handling) command.... magick -flip storm.gif cmd\_flip\_legacy.gif [![[IM Output]](cmd_flip_legacy.gif)](cmd_flip_legacy.gif) Will produce the same result as this IM version 6 command... magick storm.gif -flip cmd\_flip\_postfix.gif [![[IM Output]](cmd_flip_postfix.gif)](cmd_flip_postfix.gif) The legacy command line style works, but has the same problems that plagued IM version 5 (see [Why did the command line style change](#why) above). All settings are applied before the first read, and all the operators are just saved away to be executed when the first image is read (and only on the first image). There is also no guarantee of the order of multiple operators will be the same as the order you give, though it is likely they will be applied in that order. Also as operators are being save up until the first image is actually read, you may find repeating a command multiple times before reading the image may result in some of the earlier commands 'disappearing'. This is not a bug, but a miss-use of the legacy abilities of IM. This style of command line is for legacy support only, and as such is depreciated, so should be avoided if at all possible. Any scripts containing this old style, should also be updated to do image reads before the operators you want to apply to them. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Legacy support will continue into IM version 7, which includes a command that allows for single-pass processing of command lines. This allows it to actually read image processing options from script files and even a pipeline. However a single-pass processing technique will not allow for the saving of operators BEFORE reading an image to apply them to. In fact the "`magick`" command will produce 'no image' type errors, if you try to use an operator without an image in memory._ | ### Command Line vs API There is a couple of major differences between a command line IM, and using the Magick API's, such as PerlMagick, RMagick, PHP IMagick, and MagickWand. **Only one Active Image List** The command line only ever has one Image List which can be worked on at any one moment. You can 'push' or save an image list temporary (see [Parenthesis](#parenthesis) and [MPR: Named Memory Registers](../files/#mpr) ). You can even 'clone' (make an efficent copy) of images from the last 'pushed' list. But you can't really work on two such lists at the same time. Other language API's on the other hand allow you to have as many separate image lists or 'wands' as you like. In fact you typically save each image as a separate wand (image list and settings) for better processing and only merge the image into a list as needed or as part of the final step. You can also work on them in any order, and store them into databases or other data structures, for sorting or later comparison. On the command line however one single image list means you can not do operations in just any order, but generally try to do things in a more logical sequence, completely finishing each image processing step as you go. Basically it means is much harder to 'go back' or to change something later, using results from one set of operations to select or modify what set of processing operations should be performed next. It is especially more difficult to merge or interleave (shuffle) two completely separate lists of images into a logical whole. However some techniques have been worked out, to allow you to do this from the command line. For example see [Multi-Layer Alpha Composition of Image Lists](../anim_mods/#composite) . **Direct Access to Pixel Data** Again you can do some math processing and merging of pixel data from the command line, but you can't easily look up attributes, or read and modify a specific pixel or area using the command line interface. You can merge and mathematically modify pixel data of images using the special [FX Image Operator](../transform/#fx) , but it is generally limited to transforming whole images, and is very very slow. To make it easier many common operations developed by users using the FX operator, have now been built into IM, creating things like [Color Lookup Tables](../color_mods/#clut) , [Evaluate Math Functions](../transform/#evaluate) , and [Multi Argument Functions](../transform/#function) . As well as the [General Image Distortion Operator](../distorts/#distort) , and some special [Image Composition Methods](../compose/#composite) . API's can manipulate images in a much more direct manner, alowing you to DIY an unique operation much more easilly, at the full speed provided by the API language. **Conditional Processing** The IM command line interface cannot easilly modify images based on some image derived attribute. For example it is very hard to process images differently depending on if the image uses a light background, or a dark background. Yes you can do some limited and specific conditional actions using the [FX Image Operator](../transform/#fx) , or ask IM to adjust (rotate) an image's [Orientation](../photos/#orient) based on certain conditions, or only shrink and never enlarge when [Resizing Images](../resize/#resize) . But these are only handling special well known and common processing conditions. The only truly practical way do conditional processing is to use separate commands and temporary files. For an example of this see the well commented [Jigsaw Script](../scripts/jigsaw) . API's on the other hand can do this type of conditional processing, while holding all the images involved in memory, ready to continue processing based on the specific conditions, as and when you need it. **Looped Processing** You also cannot just simply loop over images in a controlled manner, or easily modify the process based on which image in the sequnece is being handled. that is you can not simply do something different to each image based on the image 'scene' number, or the results of previous images. For example draw text at different sizes, or gradually blur an image, or generate an animation list in the one single command. Yes you can modify specific images in an image list. For example see [Frame by Frame Modification of an Animation](../anim_mods/#frame_mod) . But you must know how many images are in the image list, and 'un-roll' the loop to process each image in the list separately. The only truly practical way to loop over images from the command line is to write out the individual images as separate image files (see [Writing a Multiple Images](files/#write_list) ) and process them one at a time in an external scripted loop. For example see the shell script that is designed to [Divide an Image Vertically](../scripts/divide_vert) . Alternatively, you can generate the images using a shell script loop, and pipe the result into a final command to merge them into the final image or image sequnece. For example of this see [Layered Images Examples](../layers/#layer_examples) , or the various [Warped Image Animations](../warping/#animations) shell script generators. API's however have no problem with looping over multiple images, either in a single image list, or even multiple image lists, or even with a whole array or data structure of image lists. It can also hold all the images in memory ready for the final combining step, without pipelining, or using temporary files. If your application needs to be able to do any of these things (though few applications actually need to go this far) then an API may be a better choice. The "`[magick conjure](#conjure) `" program (see below) was originally designed to allow better scripted use of ImageMagick, allowing the use of multiple image lists. The improvements made to IM v7 "`magick`" has seen this experimental API fall into disuse, though it is still available and still being developed. ### Argument Handling Beyond the filenames and options on the command line there are only a few basic styles of option arguments that are used. * Constant Names  (for specific settings and method types) * List of Contant Names  (for example two colors, or Channels) * Geometry Argument  (a special formated list of numbers with flags) * Floating Point Lists  (sometimes with [Percent Escapes](#arg_percent) ) * Free Form Text Strings  (with [Percent Escapes](#arg_percent) ) #### Constant Names Constant Names are specific string constants that are used to look up an internal library of allowed settings that may be used by an option. For example, the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting can take any of nine different settings. Once set that setting is then be used by all the image processing operators that follow the setting on the command line. For example: settings such as '`North`', '`East`', or '`NorthEast`'. You can get a list of all valid settings by using the [List Operational Option](#list) (see below). For example using the command... magick -list gravity Only those specific settings are allowed and if you attempt to use some other setting you will get an error. For example... magick xc: -gravity Invalid null: [![[IM Text]](gravity_error.txt.gif)](gravity_error.txt) The setting can be specified in a number of different ways, all of which are perfectly valid. IM is very forgiving about this. For example a setting can be specified in uppercase, lowercase, or any combination of the two. The individual words (specified by uppercase letters in the "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" output) can have extra spaces, hyphens, or underscores included, and which are then simply ignored (but only between words). Consequently all the follow arguments are valid to set "North East" "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `"... '`NorthEast`',  '`northeast`',  '`NORTHEAST`',  '`NorTheAst`',  '`north east`',  '`north-EAST`',  '`NORTH_EAST`',  ' `North East` ',  '`___North___East___`'. But an argument of '`Nor The Ast`' is not valid, even though the letters are all correct, as it uses spaces within the declared words of the setting. These constant names are not just for settings, but also to declare the operational method to use in some of the more complex image processing operators, such as "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `", "`[-distort](https://imagemagick.org/script/command-line-options.php?#distort) `", and "`[-morphology](https://imagemagick.org/script/command-line-options.php?#morphology) `". Some of the constant names are read from external configuration files. For example, color names such as for "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `", "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `", "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" and "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#mattecolor) `". Or the special 'threshold' maps used for "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `". Again "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" can be used to look up what names your currently installed version of IM knows about. #### Constant Name List This is a little used argument and is most commonly used in settings that need one or two colors, such as [Level Adjustment by Color](../color_mods/#level-colors) . The "`[-level-colors](https://imagemagick.org/script/command-line-options.php?#level-color) `" option can take any of the following argument styles. > `color   color1,color2   color1-color2` It is also used for Image Selection, for operations that make use of multiple image indexs, for example [Duplicate](#duplicate) and [Clone](#clone) . The indexes start with zero for the first image, while negative indexs can be used to denote image indexs starting from the end of the image list. For example '`-2-1`' means take the second last image (index '`-2`'), to the second image (index '`1`'). And yes this actually means take the images in the reverse order specified!Another option that makes heavy use of this is [Channel Selection](../color_basics/#channel) where you can specify a list of specifically named channels. For example: '`Red,Green,Blue,Black,Alpha`'. However the [Channel Setting](../color_basics/#channel) can also use a shorthand using a string of single letters (Eg: '`RGBA`') #### Geometry Arguments This is the most common form of option argument, and is typically used to specify sizes, rectangles, and offsets for various operations. But it is also used by any option that needs any list of 1 to 5 numbers, whether they are integers, or floating point. For example, options such as "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `", and "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" will use the full syntax of a geometry argument, while others like "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `", "`[-level](https://imagemagick.org/script/command-line-options.php?#level) `", and "`[-gamma](https://imagemagick.org/script/command-line-options.php?#gamma) `", may only use a small part of the full geometry syntax. This type of argument is so common that a special (and complex) parser has been written to magick such string arguments to numbers and flags, for use by any operator that needs a geometry argument. A geometry argument basically allows an user to specify a single string argument containing up to 5 floating point values (though most operators only use integers). All the following string forms are understood the geometry argument parser... > `WxH+X+Y   WxH   +X+Y   A   A/B/C   A,B,C,D,E` Users could specify the small list of numbers in ANY of these forms, but typically which form is used depends on the operation the argument is being used for. The first few is typically used for the specification of a rectangle of specific size and location, or just an offset for some purpose. Offsets are always decoded to different numbers, those on either side of an 'x' in the string. That is, a "`+X+Y`" is always decoded as a 3rd and 4th numbers while it flags that the 1st and 2rd are undefined (or zero). The last few forms will allow up to a maximum of 5 posible input values, and are typically used for specifying a value for each of the standard RGBKA image channels. On top of these numbers, the parser also reports if any special 'flag' characters are present (any of '`%`', '`^`', '`!`', '`<`', '`>`' ). The Parser however only reports if the characters is present. It does not report where they were found in the argument. IM for example does not remember that '`%` was attached to a specific number. It also does not report if it appears multiple times either. This means that a geometry argument of '`%50`' has exactly the same meaning as '`50%`' though the latter is preferred for readability. Also '`50%x30`' will probably actually mean '`50%x30%`' and NOT 50% of the images width, and 30 pixels high as you might think. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _As a geometry arguments can contain special '`%`' flags, you currently can not use [Percent Escapes](#arg_percent)
to set its values based on image attributes.

There is a [Future Proposal](../bugs/future/#settings)
about exactly when a percent escape will be expanded that could fix this problem with geometry arguments. And hopefull will be part of IMv7.

_ | #### Floating Point Lists If more than 5 floating point numbers are needed, perhaps even an unknown number of values, then a **Floating Point List** argument, is used, though at the moment these are generally parsed by individual options, as they can vary slightly from option to option. Generally they consist of a string (typically quoted) of comma or space separated floating point numbers. The [Distort Operator](../distorts/#distort) is probably the most well known operator to use a list of floating point numbers. Others include [User Defined Morphology and Convolution Kernels](../morphology/#user) , though it also has extra syntax specific to defining an array of numbers (kernels). One variant of floating point numbers is used by "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `", allowing you to substitute colors for some floating point values. Internally these are still converted to floating point values when the resulting array is passed into the core library function. #### Freeform Strings Other options just take a string as an argument. Either for generating labels, annotating text, or saving as image meta-data. These will typically include [Percent Escapes](#arg_percent) in the string which are replaced (substituted) at some point before the string is used. It may be an immediate substitution, or the substitution may be performed later, just before the arguemnt is actually used. (See [Delayed Percent Escapes](#arg_delayed) below. #### Arguments with Percent Escapes Because of their nature, either of last two types of arguments are often pre-processed so as to expand [Image Property Percent Escape](http://imagemagick.org/script/escape.php) within the string. That means that specific sequences of characters will be expanded (string replaced or substituted) into some other string, or value that is looked up or calculated from the image(s) being processed. This typically is done just before the argument is actually applied by the operator to a specific image, so that settings specific to that image can be used.If percent escapes are allowed in an argument, you can instead prefix the argument with a '`@`' so that the whole argument is instead read from the given external file (or standard input). For example '`@filename`' will be replaced with the contents of the file '`filename`'. If this happens, _no percent or other special escapes is applied_. That is, string read from the file will be taken as literal, and used without modification. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _WARNING: that file could be anything, including system and password files that may be readable by the program. As such web users should pre-check input strings for this special case, or better still feed that string to IM using the '`@filename`' clause, as a security measure._ | If the string is not read from a file or input stream, then any '`\n`' strings are replaced with a 'newline' character, and any '`%`' prefixed label is replaced with the appropriate value. See [Image Property Percent Escapes](http://imagemagick.org/script/escape.php) for the complete list of replacements. The use of Percent Escapes in arguments, means that for growing list of operators that allow the use of such escapes, such as "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `","`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `", "`[-distort](https://imagemagick.org/script/command-line-options.php?#distort) `", or "`[-morphology](https://imagemagick.org/script/command-line-options.php?#morphology) `", you can generate arguments based in various image attributes and meta-data. ImageMagick version 7 allows the use of Percent Escapes in just about EVERY argument, (a key feature of IMv7!). Not only that but you can even calculate different arguments depending in the content or index of the image! You can even pre-calculate some complex settings using per-image or predefined global settings. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.6.9-0 [Percent Escapes](http://imagemagick.org/script/escape.php)
and more specifically [FX Percent Escapes](../transform/#fx_escapes)
involving image indexes, such as '`%p`', '`%n`', '`%[fx:t]`' and '`%[fx:n]`' were broken. Typically they would only return unhelpful values of either '`0`' or '`1`', and not the actual index and number of images in the current image list._ | #### Delayed Percent Escapes Note that for some setting options [Percent Escapes](http://imagemagick.org/script/escape.php) are not be expanded immediately they are seen, but simply stored AS given. It is only later when the text is actually used, that any [Percent Escapes](http://imagemagick.org/script/escape.php) found in the string should be expanded, when the image they will be used with are finally known. That is, these arguments must delay the substitution of [Percent Escapes](http://imagemagick.org/script/escape.php) until the argument is actually used. These options include the [Input Settings](#option_in) such as: "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `", "`[-comment](https://imagemagick.org/script/command-line-options.php?#comment) `", as well as the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting, and global "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" values. This means you can specify a "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" containing image specific [Percent Escapes](http://imagemagick.org/script/escape.php) long before the image it is to be applied to is actually read in. Only when the label is actually attached to the image (just after it is read in) is the [Percent Escapes](http://imagemagick.org/script/escape.php) expanded, so that it can make use of the attributes of the image to which it is being applied. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The major limitation to the more wide spread use of [Percent Escapes](http://imagemagick.org/script/escape.php)
is that it is currently only applied to a limited set of option arguments. For example we currently can not use them with [Geometry Arguments](#arg_geomtery)
, which also use 'percent' characters, but for a different purpose.

This problem is one of the major problems that IMv7 will be fixing._ | * * * ImageMagick Commands -------------------- While the bulk of these ImageMagick example pages use the "`magick`" command to process images, there are a number of other ImageMagick commands, which I'll briefly introduce here. Some of these commands however can not be demonstrated properly on a web page. However I will try to give you hints and tips involving those commands here, even if I can't actually show their output directly, here. ### Convert -- Convert and Modify Images The "`magick`" command is the main workhorse of ImageMagick, and as such just about every set of examples in these pages uses this command. As such I will not cover the use of this command much here, but look at a little history instead. The commands original purpose when IM was first created was for the conversion of images in one image format into another. In fact it is still used for this purpose, and why it is called "`magick`". Because of this the command may not even read an image into memory, but may use secondary [Delegate](../files/#delegates) programs outside IM proper to do the conversion directly. This completely external aspect however has fallen into disuse over time, and lack of need, except as a means of reading in and writing out complex images file formats. Over a long period of time some extra image processing features was added to make minor changes to images as they were transferred between formats, or even the same format. These were generally simple options, but as of IM version 5 the use of these processing features had become extensive, and a far more important aspect to the "`magick`" command than just image conversion. As options multiplied, multiple options started to be used, the order of the options started producing weird and uncontrollable results. To users IM became known as unstable and uncontrollable when multiple image processing options was used, and it started to fall into disfavor. IM version 6 saw the switch from a simple 'options' style, to a 'do it as you see it' style for image processing, and as a result, image processing abilities become stable, predictable and IM's command line abilities became many orders of magnitude more useful. As a result of this, "`magick`", is no longer so much about 'converting' images from one format to another, but as a command line API for accessing image processing functions, to create, and modify images in very complex ways, without needing a degree in image processing, or programming in a computer language (such as Perl, PHP, or C). Of course some shell scripting knowledge is helpful, though not strictly required. ### identify \-- Print the details of images, that IM sees The "identify" command is designed to return information about an image in a simple and useful way. By default it outputs a simple compact summary, detailing the images name, file format, image size, virtual canvas size and offset, color depth, internal format type, and if known the original size of the image on disk in human terms. For example... magick identify tree.gif [![[IM Text]](identify.txt.gif)](identify.txt) Note that the '`8c`' in the above result is not the number of colors within this image (which is actually 6), but the 'pseudo-color' palette size (see later example for actual number of colors). Also note that the image 'virtual canvas' is the same size as the actual image with a zero offset, meaning it is currently not being used. Adding a [`-verbose`](#verbose) , [Operational Control](#controls) , will produce as much information about the image that IM knows about or can easily calculate. This includes color statistics, color counts, profile information, internal image save type of the image, etc. etc.. However be warned that the output really is... _verbose_! Specific information can be obtained and output in specific ways by using the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting, and IM special percent ('`%`') escapes to output [Image Properties](https://imagemagick.org/script/escape.php) . However typically you need to specify an EOL (newline under UNIX or MacOSX) as part of that argument (changed in IM v6.8.5-8). For example you can just extract a count of the number of colors within an image. magick identify -format '%k\n' tree.gif [![[IM Text]](identify_colors.txt.gif)](identify_colors.txt) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.8.5-8 "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" would automatically add an end-of-line character(s) to the output, so as to separate multiple image results. This is no longer done, so you may need to add your own appropriate EOL characters to the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" string._ | #### Identify, to Ping or not to Ping IM "`[magick identify](#identify) `" by default only reads minimal basic information about an image, using a technique know as "`[-ping](https://imagemagick.org/script/command-line-options.php?#ping) `". This means identify only reads enough of the image file to determine simple image information, such as size, without trying to read the whole image into memory. See [Ping, Operational Control](#ping) below. This is a big advantage of "`[magick identify](#identify) `" has over "`[magick](#magick) `". However, most image meta-data will not be available. For example, image labels from a PNG image file. For example, here I create an image with a 'label', and attempt to use a simple format setting to print out that label. magick rose: -set label "rose with a label" rose.png magick identify -format '"%l"\n' rose.png [![[IM Output]](rose.png)](rose.png) [![[IM Text]](identify_ping.txt.gif)](identify_ping.txt) However this only happens for very specific cases. Any "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" that has more complex escapes will automatically disable the use of a minimal 'ping' read. magick identify -format '"%[label]"\n' rose.png [![[IM Text]](identify_no_ping.txt.gif)](identify_no_ping.txt) Or you can specifically disable this minimal 'ping' read, and force identify to read in the image 'in total' so it gets the desired information. magick identify +ping -format '"%l"\n' rose.png [![[IM Text]](identify_ping_off.txt.gif)](identify_ping_off.txt) Generally you do not need to worry about it too much. Unless you are dealing with very large images such as photos. #### Identify as a floating point Calculator You can do some floating point mathematics using [FX Escape Expressions](../transform/#fx_escapes) ... magick identify -ping -format 'double_width=%[fx:w*2] PI=%[fx:atan(1)*4]\n' tree.gif [![[IM Text]](identify_maths.txt.gif)](identify_maths.txt) Note that the math does not even need to be related to the image itself, allowing you to use IM as a simple floating point calculator for use within your scripts. As we are only needing basic information we used the [Ping](#ping) control to prevent identify from reading in the whole image. It has no effect on the outcome in this case, but can speed up the command enormously. #### Extra Cavats about Identify Specific Format Details Normally IM reads in the image into memory (which is essentially into own internal data format), using various image library APIs and delegate programs, before outputting the results it sees using identify. That is "`magick identify`" analyzes the image/data content it has read in and stored. It does not analyze how the specific file format stores or handles the image data. This is important as there can be very specific aspects of specific file formats that "`magick identify`" will not report on. For example while it lists the contents of a GIF image color table for each image present (multiple images are possible), it will not tell you if all the images in the file share the same color table or not. If you need specific info about specific image file format, it may be better to use a tool designed specifically for that format. For example "[giftrans](/~anthony/software/#giftrans) " for the GIF file format, and "jpegtrans" for the JPEG file format. Color Histogram Output Note that if image has more that 1024 colors, no histogram or color tables will be included in the verbose output. To force the generation of this information you can use the special '[`histogram:`](../files/#histogram) ' file format which includes everything as a large image comment. Exit Status The identify program returns a non-zero exit status if a corrupted image is encountered and you add a [Regard Warnings Control](#regard-warnings) . error=\`magick identify -regard-warnings image 2>&1 >/dev/null;\` if \[ $? -eq 0 \]; then echo "The image is good" else echo "The image is corrupt or unknown format" echo "$error" fi #### Identify Output Alternatives As of IM v6.2.4 you can also produce identify output from the "`[convert](#convert) `" command using the special "`[info:](../files/#info) `" output file format. magick ../images/k* \ -format 'image \"%f\" is of size %G\n' info: [![[IM Text]](output_info.txt.gif)](output_info.txt) You can use a [Write Operator](../files/#write) to write to "`[info:](../files/#info) `" in the middle of a sequence of operations, say as a debugging tool. You can also have it write that output to a specific file (or file stream). A simplier method would be to use an "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" option to write to the normal 'standard output'. magick ../images/k* \ -format 'Image #%p named \"%f\" is a %m\n' -identify \ null: [![[IM Text]](output_identify.txt.gif)](output_identify.txt) This can be also combined with another option, "`[-print](https://imagemagick.org/script/command-line-options.php?#print) `" to output other information. magick null: -print ' (50 + 25)/5 ==> %[fx: (50+25)/5 ]\n' null: [![[IM Text]](output_print.txt.gif)](output_print.txt) The main difference between "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" and "`[-print](https://imagemagick.org/script/command-line-options.php?#print) `", is that first will be run once for every image in memory, while the later will only run once. That means we can generate just about any text file we want about the images in memory, completely from within a single ImageMagick command. For example, here I generate a HTML file of same set of images I have used in the previous example... magick ../images/k* \ -print "
\n" \ -print "

Display of %n Thumbnails

\n" \ -print "\n" \ -format "\"%f\"\n" -identify \ -print "\n" \ -print "
That's all folks\!\n" \ -print "\n" \ -print "
\n" \ null: [![[IM Text]](output_html.txt.gif)](output_html.txt) You can see the result of the above output as a [HTML Web Page](output_html.html) showing the images. One final word about these options. All of them by default will print to the 'standard output' of the "`magick`" command. You can not specifically output to some other 'pipeline' or to a specific file, unless you previously re-directed 'standard output'. Writing the output using "`[info:](../files/#info) `" will let you direct the output to a specific file, just like you can to an image file. You can also direct the output to a previously prepared file descriptor, using the special "`[fd:](../files/#fd) `" output file format. Of course that writes once per image, so some juggling of images may be needed to arrange for it to output once only. ### Mogrify -- in-place batch processing The "`magick mogrify`" command is in many ways like "`magick`" except it is designed to _modify images in place_. That is, it's primary purpose is to read images (or animations), one file at a time, and modify them, before save the image back into the _exact same filename_ the image was read from. Because of this... **Mogrify is dangerous, as it can easily destroy the original image!** As such, before you do anything final, test "`magick mogrify`" with a separate copy of your images. Do not do use it on an original image that has no backup. Now while "`magick mogrify`" normally saves a modified image into the same filename, it has two special options which allows it to save images into a different file. The "`magick mogrify`" specific setting "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `", defines a different format and suffix to use when saving files. As such a command like... magick mogrify -format jpg \*.png Will allow you to convert, or batch modify images, without destroying the original image. In this case converting all PNG files into JPEG files with that same filename but a different suffix. However be warned that if there is an existing file with the same name, it will be _over-written_. So let me re-iterate... **Think and check before you Mogrify** or you may find you just overwrote something you wanted to keep. As of IM v6.2.0 you can also use a new "`[-path](https://imagemagick.org/script/command-line-options.php?#path) `" option to specify a different directory in which to output the processed images. This makes it safer, however it will still overwrite any images of the same name that may already be in that directory. Also any old images that was left in that directory will not be removed. As such you can have IM save the results (say image thumbnails) into an existing sub-directory, using something like this... magick mogrify -path thumbnail-directory -thumbnail 100x100 \* | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.3.4-3 the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" and "`[-path](https://imagemagick.org/script/command-line-options.php?#path) `" settings were mutually exclusive. From that version you can change formats and output directory location._ | Due to the multi-image processing capability the "`magick mogrify`" command can not use any of the [Multi-Image List Operators](#option_list) or [Image Stack Operators](#option_stack) . That means you can not use image processing operators like "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `", "`[+swap](https://imagemagick.org/script/command-line-options.php?#swap) `", "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `", "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `", "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `", and "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" in a "`magick mogrify`" command. As some setting options are needed to be set before the first image is read in (for example (for example "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" and "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `"), these options are processed and set before the first image is read in. After this each image is read in and the operators applied to them in command line order before the image is saved and the next image read in. It is important to keep this in mind as if you change one of these settings later in the sequence you can make IM forget a previous setting. For example.. magick mogrify -format gif -size 200x200 -pointsize 18 \ -font Candice -gravity north -annotate 0 "%f" \ -font Ravie -gravity Center -annotate 0 "%f" \ -font Gecko -gravity south -annotate 0 "%f" \ -size 100x64 xc:gold xc:orange xc:tomato [![[IM Output]](gold.gif)](gold.gif) [![[IM Output]](orange.gif)](orange.gif) [![[IM Output]](tomato.gif)](tomato.gif) As you can see the size of the above images generated was determined by the second "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" input setting with the first larger setting being ignored completely. On the other hand the operational setting "`[-font](https://imagemagick.org/script/command-line-options.php?#font) `" is set correctly for each of the individul "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operations. This added complexity means that it is probably a good idea to... **Mogrify images simply.** Do not attempt to do very long and complex "`magick`"-like operations in a batch operation using "`magick mogrify`", it will probably have 'setting' issues. If you are really wanting to do complex processing, write a shell/dos/perl script to use "`magick`" to process each image one at a time, or go to an ImageMagick API interface. For examples of modifying lots of images using a script see [Advanced ImageMagick Examples](../advanced/) . Just remember, "`magick mogrify`" is a dangerous command, and should always be thoroughly tested on backup images, before putting into production. Actually I also recommend that scripts include a quick 'tests' on things like "`magick mogrify`" to make sure the command does not break anything (due to version changes or differences in computer installations) before processing a very large collection of images. That is, do a small 'test case' and abort if it fails to produce a correct, before proceeding. This is actually a good idea for any large scale image processing project, so as to protect users from unforeseen consequences. I do this myself in IM Examples, and it has saved me a lot of trouble. #### Alpha Composition using "`magick mogrify`" Because "`magick mogrify`" can not use [Multi-Image List Operators](#option_list) it can not easily overlay thing like logos, or mask images using [Alpha Composition](../compose/#compose) . There is one exception to this, using "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to perform image alpha composition. This allows you to specify the second image, as part of the operators arguments, outside of the current image list. For example, here I first make a copy of the original images I want to process using a special "`[cp_perl](http://www.ict.griffith.edu.au/anthony/software/#mv_perl) `" script. I then create temporary circle 'mask' image, which I then use to cut out a circle shape from all those images, using "`magick mogrify`" with a '`[Dst_In](../compose/#dstin) `' alpha composition method. cp_perl 's/^/mogrify_/' eye.gif news.gif storm.gif tree.gif magick -size 32x32 xc:none -draw 'circle 15.5,15.5 15.5,0' circle.gif magick mogrify -alpha Set -draw 'image Dst_In 0,0 0,0 "circle.gif"' mogrify_*.gif [![[IM Output]](../images/eye.gif)](../images/eye.gif) [![[IM Output]](../images/news.gif)](../images/news.gif) [![[IM Output]](../images/storm.gif)](../images/storm.gif) [![[IM Output]](../images/tree.gif)](../images/tree.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](circle.gif)](circle.gif) ![==>](../img_www/right.gif) [![[IM Output]](mogrify_eye.gif)](mogrify_eye.gif) [![[IM Output]](mogrify_news.gif)](mogrify_news.gif) [![[IM Output]](mogrify_storm.gif)](mogrify_storm.gif) [![[IM Output]](mogrify_tree.gif)](mogrify_tree.gif) Note that any Alpha Composition method can be used in this way, but only with a constant 'source' or 'overlay' image being applied to all the images. Also as "`magick mogrify`" will be reading the 'source' image multiple times, I suggest you use the special IM specific "[MPC:](../files/#mpc) " file format to reduce the overhead of decoding the image when reading it over and over. This image file format does not need to be parsed by IM as it will be mapped directly from disk into memory (for the same machine it was created on). This saves a lot of processing time, especially in dealing with a large number of images. #### Using Convert Instead of Morgify Using a special technique to modify the output filename using [Percent Escapes](http://imagemagick.org/script/escape.php) , (see [Filename Percent Escapes](../files/#save_escapes) ), you can replace "`[mogrify](#mogrify) `" with a more versatile "`[convert](#convert) `" command. Not only that but it will provide you with a more control of the final destination name of the image. and let you better handle multi-image processing such as compositions and animations. For example, here I create thumbnails of images in the current directory, inserting a "`_tn`" string into the input filename, to create the appropraite output image filename. magick \*.jpg -thumbnail 120x90 \\ -set filename:fname '%t\_tn' +adjoin '%\[filename:fname\].gif' Warning, do not include a different file suffix in the filename setting itself. IM will not see it when deciding on the image file format to use. Note that IM can't decide from the filename it will fall back to the original file format that was read in, so a clear suffix, or a coder prefix can be important, when using this technique. To get the exact original filename the source image came from use "`%i`", "`%d/%f`" or "`%d/%t.%e`". Of course these all have the filename suffix, in the filename setting, whch IM does not use, but that should be okay as it is the same image file format. The real problem with using "`[convert](#convert) `" instead of "`[mogrify](#mogrify) `" is that ALL the images are read into memory first! Mogrify takes great pains to only read/modify/write one file (though that file could contain multiple images) at a time. But "`[convert](#convert) `" does not. As such you can very easily exceed memory limits if you are not careful. Though there are ways around this. See examples in [Read Modifiers](../files/#read_mods) and [Thumbnails](../thumbnails/) . Also as all the images are in memory as a single image list, you will need to be careful on how you process those images. For example you can not directly use [Alpha Composition](../compose/#compose) as you normally would, but may need to use the specialised [Multi-Image List Composition](../anim_mods/#composite) to do the job. Of course just as with "`magick mogrify`" this method of using "`magick`" can be dangerous, as it could easily overwrite and destroy the original image files. #### Batch Processing Alternatives If batch processing images using "`magick mogrify`" is not practical, especially if you are copying the images rather than modifying them in place, then it may be better to use some other non-IM looping solutions. These include... # Use a simple shell loop, to process each of the images. mkdir thumbnails for f in \*.jpg do magick $f -thumbnail 200x90 thumbnails/$f.gif done # Use find to substitute filenames into a 'convert' command. # This also provides the ability to recurse though directories by removing # the -prune option, as well as doing other file checks (like image type, # or the disk space used by an image). find \* -prune -name '\*.jpg' \\ -exec magick '{}' -thumbnail 200x90 thumbnails/'{}'.gif \\; # Use xargs -- with a shell wrapper to put the argument into a variable # This can be combined with either "find" or "ls" to list filenames. ls \*.jpg | xargs -n1 sh -c 'magick $0 -thumbnail 200x90 thumbnails/$0.gif' # An alternative method on linux (rather than plain unix) # This does not need a shell to handle the argument. ls \*.jpg | xargs -r -I FILE magick FILE -thumbnail 200x90 FILE\_thumb.gif And so on. I recommend the use of both "`find`" and "`xargs`" for doing recursive or even non-recursive file processing. Read their man pages. For a quick introduction see this [IM Discussion Post](https://magick.imagemagick.org/viewtopic.php?t=17400&p=65283) , as well as the guide [Xargs - Wikipedia](http://en.wikipedia.org/wiki/Xargs) which includes information on the dangers involved. If your commands start to get more complicated than this, it may be time to go to a shell script, or API program, to read in multiple images, gather information, calculate appropriate arguments, and process the images. I also recommend a good look at the "`[parallel](http://www.gnu.org/software/parallel/) `" command (typically a drop in replacement for "`xargs`"). This can not only let you run multiple commands simultaneously, but can with a little work run each command on different computers, allowing you to do network distributed processing of a very large number of tasks. For Windows Users I refer you to the [Windows Usage](../windows/) section, and in particular [Windows, Batch Processing Several Files](../windows/#for_loops) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Remember "`[mogrify](#mogrify) `", and all other IM commands will also expand all filenames containing shell meta-characters such as '\*' and '?'. This is done to allow the use of these meta-characters on the old DOS command line shell. However this could cause a bug, repeated magick mogrify execution, or possibly even a 'hack' from a some evil source that provided the filename to use. Caution and complete understanding of security issues is advised._ | ### Composite -- overlaying images in special ways The "`magick composite`" command is designed specifically for simple alpha compositing (overlaying) of two images together in various ways. This includes limiting the area in which images are combined together, though the use of a third masking image. Unlike "`magick`" the "`magick composite`" command is a very traditional command in that it will read all its options and settings, before it actually performs the single image processing operation it was designed to do. The "`magick composite`" command also provides simple access to some of the more complex alpha composition modes. For example "`[-dissolve](https://imagemagick.org/script/command-line-options.php?#dissolve) `", "`[-blend](https://imagemagick.org/script/command-line-options.php?#blend) `", and "`[-watermark](https://imagemagick.org/script/command-line-options.php?#watermark) `" image composition. If any of these arguments are given, they will override any other "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting that was (or will be) given for that command. Note also that the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting also works differently to that of either "`magick`" or "`magick montage`" and "`magick display`". In "`magick composite`" this will cause the overlaid image to be tiled across the whole of the background image. Something not yet available in other IM commands. While these special features makes "`magick composite`" an useful command, the alpha compositing is now also available for use in the "`magick`" command. (For details see [Alpha Composition in IM](../compose/#compose) ). For a summary of multiple different ways of overlaying two or more images together see the examples in [Compostion of Mutliple Pairs of Images](../layers/#composition) . For more information on the method by which two images can be merged together see the [Alpha Compositing](../compose/) examples page. The overlay limiting or 'Masking' abilities is also detailed in the above examples page in [Using a Compose Mask to Limit the Composed Area](../compose/#mask) . ### Montage -- generating arrays of thumbnails The special IM image indexing command "`magick montage`" also followed the same 'do it as you see it' style of command line structure, as "`magick`". The only difference is that when the end of the command is reached (other that the final output image filename argument), "`magick montage`" will start to process the image list into a thumbnail image index page(s), according to the settings that are currently set. This makes "`magick montage`" much more versatile than it was in IM version 5, as you can now process the images just as you would in "`magick`", then set all the "`magick montage`" settings you want, and let it finish the job. For more details about "`magick montage`" see [Montage, Arrays of Thumbnails](../montage/) . ### display \-- Slideshows of Images The "`magick display`" program is designed to display an image, or list of images in the form of a looped slideshow. It is not designed for a carefully orchestrated and timed animation of images, for that use the "`[animate](#animate) `" command. Each image will be displayed in a window sized appropriately for the image, unless other options (like window "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `", see below) override this behaviour. The image will also generally be displayed on a checkerboard background so as to show the effects of any transparency the image may have (see below). Remember this is NOT designed for the display of an animation, but as a slideshow of actual images. As such some caution may be needed when using display in a scripting program. **Image Display Time, Loop, and other options**By default a delay of approximately 2 seconds is used on top of whatever delay the user specifies using the "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" setting. However you can make it wait for user input (spacebar) by using the option "-delay 0". However defaults can be overridden by the images themselves, depending on there file format. As such animation formats like [GIF](../formats/#gif) and [MIFF](../files/#miff) could result in either a pause, or a 2 second plus the images meta-data delay setting. It is thus recommended that you always set a "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" as appropriate (remember "`-delay 5x1`" will delay 5+2 or about 7 seconds) for your script and needs. The same goes for the "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" setting. By default "`magick display`" loops forever ("`-loop 0`") but image formats like [MIFF](../files/#miff) or [GIF](../formats/#gif) can override this so as to cause it to exit after last image in the loop. See the "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" option appropriately for your situation. Note that "`magick display`" will not handle any [GIF Animation Settings](../anim_basics/#gif_anim) so frames are not disposed of, and virtual canvas sizes and offsets are ignored. In other words you will see the raw partial images in a GIF animation, not the correctly overlaid image. It does provide a "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" option to clean up such animations for display purposes. #### Transparency Handling Images containing a full alpha channel (EG PNG and MIFF formats) will be overlaid onto a 'checkerboard' background pattern, so as to let you see the effects of any semi-transparency, such as shadow effects. You can change that by selecting a different background with "`[-texture](https://imagemagick.org/script/command-line-options.php?#texture) `" such as... magick display -texture granite: test.png magick display -texture xc:black test.png Images with a palette (or boolean) transparency, such as GIF and PNG8 formats, is displayed with a the current 'transparent color' that was used to represent transparency in the color table. That is, a generally random color may be used (typically black) rather than the default checkerboard pattern. This could be regarded as a bug, though technically it isn't. However if you like display to handle such images in the same way as other images containing transparency information, you can remove the palette meta-data before feeding the image to "`magick display`" using the following commands to change the internal style for the image output format. magick image.gif -type truecolormatte miff:- | display - Alternatively, just about any operation that modifies the image being displayed will also remove the existing palette meta-data. As such some "`magick display`" options can be used to remove the palette. For example using "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `". magick display -coalesce image.gif This has the added bonus of cleaning up GIF animation optimizations that may be present. Though for multiple, unrelated images it could have other undesirable side effects. Yes these methods are clumsy, but they work. #### Display Using Convert An alternative display method (other than using "`magick animate`", see next) is to use the simpler "`x:`" output image format (See [display output format](../files/#show) ). magick image.png x: This method does not provide a backdrop window, menu options, or other controls. It just simply displays the images one image at a time. If you do want to just simple 'display' the resulting image the special '`show:`' or '`win:`' output [Spawning Delegate](../files/delegate_spawn) will do the same thing by runing the "`[display](#display) `" command on the output image, and exiting without waiting for that window to be closed. magick image.png show: #### Display Output Size Display will not scale an image to fit it to the X window display. The window size will be adjusted to fit each image, unless set using the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting. That setting can also be used to fix the windows position on the X window display. Images which are larger that the screen, will also not be resized, but will overflow the screen, display will however also provide a 'scroll window' to let the user slide around the image. This can be painful when viewing a modern high resolution digital photo. To limit display to say a 800x600 pixel area (only resize smaller, never larger), use... magick display -resize 800x600\\> photo.jpg For JPG images you can speed up the image read by using a special jpeg input size hint setting. See [Reading JPEG Control Options](../formats/#jpg_read) . magick display -define jpeg:size=1600x1200 -thumbnail 800x600\\> photo.jpg If the image is from a modern digital camera you can also use "`[-auto-orient](https://imagemagick.org/script/command-line-options.php?#auto-orient) `" to correct the camera rotation of the displayed image, using the EXIF meta-data in the image file format. If you don't want menus, you can turn them off using the "`[-immutable](https://imagemagick.org/script/command-line-options.php?#immutable) `" setting to "`magick display`", so it knows not to allow editing. #### Scripted use of Display With these options in mind, the following is my recommendation for using "`magick display`" to display results from a complex shell script... magick display -delay 0 -loop 1 -coalesce -resize 800x600\\> some\_random\_image #### Display with X Windows The option "`[-window](https://imagemagick.org/script/command-line-options.php?#window) root`" can be used to display an image on the X window background (root) window. In this case the "`magick display`" program automatically exits. By default an image is tiled across the background. For example try this.. magick display -window root pattern:checkerboard For many other examples of image tiles, and generating them see [Tiled Canvases](../canvas/#tile) , and [Background Image Examples](../backgrounds/) . If you want to use a single image for your X Windows background, you may need to know the size of your X window display. The "`xdpyinfo`" program while not part of ImageMagick, can give you that information. xdpyinfo | grep dimensions: And here we use the output of "`xdpyinfo`", to resize an image to fill the X window background completely. screen\_size=\`xdpyinfo | sed '/dimensions:/!d;s/^\[^0-9\]\*//;s/ pixels.\*//'\` magick display -resize $screen\_size! -window root photo.jpg #### Display Remote Control Display does provide a special "`[-remote](https://imagemagick.org/script/command-line-options.php?#remote) `" option. This will look for an already running "`magick display`" command and will then pass the given arguments to it. For example... magick display wizard: & sleep 5 magick display -remote logo: & Will display the built in "wizard" image in a backgrounded command. The script will then wait 5 seconds before replace it with the built-in "logo" image.Note that if no "`magick display`" command is running, the current command will open a window and not exit. As such you should also background the "`display -remote`" commands as a precaution. At this time you can not request a remote "`magick display`" to exit. As such the best way to close the remote display is to either kill the running process, or 'delete' the display window using some X window command. For example (using the non-IM command "`xdotool`")... xdotool search -class "display" windowkill ### animate \-- Show an animation of images In many ways "`magick animate`" and "`[display](#display) `" are extremely similar. However "`[display](#display) `" only shows the images in the given image file 'as-is' without change, adding an minimal 2 second pause between each frame for user input. "`magick animate`" on the other hand will apply any [GIF Animation Settings](../anim_basics/#gif_anim) that are saved with the image, and only display each image according to its 'time delay' settings, looping back to the start to repeat the animation. In other words "`magick animate`" 'animates' animation formats properly where "`[display](#display) `" does not. However because of this, the virtual canvas of the first image will control the output image size, and other image will be overlaid into that image area. Of course as the images are animated, you do have a fine control of the image display timing, using options such as "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `". The command also has an extra argument "`[-pause](https://imagemagick.org/script/command-line-options.php?#pause) `" to add an extra pause at the end of the animation loop, beyond whatever the final frames "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" setting specifies. For example you can use "`magick animate`" to generate a [Flicker Comparison](../compare/#flicker) of two very similar images, using something like.. magick image1.png image2.png -scale 400% miff:- |\\ magick animate -delay 50 -loop 0 - I have written a script to take advantage of this method called "`[flicker_cmp](../scripts/flicker_cmp) `", and find it extremely useful to pickup very subtle changes in pixel intensity that I would otherwise miss. ### compare \-- Look for Differences All current information on this is on the [Image Comparison Page](../compare/) section of IM Examples. ### stream \-- pipeline processing of massive images "`magick stream`" is a special program that is designed to handle extracting a portion of a very large image file. It is the only such program within ImageMagick, all others read the images completely into memory before processing (the exception is JPEG images via the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", as this option is passed to the JPEG delegate library).You can select a portion of the image with the "`[-extract](https://imagemagick.org/script/command-line-options.php?#extract) `" setting. And you can specify the depth of the raw bytes with "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting. And finally, you can select which color channels to extract using the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" option. However "`magick stream`" will only output the raw color bytes of the image (RAW format) as defined by the image depth, as such you may need to pipe the output of the extracted segment into convert.For example... magick stream -map rgb -storage-type char -extract 100x100+200+100 logo: - |\\ magick -depth 8 -size 100x100 rgb:- magick stream\_wand.gif [![[IM Output]](stream_wand.gif)](stream_wand.gif) For more information and examples see [Really Massive Image Handling](../files/#massive) . ### import \-- read images from the on screen display The "`magick import`" command is a special program that can be used to grab and extract images from an X windows display. For example lets get it to grab and print a window you select from your display... magick import -page A4 -gravity center ps:- | lpr It is actually rarely used as the special file format "`[X:](../files/#x) `" also provides exactly the same functionality from within the magick command. The only difference between the two is that "`magick import`" has more X window specific settings than the "`[X:](../files/#x) `" format, such as specifying the display, screen, and/or window ID, the image is to be grabbed from. Other options include controls display 'beeping' and repeated snapshots. If no specific window is specified, the mouse can be used to select what parts of the display the user wants to grab as an image. * If a single mouse click is used the whole window clicked in is grabbed and returned as an image. Note that if any other windows on the display is obscuring part of the window selected, then you will grab an image of the obscuring other windows are obscuring the selected window being grabbed. * A click in the root window, or selecting "`-window root`" will return the whole screen. * If a mouse click and drag is used a [Cropped](../crop/#crop) section of the whole screen is returned, which of course also means the location (virtual canvas offset) on the whole display (virtual canvas, or page, size) is also returned. Other options allow you to avoid human interaction with the mouse by grabbing the whole screen ("-window root"), or a specific window, given a window title, or a X window ID, which you can find using the X window utility "`xwininfo`". You can also cut down the area of the selected window using "`[-extract](https://imagemagick.org/script/command-line-options.php?#extract) `". See also the special input format, "`[X:](../files/#x) `" as an alternative to using "`magick import`". Note to import from the Windows clipboard use magick clipboard:myimage image.png and not "import" ### conjure \-- IM experimental scripting language Was originally designed to allow scripted Imagemagick use, with the use of multiple image lists, but the improvements made to IM v6 "`magick`" has seen this experimental API fall into disuse. It is an XML based language. Though if you want XML, SVG may be better for your needs. In my opinion, using the "`magick conjure`" script is probably better and easier when dealing with multi-image list. And is being used, though not very widely, due to lack of examples and support by users. * * * Image Lists... -------------- One of the most important points to remember with ImageMagick, and one that confuses both new users and experienced users, is that... **ImageMagick works with Ordered Lists of Images, not single images** That is, IM deals not with just one image, but potentially an ordered list of images, be they separate individual images, a set of images that layer on top of each other, or the frames of an animation. Also in general all image operators will be applied to _all the images in the current list_. As such if you use a "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator, it will not only draw on the last image in the list, as many new users would assume, but it will draw onto _all_ the other images in the current image list, and does so to each image in turn. Image Layering Operators, such as "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" and "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" will replace each image in the list with a new image modified according to the other images in the list. It may even add or remove extra images! Also Image List Operators, like "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `", "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `", and "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `", will replace ALL the images in the current image list with the resulting combined image. That is, it will destroy all the images, unless they were previously saved using [Parenthesis](#parenthesis) , and [Cloned Images](#clone) were used. See [Image List Operators](#list_ops) below for practical examples. Finally when a new image is read in or created, IM only adds that new image to the end of the current image list (which always exists). Some formats (like [GIF](../formats/#gif) ) may actually add multiple images to the current image list, unless a special [Indexing Read Modifier](../files/#read_mods) is added to the input filename, to limit what is read in. When saving images, IM will save the whole image list that is in memory at the time of writing. If image format allows it IM will write ALL the images into a single file. If the format does NOT allow multiple images (for example JPEG), it will write the images into separate files (See [Writing a Multiple Images](../files/#write_list) ). ### Parenthesis -- processing images 'on-the-side' With the formalization of the command line options, the processing order is now exactly predictable, and it has also become possible to add parenthesis (or brackets) to the image processing. This has been a desired feature by IM users for a long time, and allows you to do things never before possible in a single command. The opening bracket '`(`' will in affect start a new image list, that all enclosed operators will work on. The matching close bracket '`)`' will then add the resulting image list (which may be more than one image, or none at all) to the end of the previous image list. In other words, using parenthesis means... **_"I need to do a bit of work in a separate image list before adding the results to the end of previous list."_** It allows you to work on a sub-set of images, like a scratch pad, than add the result back into the main image list without affecting the images you have already previously read in or have been working on. Let's look at some simple examples... magick eye.gif storm.gif -negate +append cmd\_negate.gif [![[IM Output]](cmd_negate.gif)](cmd_negate.gif) As you can see the "`[-negate](https://imagemagick.org/script/command-line-options.php?#negate) `" operator, color negated both images, as both were in the current image list in memory at that time. But by adding parenthesis we can limit the negation to just the second image... magick eye.gif \\( storm.gif -negate \\) +append cmd\_bracket.gif [![[IM Output]](cmd_bracket.gif)](cmd_bracket.gif) Because the "`storm.gif`" image is read into a separate image list to that of the first image (generated by the "`(`" image list operator), it can be negated without affecting the first image. Then we can add the result to the main image list (that is the "`)`" operator), before appending the two images together as before. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Parenthesis must be given as a separate argument. That is, you must separate them from the other arguments by spaces. You can not add them hard up against neighbouring arguments. In other words in the IM command line argument " `\(+clone` " is wrong, while " `\( +clone` " is correct.

Also in the last example I needed to put a backslash '`\`' before the parenthesis. That is, because when using IM on an UNIX (linux) machine, parenthesis has special meaning to the command line shell. As such I need to escape, or quote the bracket symbols, when I use them.

Windows DOS scripts do not require parenthesis to be escaped with backslash. See [Windows DOS Scripts](../windows/)
for this and other differences to linux scripting.

_ | Parenthesis also make it possible to do something not previously possible to do in a single "`magick`" command. Generating arrays of images! magick eye.gif news.gif +append \\ \\( storm.gif tree.gif +append \\) -append cmd\_array.gif [![[IM Output]](cmd_array.gif)](cmd_array.gif) Arrays like this were of course possible using "`magick montage`" (see [Montage Concatenation Mode](../montage/#concatenate) ), But using a separate command makes image processing scripts more complex. Of course if you like to make the command look more array like itself, you are free to add some extra parenthesis. magick \\( eye.gif news.gif +append \\) \\ \\( storm.gif tree.gif +append \\) \\ -append cmd\_array2.gif [![[IM Output]](cmd_array2.gif)](cmd_array2.gif) The first set of parenthesis aren't strictly needed, and do add a tiny amount of extra work to IM's internal processing, but it does make it clear what the command is doing by separating the processing steps. It may also be easier for image processing scripts to perform each processing step as a separate parenthesis, as a means of separating the processing steps, it is applying. ### Parenthesis and Settings Option 'settings' are not affected by parenthesis, and will continue across the parenthesis image operators, until the setting is changed or turned off.For example... magick -pointsize 24 \\ -font Candice label:Outside \\ \\( label:Inside \\ -font Gecko label:Inside \\) \\ label:Outside -append cmd\_settings.gif [![[IM Output]](cmd_settings.gif)](cmd_settings.gif) Note how the first "`-font Candice`" setting is NOT reset back to its default setting when the parenthesis is entered, while the second "`-font Gecko`" is not replaced by the original font setting when you leave parenthesis. In other words... **Parenthesis only create a separate Image Sequence. They do not limit settings, only the images being worked on.** As of IM v6.4.1-4 the new operational control option "`[-respect-parentheses](https://imagemagick.org/script/command-line-options.php?#respect_parenthesis) `" can override this behaviour. When given at the start of an IM command, it will cause parenthesis to also save and retrieve the previous settings that have been given. That means any settings given within parenthesis, will only remain set, until the end of the parenthesis.For example... magick -respect-parentheses -pointsize 24 \\ -font Candice label:Outside \\ \\( label:Inside \\ -font Gecko label:Inside \\) \\ label:Outside -append cmd\_settings2.gif [![[IM Output]](cmd_settings2.gif)](cmd_settings2.gif) As you can see, when the parenthesis ended, the font setting was restored to the previous 'Candice' font, instead of the 'Gecko' font that was set within the parenthesis. This can be most useful when you have to change a lot of setting, for just a short time... magick -respect-parentheses \\ -font Arial label:"This is a line of plain text." \\ \\( -font Candice -pointsize 16 -fill red -undercolor lightblue \\ label:"A line using a lot of different settings." \\) \\ label:"Text is back to normal -- like Magick\\!" \\ -append cmd\_settings\_lots.gif [![[IM Output]](cmd_settings_lots.gif)](cmd_settings_lots.gif) ### Image List Operators With the stronger emphasis by IM on image sequences, especially within parenthesis, it is no surprise that a set of new image operators have been provided to manipulate the image lists. The arguments to these operators are numbers indexing the image list, starting with zero ('`0`') for the first image, and one ('`1`') for the second image, and so on. However if you give a negative index, the images are referenced from the end (last image added) of the image list. That is, an index of '`-1`' is the last image in the current image list (generally the last image read or created), '`-2`' for the second last and so on. #### `-delete {index_range_list}` The "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" list operator is the simplest of the image list operators, it just deletes images from the current image list. magick font\_\[0-3\].gif -delete 1 +append seq\_delete.gif [![[IM Output]](seq_delete.gif)](seq_delete.gif) The 'plus' form of the operator, "`[+delete](https://imagemagick.org/script/command-line-options.php?#delete) `" does not take an argument, and just deletes the last image in the current image list. The "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" operator will also accept a comma separated list of numbers, or a number range to be deleted. magick font\_\[0-7\].gif -delete 1-4,6 +append seq\_delete2.gif [![[IM Output]](seq_delete2.gif)](seq_delete2.gif) Or delete everything (and add a new image)... magick font\_\[0-7\].gif -delete 0--1 tree.gif seq\_delete3.gif [![[IM Output]](seq_delete3.gif)](seq_delete3.gif) The '`0--1`' argument means delete images from first image (index 0) to the last image (index -1). In other words ALL images in the current image list. The tree image was then added to give IM an actual result, so as to avoid a 'no image' type error. A "`[NULL:](../files/#null) `" output image could also have been used, to produce no output. If an image index does not exist, or a number range is reversed, "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" will silently ignore that specific image deletion. For example, the argument '`-25`' will attempt to delete the last 25th image in the image list, but will silently do nothing if less than 25 images are present. As such you can generate a rolling animation of 24 images using a sequence like... magick animation.gif new_frame.gif -delete -25 animation_new.gif However no image will be deleted if the number of images was 24 or less. As a result the animation will grow by one frame, every time the command is run, until a maximim of 24 frames is reached. After that the oldest (first) frame will be delete while a new frame is added. As of IM v6.3.4 "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" will not delete images that result in the numbered range being reversed. That means that last example could be re-written like this... magick long_animation.gif new_frame.gif -delete 0--25 animation_new.gif This time the "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" will delete all images between the first, to the last 25th image, leaving at most 24 images in the list. If only 24 or less images are present, the given range of images to be deleted will be effectively reversed, and the "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" operator will not delete anything. #### `-insert {index}` The "`[-insert](https://imagemagick.org/script/command-line-options.php?#insert) `" operation is sort of the opposite of "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `". It will take the last image in the current image list and insert so that it is positioned at the given index. magick font\_\[0-3\].gif tree.gif -insert 1 +append seq\_insert.gif [![[IM Output]](seq_insert.gif)](seq_insert.gif) You can think if the insert index as the number of images that should appear before the point where the image was inserted. Of course the image that was at that index (and all the images after it), will be bumped up into the next index position to make room for the new image. If a negative index position is used, the insert position is calculated after the image being inserted is removed from the end of the list. That is, it will act as if the image being inserted was not part of the original image list. As such "`-insert -2`" will 'roll' the last three images, placing two images between the newly inserted image and the end of the image list. magick font\_\[0-3\].gif tree.gif -insert -2 +append seq\_insert2.gif [![[IM Output]](seq_insert2.gif)](seq_insert2.gif) The plus form "`[+insert](https://imagemagick.org/script/command-line-options.php?#insert) `" will move the last image to the front of the image list (index `0`), effectively rolling the whole image list by one frame. magick font\_\[0-3\].gif tree.gif +insert +append seq\_insert3.gif [![[IM Output]](seq_insert3.gif)](seq_insert3.gif) To do the inverse of the above (move an image to the end of the image list), can be done by first using "`[-duplicate](https://imagemagick.org/script/command-line-options.php?#duplicate) 1,0`" to copy the first image, then use "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) 0`" to delete the first image. #### `-swap {index}[,{index}]` Simply put "`[-swap](https://imagemagick.org/script/command-line-options.php?#swap) `", will swap the positions of two images in the current image list. For example "`-swap 0,2`" will swap the first and the third images in the current image list. magick font\_\[0-3\].gif -swap 0,2 +append seq\_swap.gif [![[IM Output]](seq_swap.gif)](seq_swap.gif) The plus form of this option "`[+swap](https://imagemagick.org/script/command-line-options.php?#swap) `" will swap the last two images in the current image list. In other words, it is equivalent to "`-swap -2,-1`". magick font\_\[0-3\].gif +swap +append seq\_swap2.gif [![[IM Output]](seq_swap2.gif)](seq_swap2.gif) Probably the most common use of this operator is to swap two images before being used by an image layering operator such as "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `", "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `", "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `", or "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `". magick tree.gif frame.gif +swap \\ -gravity center -composite framed\_tree.gif [![[IM Output]](framed_tree.gif)](framed_tree.gif) As of IM v6.4 a "`[-swap](https://imagemagick.org/script/command-line-options.php?#swap) `" with a single number will swap the last image with the number given. That is "`-swap 1`" is equivalent to a "`-swap 1,-1`". magick font\_\[0-3\].gif -swap 1 +append seq\_swap3.gif [![[IM Output]](seq_swap3.gif)](seq_swap3.gif) #### `-reverse` The "`[-reverse](https://imagemagick.org/script/command-line-options.php?#reverse) `" operator (added to IM v6.3.4) will quite simply reverse the order of the whole image list. magick font\_\[0-3\].gif -reverse +append seq\_reverse.gif [![[IM Output]](seq_reverse.gif)](seq_reverse.gif) It is basically an ultimate [Swap Operator](#swap) . #### `-clone {index_range_list}` This image list operator is a little different. Given an image list number "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `" will make a copy of an image that has been saved by the 'open bracket' or 'parenthesis' operator. That is... **Clone should only be used within parenthesis** The reason for this is that it allows you to extract a copy of an image from the last saved (pushed) image list, so you can process it further. For example. magick font\_\[0-2\].gif \\( -clone 1 -rotate 90 \\) +append seq\_clone.gif [![[IM Output]](seq_clone.gif)](seq_clone.gif) The 'plus' argument-less form "`+clone`" will just make a copy of the last image of the saved (pushed) image list so that you can process it further magick font\_\[0-2\].gif \\( +clone -flip \\) +append seq\_clone2.gif [![[IM Output]](seq_clone2.gif)](seq_clone2.gif) As of the release of version 6.2.2 "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `" operator will take a comma separated list of images, or a range of indexes of the form '`_{index}-{index}_`'. magick font\_\[0-2\].gif \\( -clone 1-2 \\) +append seq\_clone\_range.gif [![[IM Output]](seq_clone_range.gif)](seq_clone_range.gif) Of course negative indexes still behave just as you would expect. For example to duplicate the whole image list you can specify it using numbers '`0`' (first image) and '`-1`' (last image), that is by using the range '`0--1`'. It may look strange but it makes sense and works fine. magick font\_\[0-2\].gif \\( -clone 0--1 \\) +append seq\_clone\_all.gif [![[IM Output]](seq_clone_all.gif)](seq_clone_all.gif) When you use a comma separated list of indexes, the images are extracted in that order you specify. magick font\_\[0-2\].gif \\( -clone 2,0,1 \\) +append seq\_clone\_list.gif [![[IM Output]](seq_clone_list.gif)](seq_clone_list.gif) If the images in a range are reversed (after negative indexes are converted to an actual image index), the extracted images is also reversed, as part of the process. magick font\_\[0-2\].gif \\( -clone 2-0 \\) +append seq\_clone\_reversed.gif [![[IM Output]](seq_clone_reversed.gif)](seq_clone_reversed.gif) The [Clone Image Operator](#clone) can be used without parenthesis, and will just copy images from the current image list and directly append them. However this is not its intended use and is to be discouraged as it will produce a different result if you later surround that set of operations by parenthesis. Also in the examples above I am generating clones and appending them to the current image list, to demonstrate the operator. In reality I should be using the [Duplicate Image Operator](#duplicate) to duplicate images in the current image list. So should you, as it will make it clearer what you are trying to do. The [MPR:](../files/#mpr) Image Memory Register, can also be used to clone images and was available in IM v5. It is actually still an useful method for cloning and storing a whole image list (of unknown length) for later use, and not just a single individual images as the above image list operators do. #### `-duplicate {count}[,{index_range}]` You can use "`[-duplicate](https://imagemagick.org/script/command-line-options.php?#duplicate) `" to generate an extra copies (clones) of an image, from the current image list (added IM v6.6.8-7). The new images are added to the end of the list. Unlike the previous (and older) [Clone Operator](#clone) it does not require the use of parenthesis. For example to make N extra copies an image (to a total on N+1) you can do this... magick font\_5.gif -duplicate 4 +append seq\_duplicate.gif [![[IM Output]](seq_duplicate.gif)](seq_duplicate.gif) Note that this operator can generate hundreds of images very quickly, however until the images are processed, the images are simply 'clones' of each other, sharing the actual image data between them. As such duplicated images are very memory efficent. If more than one image is present, the last image is duplicated N times... magick font\_\[0-1\].gif -duplicate 3 +append seq\_dup\_n.gif [![[IM Output]](seq_dup_n.gif)](seq_dupl_n.gif) If you just want to duplicate the last image once, you can use the 'plus' form of the argument. magick font\_\[0-3\].gif +duplicate +append seq\_dup\_last.gif [![[IM Output]](seq_dup_last.gif)](seq_dup_last.gif) If you want to select a particular image mutliple times duplication you can specify image index as a second argument. magick font\_\[0-2\].gif -duplicate 2,0 +append seq\_dup\_index.gif [![[IM Output]](seq_dup_index.gif)](seq_dup_index.gif) The index part of the argument can contain a list or range of image indexes to be duplicated N times. For example duplicate the whole list twice to create three times the original number of images... magick font\_\[0-4\].gif -duplicate 2,0--1 +append seq\_dup\_list.gif [![[IM Output]](seq_dup_list.gif)](seq_dup_list.gif) A [Patrol Cycle](../anim_mods/#patrol) type of animation list is also easy to create by using an image list that is reversed. magick font\_\[0-9\].gif -duplicate 1,-2-1 \\ -set delay 50 -set dispose previous -loop 0 seq\_reverse\_anim.gif [![[IM Output]](seq_reverse_anim.gif)](seq_reverse_anim.gif) Note that I did not copy the whole image list, but skipped copying the very first (`0`) and last (`-1`) image, making the image indexes `-2` to `1`. If your version of IM is older than v6.6.8-7, you can still generate duplicate images, [Clone Image Operator](#clone) , but only one set of images at a time. Or by using a technique that basically mis-uses the [Color Morph Operator](../anim_mods/#morph) , generate multiple duplicate images. The trick is to first make one clone to generate two identical images, then use "`[-morph](https://imagemagick.org/script/command-line-options.php?#morph) `" to generate in the last N-2 images between them. magick font\_7.gif \\( +clone \\) -morph 3 +append seq\_dup\_morph.gif [![[IM Output]](seq_dup_morph.gif)](seq_dup_morph.gif) Note however that by mis-using the [Color Morph Operator](../anim_mods/#morph) the images are actually being processed, as such it takes time for morph to actually process the images (producing no change). Also the images created will contain actual copies of the original data, and are not simple, memory saving clones. ### Combining Image Sequence Operations Using these operators, you can extract a copy of a specific image, modify it, and return that image back where you got it from. For example, here I make a "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `" of the 2rd image (image index '1'), rotate the images colors from blue to red, then replace the original image with the modified one by first "`[-delete](https://imagemagick.org/script/command-line-options.php?#delete) `" it and "`[-insert](https://imagemagick.org/script/command-line-options.php?#insert) `" the new one. magick font\_\[0-3\].gif \\( -clone 1 -modulate 100,100,166 \\) \\ -delete 1 -insert 1 +append seq\_update\_1.gif [![[IM Output]](seq_update_1.gif)](seq_update_1.gif) Another way that seems to have become more common is use "`[-swap](https://imagemagick.org/script/command-line-options.php?#swap) `" to replace the original image, then "`[+delete](https://imagemagick.org/script/command-line-options.php?#delete) `" the old image that is now on the end. This only requires you to give the image position twice, instead of three times. Once to clone, and once to replace the modified image. magick font\_\[0-3\].gif \\( -clone 2 -modulate 100,100,166 \\) \\ -swap 2 +delete +append seq\_update\_2.gif [![[IM Output]](seq_update_2.gif)](seq_update_2.gif) These techniques are continued below in the next section on [Complex Image Processing and Debugging](#complex) . * * * Complex Image Processing and Debugging -------------------------------------- Thanks to the addition of [Image Sequence Operators](#image_seq) (see above), you no longer need to process images one step at a time, saving the image and re-reading it again each time. Instead you can now simply hold the intermediate image in memory and continue processing it. This saves a lot of time, both in the converting of images to a file format, and in the actual IO to save the image to slow disk. This type of image processing commands can become very long and complex. As such it is better to write the command in scripts, and try to place each major operation on a line by itself for easier programming and editing. See [Hints for Better ImageMagick Shell/PHP Scripts](../api/#scripts) .For example, here I go though a whole complex processing sequence to generate a red button on a black background. magick -size 30x30 xc:black -fill white -draw 'circle 15,15 5,15' \\ \\( +clone -shade 110x90 -normalize -negate -alpha Off \\) \\ \\( +clone -clone -2 -compose Plus -composite \\) \\ \\( -clone 0 -shade 110x50 -normalize -alpha Off \\) \\ \\( +clone -gamma 1,0,0 \\) \\ \\( -clone 2,-1 -compose Multiply -composite \\) \\ -append seq\_process\_fx.gif [![[IM Output]](seq_process_fx.gif)](seq_process_fx.gif) Each line of the magick command generates a new image, except the last line where I just [Appended](../layers/#append) all the working images together to output the results of all the processing steps, rather than just the final image. This technique lets you follow what each step (wrapped in parenthesis) the very complex command produced, and allows for easier debugging of each step in of a process. Note how it only uses the initial image's size and shape to generate the initial shape of the button, so you are free to use any shape or image you like! The rest of the command will process it just like before. Of course you would normally [Delete](#delete) all the temporary working images. That is, I would replace the last line in the above with something like this... -delete 0--2 seq_process_result.gif Other ways of checking the results is to pipe the result into the display command, so as to view the results on screen, instead of save it to an image file. That is, use something like this for the last line... +append miff:- | display - Alternatively instead of "`[display](#display) `" you can use '`show:`' which will display the resulting image on screen, and then allow the original command to continue or exit. See [Show, Display Image Output](../files/#show) for more information. +append show: You actually don't even need the "`[+append](https://imagemagick.org/script/command-line-options.php?#append) `", in which case IM will show each image in sequence, by pressing 'spacebar'. You can even get fancier by using "`[montage](#montage) `" command to view the results in a nicer way... miff:- | montage - -bordercolor blue -border 1 -geometry +2+2 show: This type of image processing also allows for easy viewing of intermediate images, immediately the image has been created. Basically you can insert lines this in between "`\( ... \)`" statements. \( +clone -write show: +delete \)\ IM will automatically continue processing once that intermediate image has been output for display purposes. See [Show, Display Image Output](../files/#show) . Alternatively, by inserting this line instead, you can display all the current images generated so far at that point in the processing... \( -clone 0--1 -append -write show: +delete \)\ After you have the image processing steps debugged and settled then you can optimize the code, so that you don't use as many parenthesis steps, as well as fewer [Cloned Images](#clone) , and resulting in less intermediate images to [Delete](#delete) at the end. Remember also that "[Image Composition](../compose/#compose) ", and or "[Layer Flattening](../layers/#flatten) " merges multiple images together, to leave just the one resulting image, which can reduce the overall number of intermediate images in memory. magick -font Ravie -pointsize 48 -background black -fill white \\ label:'IM' -bordercolor black -border 5 seq\_label.gif magick seq\_label.gif -alpha Off \\ \\( +clone -shade 110x90 -normalize -negate \\ +clone -compose Plus -composite \\) \\ \\( -clone 0 -shade 110x50 -normalize -gamma 1,0,0 -alpha Set \\) \\ -delete 0 +swap -compose Multiply -composite seq\_button.gif [![[IM Output]](seq_label.gif)](seq_label.gif) [![[IM Output]](seq_button.gif)](seq_button.gif) The ability of ImageMagick, to process any image, in a standard, programmed, and automated way, using multiple steps all in the one command is what makes IM such a powerful tool. You can script up a very complex operation, then apply it to many images. Image list operators, and parenthesis just made IM an order of magnitude more powerful, allowing you to write more complex image manipulation programs, with fewer commands. For another example of scripting a complex images process together see the example [Scripted 3-D bullets from Shapes](../advanced/#3d-bullets) . Also see [Hints for Better ImageMagick Shell/PHP Scripts](../api/#scripts) , on ways of improving your image process scripting, both for easier editing, understanding, and for others to be able to follow what you have done. * * * Image Meta-data: Attributes, Properties and Artifacts ----------------------------------------------------- So far we have look at images and the actual content or data that makes up the image. But images are more than just 'image data'. There are many attributes or meta-data that is also part of an image, and affect its image processing and how other programs should handle the image. For example an image could have an 'offset' or be part of a larger 'virtual canvas' (page). That is, a single image may only be a small part larger picture, made up of a series of other images, to form 'layers' or and 'animation'. IM also attaches has a lot of special 'settings' that is used by many image processing operators to modify how they work. For example, the 'background color' to use. Some of these are global setting, which are the same across a whole list of images, while others may be different for each image within the list. So what sort of things are also part of an images? Lots of things... * Image meta-data that are typically (though not always) saved with the image in image file formats. For example: profiles, labels, captions, and comments, and virtual canvas information (page). These are all per-image settings, and can be different for each image in the current image list. * Global settings used by many different image processing operators, but generally not save with the image: Colors such as background, bordercolor, fill, and mattecolor, also font, and pointsize, gravity, compose method, color channel handling, read/write bit depth of color values. * Expert settings and defines, used to control the deeper lower level operation of specific image processing operators. For example: distortion viewport, special compose method arguments, * How the image is actually to be stored in memory within ImageMagick: for example as RGB or CMYK. Whether an alpha channel is present, and enabled or not, also the palette an image might have had when read in. However some of these storage settings are hard coded at compile time (such as in memory color value Quality). * Some general IM operational settings, such as debugging or verbose settings, typically controlling information output or error handling. That is, a lot of information that can be saved, and/or affect how images are processed. And while they can fall into a number of groups, how well ImageMagick handles each of these things and if they are global, or image specific, depends a lot on the specific thing involved. Yes I am being vague, because until you get to specifics it is very hard not to be. It can also be very confusing. All these values are stored with the in memory images in three different ways... **Attributes** These are stored as special data structure items for each image, generally so as to allow fast and direct access by the various image processing operators. For example: image size, virtual canvas geometry, background, fill, stroke, matte colors, pointsize, density, font, compose, interpolate, virtual-pixel method, profile blocks, time delay and disposal settings; and many more things. Note that some of these are 'specific' to each image, while others are treated as a 'global' setting that is set to the same value across all images by the CLI interface, even though they are still stored as part of each individual image. Attributes are typically modified using the many options, as part of the normal image processing, or more generally using [Set](#set) . **Properties** These are a freeform set of key-value strings that are attached to each image on an individual basis. Each image can have a completely different set of strings. Essentially they are meta-data items that do not need to be accessed or decoded regularly, or are used in some special way. Typical examples of this are: label, caption, and comment strings; creation and modified dates; user defined strings; results from some operators. Users can use [Set](#set) to set or change these, as long as the 'key' does not correspond to some known 'attribute'. **Artifacts** This is a global set of freeform strings that is common across all images. It is used to hold freeform global settings that define or modify the reading and image processing of all the images. An example of which is the "`verbose`" setting that causes some operations to output general information about there actions, including more verbose magick identify output. Users can modify these global values using [Define](#define) (see below), or with a special case of the [Set](#set) , (see [Using Set "Option:" to Define and Artifact](#set_option) ). Understanding these three storage methods is the key to knowing how settings and meta-data handling works within ImageMagick. And allow you to do some very advanced and normally difficult to achieve image processing techniques. ### Setting/Changing Image Attributes/Properities Simple Meta-data are image attributes that are often have the greatest importance to image processing. So important they are decoded and made available in the image data structure to allow fast use by image processing operators. Such data is generally modified in two ways. A direct changing of the image meta-data as an image is read or created. Or as a modification of meta-data to an image that is already in memory. **For example,** "`-label 'string'`" will set the comment in every image that is read in or created _after_ that setting has been set. However "`-set label 'string'`" will change the 'label' meta-data of all images the current image list, already in memory. The reason for the two methods is due to historical backward compatibility and convenience. Basically "`-label`" has traditionally been set BEFORE the image it is applied to has been read in. It only affects the images that are read in (or created) _after_ it has been set, or changed. For example.... magick -label one image_one.png \ -label two image_two.png output_image_list On the other hand "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator changes ALL the images that are in the current image list, including the ones previously read in. Thus you must generally use parenthesis to limit what image you are applying the option to, unless you want to apply it to ALL the images read in so far. magick \( image_one.png -set label one \) \ \( image_two.png -set label two \) output_image_list You can un-define the setting using "`+label`", in which case the label meta-data will be left alone as the image is read in or created. If the image read in also doesn't have a label, IM will fall back to some logical default. For label that is just the empty string. You can see more detailed and specific examples of both methods [Montage Labeling of Images](../montage/#label) which make heavy use of this for labeling purposes. This 'duality' of setting image meta-data, also exists for other options. This includes... "`[-comment](https://imagemagick.org/script/command-line-options.php?#comment) `", "`[-caption](https://imagemagick.org/script/command-line-options.php?#comment) `", "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `", "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `", and "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `". The virtual canvas size and image offset setting (page) however also has a third method, using a special operator "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" (see [Virtual Canvas](#virtual_canvas) below). For example, here I use all the setting methods available to set the 'virtual canvas offset' or 'page' of the individual images, as I create a [Animation](../anim_basics) from them... magick -delay 100 -dispose Background \\ -page 100x100+5+10 eye.gif \\ -page +35+30 news.gif \\ \\( storm.gif -set page +62+50 \\) \\ \\( tree.gif -repage +10+55 \\) \\ -loop 0 animation\_page.gif [![[IM Output]](animation_page.gif)](animation_page.gif) As you can see the traditional (non-set) method is simpler when creating multi-image list from separate image files. But "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" or the specialized "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operators are better when you need to change an image that has already been read into memory, or was created by come complex image processing methods. For example to change the image offset of the third image (image index '`2`', or the 'tree') in the last example... magick animation\_page.gif \\ \\( -clone 2 -set page +55+10 \\) -swap 2 +delete \\ animation\_mod.gif [![[IM Output]](animation_mod.gif)](animation_mod.gif) For a more extreme example of extracting and modifying individual images in a image list see [Frame by Frame Modification of an Animation](../anim_mods/#frame_mod) . Here is another example using "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" to specify a comment on all the images, and then modify one specific image. magick xc: -duplicate 9 \ -set comment 'T minus %[fx:n-t]' \ \( -clone 7 -set comment 'We have ignition!' \) -swap 7 +delete \ -format "image #%p : %c" info: [![[IM Text]](comments.txt.gif)](comments.txt) You can use "`[mpr:](../files/#mpr) `", as an alternative way of setting attributes to in memory images. For example, here we take an image with a 'Bad' comment, that is in memory, and replace the comment with a 'Good' one... magick -comment 'Bad Comment' rose: \ -write mpr:rose +delete \ -comment Good mpr:rose rose.jpg magick identify -format "image comment = %c" rose.jpg [![[IM Text]](comment_change.txt.gif)](comment_change.txt) This works, but is extremely awkward and painful to use, especially when dealing with multiple images such as an animation. In fact this is the only way to change meta-data in images in IM version 5. (Yuck!) ### General Global Attributes **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Most of these attributes are generally set globally either before or after reading images into memory (it makes no difference). They are typically used as a general control of the later image processing operations. \* Many settings are simpley globally saved for use as needed -fill -background -bordercolor -strokecolor -mattecolor -quantize +dither -channels -size -gravity -units -density -font -pointsize -tile \* Some settings affect the way an image is saved to disk, or the meta-data saved with the image. This includes -loop -compression -quality -depth -density -background \* -compose is awkward, as it can only be set globally. But if unset then individual images can have a different setting (for layering). Most of these however can be turned off, (using a + version) which causes the operator to retrieve the setting from image meta-data (eg: +background falls back to the original images meta-data if present) but more generally it falls back to some default value. (eg: +gravity falls back to 'None' to mean no gravity has been set). A few of these also get saved with images when written. Specifically the GIF format will save an the -background and -bordercolor as part of the images attributes, however these are normally ignored by programs which read these images. You may have noticed that some settings are used in multiple places. for example -density \* used in reading in many vector format images like Postscript, PDF, and WMF image formats. \* also in special image generators such as label: caption: and text: \* used as part of font drawing in -annotate -draw and -polaroid operators. \* And finally some formats save the density or resolution as part of the the image file format. For example postscript wrapped raster images, JPEG, and TIFF. Is it any wonder then why settings can be so confusing. ### Virtual Canvas, and the Page and Repage Operators The 'page' or 'virtual canvas' settings primary purpose within IM is to define how a the 'real' part of an image, (the part that actually contains color pixel data), fits in a larger context of a 'canvas'. This is especially important when multiple images are involved and need to be positioned relative to each other for [Layers of Multiple Images](../layers/) and in [GIF Animations](../anim_basics/#gif_anim) . It is also used, (and hence its name of the term 'page') to define where an image fits on a larger physical piece of paper or 'page', in [Postscript](../text/#postscript) or in generating image of a 'page' of [Text](../text/#text) . While it is most often used for [Layers of Multiple Images](../layers/) and in [GIF Animations](../anim_basics/#gif_anim) , it is also involved with remembering the original positions of images when [Cropping](../crop/#crop) , and [Trimming](../crop/#trim) Images, as well in [Multi-Image List Composition](../anim_mods/#composite) , and in [General Image Distortions](../distorts/#distort) . Now the 'page' defines two separate parts: a 'virtual canvas' or area, defining a larger space in which the image exists, and the 'offset' or location within that 'canvas' where the actual image is positioned. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _While negative 'offsets' are allowed, the 'canvas size' is limited to an area from 0,0 to the given width and height. That is, only a positive canvas can be specified._ | These two aspects, 'size' and 'offset' are closely related, but usually you want to handle these aspects separately, or in a more controlled fashion. So in addition to the normal "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" and "`[-set](https://imagemagick.org/script/command-line-options.php?#page) page`" methods, a separate option "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" has also been provided to allow a finer control. Specifically... **+repage** Without and arguments, will reset the image virtual canvas to the actual image itself. That is, just clear any virtual canvas information that the image may have. This often important after applying the image sub-diving operators such as [Cropping](../crop/#crop) , and [Trimming](../crop/#trim) . It is especially important in removing virtual canvas size and offsets before saving to the GIF or PNG image file formats, as many browsers use the canvas/offset information as part of the image display. **\-repage WxH** Change the existing images virtual canvas size, but do not reset the image position on that canvas. Note supplying this argument to either "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" or "`[-set](https://imagemagick.org/script/command-line-options.php?#set) page`" will reset the images location to '`+0+0`' which is probably not wanted.. **\-repage +X+Y** Just move the image on the virtual canvas to this absolute location without changing the images canvas size. **\-repage +X+Y\\!** Do a relative move of the image on the virtual canvas by adding the given numbers (positive or negative) to the images existing offset position. **\-repage 0x0** Attempt to find the best virtual canvas size that contains the whole image. This however will fail for images with a negative offset as there is no way to specify a virtual canvas with negative components. To avoid problems it will use the size of the actual image as the smallest canvas size possible. That is, it will never assign a virtual canvas with a zero dimensions. **\-repage 0x0+X+Y** Move the images offset, then resize the virtual canvas to best fit the images new location. **\-repage 0x0+0+0** Equivalent to a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" or "`[+set](https://imagemagick.org/script/command-line-options.php?#set) page`" or a "`[-set](https://imagemagick.org/script/command-line-options.php?#set) page 0x0`". All virtual canvas and offset information is removed. **\-repage WxH+X+Y** Equivalent to a "`[-set](https://imagemagick.org/script/command-line-options.php?#set) page WxH+X+Y`". That is, just assign the given values directly. Note the use of a '`!`' flag will make the given offset a relative displacement to the images current offset. That is, a '`-repage +5+0\!`" will move the images offset 5 pixels to the right, without modifying the virtual canvas size. It is currently not posible to directly specify a relative resize of the virtual canvas size. However it can be done by using [FX Percent Escapes](../transform/#fx_escapes) . But this is not commonly needed. One example is given in [Trimming with a Specific Color](../crop/#trim_color) . Caution is required in giving an image a final negative offset position as the GIF file format can not handle this, and resets it to zero if negative. Also some browsers go crazy when given PNG images with negative offsets. What virtual canvas information is saved with an image is format dependent. | | | | --- | --- | | **JPEG** | Like many image file formats, JPEG images do not save virtual canvas information at all. The information is just ignored and lost. | | **GIF** | The size of the virtual canvas and offsets will be saved as part of its GIF animation handling. However it will not handle negative offsets. Any negative offset will be reset to zero on save. | | **PNG** | Offsets and even negative offsets is saved, but the PNG file format does not normally save the virtual canvas information. However PNG images saved by IM will include the virtual canvas size information, but is only used by other IM commands. If IM does read a PNG image without this IM specific attribute, it will set the image virtual canvas to an appropriate size to ensure the image is visible on the virtual canvas (as per a "`-repage 0x0`"). For images without an offset that means the virtual canvas is the same size as the actual image. | Some formats like GIF and PNG save virtual canvas information, others like JPEG do not. All of the above formats have there own limitations for virtual canvas information. Only the internal MIFF file format does not have any such limitations. Note that "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" has special meaning for "`text:`" and "`ps:`" image generator operators (See [Text: Multi-line Text Files](../text/#text) and [PS: Postscript formatted Text and Graphics](../text/#postscript) ). As such its normal canvas size and offset meaning are not used during the creation of these images. ### Set and Per-Image Properties However IM can not make an option for handling every possible setting that an image can have. That would be just impossible. Not only that users often like to add or define their own settings. Because of this the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" option can actually define ANY setting with ANY value. If the setting is not a specifically known attribute of an image (to be saved in a way to allow fast acceess by operators), it is saved into the image as a '**Property**' (an array of strings), and will be listed near the bottom of a verbose "`magick identify`" output, or retrieved and expanded using [Percent Escapes](http://imagemagick.org/script/escape.php) . The built in rose image for example automatically generates three 'properties': two date strings, and a 'signature hash'. To this I have also added my own user defined 'property' setting. magick rose: -set my_property my_value -verbose info: |\ sed -n '/Artifacts/q; /Properties/,$ p' [![[IM Text]](properties.txt.gif)](properties.txt) Some image processing operators even return values of special interest as image 'properties'. They are not needed by other operators, so are not stored as a 'attribute', but are saves as a 'property' string for posible use by the user. For example the final pointsize selected by a [Best Fit Label](../text/#label_bestfit) , will be saved as a special image property. magick -size 100x label:Anthony -verbose -identify property_label.gif |\ sed -n '/Artifacts/q; /Properties/,$ p' [![[IM Output]](property_label.gif)](property_label.gif) [![[IM Text]](property_label.txt.gif)](property_label.txt) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that the [label:](../text/#label)
generator itself also sets a 'label' attribute, which happens to be saved as a property string._ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _All 'properties' are saved as a free form string data type, and stored as image meta-data.

Because of this, not all 'attributes' are saved as 'properties', as many attributes need to be saved and used directly as numerical data by image processing operators. An example of this is the virtual canvas 'page' attribute._ | Here I use an identify "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting to get IM to output the pointsize of the label it created and discarded. magick -size 100x label:Anthony \ -format 'pointsize = %[label:pointsize]pts' info: [![[IM Output]](property_pointsize.txt.gif)](property_pointsize.txt) Using this information to generate a new label image is trick and will be looked at below. One of the most useful user defined settings you can use is the "`filename:`" setting. For example... magick rose: -set filename:my\_area '%wx%h' 'rose-%\[filename:my\_area\].png' The above will generate an image named "`rose-70x46.png`". Only user defined settings prefixed with the "`filename:`" string can be used inside the output filename, as a security measure, though any name can be used. For more examples of this see [Filename Percent Escapes](../files/#save_escapes) . ### Define and Global Artifacts Defined values are known as '**Artifacts**' and are defined globally across all images, and are set using the special "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" operator. The primary purpose of such '**Artifacts**' are as special settings that can be used as extra (or out of band) settings by _Image File Format Coders_, or _Image Processing Operators_. Basically it allows the addition of free-form settings for specific requirements without needing to create another 'attribute'. Also being globally set, they are not attached to specific images, but to all images in an Image Sequence, and are available when no images have been read in or created yet. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that API's can have multiple image list, with different sets of 'artifacts' attached, but the command line interface (CLI), only has one active image list, as such 'artifacts' really are global._ | In other words 'defined artifacts' provide a way for expert users to modify the normal or standard operation of specific operators, beyond normal argument usage. For example, [JPEG Coder Settings](../formats/#jpg_read) , for both Reading and Writing such images... -define jpeg:size=300x200 -define jpeg:preserve-settings=1 -define jpeg:optimize-coding=true [Image Distortion Options](../distorts/#distort_options) , such as... -define distort:scale=2 -define distort:viewport=44x44+15+0 [Resize Filter Controls](../filter/#options) , such as -define filter:blur=0.75 -define filter:support=1.25 Some artifact defines have shortcuts because they are used very regularly by users. For example the "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" operational control (see below), is really equivalent to using "`-define verbose`", and thus creating a '`verbose`' artifact. For example... magick xc: -verbose info: |\ sed -n '/Tainted:/q; /Artifacts:/,$ p' [![[IM Text]](artifact_verbose.txt.gif)](artifact_verbose.txt) It follows then the plus form "`[+verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" just removes the '`verbose`' artifact, and is thus equivalent to "`+define verbose`". #### Artifacts and Delayed Percent Escapes Artifacts are also often used to hold special attributes that should be assigned to images that are read in, after the define has been given. The "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" setting also just sets an artifact with the argument provided by the user. This artifact is then converted into a '`label`' [Setting or Propriety](#set) after a new image has been read in or created. For example creating a "`rose:`" image with a label set magick -label "%wx%h" rose: -verbose info: |\ sed -n '/Tainted:/q; /Properties:/,$ p' [![[IM Text]](rose_properties.txt.gif)](rose_properties.txt) That is, "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `" first defined the '`label`' artifact shown. Later when the rose image was created (and its size attributes was known), IM converted that global artifact into an image specific 'property' and only then expanding any [Percent Escapes](http://imagemagick.org/script/escape.php) at that time. This is known as a [Delayed Percent Escapes](arg_delayed) . The same thing happens with a few other setting options, such as "`[-comment](https://imagemagick.org/script/command-line-options.php?#comment) `" and "`[-caption](https://imagemagick.org/script/command-line-options.php?#caption) `" as well. It is because of [Delayed Percent Escapes](arg_delayed) that "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" will only save the strings, while the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator will do the expansion. #### Using Set "option:" to Define an Artifact We showed above how you can "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" special purpose personal [Proprieties](#properties) , on a per-image bases. For example... magick -size 80x40 xc: -set myinfo 'I love IM!' \\ -gravity center -annotate 0x0 '%\[myinfo\]' \\ property\_annotate.gif [![[IM Output]](property_annotate.gif)](property_annotate.gif) But as [Proprieties](#properties) are attached to specific images, you can't use them in the creation of new images. For example this will fail... magick rose: -set myinfo 'I love IM!' label:'== %\[myinfo\] ==' \\ -gravity center -append property\_append\_fail.gif [![[IM Output]](property_append_fail.gif)](property_append_fail.gif) As you can see the '`myinfo`' property was for found or included in the appended label. On the other hand globally defined [Artifacts](#artifacts) are available to the image generators. They have to be so that the image generators or image file coders can read them for various control settings. As such as using a "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" will work as expected. magick rose: -define myinfo='I love IM!' label:'== %\[myinfo\] ==' \\ -gravity center -append artifact\_append.gif [![[IM Output]](artifact_append.gif)](artifact_append.gif) So how can use you create a label using an image property or attribute? The "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" option does not currently allow the use of image properities! The trick is to use a special prefix "`option:`" when using the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" option. This addition causes "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" to define a 'artifact' with the name that follows the prefix. For example, this is equivelent to the last example. magick rose: -set option:myinfo 'I love IM!' label:'== %\[myinfo\] ==' \\ -gravity center -append property\_option\_append.gif [![[IM Output]](property_option_append.gif)](propertyoption_append.gif) More importantally the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" option will expand [Percent Escapes](http://imagemagick.org/script/escape.php) . Which means if we have some per-image [Propriety](#properties) , we can magick it to a global [Artifact](#artifacts) . For example, here I create a label, then magick the '`label:pointsize`' property the "`label:`" image generator created, into a global artifact '`my_pointsize`'. As an artifact, this information is available when I create a second label image. I then append the two labels together (with a separating '`gray`' line). _A very tricky example_. magick -size 100x -gravity center label:Anthony \\ -set option:my\_pointsize '%\[label:pointsize\]' \\ -set option:my\_height '%h' \\ -size 100x1 xc:gray \\ -size 100x label:'at %\[my\_pointsize\]pt and %\[my\_height\]px high' \\ -append property\_append.gif [![[IM Output]](property_append.gif)](property_append.gif) Note the placement of the "`-set option:...`" in the above. If you were to place it AFTER the creation of the "`xc:gray`" it would be that image that would be used to set the global artifact. That is, because only the properties of the last image define the value stored in the global artifact. The reason is that only the last image is used to define the artifact. Actually what realy happens is that "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" is applied to every image in the current image list, even though it is generating a globel artifact. As such each image will assign its own properties into the global artifact, replacing the previously assigned values. When finished, only the last image will have 'defined' the artifact. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _At this time the 'FX escape' has no way of reading properties or artifacts. And as such you current can not do arithmetic on such values._ | ### Image Type when Reading and Writing The "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" operator/setting defines the style or color space to use when an image is being read in or written out, to ensure the resulting image (in memory, or in the image file) is what you expect it to be. As part of this, it may do some [Color Space](../color_basics/#colorspace) modifications at the time of the file I/O, though only to ensure the image is in a form that was expected. For example "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" has a special '`bilevel`' setting that can be used magick and save images as a two color monochrome image for some image formats. Similarly '`TrueColor`' and '`TrueColorAlpha`' can be used force a [TIFF](../formats/#tiff) image to be saved as a full color RGB image even if the image is actually purely gray-scale. Other settings include '`GrayScale`' and '`GrayScaleAlpha`' which will ensure the written image is gray-scale only (without or with transparency, respectively). Or '`Palette`' to force the use of an indexed color map in formats that support this option. During reading of image file formats, a "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" setting of '`TrueColorAlpha`' will force a [JPEG](../formats/#jpeg) image being read, to have a 'Alpha' channel added to its in memory storage, even though the [JPEG](../formats/#jpeg) format itself can not handle transparency. When writing to a [PNG](../formats/#png_formats) file format setting a "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" of '`Pallette`' will force it to use a color indexed "`PNG8`' internal image format. Simularly using "`BiLevel`" will force IM to dither color images to black and white for most image file formats. Unfortunately the exact meaning and capabilities of "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" depend on the specific image format you are reading or writing. See the various [Image File Formats](../formats/) example areas. For specific PNG examples see [PNG output formats](../formats/#png_formats) . * * * Controling the Quality of Images -------------------------------- ### Depth - File Format Bit Depth **Quality and Depth** are two terms are often talked about in the discussion formums and in these example pages, so I'd like to explain them a little. _Quality_ is a compile time setting in ImageMagick, and is used to determine the size of the values use to store images in IM memory and during processing. Basically it means the **Quality of Processing** that a specific IM was compiled for. The _Depth_ is the size of the values used when an image is either read or saved to/from an Image File Format. It is as such more highly variable. and controlled by the "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting, or by the original 'depth' of the image that was read in. More on this in a moment. Remember... **Quality is 'in memory' value size, and is compiled into IM. Depth is file format value size, and is variable.** Now most image formats are of depth 8. That is, they use 8 bits (or a value from 0 to 28\-1) to hold each color value used in the image. That is a value of 0 to 255 for red, 0 to 255 for green, and 0 to 255 for the blue channel. More usually this type of image is referred to as 24 bit images (that is "bits per _pixel_", NOT "bits per _value_" as used by the "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting). This includes such formats as such as [JPEG](../formats/#jpg) ). If the alpha channel is also involved than you get 4 x 8 bit values, or a 32 bit/pixel image. This is what a [PNG](../formats/#png) image will typically use, though such images can also save using 16 bit per value too. What a lot of people refer to as 8 bit images (8 bit/pixel), are really images with an 8 bit palette or color map (giving a maximum 256 color limit over the whole image). The actual pixel data is a 8-bit index value (0-255) which is then used to look up the color for that pixel from the color table. That is the 'raster' (pixel array) is just an index used to lookup the actual pixel color from a separate table of colors. In other words while an 8-bit images also have a 8 bit depth, the 8-bit is an index into a color lookup table and not an actual color. GIF images are a good example of this. Transparency in such images are usually handled either by specifying a specific color as representing transparency (set using the "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#transparent-color) `" meta-data setting) as in [GIF](../formats/#gif) format, or using a special profile for a specific number of colors in the color table, (as used by some [PNG8](../formats/#png_formats) images (which is also a color imaged image like GIF). In general... 24 bit images are : 3 x 8 bit values - 3 color channels only 32 bit images are : 4 x 8 bit values - 3 colors + Alpha channel 8 bit images are : 8 bit color indexed image, with a 256 color limit Because most image formats only save color values at an 8 bit/value depth, a lot of people have installed IM using a 'Q' or Quality level of depth 8, which requires far less memory and processes images faster than a more normal Q16 version of IM. Often 3 or more times faster. These Q8 versions work well for general image processing (cropping etc) and converting between formats, and can also work well for generating simple images, annotating, or overlaying images. However while a low quality IM is faster and more memory efficient, it does not work work well when you start using complex sequences of operations involving multiple color changes, resizing, darkening, lightening, gamma or histogram color correction, etc.. At Q8 the intermediate images in memory will remain stored as 8 bit quality, and thus multiple operations will each introduce small incremental color distortions. The result can be rounding effects, especially for extreme colors near white and black. (see below). ### Quality - In Memory Bit Quality Remember, _Quality_ is a compile time setting in ImageMagick, and is used to determine the size of the values use to store images in IM memory and during processing. It can not be changed, except by re-compiling ImageMagick from sources. A 'Q16' ImageMagick (the IMv7 default) thus will use at least twice as much memory to hold the same amount of image data as a 'Q8' version of ImageMagick, and depending on your CPU, be a lot slower, though on today's processors that is not very likely. Similarly you can compile 'Q32' and 'Q64' versions, though these are not very common, and are typically only used in very high end image processing. Also see the new [HDRI](#hdri) compilation quality option below. A 'Q16' ImageMagick also allows you to save more bit information for each pixel value. That is, color values are saved as integers ranging in values from '`0`' to '`2^_quality_-1`'. That last value is known in IM programming as the current 'QuantumRange' (or the older obsolete name 'MaxRGB'). The higher the Quality Setting, used when compiling IM, the more precise the color values are when storing the image in memory. That means that if in processing an image you generate a lot of very small, slight variations in color, then those variations will be preserved in the in-memory storage of ImageMagick, and can be used in later processing steps. Operations such as resizing, noise filters, blurring, sharpening, averaging, global color, gamma, and histogram modifications, or lots of complex image composition operations, can all produce unwanted color errors in a Q8 IM, creating very distinct color artifacts on the resulting image. Of course saving the final image to a 8 bit 'depth' image format will 'quantize' those color values back to 8 bit, but during the processing of the image in memory, the intermediate quality of the image is preserved. Some formats are available that preserve the higher quality level information used by IM. For example the [MIFF](../files/#miff) IM format, the enumerated pixel [TXT](../files/#txt) format, as well as the [NetPBM](../formats/#netpbm) image formats. However while a Q8 version of IM it will let you output a 16 bit depth images, such image will still only have information equivalent to 8 bit depth as the quality is just not present in memory, to be saved. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _If IM reads an image using 8 bit values (many image formats do), the images 'depth' will be set to 8 bit, and when saved IM will normally save the image at that same 8 bit value depth, even if you process the image using a Q16 version of IM. You can override this setting or clearing the "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting for that image, so IM will save it at the best depth posible for the image to match the IM in-memory quality.

Also note that many operators that generate extra colors such as [Image Resizing](../resize/)
, will also reset the 'depth' of the image in memory to the compile time quality setting, so that IM will then try to save it at a higher depth, if possible.

_ | ### HDRI - floating point quality HDRI, or [High Dynamic Range Imaging](http://en.wikipedia.org/wiki/High_dynamic_range_imaging) , was originally designed to more naturally represent our eyes ability to see both bright and dark areas of a scene simultaneously. In practical image processing terms it does a lot more than that. A HDRI version of IM (the default build) is compiled to use a floating point values for images stored in memory, to allow you to perform more exact HDRI handling of image operations, so as to prevent such operations 'clipping' the image colors at the extremes. HDRI uses the same color range as the default compile-time [Quality Setting](#quality) for in memory storage. That is, values still range from '`0`' to the 'Quantum Range' as meaning black to white. But the values are saved using floating point ('`doubles`' in C programming terms) rather than integers, so that the 'quantum' effects from rounding off values into integers will not be seen. The values are also not 'clipped' when the values go beyond the 'Quantum Range' or into negatives. Basically you loose far less information between processing steps. HDRI is thus _vital_ when you plan to use extremely heavy mathematical processing of images, involving the temporary use of negative values, or strong scaling to very small or very large values. It is especially important for users that want to make full use of [Fast Fourier Transforms (FFT)](../fourier/) capabilities, and it is here that you will see the most examples of a HDRI version of IM, in these pages. For information of compiling a HDRI version of IM see [Enabling HDRI in ImageMagick](https://imagemagick.org/script/high-dynamic-range.php) on the main IM website, also for Windows and Ubuntu Linux specific information see [Fourier Transforms Announcement Discussion](.https://magick.imagemagick.org/viewtopic.php?f=4&t=14251) on the user forums. One important operator that should be kept in mind when using HDRI is "`[-clamp](https://imagemagick.org/script/command-line-options.php?#clamp) `". This option will clip the values in an image that fall outsize the normal range for images. That is, any negative value will be clipped to zero, and any value larger than 'QuantumRange' will be set to that value. It does NOT however 'round off' the floating-point values into integers. #### Quantum Effects, HDRI vs non-HDRI **Quantum Rounding...** For example, here I use the [Level](../color_mods/#level) and the [Reverse Level](../color_mods/level_plus) operators to compress the color range of a gradient image down so they only use the values from 0 to 15, then un-compress it again. The resulting gradient is also displayed as an image profile (using the script "`[im_profile](../scripts/im_profile) `") to make it easier to follow. # Using a normal non-HDRI version of IM... magick -size 20x600 gradient: -rotate 90 \\ +level 0,15 -level 0,15 level\_rounding.png im\_profile -s level\_rounding.png level\_rounding\_pf.gif [![[IM Output]](level_rounding_pf.gif)](level_rounding_pf.gif) [![[IM Output]](level_rounding.png)](level_rounding.png) Notice the sever rounding (quantum effects) that is now visible, forming steps in the gradients profile. As only 16 gray-level values were used, you effectively converted the image to a color depth of only 4 bits! Note that this type of Quantum Rounding problem becomes very common in an IM Q8 version, just by doing multiple image processing tasks, beyond a basic resize, and cropping of images. Something that the more normal IM Q16 solves with its extra memory usage. Quantum Rounding only becomes a problem for IM Q16 when you use really heavy image processing such as, [Fast Fourier Transforms (FFT)](../fourier/) or merging of images containing different exposure times (light intensity) to generate High Dynamic Range Images. This is after all why HDRI was added to ImageMagick in the first place. **Burning and Clipping...** And here I 'stretch' the gradient so that the original black and white color values go well beyond the "Quantum Range", before being restored again. # Using a normal non-HDRI version of IM... magick -size 20x600 gradient: -rotate 90 \\ -level 20% +level 20% level\_clipping.png im\_profile -s level\_clipping.png level\_clipping\_pf.gif [![[IM Output]](level_clipping_pf.gif)](level_clipping_pf.gif) [![[IM Output]](level_clipping.png)](level_clipping.png) You can see that a normal IM looses the information at both ends. The lower end values gets 'burned' as values become negative, while the upper values become 'clipped' as they go beyond the maximum 'Quantum Range' limits of the integers used to store the values. **HDRI version of ImageMagick** result... Repeating these two operations using a HDRI version of ImageMagick will not produce any of the above rounding, burning, or clipping of the results, but will have an extra cost in terms of memory (doubles need more space than integers). Speed wise, it does not cost much, and may actually even be faster on many of today's modern computer hardware, due to floating point accelerators. # Using HDRI version of IM... magick -size 20x600 gradient: -rotate 90 \ +level 0,15 -level 0,15 level_rounding_hdri.png magick -size 20x600 gradient: -rotate 90 \ -level 20% +level 20% level_clipping_hdri.png im_profile -s level_rounding_hdri.png level_rounding_hdri_pf.gif im_profile -s level_clipping_hdri.png level_clipping_hdri_pf.gif [![[IM Output]](level_rounding_hdri_pf.gif)](level_rounding_hdri_pf.gif) [![[IM Output]](level_clipping_hdri_pf.gif)](level_clipping_hdri_pf.gif) As you can see the gradient remains perfectly intact, even after heavy compression or stretching of the image and back again. #### Clamp to Enforcing image bounds in HDRI You can force HDRI image to be 'clipped' by the normal image value range by using "`[-clamp](https://imagemagick.org/script/command-line-options.php?#clamp) `" between the two level options. For example... # Using a HDRI version of IM... magick -size 20x600 gradient: -rotate 90 \ -level 20% -clamp +level 20% level_hdri_clamp.png im_profile -s level_hdri_clamp.png level_hdri_clamp_pf.gif [![[IM Output]](level_hdri_clamp_pf.gif)](level_hdri_clamp_pf.gif) The use of "`[-clamp](https://imagemagick.org/script/command-line-options.php?#clamp) `" in the above basically generated the same image as what I would have got with a normal non-HDRI version of ImageMagick. However this image would not be exactly the same as a non-HDRI result, as while "`[-clamp](https://imagemagick.org/script/command-line-options.php?#clamp) `" will burn and clip the values in the image, it does not add quantum rounding effects. As such the values are only being rounded off to integers during the final save to a non-HDRI image file format. The "`[-clamp](https://imagemagick.org/script/command-line-options.php?#clamp) `" option can be vitally important when using HDRI, to achieve the result you are wanting. #### HDRI File Formats Of course saving an image that contains very small, large or negative values into a normal image file format will also be clipped, quantized, and even color reduced, for the same reasons as above. As such if you need to save images that have not been 'normalized' back into a 0 to 'Quantum Range' scale, then you will need to use one of the rare floating point image file formats. Some image formats that can handle floating point values (without clipping or rounding) include, [NetPBM PFM](../formats/#netpbm) . This is the only image file format that does not require any extra special options. Other image file formats can also be used, but require a special switch to specify that the file is to save floating point values. Specifically you need to specify the coder option "`**-define quantum:format=floating-point**`" to request floating point values in these file formats. The "`-depth`" setting can also be used to define what type of floating point values are used. If "`-depth 32`" or less (the default in most versions of IM) is used then normal "floats" are used. But if "`-depth 64`" is set then "doubles" are used for the floating point data written to, or read from, the image file format. The image file formats that can use with this special flag to save floating point values include... [TIFF](../formats/#tiff) , FITS, and [MIFF](../files/#miff) . The raw data file format [RGB](../formats/#rgb) will also save (and read) floating point, though that format does not save image size, and you need to specify the floating point settings for reading too. Another special coder option is is "`-define quantum:scale=65535.0`". This will be multiplied with value read from the image file, so as to scale the value from a normalized floating point value of 0.0 to 1.0, into the internal value range of 0.0 to 65535.0. So if you get a near pure black image when reading a floating point image, try adding this option to scale the values being read into the appropriate range. The direct memory-to-disk file format [MPC](../files/#mpc) , will also save floating point values used by a HDRI version of IM, and will not need any special flags. But as with any [MPC](../files/#mpc) image file, only the exact same version (specific compilation) of IM on the same machine will correctly read such a file. As such it is only good for temporary 'quick read' files for scripted image processing, and not for long term storage. ### What Q-level should I use In summery what type of ImageMagick should I use? Q8, Q16, HDRI? **Q8** has a smaller memory foot print, as image values are saved in memory as 8 bit values, just like most image file formats. For basic composition, image format conversion, simple 'once off resize', or drawing on images, then Q8 is 'good enough'. **Q16** doubles the memory foot print as color values are saved in 16 bit values (higher precision). But if you plan on doing heavy image processing involving many levels of operations, such as 'color space changed (even just sRGB to/from RGB), resize, distortions, blurring, shadows, etc etc all to the same image, in the same command (which is recommended for the same reason), then having 16bit is better as it will preserves the lower precision of the images between processing steps. You can also then save in 16bit file formats (PNG, MIFF, PbmPlus) between commands, even if the final save is back to a 8bit image file format like ICO and JPEG. (This is the default for this reason) The next level is **Q16 HDRI**, that takes precision to 32 bit floating point values which allows you to deal with image values that become very small or very large without the rounding and clipping effects of images. You can even deal with negative values, especially in some colorspaces. Essentially it is used to prevent image data loss when processing images in extremes such as when using HDRI images, Fourier Transforms, or just high levels of compression, expansion you may get in mathematical processing of raw data. That is, it in a nut shell. Q16 is good middle ground for most operations involving distortions and multi-image compositions and image processing effects. Q8 if memory is tight but you are only doing simple operations, HDRI is you are doing extreme operations. ### Image Density or Resolution The _Density_ of an image is the spatial (space) resolution of the image. That is, the density (generally expressed as dpi, or dots per inch) of an image define how far apart (or how big) the individual pixels, and thus the overall size of the image in real world terms, and generally used for display or printing of the image on a real world device. It is just some number stored with the image to tell output devices such as printers and displays how many dots (or pixels) per inch the image should be displayed at, OR for vector formats like postscript, PDF, MWF, and SVG the pixel scale to draw using any real world coordinates that may be used within the image. It is completely irrelevant to the actual images pixel size, or the in-memory [Quality](#quality) and save file format [Depth](#depth) that defines the color 'resolution' of the image. You can set the resolution or density of an image as it is being read into IM by using the "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" function, _before_ reading or writing the image, or using "`[-set](https://imagemagick.org/script/command-line-options.php?#set) density`" after reading the image. A "`[-units](https://imagemagick.org/script/command-line-options.php?#units) `" setting can be used to define if the density number is expressed in the default (traditional printing) terms of '`PixelsPerInch`' or in more modern metric units of '`PixelsPerCentimeter`' (PNG uses the latter). For example, a 200x200 pixel image at 600 dpi will thus be displayed in 1/3 inch square in real world terms. On the other hand a much smaller 72x72 pixel image at 72 dpi will display in a 1 inch square, in the real world, though its spatial quality will not be very good in comparison. The former being 'photo quality' while the later being 'display resolution'. In practical terms, a 72dpi image will look 'digital' or 'dotty' on a printer. On the other hand a large modern digital photo taken at 1200dpi image would probably need to be [resampled](../resize/#resample) to show it on a display, or you may only see tiny part of the image. For more information on Resolution and Density of images see the notes on the [Resample Resize Operator](../resize/#resample) . For information of Resolution and Density for Text and Fonts see [Pointsize and Actual Font Size](../text/#pointsize) . #### Photoshop and Density The "Photoshop" image editor saves an extra copy of the images resolution into a separate profile (named '`8BIM`') in the image, which IM will NOT touch. Thus if you change the resolution of an image with IM, you probably should also strip the profiles from the image before loading it back into "photoshop", or you may not see any density changes.You can remove just that profile from an image using "`+profile 8bim`". From a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?f=1&t=14257&p=49222) , Jesper Nilsson (aka _[stroker](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=10743) _), suggests that you use the program "`[exiftool](http://www.sno.phy.queensu.ca/~phil/exiftool/) `' to directly modify the [Photoshop Tags](http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Photoshop.html) of the image. For example exiftool -g -Photoshop:XResolution=300 -Photoshop:YResolution=300 file.tif #### Speed Tests based on Quality Some speed tests were submitted to [IM Forum, Q8 vs. Q16 speed (& HDRI)](https://magick.imagemagick.org/viewtopic.php?f=1&t=26011&p=114168) . Rough results from the above article * The amount of memory used per pixel per channel is as you would expect. Q8 - 1 byte, Q16 - 2 bytes, Q32 & any HDRI - 4 bytes, Q64 (HDRI) - 8 bytes. * 64bit has significant precision improvements for floating point operations, but so does any other HDRI version of ImageMagick. * Speed wise Q8, Q16 and HDRI all about the same speed (presuming computer has floating point MPU), Q32 about 25% slower and Q64 (HDRI) is about 50% slower. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that Q64 automatically uses "double long floats", rather than 64 bit integers. It is sort of a double precision HDRI, but while very precise is the slowest of all in-memory quality settings, and most memory intensive._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The actual speed will depend on your computer specifications, and if you have a Math Co-Processor or not. If it is not important using the default Q16, or standard HDRI, is probably best.

If it is important then you should do simular tests for speed, on your equipment, but using the operations you typically expect to use in your image processing.

_ | * * * ImageMagick Special Controls ---------------------------- IM also has a few special options that it uses to control its operational working, information reporting, and for debugging purposes.**\-version**Output what version of IM, the image quality it is using, and when was it built. IM will implicitly exit after outputting this information. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _In IMv7, "`[-version](https://imagemagick.org/script/command-line-options.php?#version) `" will exit if it is the ONLY option on the command line. That is, it will make the final 'implicit write' argument, optional. If any other arguments are present, OR it was read from a script (file or pipeline), the magick command will not exit, but continue._ |  **\-list**This is an informational option only and will list the requested items, then exit. That is, you can not use this with any other option, or image processing. It is purely provides for informational purposes, especially in scripts to check input options and if IM has certain options implemented. The given argument defines what information you are wanting to list. For example a list of '`color`' names that you can use, (such as using by ("`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `", "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `", "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#mattecolor) `", "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `"). While '`font`' lists the fonts that are specifically known to IM. Here are just some of the more interesting lists... | | | | --- | --- | | **list** | what lists can "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" list! | | **font** | Known fonts (IM also knows about X and PS fonts) | | **type** | file image types ("`[-type](https://imagemagick.org/script/command-line-options.php?#type) `" )(after IM v6.3.5-7)
or the font list (before that IM version) | | **color** | known color names for various color options. | | **dispose** | all the GIF disposal settings ("`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `") | | **compose** | alpha compositions are available (includes internal methods) | | **layers** | what multi-image "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" methods has been implemented | | **distort** | The image distortion methods available. | | **morphology** | The image morphological methods available. | | **kernel** | The morphological/convolution kernels that are available. | | **command** | what command line options (both settings and operators) are available | | **configure** | what were the configuration parameters used to build ImageMagick | That last 'list' setting '`Configure`' is very important, as it will tell you what libraries, and delegates were available when IM was built. It also includes the 'point' release number, which was missing from the normal "`[-version](https://imagemagick.org/script/command-line-options.php?#version) `" output of older versions. (See [Script Version Handling](../api/#version) for one example of using this information. IM will implicitly exit after outputting this information. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _In IMv7, "`[-list](https://imagemagick.org/script/command-line-options.php?#list) `" will exit if it is the ONLY option on the command line. That is, it will make the final 'implicit write' argument, optional. If any other arguments are present, OR it was read from a script (file or pipeline), the magick command will not exit, but continue._ |  **\-verbose**Report extra info on some of the more complex operations. For example "`[-segment](https://imagemagick.org/script/command-line-options.php?#segment) `", which outputs a lot of color quantization details. And "`[-distort](https://imagemagick.org/script/command-line-options.php?#distort) `", outputting extra information and 'FX' equivalents to the requested image distortion. Also monitoring the number of changes when iterating a "`[-morphology](https://imagemagick.org/script/command-line-options.php?#morphology) `" operation.This is especially useful for generating for more detailed image information from the "`[info:](../files/#info) `" and "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" outputs. You can turn off the setting using the 'plus' form of the option, "`[+verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `".  **\-regard   -warnings**   The '`-regard-warnings`', will make some informative warnings about some image file formats fatal. It also causes IM to return a proper exit status according to such error conditions. It can be used in scripts to 'sanitize' image file being provided from uncontrolled sources. That is, this option will make IM fail and exit, if when the JPEG or TIFF image was not correct, complete or contained 'unknown' profiles.  **\-precision** _{number}_Control the number of significant digits. When IM outputs floating point values in response to various debugging, verbose, or formatting requests, this setting sets how precise you want that output. By default it will limit such numbers to 6 significant digits, but this operator will increase or decrease this default. The default setting of 6 can also be modified using the '`MAGICK_PRECISION`' environment variable. It affects output from... * The verbose "`[identify](#identify) `" command or the "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `", "`[-print](https://imagemagick.org/script/command-line-options.php?#print) `" and "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" settings. * The '`debug()`' output from a "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator and the '`%[fx:...]`' string escape. (See [FX, DIY Image processing Operator](../transform/#fx) * The floating point values of a "`[-morphology](https://imagemagick.org/script/command-line-options.php?#morphology) `" kernel when "`-set option:showkernel 1`" has been enabled. See [Displaying the Kernel](../morphology/#showkernel) .  **\-quiet**Don't report informational warning messages. Only proper errors such as I/O errors, or bad options, etc. This is especially useful for "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" or "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" and "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) optimize`" which normally report 'missed images' warnings, when the operator would produce no 'real' image as a result. This will also quieten the coders of some complex image file formats that can contain 'unknown chunks' which IM would normally ignore. For example when IM is reading TIFF images, or strange MPEG (AVI) video formats.  **\-respect   -parenthesis**   Causes [parenthesis](#parenthesis) to not only to save and restore the current image list but also all the current [operational settings](#options) are saved and restored. Than means that when given, any settings set within parenthesis, will be reset when the parenthesis ends. See the examples in [Parenthesis and Settings](#respect-parentheses) above.  **\-ping**For the "[identify](#identify) " command. IM will try to avoid completely reading and decoding the full image file format for basic information such as the images size.  **\-monitor**Report a percentage of processing during each stage of image processing, especially for very large or long image processing tasks. In a lower level API, you would use SetImageInfoProgressMonitor() or SetImageProgressMonitor()  **\-debug**Report verbosely exactly what IM is doing, in various areas. The argument is a comma separated list of options, such as... | | | | --- | --- | | **exception** | What is IM not understanding about the command | | **cache** | See how much disk space IM is caching | | **configure** | Show IM search attempts to find its configuration files. | | **trace** | Report the trace points at the start of each library function | | **annotate** | Report on font metrics when a font is used with "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `". | | **command** | IMv7 -- show the command line options (or script) as they are being processed. EG: option processing. | | **all** | Show every trace point during processing
This is very very VERY verbose and not recommended | If "`[-debug](https://imagemagick.org/script/command-line-options.php?#debug) `" is used the location of the logging output is controlled by the "`log.xml`" file. This is by default set to "`console`". To have it save to a file change `` to `` For command line and API usage you can also define an environment variable to set the debug level using actions by IM. export MAGICK\_DEBUG=all Limiting image size (quick note) To prevent excess memory usage, set your memory limit to say 16GB. Now set the disk limit to 4GB. ImageMagick will exit if the disk limit is exceeded, with a "cache resource exhausted" exception. * * * --- # Font Effects -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Compound Font Effects ========================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Compound Fonts](#fonts) ![](../img_www/space.gif) Drawing text as images in various styles [Tile Filled](#tile) ,  [Gradient Filled](#gradient) ,  [Upside-Down](#upside-down) ,  [Hard Shadow](#hard_shadow) ,  [Sheared Shadow](#slewed) ,  [Slanted](#slanted) ,  [Stamp](#stamp) ,  [Extruded](#extrude) ,  [Outline](#outline) ,  [Multi-color Outline](#multi-color) ,  [Stroke](#stroke) ,  [Thick Stroke](#thick_stroke) ,  [Thin Stroke](#thin_stroke) ,  [Double Outline](#double_outline) ,  [Psychedelic](#psychedelic) ,  [Balloon](#balloon) ,  [Joined](#joined) ,  [Overlapped](#overlapped) ,  [Jittered](#jittered) ,  [Fuzzy](#fuzzy) ,  [Fuzzy Shadow](#fuzzy_shadow) ,  [Soft Shadow](#soft_shadow) ,  [Soft Outline](#soft_outline) ,  [Denser Soft Outline](#denser_soft_outline) ,  [Distance Blurred Shadow](#var_blur) ,  [Dirty Print](#dirty_print) ,  [Bevel](#bevel) ,  [Conical](#conical) ,  [Inner Bevel](#inner_bevel) ,  [Arch](#arch) ,  [Arc](#arc) ,  [Circle](#circle) ,  [Vibrato](#vibrato) ,  [Comet](#comet) ,  [Smoking](#smoking) . [![](../img_www/granitesm_right.gif) Using a Mask Image with Fonts](#mask) ![](../img_www/space.gif) To remove parts of an image, before overlay [![](../img_www/granitesm_right.gif) Advanced Font Processing](#advanced) ![](../img_www/space.gif) Expanding fonts to produce more complex results [More Complex Fonts](#example) ,  [Neon Sign](#neon) ,   [Metallic](#metallic) Drawing text is only the start of what is possible with ImageMagick. Here we look at modifying the basic text drawing ability of IM to create fancy fonts and special effects, which you can then use on your web pages and documents. * * * Compound Font Effects --------------------- Plain old text as images is boring, but with very little effort you can overlay and color text so as to produce some very weird and wonderful effects. To do this we need to draw text multiple times, overlay different tiles and colors, and apply some of the many image operators available to generate more interesting special effects from the original, boring text. Note that many of these effects can be applied to other images besides a basic font such as we are using. In particular you can use the effects on clip-art images. **Tiled Font**: You are not limited to drawing fonts in a fixed color. You can use a tile pattern over the font. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -tile pattern:checkerboard -annotate +28+68 'Anthony' \\ font\_tile.jpg [![[IM Output]](font_tile.jpg)](font_tile.jpg) Note that the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting overrides any "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color for the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As of IM v6.3.2 you can specify a tile image using the "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" setting instead, This usage is however is not recommended as many operators that using the "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color will not understand a tiling image, and default to using 'black' instead._ | The tiling image can be offset relative to the background image origin by specifying a "`[-origin](https://imagemagick.org/script/command-line-options.php?#origin) `" setting, BEFORE you set the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" image. The image is rolled by the amount specified during its assignment as the fill tile. **Gradient Font**: The tile used does not have to be small either, but can be the size of the whole canvas. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -tile gradient: -annotate +28+68 'Anthony' \\ font\_gradient.jpg [![[IM Output]](font_gradient.jpg)](font_gradient.jpg) **Upside Down Font**: magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill Navy -annotate 180x180+300+35 'Anthony' \\ font\_upsidedown.jpg [![[IM Output]](font_upsidedown.jpg)](font_upsidedown.jpg) **Hard Shadow**: Drawing the font twice with an offset, you can make a simple 'hard' shadow effect. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill black -draw "text 28,68 'Anthony'" \\ -fill white -draw "text 25,65 'Anthony'" \\ font\_shadow.jpg [![[IM Output]](font_shadow.jpg)](font_shadow.jpg) **Sheared Shadow**: As the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" font drawing operator can rotate the vertical dimension separately to the horizontal dimension, you can specify some odd ball rotation 'slewing' or 'shearing' of the font. This is great for making weird shadows, or making your own italic or slanted font. magick -size 320x115 xc:lightblue -font Candice -pointsize 72 \\ -fill Navy -annotate 0x0+12+55 'Anthony' \\ -fill RoyalBlue -annotate 0x130+25+80 'Anthony' \\ font\_slewed.jpg [![[IM Output]](font_slewed.jpg)](font_slewed.jpg) To see a table summarizing the effects of the text rotations, see [Annotate Text Option](../misc/#annotate) . Of course the Candice font is not a good font to show this effect, and other details may need to be added to make it the result look more 3D like. For example [Blurring the shadow with distance](#var_blur) . **Slanted Font**: You can also use "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to slant your font too, though it is a little trickier, as it involves extra MVG (Magick Vector graphics) actions, to warp the drawing surface. As the surface is being warped it is a good idea to set the font location first using '`translate`' before warping. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill Navy -draw "translate 28,68 skewX -20 text 0,0 'Anthony'" \\ font\_slanted.jpg [![[IM Output]](font_slanted.jpg)](font_slanted.jpg) To see a table summarizing the effects of the text rotations, see [Annotate Text Option](../misc/#annotate) . Of course the Candice font is not a good font to show this effect, and other details may need to be added to make it the result look more 3D like. If you come up with anything interesting, pass it on to me, so it can be shared with the rest of the world. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Both "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" and "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) skew?`" operations actually rotates the X and Y axis of the drawing surface. This is different from the effects of using "`[-shear](https://imagemagick.org/script/command-line-options.php?#shear) `" on an existing image, which lengthens the sheared axis of the image so the height (or width) or the image does not change due to the operation._ | **Stamped Font**: By drawing the font three times in darker and lighter and the original colors you can make a stamp like indent. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill black -annotate +24+64 'Anthony' \\ -fill white -annotate +26+66 'Anthony' \\ -fill lightblue -annotate +25+65 'Anthony' \\ font\_stamp.jpg [![[IM Output]](font_stamp.jpg)](font_stamp.jpg) Notice how the last 'draw' of the font erases the middle portion of the font. This can only be done on a solid colored background, See [Using a Mask Image](#mask) to see how we can use this on a random background that isn't a solid color. If you swap the two colors you will of course get a raised font, instead of a indented font. **Extruded** or 3d block font: can be generated by repeating the font multiple times. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill gray -annotate +29+69 'Anthony' \\ -annotate +28+68 'Anthony' \\ -annotate +27+67 'Anthony' \\ -annotate +26+66 'Anthony' \\ -annotate +25+65 'Anthony' \\ -annotate +24+64 'Anthony' \\ -fill navy -annotate +23+63 'Anthony' \\ font\_extrude.jpg [![[IM Output]](font_extrude.jpg)](font_extrude.jpg) Note that this is NOT a simple shadow, but a proper thickening of the drawn font. This is very repetitive and can be used for any 'shaped' image. For another example of this see [Adding Thickness to a Thumbnail](../thumbnails/#thickness) . **Outlined Font**: We can create an outlined font using multiple drawing with small position offsets. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill black -annotate +24+64 'Anthony' \\ -annotate +26+64 'Anthony' \\ -annotate +26+66 'Anthony' \\ -annotate +24+66 'Anthony' \\ -fill white -annotate +25+65 'Anthony' \\ font\_outlined.jpg [![[IM Output]](font_outlined.jpg)](font_outlined.jpg) As this is also very repetitive, it is not a good outline solution. As ImageMagick allows you to draw the font outline by setting the "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `" setting, much better solutions exist. (See the [Stroke Fonts](#stroke) below). Regardless, multiple redraws like this, for generating an outline can be very useful with pre-prepared clip-art images, such as what you can find all over the Internet. It is also useful technique for other graphic libraries and programs (Like "`GD`" from "`PHP`", etc) where a "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `" setting is not available for use. Another reason for showing this style of outlining, is that the result may be better when outlining a font with very sharp points. For example, here we draw the font 12 times to show up the sharp points of the font. The outline here was also drawn to be a little thicker. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -draw "fill black text 27,67 'Anthony' \\ text 25,68 'Anthony' \\ text 23,67 'Anthony' \\ text 22,65 'Anthony' \\ text 23,63 'Anthony' \\ text 25,62 'Anthony' \\ text 27,63 'Anthony' \\ text 28,65 'Anthony' \\ fill white text 25,65 'Anthony' " \\ font\_outlined\_12.jpg [![[IM Output]](font_outlined_12.jpg)](font_outlined_12.jpg) You will also notice that the drawing [\-fill](https://imagemagick.org/script/command-line-options.php?#fill) " color can be changed inside the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" argument. **Multi-Color Outline**: The other reason this technique is useful is that you are not limited to just one outline color in drawing the font. By re-drawing the font 12 times in 5 different colors in a very carefully designed sequence, you can make a colorful "raised" font, with some edge color smoothing. magick -size 320x100 xc:lightblue \\ -font Candice -pointsize 72 -gravity center \\ -draw "fill navy text 2,2 'Anthony' \\ fill navy text 0,3 'Anthony' \\ fill navy text 3,0 'Anthony' \\ fill dodgerblue text 0,2 'Anthony' \\ fill dodgerblue text 2,0 'Anthony' \\ fill dodgerblue text -2,2 'Anthony' \\ fill dodgerblue text 2,-2 'Anthony' \\ fill lavender text -2,-2 'Anthony' \\ fill lavender text 0,-3 'Anthony' \\ fill lavender text -3,0 'Anthony' \\ fill skyblue text 0,-2 'Anthony' \\ fill skyblue text -2,0 'Anthony' \\ fill blue text 0,0 'Anthony' " \\ font\_colourful.jpg [![[IM Output]](font_colourful.jpg)](font_colourful.jpg) There are better methods to create a raised font like this, but this works, is simple, and only uses a few colors, rather that a whole range of colors. **Outline (Stroke) Font**: The "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `" setting allows you to draw an outline of the font directly. Normally the stroke color is set to "none", so is not used. The thickness of the stroke is varied with "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `", which defaults to a good value of 1. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill white -stroke black -annotate +25+65 'Anthony' \\ font\_stroke.jpg [![[IM Output]](font_stroke.jpg)](font_stroke.jpg) And here is an example with a heavier stroke width of 3. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill white -stroke black -strokewidth 3 \\ -annotate +25+65 'Anthony' font\_stroke\_3.jpg [![[IM Output]](font_stroke_3.jpg)](font_stroke_3.jpg) Notice how the stroke color eats away not only the outside of the font, but the inside as well. For more detail see the results of my [Stroke and Stroke Width Options](../draw/#stroke) . **Thick Stroke**: By again redrawing the font a second time, but without the stroke turned on, the internal parts of the lines are removed, creating a more pleasing thickly outlined font. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 -fill white \\ -stroke black -strokewidth 5 -annotate +25+65 'Anthony' \\ -stroke none -annotate +25+65 'Anthony' \\ font\_stroke\_thick.jpg [![[IM Output]](font_stroke_thick.jpg)](font_stroke_thick.jpg) Using the [\-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) " setting is taken even further, in [Stroke and StrokeWidth Options](../draw/#stroke) where is aspect of drawing operators are explored in greater depth. **Thin Stroke**: By turning off the fill color, you can leave just the outline of the font. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill none -stroke black -annotate +25+65 'Anthony' \\ font\_stroke\_thin.jpg [![[IM Output]](font_stroke_thin.jpg)](font_stroke_thin.jpg) **Doubled Outline**: By redrawing using multiple stroke thicknesses, you can generate a double outline! The first draw can use any fill color to fill the inside of the font, or left as none as we did here to leave the background alone. However the last font draw must be with done with a fill setting of "none", or it will not work. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill none -stroke black -strokewidth 3 -annotate +25+65 'Anthony' \\ -fill none -stroke white -strokewidth 1 -annotate +25+65 'Anthony' \\ font\_stroke\_double.jpg [![[IM Output]](font_stroke_double.jpg)](font_stroke_double.jpg) Unlike the 'stamped font' previously, the above did not require the middle part the of font to be erased. As such this will work on any background without complication. **Psychedelic Font**: In a similar way by slowly reducing the stroke width size while swapping colors, a psychedelic outline effect can be easily generated. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 -fill white \\ -stroke black -strokewidth 25 -annotate +25+65 'Anthony' \\ -stroke white -strokewidth 20 -annotate +25+65 'Anthony' \\ -stroke black -strokewidth 15 -annotate +25+65 'Anthony' \\ -stroke white -strokewidth 10 -annotate +25+65 'Anthony' \\ -stroke black -strokewidth 5 -annotate +25+65 'Anthony' \\ -stroke none -annotate +25+65 'Anthony' \\ font\_psychedelic.jpg [![[IM Output]](font_psychedelic.jpg)](font_psychedelic.jpg) You can make it even more psychedelic by using clashing colors, different stroke widths, or even moving the font position around a little. Experiment and see what you can come up with. **Balloon Effect**: Here I did exactly the same as the "Thick Stroke Font" above, but purely by accident I used a white stroke color when re-drawing the font. This resulted in an interesting enlargement of the font, with a thick outline. The 'puffy' looking font is as if had been inflated like a balloon. This just shows that it pays to experiment to see what you can find. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill black -stroke black -strokewidth 5 -annotate +25+65 'Anthony' \\ -fill white -stroke white -strokewidth 1 -annotate +25+65 'Anthony' \\ font\_balloon.jpg [![[IM Output]](font_balloon.jpg)](font_balloon.jpg) **Joined Characters**: By using a small negative [Character Space Kerning](../text/#kerning) setting (adding IM v6.4.7-10) and drawing the font twice (such as in the previous example), you can cause all the characters in a 'thick' font join together, so as to produce an interesting variation. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -kerning -6 -strokewidth 4 -fill white \\ -stroke black -annotate +28+68 Anthony \\ -stroke none -annotate +28+68 Anthony \\ font\_joined.jpg [![[IM Output]](font_joined.jpg)](font_joined.jpg) **Overlapped Characters**: A variation on this however is to draw each and every character separately so that each character is overlaid on top of the previous characters. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -stroke black -strokewidth 4 -fill white \\ -stroke black -annotate +28+68 A -stroke none -annotate +28+68 A \\ -stroke black -annotate +90+68 n -stroke none -annotate +90+68 n \\ -stroke black -annotate +120+68 t -stroke none -annotate +120+68 t \\ -stroke black -annotate +138+68 h -stroke none -annotate +138+68 h \\ -stroke black -annotate +168+68 o -stroke none -annotate +168+68 o \\ -stroke black -annotate +193+68 n -stroke none -annotate +193+68 n \\ -stroke black -annotate +223+68 y -stroke none -annotate +223+68 y \\ font\_overlapped.jpg [![[IM Output]](font_overlapped.jpg)](font_overlapped.jpg) This however requires you to work out (manually or automatically using a script) the appropriate position for each character. The natural width of each character can be determined by generating labels of each character without any "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewitdh) `" setting. See [Determining Font Metrics](../text/#font_info) for examples. Note unlike when using the "`[-kerning](https://imagemagick.org/script/command-line-options.php?#kerning) `" setting (previous example) each characters position in the above was adjusted artistically by different amounts rather than just some simple fixed amount. For example, only a little overlap between the 't' and the 'h', but a lot more overlay between the 'n' and 'y' characters. **Jittered Characters**: if you go so far as drawing individual characters (overlaping or not) then you can place them in a 'jitter' or randomized pattern, particularly with different up-down offsets. You can even take this to an extreme to generate a special effect such as... magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -stroke black -strokewidth 4 -fill white \\ -stroke black -annotate +26+80 A -stroke none -annotate +26+80 A \\ -stroke black -annotate +95+63 n -stroke none -annotate +95+63 n \\ -stroke black -annotate +133+54 t -stroke none -annotate +133+54 t \\ -stroke black -annotate +156+67 h -stroke none -annotate +156+67 h \\ -stroke black -annotate +193+59 o -stroke none -annotate +193+59 o \\ -stroke black -annotate +225+59 n -stroke none -annotate +225+59 n \\ -stroke black -annotate +266+54 y -stroke none -annotate +266+54 y \\ font\_jittered.jpg [![[IM Output]](font_jittered.jpg)](font_jittered.jpg) **Fuzzy Font**: A straight spreading of a font color using "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" operator. This operator allows you to take an image and spread it out in all directions. This allows you to generate softer looking shadows, and or spray paint like effects. The following examples show the effects you can achieve with this. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill navy -annotate +25+65 'Anthony' \\ -blur 0x3 font\_fuzzy.jpg [![[IM Output]](font_fuzzy.jpg)](font_fuzzy.jpg) Note that blur is applied to the WHOLE image at the point the operator is given. If you want to use a blur an existing image, you will have to draw the font separately (on a transparent background), then overlay it on the background image. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" (or "`[-gaussian](https://imagemagick.org/script/command-line-options.php?#gaussian) `") operator modifies a much larger area than you might suspect. If your background canvas is not large enough you may get an error from these operators. If this happens add extra space to the image, say using "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `", or add a limit to the working radius (first argument) of the operator._

_Also the blurring of the image generally makes the use of "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" afterward fairly useless. Manual trimming, or other adjustments may be needed whenever you use blurring on an image._ | **Fuzzy Shadow**: Use the fuzzy font as an offset for a soft shadow. Note that we also used a larger spread value. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -annotate +30+70 'Anthony' -blur 0x4 \\ -fill white -stroke black -annotate +25+65 'Anthony' \\ font\_shadow\_fuzzy.jpg [![[IM Output]](font_shadow_fuzzy.jpg)](font_shadow_fuzzy.jpg) **Soft Shadow**: The "`[-shadow](https://imagemagick.org/script/command-line-options.php?#shadow) `" operator will not only allow you to generate and position soft fuzzy shadows for images containing transparency, but will also allow you to set use any color and set a general transparency level. magick -size 300x100 xc:none -font Candice -pointsize 72 \\ -fill white -stroke black -annotate +25+65 'Anthony' \\ \\( +clone -background navy -shadow 70x4+5+5 \\) +swap \\ -background lightblue -flatten -trim +repage font\_shadow\_soft.jpg [![[IM Output]](font_shadow_soft.jpg)](font_shadow_soft.jpg) For more information about the "`[-shadow](https://imagemagick.org/script/command-line-options.php?#shadow) `" operator, see [Generating Shadows](../blur/#shadow) . As of IM v6.3.1, the "`[montage](../montage/) `" command can also generate soft 'shaped' shadows of images containing transparency. This means you can shadow a "`[label:](../text/#label) `" image very easily. montage -background none -fill white -font Candice \\ -pointsize 72 label:'Anthony' +set label \\ -shadow -background lightblue -geometry +5+5 \\ font\_montage\_shadow.jpg [![[IM Output]](font_montage_shadow.jpg)](font_montage_shadow.jpg) However you do not have any control over the offset, color, or amount of blur of the montage shadow (as yet). **Soft Outline**: use the fuzzy font as the outline border. This is like using the original font as a mask to a spray gun. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -annotate +25+65 'Anthony' -blur 0x5 \\ -fill white -annotate +25+65 'Anthony' font\_outline\_soft.jpg [![[IM Output]](font_outline_soft.jpg)](font_outline_soft.jpg) Note that the edge is very light as not only is the black color spread out, but the background color spreads inward, making the edge only 50% dark. One way to fix this is to use a [Shadow Outline](../blur/#shadow_outline) , with a [Level Adjustment](../color_mods/#level) to fix that lightness, though that uses some very advanced image processing techniques. **Denser Soft Outline**: Another way to fix the lightness of the soft outline is to blur a font that has a wide stroke outline. This effectively moved the 50% blur point further away from the edge of the font. It will also allow an even larger the blur value to be used, allowing the black color to spread out further. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -stroke black -strokewidth 8 -annotate +25+65 'Anthony' -blur 0x8 \\ -fill white -stroke none -annotate +25+65 'Anthony' \\ font\_denser\_soft\_outline.jpg [![[IM Output]](font_denser_soft_outline.jpg)](font_denser_soft_outline.jpg) As a practical example of this method see the examples generated in [Adding image labels to thumbnails](../thumbnails/#labels) and the last example in [Annotating on Top of Images](../annotating/#anno_on) . **Distance Blurred Shadow**: With the introduction of [Variable Blur Mapping](../mapping/#blur) you can now blur a shadow so that be becomes more blurry with the apparent distance of that shadow from the casting object. For example, here I took the [Sheared Shadow Font](#slewed) and blurred the shadow so it is unblurred at the top, and more blurry at the bottom. magick -size 320x40 xc:lightblue -font Candice -pointsize 72 \\ -fill RoyalBlue -annotate 0x125+20+0 'Anthony' \\ \\( -size 320x45 gradient:black -append \\) \\ -compose Blur -set option:compose:args 20x5+45 -composite \\ \\( -size 320x60 xc:lightblue \\ -fill Navy -annotate 0x0+20+59 'Anthony' \\) \\ +swap -append font\_var\_blur.jpg [![[IM Output]](font_var_blur.jpg)](font_var_blur.jpg) Note that I did not just use a circular blur, as light falling on a slanted surface will form ellipses, not circles. As such the blur also needs to form ellipses too. Basically I used an [Elliptical Blur](../mapping/#blur_ellipse) variant to achieve this effect. One final point, using the annotate angle arguments for creating the sheared text (see [Annotate Argument Usage](../misc/#annotate) ), is probably not the best way to generate the initial 3d shadow like this. Basically it can not make the shadow shorter or longer, like a real shadow, as it only does a rotational shear. A better method is to use a three point [Affine Distortion](../distorts/#affine) which gives you the better control over the placement of the shadow (See [3d Shadows, using Affine Shears](../distorts/#shadow3d) ). Of course you will still need the [Variable Blur](../mapping/#blur) technique to make look right. **Dirty Print Font**: The [pixels are spread out slightly](../transform/#spread) , and then blurred, and thresholded a few times to smooth out the final outline. The result is a font that looks like it was printed on course newspaper. magick -size 320x100 xc: \\ -font Candice -pointsize 72 -annotate +25+65 'Anthony' \\ -spread 1 -blur 0x1 -threshold 50% -blur 0x1 font\_dirty\_print.jpg [![[IM Output]](font_dirty_print.jpg)](font_dirty_print.jpg) This font was from the discussion [How to dirty a font](https://magick.imagemagick.org/viewtopic.php?t=32836) which includes other more complex methods. **Beveled Font**: The [Shade Operator](../transform/#shade) can be used to generate very nice looking 3D font with a beveled and smoothly curving edge. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +25+65 'Anthony' \\ -shade 140x45 font\_beveled.jpg [![[IM Output]](font_beveled.jpg)](font_beveled.jpg) This is much nicer than the stamped font, but shade will only generate grey-scale images. On the other hand, there are a lot of methods which can replace the grey scale of the above result with whatever colors you need. The biggest problem with using shade to 'bevel' a font is that the thickness of the bevel is not readilly adjustable. It is basically fixed to an approximatally 5 pixel thickness, regardless of the font size used. **Conical Font**: By using the new [Morphology Distance Method](../morphology/#distance) (as of IM v6.6.2) combined with the [Shade Operator](../transform/#shade) you can make the whole font look like it is a 3 dimensional mountain ridge. This does requires some special handling of the anti-aliasing pixels as per [Distance with an Anti-aliased Shape](../morphology/#distance_anti-alias) , but the result is a cone shaped mountain-like font. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +25+65 'Anthony' \\ -gamma 2 +level 0,1000 -white-threshold 999 \\ -morphology Distance Euclidean:4,1000 -auto-level \\ -shade 135x30 -auto-level +level 10,90% font\_conic.jpg [![[IM Output]](font_conic.jpg)](font_conic.jpg) By adding a bit of "`[-adaptive-blur](https://imagemagick.org/script/command-line-options.php?#adaptive-blur) `" you can smooth the result to generate a better and strangely shiny look to the resulting font. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +25+65 'Anthony' \\ -gamma 2 +level 0,1000 -white-threshold 999 \\ -morphology Distance Euclidean:4,1000 -auto-level \\ -shade 135x30 -auto-level +level 10,90% \\ -adaptive-blur 0x2 font\_conic\_smoothed.jpg [![[IM Output]](font_conic_smoothed.jpg)](font_conic_smoothed.jpg) Moving the "`[-adaptive-blur](https://imagemagick.org/script/command-line-options.php?#adaptive-blur) `" to before the use of [Shade](../transform/#shade) will cause the edges to be blured, but not the central ridge (skeleton) of the font shapes. The result look like the sharp ridges are pushing up into a rubber sheet. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +25+65 'Anthony' \\ -gamma 2 +level 0,1000 -white-threshold 999 \\ -morphology Distance Euclidean:4,1000 -auto-level \\ -adaptive-blur 0x2 \\ -shade 135x30 -auto-level +level 10,90% font\_conic\_ridge.jpg [![[IM Output]](font_conic_ridge.jpg)](font_conic_ridge.jpg) Using a different [Distance Kernel](../morphology/#distance_kernels) , such as [Chebyshev](../morphology/#chebyshev) , works better with more regular looking fonts, such as the Arial font family. magick -size 320x100 xc:black -font ArialBk -pointsize 70 \\ -fill white -annotate +5+70 'Anthony' \\ -gamma 2 +level 0,1000 -white-threshold 999 \\ -morphology Distance Chebyshev:1,1000 -auto-level \\ -shade 135x30 -auto-level +level 10,90% font\_chebyshev.jpg [![[IM Output]](font_chebyshev.jpg)](font_chebyshev.jpg) **Inner Bevel Font**: Limiting the distance by clipping the distance function will bevel just teh edges of the shape. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +25+65 'Anthony' \\ -gamma 2 +level 0,1000 -white-threshold 999 \\ -morphology Distance Euclidean:4,1000 -level 0,5000 \\ -shade 135x30 -auto-level +level 10,90% font\_inner\_bevel.jpg [![[IM Output]](font_inner_bevel.jpg)](font_inner_bevel.jpg) **Arched Font**: The "`[-wave](https://imagemagick.org/script/command-line-options.php?#wave) `" operator (see [Sine Wave Displacement](../warping/#wave) for details), will shift the pixels of the image vertically, to form an arch. Verticals will remain vertical, with the characters being sheared to produce the curve. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill navy -annotate +25+65 'Anthony' \\ -background lightblue -wave -50x640 -crop x110+0+10 \\ font\_wavy.jpg [![[IM Output]](font_wavy.jpg)](font_wavy.jpg) Note that to use "`[-wave](https://imagemagick.org/script/command-line-options.php?#wave) `" to create an arch you need to use 'wave length' that is twice the width of the image (2 × 320 or 640 pixels). Also as "`[-wave](https://imagemagick.org/script/command-line-options.php?#wave) `" adds extra space to the image by the amount it is arched, requiring that space to be trimmed or cropped afterward. It is a simple, fast but effective way of making an arch of text. **Arc Font**: The [General Distortion Operator](../distorts/#distort) also provides other text/image warping methods. The '`[Arc](../distorts/#arc) `' method for example will bend a font into a true circular arc, rather than the vertically shifted 'arch' of the previous example. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill navy -annotate +25+65 'Anthony' \\ -distort Arc 120 -trim +repage \\ -bordercolor lightblue -border 10 font\_arc.jpg [![[IM Output]](font_arc.jpg)](font_arc.jpg) **Circle Font**: You can even take it to extremes and wrap the text into a complete, or almost complete circle. magick -font Candice -pointsize 32 -background lightblue \\ -fill navy label:"Anthony's IM Examples" \\ -virtual-pixel background -distort Arc 340 \\ font\_circle.jpg [![[IM Output]](font_circle.jpg)](font_circle.jpg) See [Arc Distortion](../distorts/#arc) for more options and possibilities. **Spiral Font**: Adding a little rotation to slant the font at an angle before wrapping it, the circle can be converted into a spiral. magick -font Candice -pointsize 32 -background lightblue \\ -fill navy label:"Anthony's IM Examples" \\ -rotate 12 -virtual-pixel background -distort Arc 360 \\ -trim -bordercolor lightblue -border 5x5 font\_spiral.jpg [![[IM Output]](font_spiral.jpg)](font_spiral.jpg) The height of the text (radially) however remains constant, it is not stretched or compressed as it gets closer into the center, producing strong aspect distortion to characters. You could solve that by using a perspective distortion as part of the text rotation, to adjust the font hight, before applying the Arc distortion. The problem with this technique is that you can only do one twist of the spirl, though with multiple lines and some care to line up the lines, you could generate multiple spirals. _If you try this, please submit an example back to me?_ **Vibrato Font**: The "`[-wave](https://imagemagick.org/script/command-line-options.php?#wave) `" operator that we used in the [Arch'ed Font](#arch) above can also be used at a higher frequency and smaller amplitude to make a vibrating font. Also by adding some rotation operations, you can even make the vibration at whatever angle you like! magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill navy -annotate +25+65 'Anthony' \\ -background lightblue -rotate 85 -wave 2x5 -rotate -85 \\ -gravity center -crop 320x100+0+0 +repage font\_vibrato.jpg [![[IM Output]](font_vibrato.jpg)](font_vibrato.jpg) For more information on using distorts like this see example page on [Warping Images](../warping/) , and especially the [Wave Distortion Operator](../warping/#wave) . **Comet Font**: One of the specialised blurs operators, "`[-motion-blur](https://imagemagick.org/script/command-line-options.php?#motion-blur) `" allows you to create a comet like tail to objects in an image. magick -size 340x120 xc:lightblue -font Candice -pointsize 72 \\ -fill navy -annotate +45+95 'Anthony' -motion-blur 0x25+65 \\ -fill black -annotate +45+95 'Anthony' -motion-blur 0x1+65 \\ font\_comet.jpg [![[IM Output]](font_comet.jpg)](font_comet.jpg) You can liven this compound font up by using different colors to make a real fiery event. You can also do much more with [Specialized Blurs](../blur/#special_blurs) , however this whole aspect of IM is still experimental and the syntax of these operators may change in the near future. **Smoking Font**: combining this with wave and you can make the comet font look like smoke, a smell, or even flames are rising off the font! magick -size 320x120 xc:lightblue -font Candice -pointsize 72 \\ -fill black -annotate +25+95 'Anthony' -motion-blur 0x25+90 \\ -background lightblue -rotate 60 -wave 3x35 -rotate -60 \\ -gravity center -crop 320x120+0+0 +repage +gravity \\ -fill navy -annotate +25+95 'Anthony' font\_smoking.jpg [![[IM Output]](font_smoking.jpg)](font_smoking.jpg) Do you have an interesting transform to add to the above list? * * * Using a Mask Image with Fonts ----------------------------- Drawing a "Stamped Font" on a background image is actually a lot more difficult that most of the methods of generating fancy fonts I detailed above. The reason is that part of the original font is erased, which presents a problem when drawing it on a background that is not a simple solid color. Here is the composite font image we generated above. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \ -fill black -annotate +24+64 'Anthony' \ -fill white -annotate +26+66 'Anthony' \ -fill lightblue -annotate +25+65 'Anthony' \ font_stamp.jpg [![[IM Output]](font_stamp.jpg)](font_stamp.jpg) If we try to draw the font on a transparent background (PNG format image), using exactly the same method, we just fail... magick -size 320x100 xc:transparent -font Candice -pointsize 72 \\ -fill black -annotate +24+64 'Anthony' \\ -fill white -annotate +26+66 'Anthony' \\ -fill transparent -annotate +25+65 'Anthony' \\ trans\_stamp.png [![[IM Output]](trans_stamp.png)](trans_stamp.png) What happened was that we tried to erase the center part of the font with the "transparency" color. But as you can see drawing with transparency, just draws nothing! So the result above was the same as if the last 'erase' [\-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) " operator do not work at all. There are about half a dozen solutions to this problem. I will present three such methods here, while others are talked about in various other places in the IM example pages. Probably the simplest is not to fix the above font at all, but to use a 'mask' when drawing it onto the background image to tell the "`magick composite`" command, to ignore the middle section. A "`magick composite`" mask image is a grey-scale image, pure black for parts that will be transparent, and pure white for any parts that you want completely visible (opaque). Any grey shades will be draw as semi-transparent, merging into the background colors underneath. Well our image above is almost right, so lets just mask out all the parts we don't want. We start with a black background (fully transparent), then draw anything we want in white, and anything we don't want in black. magick -size 320x100 xc:black -font Candice -pointsize 72 \\ -fill white -annotate +24+64 'Anthony' \\ -fill white -annotate +26+66 'Anthony' \\ -fill black -annotate +25+65 'Anthony' \\ mask\_mask.jpg [![[IM Output]](mask_mask.jpg)](mask_mask.jpg) Note that the mask we created is _not_ just black and white, but has various shades of grey along the edges of the areas due to anti-aliasing (See [Anti-Aliasing Examples](../antialiasing/) for details). These grey pixels makes the final image edges smoother, and is very important, as these pixels represent semi-transparent (only half visible) pixels. Now that we have a mask, we can mask out the unwanted sections of the image. We can do this while we are drawing (overlaying) the image onto a plasma background. Note the order of all three image arguments (font, background, then mask). magick -size 320x180 plasma: -shave 0x40 plasma\_background.jpg magick composite trans\_stamp.png plasma\_background.jpg mask\_mask.jpg \\ mask\_result.jpg [![[IM Output]](mask_result.jpg)](mask_result.jpg) A three argument "`magick -composite`" form of this is... magick plasma\_background.jpg trans\_stamp.png mask\_mask.jpg \\ -composite mask\_result2.jpg [![[IM Output]](mask_result2.jpg)](mask_result2.jpg) Good result, but we now need two images to draw the compound font. It would be better if, we only need one image, with the mask built directly into the the image itself. Basically we want to completely replace the alpha channel of our font image with a copy of the font image mask we created. That is, we merge the font image (supplying the colors of the pixels) directly with its mask (supplying the images alpha channel). The alpha composition setting '`[CopyOpacity](../compose/#copyopacity) `' does this replacement. Note the order of the arguments in the command. In this case, the font itself is the background image, while the mask is the image being overlaid into the background image. magick composite -compose CopyOpacity mask\_mask.jpg trans\_stamp.png \\ trans\_stamp3.png magick composite trans\_stamp3.png plasma\_background.jpg mask\_result3.jpg [![[IM Output]](trans_stamp3.png)](trans_stamp3.png) [![[IM Output]](mask_result3.jpg)](mask_result3.jpg) The result of all this is that the central part of the font has been, finally, properly erased by making it fully transparent. The resulting single image can thus be overlaid onto any background easily, without needing any extra masking image. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Shrinking a larger transparent font stamp like the above creates a very good watermark. Shrinking will make the outline less opaque and less pronounced, just as a watermark should be. The two colors also ensure the mark is reliably visible on both very light and very dark images._ | For more information on using image masks, see [Editing Image Masks](../masking/#editing) . * * * Advanced Font Processing ------------------------ By combining the above techniques together, with appropriate colors and other fancy fonts that are available, you can make some fantastic effects, which often look completely different to the original techniques shown above. ### More Complex Fonts - an example For example, here we generate a very complex and colorful bit of text. magick -font Times-Bold -pointsize 64 \\ -background none label:"Colorful Arc" \\ \\( +clone -sparse-color Barycentric '0,%h blue %w,0 red' \\ \\) -compose In -composite \\ -virtual-pixel transparent -distort arc 120 \\ \\( +clone -background black -shadow 100x2+4+4 \\ \\) +swap -background white -compose over -layers merge +repage \\ colorful\_arc.jpg [![[IM Output]](colorful_arc.jpg)](colorful_arc.jpg) The complex command above is laid out so as to perform each major image processing step on separate lines. First the text image is created. Then a [Two Point Gradient](../canvas/#two_point_graidens) is generated as a color overlay. Other coloring methods such as [Blurred Random Images](../canvas/#random_blur) , [Fractal Plasma](../canvas/#plasma_fractal) , or [Tiled Canvases](../canvas/#tile) could also have been used. The color overlay then used to color the text using the [In](../compose/#in) Alpha Composition operator. The colored text is then distorted using an [Arc Distortion](../distorts/#arc) , and finally a [Shadow](../blur/#shadow) is generated and [Layer Merged](../layers/#merge) under the text. That last method also [Removes the Transparency](../masking/#remove) , replacing it with white, before saving to JPEG. For more information on such complex image processing see, [Complex Image Processing and Debugging](../basics/#complex) . ### Neon Sign Here is another simple example. By using a [Soft Outline](#soft_outline) font on a dark background, but using all the same colors, and an appropriate font, you can generate a simple 'Neon Sign' effect... magick -fill dodgerblue -background black -font Anaconda -pointsize 72 \\ label:' I M Examples ' -bordercolor black -border 30x30 \\ \\( +clone -blur 0x25 -level 0%,50% \\) \\ -compose screen -composite neon\_sign.gif [![[IM Output]](neon_sign.gif)](neon_sign.gif) And with just a little more work, you can animate it too! But I'll leave that as an exercise for the reader. See [Advanced IM Examples](../advanced/) for special effects such as ["Gel" Effects](../advanced/#gel_effects) , and ["Aqua" Effects](../advanced/#aqua_effects) . For some examples of other font effects you may like to try and implement see [XaraXone, Using Contour Tool](http://www.xaraxone.com/webxealot/workbook35/page_3.htm) . IM can easilly create contour effects such as those shown. ### Metallic Effect This effect is essentually a rounding, and Color Lookup Table replacement effect. See discussion [Metallic Effect](https://magick.imagemagick.org/viewtopic.php?f=1&t=23904) . Working Example by [snibgo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=16096) # Generate a blured input font shaped mask # first blur-level is a rounding or 'puddling' effect # the second blur is the important one for the metallic effect. magick -background none -pointsize 160 -font Candice label:" Anthony " \\ -blur 0x5 -channel A -level 40%,60% +channel \\ -blur 0x3 metallic\_input.png # Metallic Color Lookup Table magick \\ -size 1x1000 gradient: -gamma 0.9 \\ -function Sinusoid 2.25,0,0.5,0.5 \\ \\( gradient:'rgb(100%,100%,80%)-black' -gamma 1 \\) \\ +swap \\ -compose Overlay -composite \\ -rotate 90 \\ metallic\_clut.png # Give blurred font a metallic look # \* first create a vertial gradient # \* then merge this with a 'shade' reflective gradient # \* before applying the color to the resulting gradient # \* finally add a shadow. magick metallic\_input.png -set colorspace RGB \\ \\( -clone 0 -alpha off \\ -sparse-color Barycentric "0,0 White 0,%\[fx:h-1\] Black" \\ -alpha on \\ \\) \\ \\( -clone 0 -alpha extract -shade 135x45 -auto-gamma -auto-level \\ -alpha on -channel A -level 0%x10% +channel \\ \\) \\ -delete 0 -compose Overlay -composite \\ metallic\_clut.png -clut -set colorspace sRGB \\ \\ \\( +clone -background navy -shadow 80x2+5+5 \\ \\) +swap -background None -compose Over -layers merge \\ \\ -trim +repage metallic.png [![[IM Output]](metallic.png)](metallic.png) * * * --- # Photo Handling -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Digital Photo Handling ========================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Digital Camera Meta-Data, the EXIF Profile](#exif) [![](../img_www/granitesm_right.gif) Digital Photo Orientation](#orient) [![](../img_www/granitesm_right.gif) Color Improvements](#color) * [Brightening Under-exposed Photos](#brightening) * [Binning - Reducing Digital Noise](#binning) (Under Construction) [![](../img_www/granitesm_right.gif) Photo Conversion Cookbook](#cookbook) * [Minor Rotation Correction](#rotation) \- fix a photo that is not quite level * [Tilt-Shift Effect](#tilt_shift) \- make scenery look like an artificial model * [PNG-JPEG Layered Images](#png_jpg) \- compressing pages while keeping text sharp * [Overlapping Photos](#overlap) \- blurred overlaps of appended photos * [Double Exposures](#double) \- mixing multiple photos of the same scene * [Protect Someone's Anonymity](#anonymity) \- fuzzing out some part of a photo * [Add a Texture to an Image](#texture) * [Chroma Key Masking](#chroma_key) \- Modifying by areas of specific color * [Children's Color-In Images](#color-in) * [Pencil Sketch](#pencil) * [Vignette Removal](#vignettation) One of the prime uses of ImageMagick is the handling and modification of photographs that were taken with the new modern digital camera. These cameras generally take quite large, high resolution photos, and include in them meta-data about the time, scale, zoom, camera, orientation, and so on. There are even plans to link cameras to mobile phones, so that it can even make a guess as to where you were when the photo was taken and who might be in the photo (from what mobile phones are in font of it). Here we look at the basics of handling digital photos, and even converting them for other purposes, such as artistic renderings. Special thanks goes to Walter Dnes, a digital camera user, for his help in the enhancement of digital photos. * * * Digital Camera Meta-Data, the EXIF Profile ------------------------------------------ When a digital camera takes a photo, it also includes a lot of extra information in the JPEG save file. This meta-data is known as the EXIF profile, and is provided specifically for photographic labs and development. The ImageMagick "`magick identify`" with a "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" setting will display this Exif information. Here is the EXIF data of a photo I took of a [Pagoda, Kunming Zoo, in Southern China](../img_photos/pagoda_sm.jpg) . magick identify -format "%[EXIF:*]" pagoda_sm.jpg |\ sed 's/\(.\{46\}\).*/\1/' | column -c 110 [![[IM Text]](pagoda_sm_exif.txt.gif)](pagoda_sm_exif.txt) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The EXIF data, or any identify output, should be processed in a case in-sensitive way. Many older versions of IM for example, will output "`EXIF:`" (uppercase) rather than "`exif:`" (lowercase)._ | Here is a similar example but using 'globbing' (shell-like) expression to limit output to EXIF fields involving Time... magick identify -format "%[exif:*time*]" pagoda_sm.jpg [![[IM Text]](pagoda_sm_time.txt.gif)](pagoda_sm_time.txt) There is a lot of information about this photo in the EXIF profile. For example * My camera is a Panasonic ('`Make`'), DMC-LZ1 ('`Model`') * The camera was rotated ('`Orientation`'). But I must have corrected that rotation without adjusting the EXIF data. The camera was also tilted upward slightly, but that info is not recorded. * The '`FocalLength`' of '`37mm` shows that I did not make use of my cameras 'Optical Zoom' feature. My camera could go up to a 6X optical zoom for a '`FocalLength`' of '`366/10`' or '`222mm`'. * And '`DigitalZoomRatio`' shows I did not digitally zoom either. * The camera also used a fast 1/8 second '`ExposureTime`', and an aperture '`MaxApertureValue`' of 3mm, or '`FNumber`' of '`5.6`' and a '`ISOSpeedRating`' of '`64`'. * The flash ('`LightSource`') was not used. * The original image was 1728 by 2304 pixels ('`ExifImageLength`' and '`ExifImageWidth`'). Though the actual image, if you like to check is smaller, so I must have cropped and/or resized it. * And probably most importantly, it was taken around 14:05pm on 9th of July 2005, according to the '`DateTime`' string. That assumes that I had the cameras time set correctly (which I did). * More modern cameras may even have a GPS location and posibily a compass direction of the view! Also included but not listed above is a small 'thumbnail' preview image that the camera used on its own display. There is also features to mark photos you want to be 'developed' or printed by photographic printers, and to adjust other printing parameters. However this is rarely used by most people. Many of these settings can be very useful to users, but the most useful to people is generally the date and time of the photo. This of course assumes that the date and time was set correctly on the cemera before the photo was taken. Also many people are interested in the orientation of the image so it can be rotated correctly when displayed, and That is, what we'll look at next. All this data, and especially the preview image, can take up quite a lot of space in the image. And it may be that I don't actually want everyone in the world knowing that I was in Kunming, China in July 2005. As such you may like to remove EXIF data from your images before actually publishing it on the World Wide Web. Also the size of an image from a digital camera usually very large (and getting larger), allowing you to print it at photo quality level, but is far too large for use of the WWW, and especially not for thumbnails. As such unless you want users to actually be able to print photo quality images, I would not publish the original image directly. The above image for example has been cropped and resized for IM examples usage, but I purposely left the EXIF data intact for the example. Normally I would strip this information. * * * Digital Photo Orientation ------------------------- I have been told that Photoshop will automatically rotate digital images based on the EXIF '`Orientation`' setting, IM will also do this by including a "`[-auto-orient](https://imagemagick.org/script/command-line-options.php?#auto-orient) `" operator, after reading in the image. However, and this is important **JPEG Format is Lossy** What this means is that any time you decode and save the JPEG file format you will degrade the image slightly. As a general image processor, IM will always completely decode and re-encode the format, as such it will always degrade JPEG images when it re-saves the image. For more information on the nature of the JPEG format see [JPEG Image File Format](../formats/#jpg) . The point is to only use IM to correct digital photo orientation (using "`[-auto-orient](https://imagemagick.org/script/command-line-options.php?#auto-orient) `") when you are also performing other image modifying operations, such as [Thumbnail Creation](../thumbnails/#creation) , [Annotating Images](../annotating/#anno_on) , [Watermarking](../annotating/#watermarking) or even [Exposure Adjustments](#brightening) . IM can extract the current orientation (as a number) from the photo using an [Image Property Escape](https://imagemagick.org/script/escape.php) ... magick identify -format '%[exif:orientation]' pagoda_sm.jpg [![[IM Text]](orient_show.txt.gif)](orient_show.txt) IM provides a special "`[-orient](https://imagemagick.org/script/command-line-options.php?#orient) `" operator (use "`[-list](https://imagemagick.org/script/command-line-options.php?#list) orientation`" to see possible values). magick pagoda_sm.jpg -orient bottom-right \ -format '%[exif:orientation]' info: [![[IM Text]](orient_setting.txt.gif)](orient_setting.txt) These meta-data setting methods, allow you to adjust the orientation of photos you have modified, especially ones you have rotated. Note that a correctly orientated photo has an orientation of '`Top-Left`' or 1. Of course you should not remove the EXIF meta-data (using either "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" or "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `"), if you plan to use "`[-auto-orient](https://imagemagick.org/script/command-line-options.php?#auto-orient) `" later in the image processing. Use it before stripping the image meta-data. If you do want to correct the orientation of your photo, without degrading or otherwise modifying your image, I suggest you use the [JHead](http://www.sentex.net/~mwandel/jhead/) program. For example here I correct a photos orientation, and delete the built-in preview thumbnail all the digital photos in a directory. jhead -autorot \*.jpg | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The JPEG lossless rotation will only work correctly for images that have a size that is divisible by 8 or 16. This is true with most (but not all) digital camera photos. If you try this with an image that is an odd size the right or bottom edge blocks (containing the partial size) will not be positioned correctly in the final image, as these block can only exist on the right or bottom edge.

For an example of this see this [specific discussion](https://magick.imagemagick.org/viewtopic.php?t=16784&p=62157)
_ | The [JHead](http://www.sentex.net/~mwandel/jhead/) program will also let you adjust the photos date (if your camera time was set wrong, or you have travelled to different time zones), extract/remove/replace the preview thumbnail, set the comment field of the image, remove photoshop profiles, and do basic image cropping (to remove that stranger exposing himself ;-) so on, without degrading the JPEG image data. I recommend this program, or other programs like it (see [Other JPEG Processing Programs](../formats/#jpg_non-im) ), to fix this information. Just be sure that it does not actually decode/re-encode the JPEG image data. One final point about orientation. If you pointed your camera almost straight up or down, the EXIF orientation setting may not resolve correctly. The same goes for angled or slanted shots. The orientation (and cameras) just have no senses for these situations. Your only choice for such photos is to do the rotates yourself using the lower level non-lossy "`jpegtrans`", or IM "`[-rotate](https://imagemagick.org/script/command-line-options.php?#rotate) `", and then either reset the EXIF orientation setting (using [JHead](http://www.sentex.net/~mwandel/jhead/) or the IM "`[-orient](https://imagemagick.org/script/command-line-options.php?#orient) `" operator), or just strip the EXIF profile. Other IM Lossy Modifications... If you are also resizing or otherwise modifying the image, such as reducing its quality and size for use on the web, then data loss is already a fact. As such during those operations IM can do similar things, allowing you to do all the required operations in a single 'load-save' cycle. Rotate ALL images to landscape -rotate 90\\< portrait -rotate -90\\> * * * Color Improvements ------------------ Before proceeding, it is recommended that you first look at [Color Modifications](../color_mods/) for an introduction to general color modification techniques that will be used. [Normalizing](../color_mods/#normalize) (using "`[-normalize](https://imagemagick.org/script/command-line-options.php?#normalize) `") high-contrast line art and graphics can be great. But normalized photos may look unreal, and, as was said earlier, may not print well either. The "`[-contrast-stretch](https://imagemagick.org/script/command-line-options.php?#contrast-stretch) `" operator can limit the "boundaries" of the normalization, but the "`[-levels](https://imagemagick.org/script/command-line-options.php?#levels) `" and/or "`[-sigmoidal-contrast](https://imagemagick.org/script/command-line-options.php?#sigmoidal-contrast) `" operator can make "smoother" adjustments (see [Histogram Adjustments](../color_mods/#histogram) for a lower level discussion of what these operators do). The above input is courtesy of "Tong" form the IM Mailing List. ### Brightening Under-exposed Photos Contributed by Walter Dnes Sometimes there simply isn't enough available light to allow for a proper exposure. At other times, you may have to use shorter exposure times than optimal, in order to eliminate motion-blur. Underexposed digital photos can have darker areas preferentially brightened, without blowing highlights, by using the "`[-sigmoidal-contrast](https://imagemagick.org/script/command-line-options.php?#sigmoidal-contrast) `" operator, with a '`0%`' threshold level. See [Sigmoidal Non-linearity Contrast](../color_mods/#sigmoidal) for more details. Here is a minor underexposure example, which was taken at a free concert after sunset. This has lots of brightly lit areas, which are clear, but also dark areas I would like to make more visible. magick night\_club\_orig.jpg -sigmoidal-contrast 4,0% night\_club\_fixed.jpg [![[IM Output]](../img_photos/night_club_tn.gif)](../img_photos/night_club_orig.jpg) ![==>](../img_www/right.gif) [![[IM Output]](night_club_fixed.gif)](night_club_fixed.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As always, you should use a non-lossy format like TIFF or PNG for intermediate work. The JPEG format is only used here to reduce disk space and download bandwidth for web publishing.

Select image to see the enlarged version actually used by the examples rather than the small thumbnail shown._ | And here is a major underexposed example, which was a night-time shot from my balcony looking southwards towards the city of Toronto. magick night\_scape\_orig.jpg -sigmoidal-contrast 10,0% night\_scape\_fixed.jpg [![[IM Output]](../img_photos/night_scape_tn.gif)](../img_photos/night_scape_orig.jpg) ![==>](../img_www/right.gif) [![[IM Output]](night_scape_fixed.gif)](night_scape_fixed.jpg) The main parameter controls the amount of brightening. The more brightening required the higher value used. And the grainier the output picture will look. This is due to the smaller pixel errors also being enhanced. Sigmoidal contrast brightening tends to de-emphasize the red end of the spectrum. You may end up having to select a parameter that results in the most natural flesh tones, rather than the brightness level you really want. In the case of major underexposure, you will end up with a glorified grainy black-and-white image after brightening. This is a physical limitation of digital image enhancement. If there's no colour data present, IM won't generate it for you. In real life the bricks on the right-hand side of my balcony are reddish, and the trees below are green. ### Binning -- Reducing Digital Noise Contributed by Walter Dnes A lot of serious photographers are unhappy with the side-effects of the "megapixel race" by digital camera manufacturers. Manufacturers pack more megapixels into a digital camera's sensor by making them smaller. Smaller pixels result in a noisier picture at the same ISO setting, which forces people to use lower ISO settings. Using lower ISO ratings to avoid noise requires longer exposure times. This, in turn, means that most consumer digital cameras are effectively useless indoors beyond the 10-foot range of their built-in flash for anything except a still-life picture taken with the camera on a tripod. Many digital camera users would gladly trade some pixels for less noisy pictures at higher ISO settings, but the marketeers who control the companies refuse to consider this as an option. Fortunately, the trade-off can be done after the fact on digital photos. The technical term is 'binning'. The simplified theory goes like so... * Take an n-by-n grid of pixels, and average their components to obtain one "super-pixel". * Signal is proportional to the combined pixel area, which means that the amount of signal has increased by a factor of n^2 * Noise is random. Which means that it is proportional to the square root of the combined pixel area, a factor of n. The net result is that SNR (signal-to-noise ratio) has increased by a factor of n. See [Photo Glossary, Binning](http://www.noao.edu/outreach/aop/glossary/binning.html) for more details. When a 1600x1200 digital photo is binned down to 800x600 (i.e. a 2x2 grid) the signal-to-noise ratio is doubled. Similarly, a 2560x1920 picture binned 3x3 to 853x640 pixels will have a factor of 3 improvement in signal-to-noise ratio. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _In order to make use of binning, the photo image must be a whole number multiple of the final desired size._ | In ImageMagick, the special "`[-filter](https://imagemagick.org/script/command-line-options.php?#filter) `" setting '`box`' will average groups of pixels down to a single pixel when you "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" an image (See [Resampling Filters](../filter/#filter) for details. This means that to do a 'binning' you only need to resize the image correctly. **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Walter Dnes also provided the original script [binn](binning/binn) to perform the calculations, minimally crop the image and perform the 'binning'. [Binning examples 3](binning/sample3.html) [Binning examples 4](binning/sample4.html) * * * Photo Conversion Cookbook ------------------------- ### Minor Rotation Correction \-- Make a photo more level Typical situation. You have taken a photo, but the image isn't level, and you want to correct it. [![[IM Output]](beijing_tn.png)](../img_photos/beijing_md.jpg) For example, here is a photo I took using a hand held camera in Beijing, 2008, from the hill in Jingshan Park, immediately behind the Forbidden City. No it isn't of the Forbidden City itself, but a temple on the other side of the hill. _Click on the thumbnail, to see a larger image._ Yes the image is small, and you should apply the solution to the original image not a small thumbnail, but the techniques is the same for any image. In this case the image needs to be rotated by -1.8 degrees, to correct it.Now if you just simply rotate the image you will get a slightly larger image containing areas of color in the corners, making the correction look obvious and horible. magick beijing\_tn.png -rotate -1.95 beijing\_rotate.png Even if you were to crop the image back to its original size, such as demonstarted in [Simple Image Rotations](../warping/#rotate) you will still get some colored corners.[![[IM Output]](beijing_rotate.png)](beijing_rotate.png) The simplist solution would be to now crop that result so as to remove those borders, but then your image becomes a rather odd size, which is again rather obvious that something has been done. Though the formula to do that clipping is not simple, but is demonstrated in [Distortion Rotation Methods](../distorts/#rotate_methods) .The better solution is to not only rotate the image, but scale it slightly so as to produce a rotated image that is the same size as the original. angle=-1.95 magick beijing\_tn.png -distort SRT \\ "%\[fx:aa=$angle\*pi/180;(w\*abs(sin(aa))+h\*abs(cos(aa)))/min(w,h)\], $angle" \\ beijing\_rot\_correction.png [![[IM Output]](beijing_rot_correction.png)](beijing_rot_correction.png) And the image is clean looking with a perfectly level wall. The angle calculation is reasonably straight forward trigonometry, using the pixel locations at the ends of a long straight line in the image. However I found that simply rotating the image at various small angles by trial and error will find a good rotation angle relatively quickly. When looking how good a particular angle is, take a very close zoomed in look at the pixels along the line or edge you using. The top of the wall in this photo. And remember in image rotations a left or anti-clockwise rotation is negative (due to Y-axis pointing downward). Also remember that if at all possible, always apply operations to the original image, avoiding the use intermediate images (and especially intermediate JPEG images). It is always better to apply any photo modification starting with the original source than any saved intermediate copy. ### Tilt-Shift Effect \-- make scenery look like an artificial model [![[IM Output]](beijing_tn.png)](../img_photos/beijing_md.jpg) The 'Tilt-Shift' is a technique which causes an image be be blurred at the top and bottom, while leaving the center of the image unblurred. It was originally done in very old bellow type cameras where the lens was tilted to bring the top and bottom of the image out of focus. Thanks of the introduction of [Variable Blur Mapping](../mapping/#blur) , added to ImageMagick in v6.5.4-0 this is now easy to do. If you add to this a very high contrast so as to enhance shadows, and saturate the colors, a typical result is that a normal image can be made to look artificial. Almost as if you were taking a photo of a small, highly detailed, and brightly lit, model. The first thing we need to do, is enhance the colors in the image to give it a very high contrast, and perhaps brighten it a bit to make it look like it is very well lit with strong studio lights. magick beijing\_md.jpg -sigmoidal-contrast 15x30% beijing\_contrast.jpg [![[IM Output]](beijing_contrast_tn.gif)](beijing_contrast.jpg) Note how I used a strong [Sigmodial Contrast Operation](../color_mods/#sigmoidal-contrast) , to achieve these color effects. I did not just simply use a linear contrast as I did not want to 'clip' the brightest and darkest colors of the image. The contrasting value of '`15`' is a very very strong contrast. I also brightened the image a bit by offsetting the center of the contrast threshold to a '`30%`' gray value. If the colors of the contrast enhanced image does not come out cartoonish enough, you may like to try increasing the color saturation of the image, using the [Modulate Operator](../color_mods/#modulate) . This image did not need it as it as the tiled roof and bright green trees already provides enough color effects. If you look at an enlargement of the image (_Click on the thumbnail_), you will see that even just enhancing colors gives the image a feel of artificial lights, though it does not look like a model, with too much detail to the cars in the background, and people in the foreground.Now for the tilt-shift. For this we prepare a gradient image that is white at the top and bottom, and black in the middle. Some people might use a linear gradient for this, but I find a parabolic gradient better. magick beijing\_contrast.jpg \\ -sparse-color Barycentric '0,0 black 0,%h white' \\ -function polynomial 4,-4,1 beijing\_blurmap.jpg [![[IM Output]](beijing_blurmap_tn.gif)](beijing_blurmap.jpg) Note that I used the original image itself with a two point [Barycentric Sparse Coloring](../canvas/#barycentric) to generate a linear gradient over the whole image. That linear gradient is then modified using a basic [Polynomial Function](../transform/#function_polynomial) to make it a parabolic gradient with black in the middle. Now it is simply a matter of blurring the image according to the blur map to create a 'tilt-shift' effect. The result is that the original image looks rather like a scale model, rather than quick snap-shot of the real thing. magick beijing\_contrast.jpg beijing\_blurmap.jpg \\ -compose Blur -set option:compose:args 10 -composite \\ beijing\_model.jpg [![[IM Output]](beijing_model.jpg)](beijing_model.jpg) As you can see in the final image, the trees and the buildings look very artificial, due to the strong colors, while the blurring of the near and far parts gives the image a 'small' model-like feel to it. Though this must have been a very detailed model! The result could have been improved further by performing a [Rotation Correction](#rotation) (see previous) as part of the tilt shift processing. A perfect camera orientation would simply added to the artificial feel. Of course you can string all these operations together to to it all in one command, and avoid temporary files, or loss of quality. magick beijing\_md.jpg -sigmoidal-contrast 15x30% \\ \\( +clone -sparse-color Barycentric '0,0 black 0,%h gray80' \\ -solarize 50% -level 50%,0 \\) \\ -compose Blur -set option:compose:args 10 -composite \\ beijing\_model.jpg In the above I replaced the parabolic gradient with a more traditional linear black-white-gray gradient (with the same slope) to the 'tilt-shift' blur map. The [Solarize & Level](../color_mods/#solarize) technique was used to make the linear gradient peak horizontally about 1/3 from the bottom of the image. However I find that the area of focus in a linear gradient too small and not very practical. There are many other way of generating a suitable gradient for a tilt shift effect. For example using [Resized Gradients](../canvas/#gradient_resize) . Or horizontally scaling a [Shepards Sparse Color](../canvas/#shepards) of single column of pixels. Sine curve gradients may also be useful. ##### Speed Optimization The [Variable Blur Mapping](../mapping/#blur) operation is essentually using a single pass 2-dimentional blurring method (equivelent to an uniform Gaussaian Blur). However you can get a general speed boost by doing the bluring operation in two 1-dimensional variable blur operations. For example, here I first blur horizontaly, the vertially... magick beijing\_md.jpg -sigmoidal-contrast 15x30% \\ \\( +clone -sparse-color Barycentric '0,0 black 0,%h gray80' \\ -solarize 50% -level 50%,0 -write mpr:blur\_map \\) \\ -compose Blur -set option:compose:args 10x0 -composite \\ mpr:blur\_map \\ -compose Blur -set option:compose:args 0x10 -composite \\ beijing\_model\_2pass.jpg The result is practially identical (though does differ somewhat), but is a lot faster to process. ASIDE: I believe that swaping the operations (blur vertical then horizontally) will generate a more accurite result for this type of blur mapping. basically as the horizontal blur is a constant in the direction of that blur pas, so should be done last. ##### Problems with Tilt-Shift Effect vs A Real Model If you examine the resulting photo carefully, you will be able to tell it is a fake tilt-shift, and not a photo of a real model. You can see this in that the roof of the larger building is too blurry when compared to the base of the building. Even though it is about the same distance as the base. Similarly the base of the 'wall' is more blurry than the top of the wall. That is, it can be seen to be a fake. The problem is that large vertical objects, should be blurred by the same amount over the whole surface, and not just variably blurred by height. Remember the blur gradient is meant to represent the focal depth, or distance of the various objects in the image, as such the surface of a vertical object should all be the same 'distance' and thus blurred by the same amount. To fix I would need to adjust the blur gradient to make those areas have a with a constant (or near constant) color of the 'base' of that object, relative to rest of the image. That is, vertical surfaces have a constant blur amount while all the horizontal surfaces have a blur gradient. Basically the blurred gradient should represent the actual 'depth' of each point in the image, which for most images is a very complex gradient. This adjustment can be difficult to achieve, as it most likely requires some human interpretation of what is a horizontal wall and how far the object is in the image. It is also unlikely to be easily automated. What can you do with this effect? Mail me your tilt-shift images! I'll reference them here. Or perhaps you can correct the tilt-shift faults in the above example. ### PNG-JPEG Layered Images By separating a large newspaper or magazine page into a text layer that is saved as a PNG, and an image layer saved as JPG, both using just a white background, it is possible to use much less disk space than the two images combined! More importantally images can use a lossy compression (JPEG), the text components will remain sharp an clear (PNG). It sounds silly and weird but it is actually true. The separated images can save 3 to 4 times the disk space used by a single combined image. Usually the two images are generated during the publication process as separate layers. But you can also separate images after the fact too. The images are just overlayed together... magick ny\_family.jpg ny\_family.png -composite ny\_family\_merged.jpg [![[IM Output]](../img_photos/ny_family_tn.jpg)](../img_photos/ny_family.jpg) ![==>](../img_www/multiply.gif) [![[IM Output]](../img_photos/ny_family_tn.png)](../img_photos/ny_family.png) ![==>](../img_www/right.gif) [![[IM Output]](ny_family_merged_tn.jpg)](ny_family_merged.jpg) Select the resulting images to see a larger copy. This uses a normal [Over Composition](../compose/#over) , which requires the PNG (overlay) image to be transparent. This transparency comes in two forms. Either as a boolean (pure on/off) mask, such as seen in the above. Example code for image separation welcome. ### Overlapping Photos \-- blurred overlaps of appended photos Creating a series of overlapping photos (and I don't mean a panarama) is a common task, especially in web site creation. But is can be tricky to do unless you have the right knowledge of IM operators. The simplest method is to use a [Masked Composite](../compose/#mask) of the two images, and a mask to select which image to overlay. First however you need to do simple mathematics. For this example, I am using two thumbnail images 120x90 pixels in size and I want to overlap them horizontally by 40 pixels. This means the resulting image should be 120 + 120 - 40 pixels wide, or a 200x90 pixel image. Next we need a mask. This needs to black one one side, white on the other, with a 40 pixel gradient in the middle, the size of the final output image. That is, 120 pixels - 40 pixel gives an 80 pixel area for each of the two non-overlapped areas. So lets generate a masking image... magick -size 90x80 xc:white xc:black -size 90x40 gradient: \\ +swap -append -rotate 90 overlap\_mask.png [![[IM Output]](overlap_mask.png)](overlap_mask.png) An alternative way of generating the masking image is to use Fred Weinhaus's "`[plmlut](http://www.fmwconcepts.com/imagemagick/plmlut/index.php) `" horizontal gradient generator script. This has finer controls for the curvature of the gradient rather than a sharp linear gradient I generate above. Now that all of the math is out of the way, all that is left is to do a three image masked composition, using the mask we just generated. However we will also need to enlarge the destination (left) image so as to provide enough space for the overlapping right image (any color), and position the second image correctly using the appropriate gravity (right, or '`East`'). magick holocaust\_tn.gif -extent 200x90 spiral\_stairs\_tn.gif \\ overlap\_mask.png -gravity East -composite overlap\_photos.jpg [![[IM Output]](../img_photos/holocaust_tn.gif)](../img_photos/holocaust_tn.gif) [![[IM Output]](../img_photos/spiral_stairs_tn.gif)](../img_photos/spiral_stairs_tn.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](overlap_mask.png)](overlap_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](overlap_photos.jpg)](overlap_photos.jpg) And we now have two images, which are overlapped using a linear gradient. Of course the two commands can be merged into a single command, so that you don't need to save the 'mask' intermediate image. This is left as an exercise to the reader. A slight improvement is to use a more curved gradient over a larger overlap between the images. This reduces the sharp change visible at the start and end of the overlap area of the final image. Especially with images contain large areas of very different colors. For example, this uses some [Distorted Gradient](../canvas/#gradient_distort) techniques to not only generate a smoother gradient curve, but also to rotate that gradient so as to have a highly angled overlap. magick -page +0-15 -size 1x30 gradient: \\ -sigmoidal-contrast 5,50% -contrast-stretch 0 \\ -set option:distort:viewport 180x90-90-45 \\ +distort SRT 115 +repage \\ holocaust\_tn.gif -extent 180x90 +swap \\ spiral\_stairs\_tn.gif +swap \\ -gravity East -composite overlap\_angled.jpg [![[IM Output]](overlap_angled.jpg)](overlap_angled.jpg) Yes, the above is rather complex, but it shows just what is possible. If you plan to do more than two images, a better method is to use the mask to directly set the transparency of the second and later images. The multiple images can then be overlaid together using a techniques seen in [Layered Image Examples](../layers/#layer_prog) . Some of these techniques do not require you calculate the final image size, as IM can do this for you. You only need to make sure you position the images correctly. For example, here I add a 30 pixel gradient to a second and third image, requiring the images to be placed every 90 pixels (width 120 minus 30 pixel overlap) from each other. When all images are given the appropriate transparency and positioning, we just [Mosaic](../layers/#mosaic) the layers together (all offsets are positive), letting IM figure out the final canvas size. magick -size 90x90 xc:white -size 90x30 gradient: -append -rotate 90 \\ hatching\_tn.gif \\ \\( chinese\_chess\_tn.gif -clone 0 \\ -compose CopyOpacity -alpha off -composite -repage +90+0 \\) \\ \\( holocaust\_tn.gif -clone 0 \\ -compose CopyOpacity -alpha off -composite -repage +180+0 \\) \\ \\( spiral\_stairs\_tn.gif -clone 0 \\ -compose CopyOpacity -alpha off -composite -repage +270+0 \\) \\ -delete 0 -compose Over -mosaic overlap\_series.jpg [![[IM Output]](overlap_series.jpg)](overlap_series.jpg) Rather than pre-calculating the positions of the overlapping masked images, you can use techniques found in [Append Overlap](../layers/#append_overlap) , as well as [Incrementally Calculated Positions](../layers/#layer_calc_inc) for longer image sequences. **Final Notes:** Overlapping photos like this works best for images with a reasonably common overall color. Also you may notice that for the images at either end of the sequence, a centered subject may not look very centered due to the overlap on one side of the image only. This problem can be improved either by fading the outside edge of those images into transparency, or chopping of some of outside edge to help re-center the subject of those images. _`ASIDE: It may be that doing the composition in a different colorspace may work better. Anyone like to experiment and report on your results, good or bad?`_ ### Double Exposures \-- mixing multiple photos of the same scene With old time film based cameras, there was a technique where a picture was take two or more times without 'rolling' the film. This allowed you to create what was known as double exposures, where two images taken at slightly different times were merged together. The result was often a ghosting or dimming of parts of the image which moved or changed. However with careful control of the subjects in the image, the lighting effects, and even the development process, it became possible to make some very weird or even 'impossible' photos. With digital images it is even easier as you have even better control of the images. Basically... _Seeing may be believing, but cameras lie!_ For example suppose I wanted an image in which I appear in twice! Well that is easy to do. Here for example are the thumbnails of two quick photos I took specifically for this example, using a tripod and timer, which I'll use directly. [![[IM Output]](../img_photos/anthony_1.jpg)](../img_photos/anthony_1.jpg) [![[IM Output]](../img_photos/anthony_2.jpg)](../img_photos/anthony_2.jpg) _Perhaps you can supply a better more amusing photo set?_ I will apply the double exposure techniques directly to these thumbnails, though more typically I would do this using original image files as inputs, so as to get a result of the highest quality. Now if I used a traditional film-like 'double exposure' with an old style camera, the result would be an average of these two images, generating see-thru 'ghosts' of myself. Here is the digital simulation of this technique... magick anthony\_1.jpg anthony\_2.jpg -evaluate-sequence mean anthony\_ghosts.jpg [![[IM Output]](anthony_ghosts.jpg)](anthony_ghosts.jpg) However, what if I don't want ghosts, but properly solid images of myself. Well then you need to use a mask to select which parts you want to come from which image. This mask can be generated in two ways. You can just manually create the mask by dividing the image along the static or unchanging parts. A rather simple matter in this particular case... magick -size 100x90 xc: -draw 'rectangle 0,0 50,89' \\ -blur 0x3 anthony\_mask.jpg [![[IM Output]](anthony_mask.jpg)](anthony_mask.jpg) Note that I blurred the mask, so as to 'feather' the cut-over between the two images. And here I use a [Masked Composition](../compose/#mask) to merge the images. magick anthony\_1.jpg anthony\_2.jpg anthony\_mask.jpg \\ -composite anthony\_doubled.jpg [![[IM Output]](anthony_doubled.jpg)](anthony_doubled.jpg) How if you had two (or more) family photos, where some people had eyes closed, were speaking, pulling faces, or just looking away. You could pick and choose each 'head' from different images and merge the multiple images to form a montage, so as to get a photo where everyone is looking at the camera, and have their eyes open. By swapping the input images, or just negating the mask, you can remove me completely from the image, so get an unrestricted view of the static background. magick anthony\_2.jpg anthony\_1.jpg anthony\_mask.jpg \\ -composite anthony\_removed.jpg [![[IM Output]](anthony_removed.jpg)](anthony_removed.jpg) This can be handy when taking photos of a public monument, where you can't afford the expense of crowd control. Just take lots and lots of photos from a tripod, and hopefully you can combine them to remove everyone from the scene! An alturnative to generating a background image which you have hundredes of images (video) is to just create an average of all the images. This Turn all the people or other transient objects into a light haze of 'ghosts'. That can be an interesting effect in and of itself, but not always what is wanted. An average image can be an useful step, as once you have it you can compare it against each individual image to mask out the person (transient object) from each frame, before again combining the backgrounds together, to create a clean (no haze) background image). A major discussion on automatically generating a 'clean background' from video images is in IM Discussion Forum on [Creating a Referance Image](https://magick.imagemagick.org/viewtopic.php?t=29245) and [Extracting change events](https://magick.imagemagick.org/viewtopic.php?t=29233) . With a clean background photo, we we can threshold a difference image to mask out the parts of the image that changed. You may need to use some further blurring and threshold to expand that mask appropriately to cover not only the object within the image, but any shadows or reflections it may cast on the background scenery. A little trial and error may also be needed to get it right. magick anthony\_removed.jpg anthony\_2.jpg \\ -compose difference -composite \\ -threshold 5% -blur 0x3 -threshold 20% -blur 0x3 \\ anthony\_automask.jpg [![[IM Output]](anthony_automask.jpg)](anthony_automask.jpg) Now lets use this mask to mix my 'ghosts' image with the original image so it looks like my conscience is 'haunting' me for making such 'impossible' pictures. magick anthony\_1.jpg anthony\_ghosts.jpg anthony\_mask.jpg \\ -composite anthony\_haunted.jpg [![[IM Output]](anthony_haunted.jpg)](anthony_haunted.jpg) As a final point, all the above techniques assumes the photos were taken from a camera that was locked down securely on a stationary tripod. If this was not the case, but just taken from a hand held position, I can guarantee that the images will not match-up or 'align' properly, no matter how hard you tried to do it. In such cases you may require some [Affine](../distorts/#affine) or even [Perspective](../distorts/#perspective) distortion of at least one of the two images to get the backgrounds to align properly. The more complex the background, the more exacting the needed re-alignment. If a flash was used, or the day was cloudy with variable light, you may also need some brightness adjustments to the photo. The cause is that most cameras 'auto-adjust' the brightness of the images, and a flash, or variable light can change its handling of the 'auto-level' adjustment for each and every image. As a final example, here is another image I created from two separate photos, of my nephew fencing with himself, in front of a climbing wall. As I was holding the camera and used a flash, I did need to do some affine distortion adjustments, as well as slight brightness adjustment to get the seamless result you see. [![[IM Output]](../img_photos/jacob_vs_jacob_md.jpg)](../img_photos/jacob_vs_jacob_md.jpg) **_Jacob_ vs _Jacob_** If you were trying to decide if this photo was fake or not, you would look at the lighting, shadows and reflections. In the above, a close examination of the floor will show that the right 'Jacob' does not have a proper reflection on the floor (it was clipped by the photos edge). But you would really need to study the photo well to notice this! Now think of the possibilities you can use this 'double exposure' technique for. For example how about some [Funny Mirrors](http://todaypictures.blogspot.com/2006/03/funny-mirror.html) . Email me your results! If you like to get into this further the research paper "[Interactive Digital Photomontage](http://grail.cs.washington.edu/projects/photomontage/photomontage.pdf) ", goes into using "Double Exposures" (or as it terms it "photo montage"), but making use of user selections expanded using "image segmentation", to select what parts of the image is to come from where. One example is if you have a number of photos of a large group of people, in each photo someone does not 'look good'. You can use this technique to select which person comes from which image so that you can get a perfect group photo where everyone is: facing front, with eyes open, and smiling! ### Protect Someone's Anonymity \-- fuzzing out some part of a photo The above technique of using a 3 image composite mask can also be used in other ways. For example you can 'pixelate' and image, then use a mask to limit the effect to just the face of a person, so as to "Protect their Identity". magick zelda\_tn.gif -scale 25% -scale 400% zelda\_pixelate.gif magick zelda\_tn.gif -gamma 0 -fill white \\ -draw 'circle 65,53 50,40' zelda\_face\_mask.gif magick zelda\_tn.gif zelda\_pixelate.gif zelda\_face\_mask.gif \\ -composite zelda\_anonymity.png [![[IM Output]](../img_photos/zelda_tn.gif)](../img_photos/zelda_tn.gif) ![==>](../img_www/right.gif) [![[IM Output]](zelda_pixelate.gif)](zelda_pixelate.gif) [![[IM Output]](zelda_face_mask.gif)](zelda_face_mask.gif) ![==>](../img_www/right.gif) [![[IM Output]](zelda_anonymity.png)](zelda_anonymity.png) Of course you can do this all in one go, and even smooth the change from pixelated to normal. For example.. magick zelda\_tn.gif \\( +clone -scale 25% -scale 400% \\) \\ \\( +clone -gamma 0 -fill white \\ -draw 'circle 65,53 50,40' -blur 10x4 \\) \\ -composite zelda\_anonymity.jpg [![[IM Output]](zelda_anonymity.jpg)](zelda_anonymity.jpg) Of course rather than pixelate the offending part, you can also blur the area instead. Just replace the two "`[-scale](https://imagemagick.org/script/command-line-options.php?#scale) `" operators with a single "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" to fuzz out the details. This technique replacing a masked area can also be used to remove unwanted text and logos from images. For details see [Hole Filling](../masking/#hole_filling) . ### Add a Texture to an Image The [Hardlight](../compose/#hardlight) alpha compositing method or even any of the various [Lighting Composition Methods](../compose/#light) provide ways to give an image a texture pattern. For example, here I add a texture of course fabric to a photo I took of a pagoda at the Kunming Zoo, in southern China. magick tile\_fabric.gif -colorspace gray -normalize \\ -fill gray50 +level 35% texture\_fabric.gif magick composite texture\_fabric.gif pagoda\_sm.jpg \\ -tile -compose Hardlight photo\_texture.jpg [![[IM Output]](../images/tile_fabric.gif)](../images/tile_fabric.gif) ![==>](../img_www/right.gif) [![[IM Output]](texture_fabric.gif)](texture_fabric.gif) ![==>](../img_www/right.gif) [![[IM Output]](photo_texture.jpg)](photo_texture.jpg) Note that if you want to actually _tile_ the texture over the image you need to use the "`magick composite`" command rather than the more versatile "`magick`" command, though there are a number of other ways to [Tile Images in Memory](../canvas/#tile_memory) using convert. Also note that when adding a texture like this, the smaller details in the original photo can be lost by excess noise of the overlaid texture, textures should ge hept either simple, or their effect appropriatally moderated, such as the [Decontrasting Level Adjustment](../color_mods/#level_plus) used above. To use an image pattern as a texture it should be modified so that a perfect gray color is used for areas that is unchanged in the original image. That is the average color of the image should be about 50% gray. In the example I demonstrate one way that you can do this with just about any tileable image, though this specific method may not always work well. Such textures can be found all over the web, as various background patterns for web pages. They may not even look like a texture, be colorful, or even very bright or very dark. After adjustment however you will find that you can get some very interesting effects. Just as we did previously, you can limit what parts of an image is actually textured by creating an appropriate mask. For example lets create a mask of just the near 'white' sky in the pagoda photo. magick pagoda\_sm.jpg -fuzz 10% -transparent white \\ -alpha extract -negate pagoda\_mask.png magick pagoda\_sm.jpg photo\_texture.jpg pagoda\_mask.png \\ -composite photo\_texture\_masked.jpg [![[IM Output]](pagoda_mask.png)](pagoda_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](photo_texture_masked.jpg)](photo_texture_masked.jpg) Now imagine an picture of a lady wearing a dress. You can get any pattern shade it appropriately, and then overlay that on the original image so as to replace the dress with a completely different design. Of course there are lots of variations on the above to achieve the final result, and which specific technique you use is up to you, but the basic idea is the same. Texture the image, mask and overlay the result. As an aside, I also recommend you look at the [Overlay](../compose/#overlay) alpha composing method, which is simply the same as [Hard\_Light](../compose/#hardlight) composition, but with the two images swapped. There is also a lot of other [Shading Composition Methods](../compose/#shade) that can be used to texture an image in various ways. [![[IM Output]](../img_photos/shirt.jpg)](../img_photos/shirt.jpg) ### Chroma Key Masking \-- Modifying by areas of specific color The photo to the left was given by an user in a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=18094) . he wanted to change the color of the girls shirt, which was a nice 'pink' color. The problem is the color is not just 'pink' but a whole range of different shades of 'pink'. As you have seen above, to make changed to an image, the first step is typically generating an appropriate mask of the area you are interested in. Here I will use a technique known as [Chroma Key](http://en.wikipedia.org/wiki/Chroma_key) to generate mask that specific color. This technique generally looks for a specific color in an image for use as the mask. It is also the technique used for 'blue' and 'green' screen effects used extensively on TV and in Movies.   This basically involves extracting the 'Hue' by [Separating Channel Images](../color_basics/#separate) , then looking up the 'hue shade' wanted. For example... magick shirt.jpg -colorspace HSL -channel Hue -separate shirt\_hue.jpg However this Hue image has a couple of problems. * First a 'pink' color is very close to 'red' which is at the division where Hue 'rolls over'. To ensure this is not a problem I use [Modulate](../color_mods/#modulate) to adjust the hue away from that 'discontinuity' in the hue. This is not a problem for extracting a 'chroma key' for 'green' or 'blue' screens. * This 'pink' color is also not a highly saturated color, but has a very low saturation value. This means its 'hue' is not as strong as it should be. * The other problem is the gray background!!!!! Gray is has very little hue, so I need to remove any areas with little to no saturation from my final mask, or I'll be changing things in the background. Note that this is technically not needed if I limit changes to hue rolls, which does not effect unsaturated colors. In short, the input image would have worked better with a brighter stronger color that was also not as simial to skin (or hair) color. A strong blue or green shirt for example. But I will work with what I was given.[![[IM Output]](shirt_hue.jpg)](shirt_hue.jpg) So lest extract and combine the two channel masks. Note that Hue = Gray64 after the image hues was 'rolled' using module, and Saturated = Black for the grey background. magick shirt.jpg -modulate 100,100,33.3 -colorspace HSL \\ -channel Hue,Saturation -separate +channel \\ \\( -clone 0 -background none -fuzz 5% +transparent grey64 \\) \\ \\( -clone 1 -background none -fuzz 10% -transparent black \\) \\ -delete 0,1 -alpha extract -compose multiply -composite \\ shirt\_mask.png That just leaves a number of small isolated 'specks' that can be removed with some [Morphology Smoothing](../morphology/#smooth) (`-morphology Smooth Square`). It isn't perfect but it will do the job. The better way would be to edit the mask by hand to clean it up. Now a mask can be used with [Composite Masking](../compose/#mask) much like we did with [Double Exposures](#double) and [Anonymity](#anonymity) examples above. However If you are using a mask to modify an existing image (without distorting, or changing the images size), then it is easier to use it to define what areas are un-writable. These are known as [Clip or Write Masks](../masking/#clip-mask) (see "`[-mask](https://imagemagick.org/script/command-line-options.php?#-mask) `"[![[IM Output]](shirt_mask.png)](shirt_mask.png) Here I cleanup the previous mask of the small defects (optional), and negate it to define what areas I want to 'write protect'. Then I set this mask, shift the hues to turn 'pink' into a 'light blue' color, and save the resulting image. magick shirt\_mask.png -morphology Smooth Square \\ -negate shirt\_write\_mask.png magick shirt.jpg -mask shirt\_write\_mask.png \\ -modulate 100,100,25 +mask shirt\_blue.jpg Yes there is a slight 'pink' border, especially in the inside sleeve. Also a small area of skin on her arm turned a rather dark blue. Basically these are mask defects, and with a little more work in perfecting the mask you can fix these problems. But it is not bad result. One method of generating a better mask is to use a much larger higher resolution image. When the resulting image is later resized these small defects will (hopefully) also be reduced to insignificance.[![[IM Output]](shirt_blue.jpg)](shirt_blue.jpg) The real problem with this specific example, is the 'key color' is so close to a normal skin color you are really just asking for trouble! This is why people using this technique use 'green' and 'blue' screens, as those colors are as different as possible from 'skin' color of people in front of the screen. Note that you are better off NOT using JPEG as your source or working images. Really JPEG should only be used for your final images only! This is part of the reason why so many 'mask defects' was generated in the first place. ### Green Screen _Future example, using Chroma Key Masking of a 'green screen background'. Expanded from the wikipedia artical, [Chroma Key](http://en.wikipedia.org/wiki/Chroma_key) Real problems in 'green screen' handling is the 'color spill', with fine light color hair (blonde) and semi-transparent areas producing the worse color spill effects. Simplistic Colorspill removal (color fix)_ _`g(r,g,b) => (r, min(g, b), b)`_ _Alpha determination..._ _`a(r,b,g) => K0 * b − K1 * g + K2`_ _Using values of 1.0 for all K coefficients is good initial guess. As the Background color is well known, and once the 'alpha' is known you can use techniques shown in [Background Removal using Two Backgrounds](../masking/#two_background) to remove any 'green screen halo' that may be present better that the first color formula. _ ### Artist Charcoal Sketch of Image The [Charcoal Sketch Transform](../transform/#charcoal) , offers users a very simple way of generating a simplified gray-scale rendering of the image. It does not work well for 'busy images' but for simpler images it can produce a very striking result. magick holocaust\_sm.jpg -charcoal 5 charcoal.gif [![[IM Output]](../img_photos/holocaust_sm.jpg)](../img_photos/holocaust_sm.jpg) ![==>](../img_www/right.gif) [![[IM Output]](charcoal.gif)](charcoal.gif) ### Children's Color-In Outline Image In a long discussion about [Generating Coloring-In Pages](https://magick.imagemagick.org/viewtopic.php?t=6974) on the IM Users Forum, the following cookbook recipe was developed to magick a simple photo into something children can color in. Here is the best result we have so far, applied to a photo I took of the holocaust memorial, Berlin. magick holocaust\_sm.jpg \\ -edge 1 -negate -normalize \\ -colorspace Gray -blur 0x.5 -contrast-stretch 0x50% \\ color-in.gif # For heavily shaded pictures... # #-segment 1x1 +dither -colors 2 -edge 1 -negate -normalize \\ [![[IM Output]](../img_photos/holocaust_sm.jpg)](../img_photos/holocaust_sm.jpg) ![==>](../img_www/right.gif) [![[IM Output]](color-in.gif)](color-in.gif) The final operations in the above attempt to smooth out the lines and improve the overall result. Of course the above technique is only useful for images with good sharp color changes, and preferably a higher resolution image than I used above. For cartoon images that already have black outlines with a light colored background, the use of [Edge Detection](../transform/#edge) with the above method will directly produce a 'twinning' effect of the black outlines. You can see this effect in the twinned lines of tiles on the path leading into the memorial, in the lower-left corner. This is an artifact of the way [Edge Detection](../transform/#edge) works, and you can see more examples of this in that section of IM Examples. The solution is to negate images of this type before using "`[-edge](https://imagemagick.org/script/command-line-options.php?#edge) `" to outline the colored areas. magick piglet.gif -background white -flatten \\ -colorspace Gray -negate -edge 1 -negate -normalize \\ -threshold 50% -despeckle \\ -blur 0x.5 -contrast-stretch 0x50% \\ color-in\_cartoon.gif [![[IM Output]](../images/piglet.gif)](../images/piglet.gif) ![==>](../img_www/right.gif) [![[IM Output]](color-in_cartoon.gif)](color-in_cartoon.gif) I also "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" so I can then remove individual dots that "`[-edge](https://imagemagick.org/script/command-line-options.php?#edge) `" seem to like to generate. After that I again attempt to smooth out the aliased lines in the image. The above was added to in a discussion on [GIMP Photocopy Filter](https://magick.imagemagick.org/viewtopic.php?t=6974) to make use of the [Compose Divide](../compose/#divide) method, to find outlines. magick taj\_mahal\_sm.png -colorspace gray \\ \\( +clone -blur 0x2 \\) +swap -compose divide -composite \\ -linear-stretch 5%x0% photocopy.png [![[IM Output]](../img_photos/taj_mahal_sm.png)](../img_photos/taj_mahal_sm.png) ![==>](../img_www/right.gif) [![[IM Output]](photocopy.png)](photocopy.png) The "`[-linear-stretch](https://imagemagick.org/script/command-line-options.php?#linear-stretch) `" operation in the above adjusts how black the dark areas of the images will be, while the "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" 'sigma' defines the shading sharpness. ### Pencil Sketch Using a [Photoshop (PSP) tutorial](http://www.state-of-entropy.com/) on converting images to [Pencil Sketches](http://www.state-of-entropy.com/sketching.htm) , _[dognose](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=3441) _ from the [IM Users Forum](https://magick.imagemagick.org/viewforum.php?f=1) , managed to create the equivalent ImageMagick commands. Here is his conversion, simplified into a few IM commands, allowing you to batch process lots of images into a 'artists pencil sketch' form. First we need a special "`pencil.gif`" image. This can take a long time, so for this example I made it a bit smaller, while preserving its ability to be tiled across larger images. See [Modifying Tile Images](../canvas/#tile_mod) for details of the techniques.This only needs to be done once and can then be re-used. As such you can generate a much larger one for your own use, so as to avoid any tiling effects. Ideally make it as large as the images you plan to convert. magick -size 256x256 xc: +noise Random -virtual-pixel tile \\ -motion-blur 0x20+135 -charcoal 1 -resize 50% pencil\_tile.gif [![[IM Output]](pencil_tile.gif)](pencil_tile.gif) Now it is only a matter of overlaying and blending this 'pencil' shading image with a photo. The pencil image is tiled to make a canvas the same size as the image we are processing. Then it is applied to the image using techniques found in [Tiled Canvases](../canvas/#tile) . This is then merged into a gray-scaled copy of the original image. magick pagoda\_sm.jpg -colorspace gray \\ \\( +clone -tile pencil\_tile.gif -draw "color 0,0 reset" \\ +clone +swap -compose color\_dodge -composite \\) \\ -fx 'u\*.2+v\*.8' sketch.gif [![[IM Output]](../img_photos/pagoda_sm.jpg)](../img_photos/pagoda_sm.jpg) ![==>](../img_www/right.gif) [![[IM Output]](sketch.gif)](sketch.gif) Note that as the "`[-blend](https://imagemagick.org/script/command-line-options.php?#blend) `" operator of the "`[composite](../basics/#composite) `" command is not available to the "`magick`" command, I opted to do the equivalent using the DIY "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator. There are probably better, faster but more complicated ways of doing this. (suggestions are welcome) This is not the final version, as the operator misses some edge enhancement aspects needed for outline some of the more lighter but sharp color changes in the image. Can you improve the above? The above algorithm was built into IM as an artistic transform "`[-sketch](https://imagemagick.org/script/command-line-options.php?#sketch) `", though without the "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" smoothing for the generated 'pencil tile'... magick pagoda\_sm.jpg -colorspace gray -sketch 0x20+120 sketch\_new.gif [![[IM Output]](../img_photos/pagoda_sm.jpg)](../img_photos/pagoda_sm.jpg) ![==>](../img_www/right.gif) [![[IM Output]](sketch_new.gif)](sketch_new.gif) ### Vignette Removal When taking photos (digital or otherwise, the camera lens generally darkens the edges and corners of the image. This is called 'vignetting'. In fact this lens effect is so common, it is often faked on purpose using the "`[-vignette](https://imagemagick.org/script/command-line-options.php?#vignette) `" operator. See the [Vignette Transform](../transform/#vignette) . Martin Herrmann wanted to remove camera vignetting from the photos. Basically he took a photo of a white sheet of paper in a bright light without using a flash. He then wanted to combine this with his actual photos to brighten the edges and corners of the image appropriately. Basically what we want to do is divide the original photo by the grey-scale image of the photo of the brightly lit white piece of paper and it will then brighten the parts of the image by the amount that the 'white paper' photo was darkened. This is basically the compose method '`[Divide](../compose/#divide) `' which divides the 'source' image by the 'background' image. For example, magick nikon18-70dx\_18mm\_f3.5.jpg vegas\_orig.jpg \\ -compose Divide -composite vegas\_fixed.jpg [![[photo]](../img_photos/vegas_tn.gif)](../img_photos/vegas_orig.jpg) ![ + ](../img_www/plus.gif) [![[photo]](../img_photos/nikon18-70dx_18mm_f3.5.gif)](../img_photos/nikon18-70dx_18mm_f3.5.jpg) ![==>](../img_www/right.gif) [![[photo]](vegas_fixed.gif)](vegas_fixed.jpg) (click to see larger photo image) However as the photo of the 'white paper' will probably not be a true white, and you probably do not want to brighten the image by this 'off-white' color. To fix this we need to multiply the divisor image by its the center pixel color. Here is the final solution provided to Martin, which used the very slow [FX DIY Operator](../transform/#fx) . This pre-dated the addition of a [Divise Compose Method](../compose/#divide) which can be used to speed up this process enormously. The white photo was also grey scaled to remove any color distortion as well, note that I changed the ordering which will also preserve any 'meta-data' that was in the original (as it is the 'destination' image in this case. magick vegas_orig.jpg \( nikon18-70dx_18mm_f3.5.jpg -colorspace Gray \) \ -fx '(u/v)*v.p{w/2,h/2}' vegas_fixed_fx.jpg [![[photo]](../img_photos/vegas_fixed_fx.gif)](../img_photos/vegas_fixed_fx.jpg) If you look carefully at the enlarged photos, particularly the top-left and top-right 'sky' corners, you can see the vignetting effects, and the correction that was made. It is not a perfect solution, and could use a little more tweaking. For example rather than using a scaling pixel, we could pre-process the 'white page' image, and also adjust it for a better vignette removal result. Note that using JPEG is not recommended for any sort of photographic work, as the format can introduce some artifacts and inconsistencies in the results. The format is only good for storage and display of the final results. A major discussion on correcting vignettation is in the IM User Forums in the discussion [Algorithmic vignetting correction for pinhole cameras?](https://magick.imagemagick.org/viewtopic.php?f=1&t=18944) . Things that can effect vignettation include... * Distance of film from lens, further away means more light spread. * Area of the aperture 'circle' (lens or pinhole) due to angle of light. * Arrangement of camera material around the aperture. For example the lens holder or pinhole thickness. * * * --- # Layering -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Multi-Image Layers ====================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Layers Introduction](#intro) [![](../img_www/granitesm_right.gif) Appending Images](#append) (-append) * [Append an Array of Images](#append_array) * [Append with Overlap](#append_overlap) * [Smushing Append](#smush) (-smush) [![](../img_www/granitesm_right.gif) Composition of Multiple Pairs of Images](#composition) * [Using Composite Command](#composite) (composite, -geometry) * [Composite Operator of Convert](#convert) (-composite, -geometry) * [Draw Multiple Images](#draw) (-draw 'image ..') [![](../img_www/granitesm_right.gif) Layering Multiple Images](#layers) * [Flatten - onto a Background Image](#flatten) * [Mosaics - Canvas Expanding](#mosaic) * [Merging - to Create a New Layer Image](#merge) * [Coalesce Composition - a Progressive Layering](#coalesce) * [Compose Methods and Layering](#compose) * [Layers Composite - Merge Two Image Lists](#layer_composite) [![](../img_www/granitesm_right.gif) Layering Image Examples](#layer_examples) * [Layering Thumbnails](#layer_thumbnails) * [Calculated Positioning of Images](#layer_calc) * [Two Stage Positioning of Images](#layer_prog) * [Pins in a Map](#layer_pins) * [Layers of Shadows](#layer_shadow) * [Distorted Image Placement using Layers](#layer_distort) [![](../img_www/granitesm_right.gif) Evaluate Sequence Multi-Image Merging](#evaluate-sequence) [Mean (average)](#eval-seq_mean) ,  [Min/Max Value](#eval-seq_max) ,  [Median Pixel](#eval-seq_median) ,   [Add](#eval-seq_add) ,  [Multiply](#eval-seq_multiply) [![](../img_www/granitesm_right.gif) Poly - Merge Mutli-images Using a Polynomial](#poly) Overlaying multiple images onto each other to generate a larger 'composite' is generally known as using image 'layering'. These examples involve the combining of multiple 'layers' of images to produce the final larger more complex image. * * * Layering Images Introduction ---------------------------- As we have previously noted, ImageMagick does not deal with just one image, but a sequence or list of images. This allows you to use IM in two very special image processing techniques. You can for example think of each image in the list as a single frame in time, so that the whole list can be regarded as being a _Animation_. This will be explored in other IM Example Pages. See [Animation Basics](../anim_basics/) . Alternatively, you can think of each image in the sequence as _Layers_ of a set of see-through overhead transparencies. That is, each image represents a small part of the final image. For example: the first (lowest) layer can represent a background image. Above that you can have a fuzzy see though shadow. Then the next layer image contains the object that casts that shadow. On top of this a layer with some text that is written over that object. That is, you can have a sequence of images or 'layers' that each adds one more piece to a much more complex image. Each image layer can be moved, edited, or modified completely separately from any other layer, and even saved into a multi-image file (such as TIFF:, MIFF: or XCF:) or as separate images, for future processing. And that is the point of image layering. Only when all the image layers have been created do you [Flatten](#flatten) , [Mosaic](#mosaic) , or [Merge](#merge) all the [Layered Images](#example) into a single final image. * * * Appending Images ---------------- Appending is probably the simplest, of the multi-image operations provided to handle multiple images. Basically it joins the current sequence of images in memory into a column, or a row, without gaps. The "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" option appends vertically, while the plus form "`[+append](https://imagemagick.org/script/command-line-options.php?#append) `" appends horizontally. For example, here we append a set of letter images together, side-by-side, to form a fancy word, in a similar way that individual 'glyphs' or letters of a 'font', are joined together. magick font\_A.gif font\_P.gif font\_P.gif font\_E.gif font\_N.gif \\ font\_D.gif font\_E.gif font\_D.gif +append append\_row.gif [![[IM Output]](append_row.gif)](append_row.gif) The above is similar (in a very basic way) to how fonts are handled. Unlike real fonts you are not limited to just two colors, but can generate some very fancy colorful alphabets from individual character images. Many of these 'image fonts' are available on the WWW for download. A very small set can be found in [Anthony's Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) , in [Fonts for Text and Counters](http://www.ict.griffith.edu.au/anthony/icons/prog/fonts/Icons.html) , which is also where I found the above [Blue Bubble Font](http://www.ict.griffith.edu.au/anthony/icons/prog/fonts/bubble_blue.xpm) . Note also how the "`[+append](https://imagemagick.org/script/command-line-options.php?#append) `" operator was done as the last operation, after all the images that you want to append have been added to the current image sequence. This is great for appending a label to an image, for example... magick rose: -background LawnGreen label:Rose \\ -background white -append append\_label.jpg [![[IM Output]](append_label.jpg)](append_label.jpg) Note that the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color was used to fill in any space that was not filled in. Of course if the all the images are the same width, no space will be left for this fill. From IM v6.4.7-1 the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting can be used to specify how the images should be added together. As such in a vertical append, a setting of '`Center`' will center the image relative to the final resulting image (so will a setting of either '`North`' or '`South`'). magick rose: -background LawnGreen label:Rose \\ -background white -gravity center -append \\ append\_center.jpg [![[IM Output]](append_center.jpg)](append_center.jpg) Naturally any '`East`' gravity setting will align the images on the right side. magick rose: -background LawnGreen label:Rose \\ -background white -gravity east -append \\ append\_east.jpg [![[IM Output]](append_east.jpg)](append_east.jpg) Similar vertical alignment can be achieved when using "`[+append](https://imagemagick.org/script/command-line-options.php?#append) `"![](../img_www/warning.gif)![](../img_www/space.gif)_Before IM v6.4.7 it was much more difficult to align appended images, and generally involved using a "`[-flop](https://imagemagick.org/script/command-line-options.php?#flop) `" for right alignment. Or using "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `" or "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" to adjust the image width for centered aligned appends. For example, this will work with an older 6.3.2 version of IM..._ magick rose: -background SkyBlue label:Rose \\ -background White -gravity center -extent 200x \\ -append -trim +repage append\_center\_old.jpg [![[IM Output]](append_center_old.jpg)](append_center_old.jpg) You can also use multiple append operations, in the same command without conflict or confusion as to the outcome of the operations (which was not the case before IM v6). magick font\_{0,0,6,1,2}.gif +append dragon\_long.gif \\ -background none -append append\_multi.gif [![[IM Output]](append_multi.gif)](append_multi.gif) We appended each row of images together, then appende a larger image below that. This is very simple, and straight-forward. By using [parenthesis](../basics/#parenthesis) , you can append just the numbers after the larger image. For example, here append all the numbers together, before appending them vertically to the dragon image we read in before the numbers. magick dragon\_long.gif '(' font\_{0,0,6,2,9}.gif +append ')' \\ -background none -append append\_parenthesis.gif [![[IM Output]](append_parenthesis.gif)](append_parenthesis.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The parenthesis in the above must be either quoted, or escaped with a backslashed ('`\`') when used with an UNIX shell, otherwise they will be interpreted by the shell as something completely different._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As only two images were involved we could have just used "`[+swap](https://imagemagick.org/script/command-line-options.php?#swap) `" or "`[-reverse](https://imagemagick.org/script/command-line-options.php?#reverse) `" instead of using parenthesis._ | Append an Array of Images ------------------------- You can take this further to make a whole array of images, and build them either by rows, or by columns. magick \\( font\_1.gif font\_2.gif font\_3.gif +append \\) \\ \\( font\_4.gif font\_5.gif font\_6.gif +append \\) \\ \\( font\_7.gif font\_8.gif font\_9.gif +append \\) \\ \\( -size 32x32 xc:none font\_0.gif +append \\) \\ -background none -append append\_array.gif [![[IM Output]](append_array.gif)](append_array.gif) Technically the first set of parenthesis is not needed, as no images have been read in yet, but it makes the whole thing look uniform and shows the intent of the command, in making an array of images. See also [Montage Concatenation Mode](../montage/#concatenate) , for an alternative way of creating arrays of equal sized images. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" operator will only append the actual images, and does not make use the virtual canvas (image page) size, or the image offset. However the virtual canvas information seems to be left in a funny state with the canvas sizes being added together and the offset set to some undefined value.

This may be regarded as a bug, and means either the input images or result should have the virtual canvas reset using "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `", before saving, or using the image in operations where this information can become important.

This situation will probably be fixed in some future expansion of the operation. Caution is thus advised, especially if re-appending [Tile Cropped](../crop/#crop_tile)
images._ | Append with Overlap ------------------- On the IM Forum an user asked for a simple way to [Append images with some overlap](https://magick.imagemagick.org/viewtopic.php?t=30720) . Many solutions were offered. This was one of the simplest solutions, with the amount of overlap given in a single location. magick granite: rose: -gravity east -background none \\ \\( -clone 1 -chop 30x0 \\) \\( -clone 0,2 +append \\) \\ -delete 0,2 +swap -composite append\_overlap.gif [![[IM Output]](append_overlap.gif)](append_overlap.gif) The above did not need to any image positioning calculations, typically involving image sizes, that would represent a more general solution. See [Handling Image Layers](#layer_examples) below. What this did was chop off the part that overlapped, before appending the result to the first image, producing the final image size. The original image is then composed (with gravity) on top to generate the actual overlap. It can be easily modified for vertical overlapping, or even right to left overlapping relatively easily. Smushing Append --------------- Another way of appending images is by smushing. The "`[-smush](https://imagemagick.org/script/command-line-options.php?#smush) `" operator works much like the [Append Operator](#addend) (see above) does, but it takes an argument of how much space (or anti-space) you want between the images. For example, lets use it to so the previous example more simply. magick granite: rose: -background none -gravity Center \\ +smush -20 smush\_overlap.png [![[IM Output]](smush_overlap.png)](smush_overlap.png) That works very well, though that is not what the operator is actually designed for, and it is probably a lot slower. What smush actually is ment to do is move 'shaped images' as close togther as posible. For example, here I generate the letters '`A`' and '`V`' and 'smush' them together with as little space between them as posible. magick -background none -pointsize 72 \\ -fill red label:A -fill blue label:V \\ +smush 0 smush\_append.png [![[IM Output]](smush_append.png)](smush_append.png) Notice that how the two letters were appended together far closer than append would, taking advantage of the empty space of the images 'shape'. The gap in the above is caused by anti-aliasing edge pixels of the two letters. That is, what "`[-smush](https://imagemagick.org/script/command-line-options.php?#smush) `" is designed to do, though it requires a lot of calculations, so is a lot slower than [Append](#addend) (see above). The argument, is an offset for that final position, and is usually a positive value to generate a gap, but can be negative to create an overlap. magick -background none -pointsize 72 \\ -fill red label:A -fill blue label:V \\ +smush -15 smush\_offset.png [![[IM Output]](smush_offset.png)](smush_offset.png) Images may become clipped in undocumented ways if a very large negative value is used. * * * Composition of Multiple Pairs of Images --------------------------------------- Composition is the low-level operation that is used to merge two individual images together. Almost all layering techniques eventually devolve down to merging images together two at a time, until only one image is left. So lets start by looking at ways of doing low-level composition of image pairs. ### Using the Composite Command The traditional method of combining two images together using ImageMagick is though the "`magick composite`" command. This command can only combine only two images at a time, saving the results of each operation into a file. This of course does not stop you from using it to layer multiple images, one image at a time... magick -size 100x100 xc:skyblue composite.gif magick composite -geometry +5+10 balloon.gif composite.gif composite.gif magick composite -geometry +35+30 medical.gif composite.gif composite.gif magick composite -geometry +62+50 present.gif composite.gif composite.gif magick composite -geometry +10+55 shading.gif composite.gif composite.gif [![[IM Output]](composite.gif)](composite.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As all input images are read in by ImageMagick BEFORE the output image is opened, you can output to one of the input images. This allows you to work on the same image over and over, as shown above, without problems.

Do not do this with a lossy image format like "JPEG" as the format errors are accumulative, and the base image will quickly degrade._ | You can also resize the overlaid image as well as position it using the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting. magick -size 100x100 xc:skyblue comp_resize.gif magick composite -geometry 40x40+5+10 balloon.gif comp_resize.gif comp_resize.gif magick composite -geometry +35+30 medical.gif comp_resize.gif comp_resize.gif magick composite -geometry 24x24+62+50 present.gif comp_resize.gif comp_resize.gif magick composite -geometry 16x16+10+55 shading.gif comp_resize.gif comp_resize.gif [![[IM Output]](comp_resize.gif)](comp_resize.gif) The "`magick composite`" command also has a few other advantages in that you can use to control the way the image is drawn onto the background with the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" option and its relative position is effected by the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. You can also "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" the overlay so that it will just cover the background image, without needing to specify tile limits. This is something only available when using "`magick composite`". The big disadvantage with this method is that you are using multiple commands, and IM has to write-out the working image, either to a pipeline, or to disk, for the next command to read-in again. To find more examples of using the "`magick composite`" command, to overlay images on top of other images, see "[Annotating by Overlaying Images](../annotating/#overlay) " and "[Image Positioning using Gravity](../annotating/#image_gravity) ". ### Composite Operator of Convert The "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" operator is available within the "`magick`" command. For more details see [Image Composition in IM](../compose/#composite) . This allows you to do the same as the above, but all in one command. magick -size 100x100 xc:skyblue \\ balloon.gif -geometry +5+10 -composite \\ medical.gif -geometry +35+30 -composite \\ present.gif -geometry +62+50 -composite \\ shading.gif -geometry +10+55 -composite \\ compose.gif [![[IM Output]](compose.gif)](compose.gif) This first creates a [Canvas Image](../canvas/#solid) which is "`skyblue`" in color, and then layers each of the later images onto that canvas at the given locations. Now the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" is is a very special operator that not only sets an overlay position for the next "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" operation, it will also "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" the _last_ image (and only the last image) in the current image sequence. magick -size 100x100 xc:skyblue \\ balloon.gif -geometry 40x40+5+10 -composite \\ medical.gif -geometry +35+30 -composite \\ present.gif -geometry 24x24+62+50 -composite \\ shading.gif -geometry 16x16+10+55 -composite \\ compose\_geometry.gif [![[IM Output]](compose_geometry.gif)](compose_geometry.gif) Note it is recommended that you avoid this 'resize' side-effect of of the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `", even if it is convenient. Basically as it is more of a backward compatibility effect and may in some situations generate other effects. Here is the more verbose recommendation... magick -size 100x100 xc:skyblue \\ \\( balloon.gif -resize 40x40 \\) -geometry +5+10 -composite \\ \\( medical.gif \\) -geometry +35+30 -composite \\ \\( present.gif -resize 24x24 \\) -geometry +62+50 -composite \\ \\( shading.gif -resize 16x16 \\) -geometry +10+55 -composite \\ compose\_resize.gif [![[IM Output]](compose_resize.gif)](compose_resize.gif) ### Draw Multiple Images Also using "`magick`" you can also use [Draw Primitives](../draw/#primitive) to overlay images onto its working canvas. magick -size 100x100 xc:skyblue \\ -draw "image over 5,10 0,0 'balloon.gif'" \\ -draw "image over 35,30 0,0 'medical.gif'" \\ -draw "image over 62,50 0,0 'present.gif'" \\ -draw "image over 10,55 0,0 'shading.gif'" \\ drawn.gif [![[IM Output]](drawn.gif)](drawn.gif) You can of course also specify a resize for the overlaid image too.. magick -size 100x100 xc:skyblue \\ -draw "image over 5,10 40,40 'balloon.gif'" \\ -draw "image over 35,30 0,0 'medical.gif'" \\ -draw "image over 62,50 24,24 'present.gif'" \\ -draw "image over 10,55 16,16 'shading.gif'" \\ drawn\_resize.gif [![[IM Output]](drawn_resize.gif)](drawn_resize.gif) The 'drawn' images can also be [Rotated, Scaled, and Affine Distorted](../draw/#transform) during the overlay process. Though that can be tricky to get working the way you want. Drawn images are "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" effected, just like text. * * * Layering Multiple Images ------------------------ True layering of images requires methods to combine multiple images together, without needing to individually compose each pair of images separately. This is where the various `[-layers](https://imagemagick.org/script/command-line-options.php?#layers) ` operator methods come into their own. Ordering of layered images can be important, so it is a good idea to understand the special [Image Sequence or List Operators](../basics/#image_seq) . Note that 'layered images' is practically identical to the handling 'animated frames'. As such it is recommended you also look at both [Animation Basics](../anim_basics/) and [Animation Modifications](../anim_mods/) for techniques involving processing individual 'layers' or 'frames'. Actually animations often use the same `[-layers](https://imagemagick.org/script/command-line-options.php?#layers) ` operator for processing images. ### Flatten - onto a Background Image The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) **flatten**`" image list operator, (or its shortcut "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `") will basically "[Compose](../compose/) " each of the given images on to a background to form one single image. However the image positions are specified using their current [Virtual Canvas, or Page](../basics/#page) offset. For example, here I create a nice canvas, and specify each of the images I want to overlay onto that canvas. magick -size 100x100 xc:skyblue \\ -fill dodgerblue -draw 'circle 50,50 15,25' \\ \\( -page +5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -layers flatten flatten\_canvas.gif [![[IM Output]](flatten_canvas.gif)](flatten_canvas.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As of IM v6.3.6-2 the "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" operator is only an alias for a "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) 'flatten'`" method.

Thus the "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" option can be regarded as a short cut for the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method of the same name._ | You don't need to create an initial canvas as we did above, you can instead let "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" create one for you. The canvas color will be the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color, while its size is defined by the first images [Virtual Canvas](../basics/#page) size. magick \\( -page 100x100+5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( --page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -layers flatten flatten\_page.gif [![[IM Output]](flatten_page.gif)](flatten_page.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _While the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting will effect image placement defined using "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" settings, it will not effect image positioning using [virtual canvas offsets](../basics/#page)
set via the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" setting. This is part of the definition of such offsets. See [Geometry vs Page Offsets](../compose/#geometry)
for more details.

If placement with "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" is need look at either the above multi-image composition methods, or the special [Layers Composition](../anim_mods/#composite)
method that can handle both positioning methods simultaneously._ | If any image does not appear in the defined virtual canvas area, it will either be clipped or ignored, as appropriate. For example, here we used a smaller canvas size, causing the later images not to appear completely on that canvas. magick \\( -page 75x75+5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -flatten flatten\_bounds.gif [![[IM Output]](flatten_bounds.gif)](flatten_bounds.gif) The normal use of [Flatten](#flatten) is to merge multiple 'layers' of images together. That is, you can be generating various parts of a larger image, usually using [Parenthesis](../basics/#parenthesis) to limit image operators to the single 'layer' image being generated, and then flatten the final result together. For example one typical use is to create a [Shadow Image](../blur/#shadow) layer, onto which the original image is flattened. For example... magick balloon.gif \\( +clone -background navy -shadow 80x3+5+5 \\) +swap \\ -background none -flatten flatten\_shadow.png [![[IM Output]](flatten_shadow.png)](flatten_shadow.png) Note that as I want the shadow under the original image, I needed to [swap](../basics/#swap) the two images place them in the right order. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Using [Flatten](#flatten)
for adding generated [Shadow Images](../blur/#shadow)
is not recommended, as generated shadow images can have negative image offsets.

The recommended solution, as given in the section on [Shadow Images](../blur/#shadow)
, is to use the more advanced [Layer Merging](#merge)
technique, we will look at later._ | Because the [Virtual Canvas](../basics/#page) consists of just a size, the resulting image will be that size, but have no virtual canvas offset, as such you do not need to worry about any offsets present in the final image. This use of the virtual canvas to define the canvas on which to overlay the image means you can use it to add a surrounding border to an image. For example here I set an image's size and virtual offset to 'pad out' an image to a specific size. magick medical.gif -set page 64x64+20+20 \\ -background SkyBlue -flatten flatten\_padding.gif [![[IM Output]](flatten_padding.gif)](flatten_padding.gif) Of course there are better ways to [Pad Out an Image](../thumbnails/#pad) so that IM automatically centers the image in the larger area.Strangely the exact same handling can be used to 'clip' or [Crop](../crop/#crop) an image to a virtual canvas that is smaller than the original image. In this case however you want to use a negative offset to position the 'crop' location, as you are offsetting the image and not positioning the crop 'window'. magick logo: -repage 100x100-190-60 -flatten flatten\_crop.gif [![[IM Output]](flatten_crop.gif)](flatten_crop.gif) Of course a [Viewport Crop](../crop/#crop_viewport) would also do this better, without the extra processing of canvas generation and overlaying that "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" also does. It also will not 'expand' the image itself to cover the whole viewport if the image was only partially contained in that viewing window. A common mis-use of the "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" operator is to [Remove Transparency](../masking/#remove) from an image. That is, to get rid of any transparency that an image may have, but overlaying it on the background color. However this will not work when multiple images are involved as as such no longer recommended. ### Mosaic - Canvas Expanding The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) **mosaic**`" operator (or its "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" shortcut) is more like an expanding canvas version of the [Flatten Operator](.#flatten) . Rather than only creating an initial canvas based on just the canvas size of the initial image, the [Mosaic Operator](#mosaic) creates a canvas that is large enough to hold all the images (in the positive direction only). For example, here I don't even set an appropriate [Virtual Canvas](../basics/#page) , however the "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" operator will work out how big such a canvas needs to be to hold all the image layers. magick \\( -page +5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -layers mosaic mosaic.gif [![[IM Output]](mosaic.gif)](mosaic.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As on IM v6.3.6-2 the "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" operator is only an alias for a "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) 'mosaic'`".

Thus the "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" option can be regarded as a short cut for the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method of the same name._ | Note that both "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" and "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" still creates a canvas that started from the 'origin' or 0,0 pixel. This is part of the definition of an images 'virtual canvas' or 'page' and because of this you can be sure that the final image for both operators will have a no virtual offset, and the whole canvas will be fully defined in terms of actual pixel data. Also note that "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" will only expand the canvas in the positive directions (the bottom or right edges), as the top and left edge are fixed to the virtual origin. That of course means "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" will still clip images with negative offsets... magick \\( -page -5-10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -mosaic mosaic\_clip.gif [![[IM Output]](mosaic_clip.gif)](mosaic_clip.gif) ### Merging - to Create a New Layer Image The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) **merge**`" operator is almost identical to the previous operators and was added with IM v6.3.6-2. It only creates a canvas image just large enough to hold all the given images at their respective offsets. Like [Mosaic](#mosaic) will also expand the canvas, but not only in the positive direction, but also in the negative direction. Basically it means that you don't have to worry about clipping, offset, or other aspects when merging layer images together. All images will be merged relative to each others location. The output does not include or ensure the origin is part of the expanded canvas. As such the output of a [Layers Merge](#merge) can contain a 'layers offset' which may be positive or negative. In other words.. [Layers Merge](#merge) merges layer images to produce a new _layer image_. As such if you don't want that offset when finished you will probably want to include a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator before the final save. For example, here is the same set of layer image we have used previously... magick \\( -page +5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -layers merge +repage layers\_merge.gif [![[IM Output]](layers_merge.gif)](layers_merge.gif) As you can see the image is only just big enough to hold all the images which were placed relative to each other, while I discarded the resulting images offset relative to the virtual canvas origin. This preservation of relative position without clipping or extra unneeded space is what make this variant so powerful. Lets try this again by giving one image a negative offset... magick \\( -page -5-10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( -page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background dodgerblue -layers merge +repage layers\_merge\_2.gif [![[IM Output]](layers_merge_2.gif)](layers_merge_2.gif) As you can see the "balloon" was not clipped, just moved further away from the others so as to preserve its relative distance to them. Of course the "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator in the above examples, removes the absolute virtual canvas offset in the final image, preserving only the relative image placements between the images. The offset was removed as web browsers often have trouble with image offsets and especially negative image offsets, unless part of a GIF animation. But if I did not remove that offset, all the images will remain in their correct location on the virtual canvas within the generated single layer image, allowing you to continue to process and add more images to the merged image. Typically you would use a "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color of '`None`', to make the unused areas of the merged image transparent. When applied to a single image, [Layer Merging](#merge) will replace any transparency in the image with the solid color background, but preserve the images original size, as well as any any offsets in that image, The virtual canvas size of the image however may be adjusted to 'best fit' that images size and offset. The operators original purpose was allow users to more easily merge multiple distorted images into an unified whole, regardless of the individual images offset. For example when aligning photos to form a larger 'panorama'. You could simply start with a central undistorted base image (without an offset), and use this operator to overlay the other images around that starting point (using either negative or positive offsets) that have been aligned and distorted to match that central image. For other examples of using this operator by distorting images to align common control points, see [3D Isometric Photo Cube](../distorts/#cube3d) , and [3D Perspective Box](../distorts/#cube3d) . Other examples of using this operator is to generate a simple series of [Overlapping Photos](../photos/#overlap) . The operation "`-layers trim-bounds`" can be used to ensure all images get a positive offset on a minimal canvas size, while retaining there relative positions, and without actually layer merging the images into one final image. This lets you then perform further processing of the images before they are actually merged, such as placing more images relative to the that image group but looking up the resulting virtual canvas bounds. However if images have a transparency, it is probably a good idea to trim that transparency from images first, making the ideal usage... -alpha set -bordercolor none -border 1x1 -trim -layers trim-bounds This minimizes the image layers including any and all transparent areas of actual image data, while ensuring everything is contained on a valid virtual (positive) canvas of minimal size. ### Coalesce Composition - a Progressive Layering The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) **coalesce**`" image operator (or its "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" shortcut) is really designed for converting GIF animations into a sequence of images. For examples, see [Coalescing Animations](../anim_basics/#coalesce) for details. However, it is very closely associated with "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" and has very useful effects for multi-layered images in this regard.For example using [Coalesce](#coalesce) on a single image, will do exact the same job as using [Flatten](#flatten) with a "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color of '`None`' or '`Transparency`'. That is, it will 'fill out' the canvas of the image with transparent pixels. magick \\( -page 100x100+5+10 balloon.gif \\) -layers coalesce coalesce\_canvas.gif [![[IM Output]](coalesce_canvas.gif)](coalesce_canvas.gif) When dealing with an image consisting on multiple layers, [Coalesce](#coalesce) can be used to generate a 'Progressive Layering' of the image. But to do this we need to take a few precautions, to disable any 'GIF animation' handling by the operator. magick \\( -page 100x100+5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( --page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -set dispose None -coalesce miff:- |\\ montage - -frame 4 -tile x1 -geometry +2+2 \\ -background none -bordercolor none coalesce\_none.gif [![[IM Output]](coalesce_none.gif)](coalesce_none.gif) In the above, we "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" all the "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" settings to '`[None](../anim_basics/#none) `'. This effectively tells "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" to just overlay each frame on top the results of the previous overlays. The result is the first image is just a 'fill out' of the images canvas, with a transparency background. The next image is the previous image with that layer overlaid. And so on. A 'progressive' flatten of the image sequence. The last image in the sequence will thus be the same as if you did a normal "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" with a transparent background. You can get a completely different sort of effect if you had used a "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting of '`[Background](../anim_basics/#background) `'. In this case "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" will just 'fill out' the canvas of each image, as if they were completely separate images! magick \\( -page 100x100+5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( --page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -set dispose Background -coalesce miff:- |\\ montage - -frame 4 -tile x1 -geometry +2+2 \\ -background none -bordercolor none coalesce\_bgnd.gif [![[IM Output]](coalesce_bgnd.gif)](coalesce_bgnd.gif) Please note however that unlike [Flatten](#flatten) , [Mosaic](#mosaic) , or [Merge](#merge) the "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator does _not_ make use of the current "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" alpha composition setting. It only uses an '`[Over](../compose/#over) `' compose method, as this is what is required for GIF animation handling. Using different "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" methods with the more standard image layering operators is the subject of the next set of examples. ### Compose Methods and Layering The three [Layering](#layers) methods: [Flatten](#flatten) , [Mosaic](#mosaic) , and [Merge](#merge) ; will make use of the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting to determine the composition method used to overlay each image in sequence. As such you could think of these functions as a multi-image "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" operator with the ability to set an initial "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" canvas of a specified color. However using anything but the default [Alpha Composition](../compose/) of '`Over`' requires some thought before applying or you will get unexpected results. You may also may need to think about the effect of the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color that is used by these operators to generate a starting canvas, onto with each image (including the first) in composed. For example lets place each successive image _under_ the previous images using a '`[DstOver](../compose/#dstover) `'... magick \\( -page 100x100+5+10 balloon.gif \\) \\( -page +35+30 medical.gif \\) \\ \\( --page +62+50 present.gif \\) \\( -page +10+55 shading.gif \\) \\ -background none -compose DstOver -flatten flatten\_dstover.gif [![[IM Output]](flatten_dstover.gif)](flatten_dstover.gif) Here the background was set to be transparent, otherwise you will only see the background canvas in the result as all the other images will have been placed 'under' this initial canvas! This does provide a way of 'blanking' an image with a particular color, as shown in [Canvases Sized to an Existing Image](../canvas/#sized) . Here is a more practical example. Rather than layering the images with the background canvas first, which awkward and un-natural in some image processing situations, you can just generate the images top-down or foreground to background order. magick rose: -repage +10+10 \\ \\( +clone -background black -shadow 60x3+5+5 \\) \\ \\( granite: -crop 100x80+0+0 +repage \\) \\ -background none -compose DstOver -layers merge layer\_dstover.gif [![[IM Output]](layer_dstover.gif)](layer_dstover.gif) Each of the first three lines generates one layer image, with the final line merging all the layers under the previous layers, effectively reversing the order. As you can see the image processing for the above was simpler and cleaner than you normally would see with shadow generation, just by underlaying each image in sequence (with a transparent starting canvas) Of course I could have just as easily [Reverse](../basics/#reverse) the image list instead. magick rose: -repage +10+10 \\ \\( +clone -background black -shadow 60x3+5+5 \\) \\ \\( granite: -crop 100x80+0+0 +repage \\) \\ -reverse -layers merge layer\_reverse.gif [![[IM Output]](layer_reverse.gif)](layer_reverse.gif) However remember that this only re-orders the existing images, and does not effect the 'starting background canvas' that the layering methods create. The compose methods can also be used to produce some interesting effects. For example, if you draw three circles, then by overlaying them using the '`Xor`' compose method, you get an unusual and complex looking symbol, for minimal effort. magick -size 60x60 \\ \\( xc:none -fill blue -draw 'circle 21,39 24,57' \\) \\ \\( xc:none -fill red -draw 'circle 39,39 36,57' \\) \\ \\( xc:none -fill green -draw 'circle 30,21 30,3' \\) \\ -background none -compose Xor -flatten flatten\_xor.png [![[IM Output]](flatten_xor.png)](flatten_xor.png) ### Layers Composite - Merge Two Layer Lists With IM v6.3.3-7 the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method, '`**Composite**`' was added allowing you compose two completely separate sets of images together. To do this on the command line a special '`[null:](../files/#null) `' marker image is needed to define where the first _destination_ list of images ends and the overlaid _source_ image list begins. But that is the only real complication of this method. Basically each image from the first list is composed against the corresponding image in the second list, effectively merging the two lists together. The second list can be positioned globally relative to the first list, using a [Geometry Offset](../compose/#geometry) , just as you can with a normal [Composite Operator](../compose/#convert) (see above). Gravity is also applied using the canvas size of the first image, to do the calculations. On top of that 'global offset', the individual virtual offset of image is also preserved, as each pair of images is composited together. One special case is also handled. If one of the image lists contains only one image, that image will be composed against all the images of the other list. Also in that case the image meta-data (such as animation timings) of larger list is what will be kept, even if it is not the destination side of the composition. This laying operator is more typically used when composing two animations, which can be regarded as a sort of time-wise layered image list. Because of this it is better exampled in the [Animation Modifications](../anim_mods/) section of the examples. So see [Multi-Image Alpha Composition](../anim_mods/#compose) for more details. * * * Handling Image Layers --------------------- Laying multiple images using the various layer operators above is a very versatile technique. It lets you work on a large number of images individually, and then when finished you combine them all into a single unified whole. So far we have shown various ways of merging (composing or layering) multiple images in many different ways. Here I provide some more practical examples on just how to make use of those techniques. ### Layering Of Thumbnail Images You can also use this technique for merging multiple thumbnails together in various complex ways. Here I add a [Soft Edge](../thumbnails/#soft_edges) to the images as you read and position them, you can generate a rather nice composition of images, on a [Tiled Canvas](../canvas/#tile) . magick -page +5+5 holocaust\_tn.gif \\ -page +80+50 spiral\_stairs\_tn.gif \\ -page +40+105 chinese\_chess\_tn.gif \\ +page \\ -alpha Set -virtual-pixel transparent \\ -channel A -blur 0x10 -level 50,100% +channel \\ \\( -size 200x200 tile:tile\_fabric.gif -alpha Set \\) -insert 0 \\ -background None -flatten overlap\_canvas.jpg [![[IM Output]](overlap_canvas.jpg)](overlap_canvas.jpg) ### Calculated Positioning of Images. The [Virtual Canvas Offset (page)](../basics/#page) can be set in many ways. More specifically you can "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" set this per-image [Attribute](../basics/#attribute) , and even calculate a different location for each and every image. For example, here I read in a big set of images (small icon images all the same size) and arrange them in a circle. magick {balloon,castle,eye,eyeguy,ghost,hand\_point,medical}.gif \\ {news,noseguy,paint\_brush,pencil,present,recycle}.gif \\ {shading,skull,snowman,storm,terminal,tree}.gif \\ \\ -set page '+%\[fx:80\*cos((t/n)\*2\*pi)\]+%\[fx:80\*sin((t/n)\*2\*pi)\]' \\ \\ -background none -layers merge +repage image\_circle.png [![[IM Output]](image_circle.png)](image_circle.png) The key to the above example is the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) page`" operation that uses the normalized image index (the [FX Expression](https://imagemagick.org/script/fx.php) '`t/n`' ) to create a value from 0.0 to not quite 1.0 for each individual image. This value is then mapped to position the image (by angle) in a circle of 80 pixels radius, using [FX Expressions as a Percent Escape](../transform/#fx_escapes) . The position calculated is of the top-left corner of the image (not its center, though that is a simple adjustment), which is then [Merged](#merge) to generate a new image. The positioning is done without regard of the offset being positive or negative, which is the power of the [Merge Laying Operator](#merge) . That is, we generated a new image of all the images as they are relative to each other. The final "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" removes the final resulting negative offset of the merged layer image, as this is no longer needed and can cause problems when viewing the resulting image. Note that the first image (right-most in result) is layered below every other image. If you want the layering to be truly cyclic so the last image was below this first one, you may have to divide that first image in half and put the top half at the end of the sequence so the top half of the first image layers over last image, while the lower half remains below the second image. This technique is powerful, but it can only position images to an integer offset. If you need more exact sub-pixel positioning of images then the images will need to be distorted (translated) to the exact sub-pixel location rather than simply adjusting its virtual offset. #### Incrementally Calculated Positions You can access some image attributes of other images using FX expressions, while setting the attribute of images as they are processed. This means that you can set the location of each image, relative the calculated position of the previous image. For example this sets the position of each image to be to the right of the previous image. That is, the previous image's position plus its width. magick rose: netscape: granite: \\ \\ +repage -set page '+%\[fx:u\[t-1\]page.x+u\[t-1\].w\]+0' \\ \\ -background none -layers merge +repage append\_diy.png [![[IM Output]](append_diy.png)](append_diy.png) Each image is appended to the location of the previous image, by looking up that location and adding that images width. This previous location was in fact just calculated, as IM looped through each image setting the '`page`' (virtual offset) attribute. The result is a DIY [Append Operator](#append) equivalent, and from which you can develop your own variations. You should note that the whole sequence is actually shifted by '`u[-1].w`' set during the position calculation of the first image. This should be the width of the last image in the current image sequence. That overall displacement however is junked by the final "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `". You can use some extra calculation to have it ignore this offset, but it isn't needed in the above. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _When using an image index such as '`u[t]`' all image selectors '`u`', '`v`', and '`s`', all references the same image, according to the '`[index]`' given. As such it is better to use '`u`' (the first or zeroth image) as a mnemonic of this indexing behaviour (and in case this changes).

For more information see [FX, The DIY Image Operator](../transform/#fx)
._ | Here is another example. Each image is offset relative to the previous image, using both position and width of that image, so as to calculate a [Overlapped Append](#append_overlap) . magick font\_\[0-9\].gif \\ -set page '+%\[fx:u\[t-1\]page.x+u\[t-1\].w-8\]+%\[fx:u\[t-1\]page.y+4\]' \\ -background none -layers merge +repage append\_offset.gif [![[IM Output]](append_offset.gif)](append_offset.gif) This ability to access attributes of other images, also includes the pixel data of other images. That means you could create a special image where the color values represent the 'mapped positions' of the other images. Of course that 'mapping' image would also be positioned, and would need to be removed before the overlay is performed. How useful creating special 'mapped position' images is another matter. It is just another possibility. ### Two Stage Positioning of Images You can simplify your image processing, by separating them into two steps. One step can be used to generate, distort, position and add fluff to images, with a final step to merge them all together. For example, lets create [Polaroid Thumbnails](../transform/#polaroid) from the larger original images in [Photo Store](../img_photos/INDEX.html) , processing each of them individually (keeping that aspect separate and simple). center=0 # Start position of the center of the first image. # This can be ANYTHING, as only relative changes are important. for image in ../img_photos/[a-m]*_orig.jpg do # Add 70 to the previous images relative offset to add to each image # center=`magick xc: -format "%[fx: $center +70 ]" info:` # read image, add fluff, and using centered padding/trim locate the # center of the image at the next location (relative to the last). # magick -size 500x500 "$image" -thumbnail 240x240 \ -set caption '%t' -bordercolor Lavender -background black \ -pointsize 12 -density 96x96 +polaroid -resize 30% \ -gravity center -background None -extent 100x100 -trim \ -repage +${center}+0\! MIFF:- done | # read pipeline of positioned images, and merge together magick -background skyblue MIFF:- -layers merge +repage \ -bordercolor skyblue -border 3x3 overlapped_polaroids.jpg [![[IM Output]](overlapped_polaroids.jpg)](overlapped_polaroids.jpg) The script above seem complicated but isn't really. It simply generates each thumbnail image in a loop, while at the same time center pads (using [Extent](../crop/#extent) ) and [Trims](../canvas/#trim) each image so that the images 'center' is in a known location on the virtual canvas. It could actually calculate that postion, though that may require temporary files, so it is better to ensure it is in a well known location, for all images. The image is then translated (using a relative "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator, see [Canvas Offsets](../basics/#page) ), so that each image generated will be exactly 60 pixels to the right of the previous image. That is, each image center is spaced a fixed distance apart, regardless of the images actual size, which could have changed due to aspect ratios and rotations. The other major trick with this script is that rather than save each 'layer image' into a temporary file, you can just write the image into a pipeline using the [MIFF:](../files/#miff) file format. A method known as a [MIFF Image Streaming](../files/#miff_stream) . This works because the "`MIFF:`" file format allows you to simply concatenate multiple images together into a single data stream, while preserving all the images meta-data, such as its virtual canvas offset. This technique provides a good starting point for many other scripts. Images can be generated, or modified and the final size and position can be calculated in any way you like. Another example is the script "`[hsl_named_colors](../scripts/hsl_named_colors) `" which takes the list of named colors found in ImageMagick and sorts them into a chart of those colors in HSL colorspace. You can see its output in [Color Specification](../color_basics/#colors) . Other possibilities include... * Use any type of thumbnail (or other [Fluff](../thumbnails/#fluff) ), or just simply use a raw small thumbnail directly. * Generate images so the first image is centered and the other images are arrange to the left and right under that first image, like a pyramid. * Position images into Arcs, Circles and spirals, by placing them at specific X and Y coordinates relative to each other. For example: [PhD Circle](http://www.flickr.com/photos/dsevilla/2363002372) , [Sunset Flower](http://www.flickr.com/photos/krazydad/4994679) , [Fibonacci Spiral](http://www.flickr.com/photos/krazydad/4109739) . * Position images according to their color. For example: [Book Covers](http://www.flickr.com/photos/davepattern/2954305171) . * Position images by time of day or time submitted. For example: [Year of Sunsets](http://www.flickr.com/photos/krazydad/292081922) Basically you have complete freedom in the positioning of images on the virtual canvas, and can then simply leave IM to sort out the final size of the canvas needed to whole all the images. ### Pins in a Map Here is a typical layering example, placing coloured pins in a map, at specific locations. [![[IM Output]](../images/push_pin.png)](../images/push_pin.png) To the left is a 'push pin' image. The end of the pin is at position `+18+41`. I also have an image of a [Map of Venice](../images/map_venice.jpg) , and want to put a pin at various points on the map. For example 'Accademia' is locate at pixel position, `+160+283`. To align the push-pin with that position you need to subtract the location of the end of the pin from map position. This produces an offset of `+142+242` for our 'pin' image. Here is the result, using layered images magick map\_venice.jpg -page +142+242 push\_pin.png \\ -flatten map\_push\_pin.jpg [![[IM Output]](map_push_pin.jpg)](map_push_pin.jpg) This example was from an IM Forum Discussion, [Layering Images with Convert](https://magick.imagemagick.org/viewtopic.php?f=1&t=20251) . **Lets automate this further.** We have a file listing the locations and colors for each of the pins we want to place in the map. The location name in the file is not used and is just a reference comment on the pixel location listed. [![[Data File]](map_venice_pins.txt.gif)](../images/map_venice_pins.txt) Lets read this text file, to create 'pins' in a loop. pin_x=18 pin_y=41 cat map_venice_pins.txt |\ while read x y color location; do [ "X$x" = "X#" ] && continue # skip comments in data x=$(( x - pin_x )) # magick x,y to pin image offsets y=$(( y - pin_y )) # magick 'color' to settings for color modulate (hue only) # assumes a pure 'red' color for the original push pin mod_args=$( magick xc:$color -colorspace HSL txt: | tr -sc '0-9\012' ' ' |\ awk 'NR==1 { depth=$3 } NR==2 { hue=$3; print "100,100," 100+200*hue/depth }'; ) # re-color and position the push pin magick push_pin.png -repage +${x}+${y} -modulate $mod_args miff:- done |\ # read pipeline of positioned images, and merge together magick map_venice.jpg MIFF:- -flatten map_venice_pins.jpg [![[IM Output]](map_venice_pins.jpg)](map_venice_pins.jpg) Note it assumes the original pin color is red ( which has a hue of 0 ) and uses the [Modulate Operator](../color_mods/#modulate) to re-color it to other colors, with the appropriate scaling calculations. Note that the modulate argument for a no-op hue change is 100, with it cycling over a value of 200 (a sort of pseudo-percentage value). _FUTURE: perspective distort map, adjust pin size for 'depth' on the map calculate change in pin position due to distortion, and 'pin' it to the distorted map._ The above used a method known as a [MIFF Image Streaming](../files/#miff_stream) , with each image generated individually in a loop, then 'piped' into the 'layering' command to generate the final image. The alternative method (commonly using in PHP scripts) is to use a 'generated command' technique, that uses a shell script to generate a long "`magick`" command to be run. The scripts in [Image Warping Animations](../warping/#animations) use this technique. Both methods avoid the need to generate temporary images. ### Layers of Shadows Correctly handling semi-transparent shadow effects in a set of overlapping images is actually a lot more difficult than it seems. Just overlaying photos with shadows will cause the shadows to be applied twice. That is, two overlapping shadows become very dark, where in reality they do not overlay together in quite the same way that the overlaying images do. The various parts of the image should be simply shadowed or not shadowed. That is, shadows should be applied once only to any part of the image. You should not get darker areas, unless you have two separate light sources, and that can make things harder still. Tomas Zathurecky < tom @ ksp.sk > took up the challenge of handling shadow effects in layered images, and developed image accumulator technique, to handle the problem. Basically we need to add each image to the bottom of stack one at a time. As we add a new image the shadow of all the previous images needs to darken the new image, before it is added to the stack. However only the shadow falling on the new image, needs to be added. Shadows not falling on the new image needs to be ignored until later, when it falls on some other image, or the background (if any). Here is an example... magick \\ \\( holocaust\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 5 -repage +0+0 \\) \\ \\ \\( spiral\_stairs\_tn.gif -frame 10x10+3+3 \\ -background none -rotate -15 -repage -90+60 \\) \\ \\( -clone 0 -background black -shadow 70x3+4+7 \\ -clone 1 -background black -compose DstATop -layers merge \\ -trim \\) \\ \\( -clone 2,0 -background none -compose Over -layers merge \\) \\ -delete 0--2 \\ \\ \\( chinese\_chess\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 20 -repage +60+90 \\) \\ \\( -clone 0 -background black -shadow 70x3+4+7 \\ -clone 1 -background black -compose DstATop -layers merge \\ -trim \\) \\ \\( -clone 2,0 -background none -compose Over -layers merge \\) \\ -delete 0--2 \\ \\ \\( +clone -background black -shadow 70x3+4+7 \\) +swap \\ -background none -compose Over -layers merge +repage \\ layers\_of\_shadows.png [![[IM Output]](layers_of_shadows.png)](layers_of_shadows.png) The above program seems complex, but is actually quite straight forward. The first image is used to start an accumulating stack of images (image index #0). Note we could have actually started with a single transparent pixel ("`-size 1x1 xc:none`"), if you don't want to use that first image to initialize the stack. Now to add a new image to the bottom of the image stack, we apply the same set of operations, each time... * First the thumbnail image is read into memory, and any rotations, relative placements (may be negative), is applied. You could also do apply other thumbnailing operations to the image at this point if you want, though for his example that have already been performed. The new image forms image index #1. * We now grab the previous stack of images (#0), generate a shadow with appropriate color, blur, offset, and ambient light percentage. * This shadow is overlaid on the new image (#1) so only the shadow that falls '`[ATop](../compose/#atop) `' the new image is kept. We also (optionally) apply a [Trim Operation](../crop/#trim) the result to remove any extra space added from the shadowing operation, to form image #2. * Now we simply add the new image (#2) to the accumulating stack of images (#0). * and delete all the previous working images, except the last. To add more images we basically just repeat the above block of operations. After all the images has been added to the stack, it is simply a matter of doing a normal shadowing operation on the accumulated stack of images. removing any remaining image offsets (which many web browsers hate). Using [Merge](#merge) I can automatically handle virtual offsets, especially negative ones, allowing to to simply place images anywhere you like relative to the previous image placements. It also make applying shadows which can generate larger images with negative offsets properly. Now the above handles multi-layered image shadows properly, but while the shadow is offset, it is actually offset equally for all the images! What really should happen is that the shadow should become more offset and also more blurry as it falls on images deeper and deeper in the stack. That is, an image at the top should case a very blurry shadow on the background, compared to the bottom-most image. This is actually harder to do as you not only need to keep a track of the stack of images, you also need to keep a track of how 'fuzzy' the shadow has become as the stack of images becomes larger. Thus you really need two accumulators. The image stack (as above), and the shadow accumulation, as we add more images. For example, here is the same set of images but with shadows that get more blurry with depth. magick xc:none xc:none \\ \\ \\( holocaust\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 5 -repage +0+0 \\) \\ \\( -clone 1 -background black -shadow 70x0+0+0 \\ -clone 2 -background black -compose DstATop -layers merge \\ -clone 0 -background none -compose Over -layers merge \\) \\ \\( -clone 2,1 -background none -compose Over -layers merge \\ -background black -shadow 100x2+4+7 \\) \\ -delete 0-2 \\ \\ \\( spiral\_stairs\_tn.gif -frame 10x10+3+3 \\ -background none -rotate -15 -repage -90+60 \\) \\ \\( -clone 1 -background black -shadow 70x0+0+0 \\ -clone 2 -background black -compose DstATop -layers merge \\ -clone 0 -background none -compose Over -layers merge \\) \\ \\( -clone 2,1 -background none -compose Over -layers merge \\ -background black -shadow 100x2+4+7 \\) \\ -delete 0-2 \\ \\ \\( chinese\_chess\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 20 -repage +60+90 \\) \\ \\( -clone 1 -background black -shadow 70x0+0+0 \\ -clone 2 -background black -compose DstATop -layers merge \\ -clone 0 -background none -compose Over -layers merge \\) \\ \\( -clone 2,1 -background none -compose Over -layers merge \\ -background black -shadow 100x2+4+7 \\) \\ -delete 0-2 \\ \\ \\( -clone 1 -background black -shadow 70x0+0+0 \\ -clone 0 -background none -compose Over -layers merge \\) \\ -delete 0-1 -trim +repage \\ layers\_of\_deep\_shadows.png [![[IM Output]](layers_of_deep_shadows.png)](layers_of_deep_shadows.png) Look carefully at the result. The offset and blurriness of the shadow is different in different parts of the image. It is very thin between images in adjacent layers, but very thick when it falls on an image, or even the background much deeper down. Of course in this example, the shadow offset is probably too large, but the result seems very realistic giving a better sense of depth to the layers. Note how we split the operation of shadow into two steps. When applying the accumulated shadow (image index #1) to the new image (#2), we only add the ambient light percentage, without any blur, or offset ('`70x0+0+0`' in this case). The new image is then added to the accumulating stack of images (#0). But after adding new images (#2) shadow directly to the accumulated shadow (#1), again without blur or offset, only then do we blur and offset ALL the shadows, to form the new accumulated shadow image. In other words, the accumulated shadow image becomes more and more blurry and offset as the stack gets thicker and thicker. Only the shadow of deeper images has not accumulated the effect as much. This program essentually separates the application of the shadow, from the incremental shadow accumulator. This allows you control things like... * Realistic Shadow (as above): 70x0+0+0 and 100x2+4+7 * Constant Shadow (as basic example): 70x2+4+7 and 100x0+0+0 * constant blur, but cumulative offset: 70x2+0+0 and 100x0+4+7 * both constant and progressive offset: 60x0+4+7 and 100x0+1+1 * cumulative ambient light effect: 80x0+0+0 and and 95x2+4+7 Most of them are probably unrealistic, but may look good in another situations. Also setting the "`-background`" color before the "`-compose ATOP`" composition will let you define the color of the shadow (actually a colored ambient light). You can even even use a different color for the shadow that eventually falls on the final background layer (the last "`-background black`" setting), or leave it off entirely to make it look like the images are not above any background at all (that is floating in mid-air). It is highly versitile. Tomas Zathurecky went on to develop another method of handling the shadows of layered images, by dealing with a list of layered images as a whole. Something I would not have considered posible myself. The advantage of this method is that you can deal with a whole list of images as a whole, rather than having to accumulate one image at a time, and repeating the same block of operations over and over. First lets again look at the simplier 'contant shadow' problem. magick \\ \\( holocaust\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 5 -repage +0+0 \\) \\ \\( spiral\_stairs\_tn.gif -frame 10x10+3+3 \\ -background none -rotate -15 -repage -90+60 \\) \\ \\( chinese\_chess\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 20 -repage +60+90 \\) \\ \\ -layers trim-bounds \\ \\ \\( -clone 0--1 -dispose None -coalesce \\ -background black -shadow 70x2+4+7 \\ xc:none +insert null: +insert +insert xc:none \\) \\ -layers trim-bounds -compose Atop -layers composite \\ \\ -fuzz 10% -trim \\ -reverse -background none -compose Over -layers merge +repage \\ coalesced\_shadows.png [![[IM Output]](coalesced_shadows.png)](coalesced_shadows.png) The first block of opertors is just generating the list of layered images. It could be a separate programmed loop, as shown previously. The the operation starts with a "`-layers trim-bounds`", a [Bounds Trimming](../anim_mods/#trim) operation that expands the virtual canvas of all images so as to contain all the images, and also ensure all offsets are positive. This is then cloned, [Coalesced](#coalesce) and shadowed to create a separate progressing list of shadows. Now we can use [Layer Compostion](#layer_composite) to merge the shadows and the original list of images together. The complication here is that before merging we need to not only add a special '`null:`' marker image to divide the two lists, but also add a special blank image '`xc:none`' so as to offset the shadow list. that way each shadow image will be overlaid '`[ATop](../compose/#atop) `' the next image of the original list. All that is left is to merge the now correctly shadowed images from bottom to top ([Reverse](../basics/#reverse) ) order. To handle 'deep shadows' requires [Layer Calculations](#layer_calc) . magick \\ \\( holocaust\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 5 -repage +0+0 \\) \\ \\( spiral\_stairs\_tn.gif -frame 10x10+3+3 \\ -background none -rotate -15 -repage -90+60 \\) \\ \\( chinese\_chess\_tn.gif -frame 10x10+3+3 \\ -background none -rotate 20 -repage +60+90 \\) \\ \\ \\( -clone 0--1 \\ -set page '+%\[fx:page.x-4\*t\]+%\[fx:page.y-7\*t\]' -layers merge \\) \\ -layers trim-bounds +delete \\ \\ \\( -clone 0--1 \\ -set page '+%\[fx:page.x-4\*t\]+%\[fx:page.y-7\*t\]' \\ -dispose None -coalesce \\ -set page '+%\[fx:page.x+4\*t\]+%\[fx:page.y+7\*t\]' \\ -background black -shadow 70x2+4+7 \\ xc:none +insert null: +insert +insert xc:none \\) \\ -layers trim-bounds -compose Atop -layers composite \\ \\ -fuzz 10% -trim \\ -reverse -background none -compose Over -layers merge +repage \\ coalesced\_deep\_shadows.png [![[IM Output]](coalesced_deep_shadows.png)](coalesced_deep_shadows.png) You can see the same set of blocks that was used previously, but with much more complicated caculations to set the initial [Bounds Trimming](../anim_mods/#trim) , and later calculate the offsets needed for the 'progressive shadow list'. However the shadow currently does not become more blurry with depth. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The above will be a lot simplier using the IMv7 "magick" command, which would allow you to use 'fx calculations' directly the argument to "`-shadow`", that would let you not only calculate a larger offset for the shadow with depth, but also let you mak ethe shadow more blurry with depth._ | ### Positioning Distorted Perspective Images Aligning distorted images can be tricky, and here I will look at aligning such images to match up at a very specific location. Here I have two images that highlight a specific point on each image. [![[IM Output]](align_blue.png)](align_blue.png) [![[IM Output]](align_red.png)](align_red.png) The second image is 65% semi-transparent, which allow you to see though it when it is composed onto the blue image, so you can see if the marked points align. The marked control points themselves are at the coordinates `59,26` (blue) and `35,14` (red) respectively. If you are simply overlaying the two images, you can just subtract the offsets and 'compose' the two image on top of each other, producing an offset of `+24+12`. magick align\_blue.png align\_red.png -geometry +24+12 \\ -composite align\_composite.png [![[IM Output]](align_composite.png)](align_composite.png) Note that this offset could be negative! And that is something we will deal with shortly. This only works as the coordinates are integer pixel coordinates. If the matching coordinates are sub-pixel locations (as is typically the case in a photo montage), simple composition will not work. It will also not work well if any sort of distortion is involved (which is also common for real-life images). And this is the problem we will explore. When distorting the image, you will want to ensure the two pixels remain aligned. The best way to do that would be to use the points you want to align as [Distort Control Points](../distorts/#control_points) . This will ensure they are positioned properly. magick align\_blue.png \\ \\( align\_red.png -alpha set -virtual-pixel transparent \\ +distort SRT '35.5,14.5 1 75 59.5,26.5' \\ \\) -flatten align\_rotate.png [![[IM Output]](align_rotate.png)](align_rotate.png) As distort generates a 'layer image' with a 'canvas offset' you can not simply use [Composite](../compose/#composite) to overlay the images (too low level), instead we need to use a [Flatten](#flatten) operator, so that it will position them using the distort generated offset. Note how I also added a value of 0.5 to the 'pixel' coordinates. This is because pixels have area, while mathematical points do not, as such if you want to align the center of a pixel, you need to add 0.5 to the location of the center 'point' within the pixel. See [Image Coordinates vs Pixel Coordinates](../distorts/#control_coordinates) for more information. The other problem with the above was that the overlaid image was 'clipped' by the blue background canvas image, just as the [Composite Operator](../compose/#composite) does. That is, to say the 'blue' image provided the 'clipping viewport' for the result during the composition. To prevent this we use [Layer Merge](#merge) instead which automatically calculates a 'viewport' canvas that is large enough contain hold all the images being composted together. magick align\_blue.png \\ \\( align\_red.png -alpha set -virtual-pixel transparent \\ +distort SRT '35.5,14.5 1 75 59.5,26.5' \\ \\) -background none -layers merge +repage align\_rotate\_merge.png [![[IM Output]](align_rotate_merge.png)](align_rotate_merge.png) As the result of the 'merge' the image will have a 'negative' offset (so as to preserve layer positions of the images). To display the results I needed to junk that offset as many browsers do not handle negative offsets in images. I do this using "`+repage`" before saving the final image. If I was going to do further processing (without displaying the result on the web) I would keep that offset (remove the "`+repage`"), so the image positions remains in their correct and known position for later processing. Now the same techniques as shown above would also apply if you were doing a more complex distortion such as [Perspective](../distorts/#perspective) . magick align\_blue.png \\ \\( align\_red.png -alpha set -virtual-pixel transparent \\ +distort Perspective '35.5,14.5 59.5,26.5 0,0 32,4 0,%h 14,36 %w,%h 72,53 ' \\ \\) -background none -layers merge +repage align\_perspective.png [![[IM Output]](align_perspective.png)](align_perspective.png) The problem with this technique is that you position the perspective distortion using an internal control point. That is, one point in the inside of the image, and 3 points around the edge. That can make it hard to control the actual perspective shape, as a small movement of any control point can make the 'free corner' move wildly. This situation can be even worse if you are using a large list of 'registered points' to get a more exact 'least squares fit' to position images. In that case the point you are interested in be no wehere near one of the control 'registered' points used to distort the image. The alternative is to simply distort the image the way we need to, then figure out how we need to translate the resulting image to align the points we are interested in. To make this work we will need to know how the 'point of interest' moved as a result of the distortion. This is real problem with distorting and positioning images, especially real life images. For example, here I distort the image using all four corners to produce a specific (suposedally desired) distortion shape, but I will not try to align the control points at this point, just apply the distortion... magick align\_blue.png \\ \\( align\_red.png -alpha set -virtual-pixel transparent \\ +distort Perspective '0,0 10,12 0,%h 14,40 %w,0 68,6 %w,%h 63,48 ' \\ \\) -background none -layers merge +repage align\_persp\_shape.png [![[IM Output]](align_persp_shape.png)](align_persp_shape.png) As you can see while the red image was distorted, the position of the red control point is no where near the blue control point we want to align. You can not just simply measure these two points as the red point is unlikely to be at an exact pixel position, but will have a sub-pixel offset involved. We will need to first calculate exactly where the red point is. To do that we can re-run the above distortion with verbose enabled to get the perspective forward mapping coefficients. These can then be used to calculate as described in [Perspective Projection Distortion](../distorts/#perspective_projection) . magick align_red.png -define distort:viewport=1x1 -verbose \ +distort Perspective '0,0 10,12 0,%h 14,40 %w,0 68,6 %w,%h 63,48 ' null: [![[IM Text]](align_persp_verbose.txt.gif)](align_persp_verbose.txt) All we want is just the calculated coefficients used by the distortion. As such we don't need the destination image, so we just the output using a "`null:`" image file format. We also tell the distort that the new image it is generating is only one pixel is size using a [Distort Viewport](../distorts/#distort_viewport) . That way it does the distortion preparation and verbose reporting, but then only distorts a single 'destination' pixel, which is then junked. This can save a lot of processing time. Actually if the distortion did not use source image meta-data (needed for the percent escapes '`%w`' and '`%h`') as part of its calculations, we would not even need the source image "`align_red.png`". In that case we could have used a single pixel "`null:`" image, for the input image too. We are also not really interested in the virtual pixels, backgrounds, or anything else for this information gathering step, so we don't need to worry about setting those features. Now we can get the distort information, we need to extract the 8 perspective coefficients, from the 3rd and 4th line of the output. These can then be used to map the red control point to its new distorted position, and from there subtract it from the blue control point, so as to get the actual amount of translation that is needed, to align the marked red coordinate with the blue coordinate. bluex=59; bluey=26 redx=35; redy=14 magick align_red.png -verbose \ +distort Perspective '0,0 10,12 0,%h 14,40 %w,0 68,6 %w,%h 63,48 ' null: 2>&1 |\ tr -d "'," |\ awk 'BEGIN { redx='"$redx"'+0.5; redy='"$redy"+0.5'; bluex='"$bluex"'+0.5; bluey='"$bluey"'+0.5; } NR == 3 { sx=$1; ry=$2; tx=$3; rx=$4; } NR == 4 { sy=$1; ty=$2; px=$3; py=$4; } END { div = redx*px + redy*py + 1.0; dx = ( redx*sx + redy*ry + tx ) / div; dy = ( redx*rx + redy*sy + ty ) / div; printf "red point now at %f,%f\n", dx, dy; printf "translate shape by %+f %+f\n", bluex-dx, bluey-dy; }' [![[IM Text]](align_persp_coord.txt.gif)](align_persp_coord.txt) The above used the "`tr`" text filter to remove extra quotes and commas from the output. It then uses the "`awk`" program to extract the coefficients, and do the floating point mathematics required to 'forward map' the red marker to match the blue marker. Note that I again added 0.5 to the 'pixel coordinates' of the control points to ensure that the center of the pixel is what is used for the calculations. See [Image Coordinates vs Pixel Coordinates](../distorts/#control_coordinates) . Now we know the amount of translation needed by the distorted image, we have two ways you add that translation to the distortion. Either by modifying the coefficients of the perspective projection appropriately (not easy). Or we could just add the translation amounts to each of the destination coordinates of the original (very easy). Here is the result of the latter (add translations to destination coordinates)... magick align\_blue.png \\ \\( align\_red.png -alpha set -virtual-pixel transparent \\ +distort Perspective '0,0 31.408223,15.334305 0,%h 35.408223,43.334305 %w,0 89.408223, 9.334305 %w,%h 84.408223,51.334305 ' \\ \\) -background none -layers merge +repage align\_persp\_move.png [![[IM Output]](align_persp_move.png)](align_persp_move.png) To the right I have cropped and scaled the result around the control points to show they are perfectly aligned! magick align\_persp\_shape.png -crop 19x19+50+17 +repage \\ -scale 500% align\_persp\_shape\_mag.png [![[IM Output]](align_persp_shape_mag.png)](align_persp_shape_mag.png) As you can see we have a perfect alignment of the two pixels, without any sub-pixel overflow to any one side. Even the smallest miss-alignment would show as an asymmetrical coloring on either side of the central pixel. This scaling even shows a slight asymmetrical difference between left and right sides of the red cross due to the perspective distortion. That is, how accurate this pixel level view test is. A similar but simpler problem is looked at in [Text Positioning using Distort](../annotating/#distort) . * * * Evaluate-Sequence - Direct Mutli-Image Merging Methods ------------------------------------------------------ The "**`[-evaluate-sequence](https://imagemagick.org/script/command-line-options.php?#evaluate-sequence) `**" methods, are designed to merge multiple images of the **same size** together in very specific ways. In some ways it is a blend of the [Evaluate and Function Operators](../transform/#evaluate) combined with multi-image [Composition](#composite) techniques we have seen above. Many of the methods provided can even be performed using normal multi-image layering composition techniques, but not all.The operator uses the same methods as "`[-evaluate](https://imagemagick.org/script/command-line-options.php?#evaluate) `" so you can get a list of them using "`-list Evaluate`". Though some of these (such as '`Mean`' and '`Medium`') are really only useful when used with this operator. ### Mean (Average) of multiple images Essentially both the older "`-evaluate-sequence mean`" and the newer "`[-evaluate-sequence](https://imagemagick.org/script/command-line-options.php?#evaluate-sequence) **mean**`" will create an average of all the images provided. For example, here is an average of the rose image using all its [Flipped and Flopped](../warping/#flip) versions. magick rose: -flip rose: \\( -clone 0--1 -flop \\) \\ -evaluate-sequence mean average.png [![[IM Output]](average.png)](average.png) Averaging hundreds of images of the same fixed scene, can be used to remove most transient effects, such moving people, making them less important. However areas that get lots of transient effects may have a 'ghostly blur' left behind that may be very hard to remove. As video sequences are notoriously noisy when you look at the individual frames, you can average a number of consecutive, but unchanging, frames together to produce much better cleaner and sharper result. Matt Leigh, of the University of Arizona, reports that he has used this technique to improve the resolution of microscope images. He takes multiple images of the same 'target' then averages them all together to increase the signal/noise ratio of the results. He suggests others may also find it useful for this purpose. An alternative for averaging two images together is to use a "`composite -blend 50%`" image operation, which will work with two different sized images. See the example of [Blend Two Images Together](../compose/#blend) for more detail. The [IM Discussion Forum](https://magick.imagemagick.org/viewforum.php?f=1) had a discussion on [Averaging a sequence 10 frames at a time](https://magick.imagemagick.org/viewtopic.php?f=1&t=19945) , so as to average thousands of images, without filling up the computers memory (making it very slow). Related to this, and containing relevent maths is the discussion [Don't load all images at once](https://magick.imagemagick.org/viewtopic.php?f=1&t=19855) . Another alternative to using '`mean`' is to use the newer [Poly Operator](#poly) , which can individually weight each image. ### Max/Min Value of multiple images The '**`Max`**' and '**`Min`**' methods will get the maximum (lighter) values and minimum (darker) values from a sequence of images. Again they are basically equivalent to using a [Lighten and Darken Composition Methods](../compose/#lighten) , but with multiple images. With the right selection of background canvas color, you could use [Flatten Operator](#flatten) with the equivelent compose method. magick rose: -flip rose: \\( -clone 0--1 -flop \\) \\ -evaluate-sequence max max.png [![[IM Output]](max.png)](max.png) magick rose: -flip rose: \\( -clone 0--1 -flop \\) \\ -evaluate-sequence min min.png [![[IM Output]](min.png)](min.png) WARNING: This is not a selection of pixels (by intensity), but a selection of values. That means the output image could result in the individule red, green and blue values from different images, resulting in a new color not found in any of the input images. If you need the pixels selected by their max/min by intensity, see the [Lighten by Intensity Compose Method](../compose/#lighten_intensity) . ### Median Pixel by Intensity The "`[-evaluate-sequence](https://imagemagick.org/script/command-line-options.php?#evaluate-sequence) **Median**`" will look for the pixel which has an intensity of the middle pixel from all the images that are given. That is, for each position it collects and sorts the pixel intensity from each of the images. Then it will pick the pixel that falls in the middle of the sequence. It can also be used as an alternative to simply averaging the pixels of a collection of images. This could be used for example by combining an image with two upper and lower 'limiting' images. As the pixel will be the middle intensity you will either get the pixel from the original image, or a pixel from the 'limiting' images. In other words you can use this to 'clip' the intensity of the original image. Strange but true. For an even number of images, the pixel on the brighter side of the middle will be selected. As such with only two images, this operator will be equivalent to a pixel-wise "lighten by intensity". The key point is that each pixel will come completely from one image, and sorted by intensity. The exact color of each pixel will come completely from one of the given images, as such no new colors are generated. For example, here is pixels of median intensity of the rose image using all its [Flipped and Flopped](../warping/#flip) versions. Note how it isn't as smooth, but could get sharp boundaries, as it is basied on intensities of the pixels. magick rose: -flip rose: \\( -clone 0--1 -flop \\) \\ -evaluate-sequence median median.png [![[IM Output]](median.png)](median.png) ### Add Multiple Images The '**`Add`**' method is will of course simply add all the images together. magick ... -evaluate-sequence add ... Which is a faster (more direct) version of using [Flatten](#flatten) to [Plus Compose](../compose/#plus) all the images together... magick ... -background black -compose plus -layers flatten ... Be warned that adding images in this way can very easilly overflow the Quantum Range of the image, and as such it may get 'clipped', unless you use a [HDRI version of IM](../basics/#hdri) . This is why an [Average, or Mean](#eval-seq_mean) is generally used instead, as this will divide all images equally to ensure the resulting image is not clipped. Another alturnative is to use the newer [Poly Operator](#poly) , which can individually weight each image. ### Subtract Multiple Images The '**`Subtract`**' method subtracts each image from the first. Or at least that is what it should do. Internally it has arguments swapped and it is subtracting the previous results from the next image. Arrggggg! However by using a quirk of the [Linear Burn Compose Method](../compose/#linearburn) you can subtract the second and later images from the first. Basically by [Negating](../color_mods/#negate) all but the first image, and setting a '`white`' (negated zero) as a the starting background color you can then use [Flatten](../layering/#flatten) to subtract all the images from the first. magick ... \\ -negate \\( -clone 0 -negate \\) -swap 0 +delete \\ -compose LinearBurn -background white -flatten \\ ... ### Multiple/Divide Multiple Images '**Multiply**' and '**Divide**' are accepted as methods by "`[-evaluate-sequence](https://imagemagick.org/script/command-line-options.php?#evaluate-sequence) `" but they generate unexpected and odd results, as they are using the actual color value of the images rather than the normalised color value, just as "`[-evaluate](https://imagemagick.org/script/command-line-options.php?#evaluate) `" does. As a result the scale of the multiply and divide is too large. This could be classed as a bug. In the meantime, you are better using the equivelent 'flatten' method for Multiply, which does work as expected. magick ... -background white -compose multiply -layers flatten ... Poly - Merge Multiple Images Using a Polynomial ----------------------------------------------- Closely related to "`[-evaluate-sequence](https://imagemagick.org/script/command-line-options.php?#evaluate-sequence) `" and specifically to the '[mean](#eval-seq_mean) ' method (image averaging), is the "`[-poly](https://imagemagick.org/script/command-line-options.php?#poly) `" operator (added IM v6.8.0-5). This operator is given a list of two numbers for each image in memory, one to provide a multiplicative weight for each image, but also a power-of exponent to each image. This lets you merge a list of images as if each image was the variable input to a polynomial equation. The color values from each image is treated as if they were a normalized 0 to 1 value.With each pair of values the image color (normalized) is first powered by the second 'power-of' exponent, then it is weighted (multiplied) by the first number. If the exponent is '`1`' then the value is just multiplied by the given weighting. However if the exponent is '`0`' the weight becomes the final value, producing a normalized color constant addition (value from 0.0 to 1.0). A single pixel image can be provided in the current image sequence, and can be used to add a specific color, with a different normalized color value for each channel. (using a weight and exponent = 1.0). Or you can provide a "`NULL:`' image (or any other junk image), and use an exponent of 0.0. This will will only add the given weighting factor as constant. The final image is generated from the first image (and its size and other meta-data), just as it is with [FX DIY Operator](../transforms/#fx) . For example... magick rose: granite: null: -poly '1,1 2,1 -1.0,0' poly\_rose.png [![[IM Output]](poly_rose.png)](poly_rose.png) This takes a '`rose:`' (unmodified using a weight of 1 and power-of 1), adds to this twice the color values from the '`granite:`' image (weight=2), and finally subtracts a value of 1 using a '`null:`' image, using an exponent of 0 (ignore image input) and a weighting value of -1.0. The resulting image is equivalent to... `rose + 2.0*granite - 1.0` or `rose + 2.0*(granite-0.5)` In other words the rose image is given a noisy granite texture overlay (with a 50% grey bias). This is in fact exactly like a very strong '`[Hard_Light](../compose/#hardlight) `' composition lighting effect but with very explicit weighting of the granite overlay. The key difference to this over other multi-image operations is the ability to weight each image individually, but perform all calculations in a single image processing operation without the need for extra intermediate images. This avoids any quantum rounding, clipping or other effects on the final results, in a non-[HDRI](../basics/#hdri) version of ImagMagick. (See [Quantum Effects](#../basics/#quantium_effects) ). It can for example be used to perform a weighted average of large numbers of images, such as averaging smaller groups of images, then averaging those groups together. * * * --- # Lens Correction -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Lens Correction =================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Introduction to Lens Correction](#lens_correction) [![](../img_www/granitesm_right.gif) Non-scaling Restraint](#non-scaling) [![](../img_www/granitesm_right.gif) Ready-made Parameter Sets](#ready_made) [![](../img_www/granitesm_right.gif) Calibrating From Scratch](#scratch) * [Basic Appoach](#basic) * [Determining lens parameter sets with Hugin](#practice) * [Defining point sets](#pointsets) * [Re-engineering parameters from camera created thumbnail](#re-engineered) [![](../img_www/granitesm_right.gif) Example](#examples) [![](../img_www/granitesm_right.gif) Keyboard Example](#keyboard) (by El-Supremo) [![](../img_www/scroll.gif) Correcting Lens Distortion (PDF)](correcting_lens_distortions.pdf) When taking photographs, the images generated are actually distorted by both lens effects and spherical perspective effects. If you plane to use photos you will generally need to correct for these effects, and that is what will be looked at in this section. The majority of this page was contributed by Wolfgang Hugemann. * * * Introduction to Lens Correction ------------------------------- Fisheye lenses and low-cost wide-angle lenses (or rather zoom lenses when set to short focal length) typically produce a pronounced barrel distortion. This distortion can however be mostly corrected by applying suitable algorithmic transformations to the digital photograph. One of the most-used lens correction algorithms, introduced by Panorama Tools and used by [PTlens](http://epaperpress.com/ptlens) , is also offered by ImageMagick, as [Barrel Correction Distortion Method](../distorts/#barrel) . In this approach to the problem, the distortion is controlled by four transformation parameters `a, b, c, d`, which have to be chosen sensibly in order to correct the distortion produced by a specific lens (or rather a zoom camera when set to a certain focal length). Suitable values for these parameters can hardly be found by trial and error. In the following, we describe how to determine the lens correction parameters of this model effectively by the use of [Hugin](http://hugin.sourceforge.net) , a free graphical user interface for [Panorama Tools](http://panotools.sourceforge.net) , which is available for various operating systems. If you don't want to deal with the details of lens correction, you may skip the rest of this page and just buy [PTlens](http://epaperpress.com/ptlens) , which offers sophisticated lens correction for a vast number of digital cameras and lenses at a reasonable price (by use of its large lens database). Nowadays, some digital cameras (such as the Nikon P7000) even incorporate lens correction in their internal image processing steps. For photographs taken with cameras that don't offer this possibility, ImageMagick enables you to integrate lens correction as one step of a larger image processing script. The following text is an abridged version of paper [Correcting Lens Distortion (PDF)](correcting_lens_distortions.pdf) (dealing with applications in accident reconstruction). The explanations given here are a more hands-on approach, concentrating on the ways to get in hold of the adequate lens correction parameters. Non-scaling Restraint --------------------- As described in the [Barrel Distortions](../distorts/#barrel) The barrel distortion is defined by the mathematical formula R = ( a \* r^3 + b \* r^2 + c \* r + d ) \* r with `r` as the distance to the geometrical image center of the digital photograph and `R` as the equivalent radius in the original image. As always with such mappings, the equation above defines a kind of "color look-up function", i.e. where to look for the color of the pixel at radius `r`. The radii `r` and `R` are normalised by half of the smaller image dimension (i.e. usually the height of the image), such that `r = R = 1` for the midpoints of the upper and lower edge of the image. When correcting digital photographs, we should pay attention to the non-scaling restraint a + b + c + d = 1 which obviously gives `R` = 1 for `r` = 1. Panorama Tools calculates the parameter `d` by the other parameters via d = 1 - a - b - c leaving us with three free model parameters, so the parameter `d` is typically omitted. ImageMagick will automatically calculate `d` by the non-scaling restraint, if it is omitted. So a typical ImageMagick command line for lens correction would look something like magick input.jpg -distort barrel '0.06335 -0.18432 -0.13008' output.jpg leaving the calculation of `d` to ImageMagick. The lens correction method of Panorama Tools that we are speaking of here assumes the optical axis of the lens and the centre of the image to be identical, which is not strictly the case in practice (due to manufacturing tolerances). Furthermore, it leaves effects like [mustache distortion](http://en.wikipedia.org/wiki/Distortion_%28optics%29#Radial_distortion) aside. Nevertheless, it seems to work astonishingly precisely in practice. [![[Graph]](curve.gif)](curve.gif) As demonstrated by the curve (`a = 0.05, b = -0.25, c = 0.05`), the relationship is typically used in the range 0 to 1.5 (aspect ratio 3:2), passes through the points (0,0) and (1,1) and must be degressive for `r > 1`. * * * Ready-made Parameter Sets ------------------------- PTlens's current lens database, being the "marrow" of the program, is encrypted and can only be read by PTlens itself. Until February 2006, however, PTlens's database was coded in XML format, i.e. an easily editable text format. This 2006 version of PTlens's XML database is still (legally) available at [Hugin's SourceForge Website](http://sourceforge.net/projects/hugin/files/PTLens%20Database/) and provides data for a lot of older camera models. When PTlens's database became encrypted, the authors of Hugin tried to establish a free XML coded lens database as an alternative. This database is called [LensFun](http://sourceforge.net/projects/lensfun/) and can be downloaded. It comes with a complete programming interface, but all you basically need is the information for your camera in the XML file. As an example, the lens correction parameters for the once popular Nikon Coolpix 995 are found in the file `compact-nikon.xml`, which resides in the directory `\data\db`. The file can be examined by the use of a text editor or an XML viewer: Nikon Standard nikon995 4.843 As can be taken from the camera's technical data sheet, the zoom range of the Nikon Coolpix 995 is 8.2 – 31.0 mm, corresponding to 38 – 152 mm for 35 mm film cameras. This gives a crop factor of 152 / 31 = 4.90, which roughly corresponds to the 4.843 given the XML file. The coefficients of the correction by barrel distortion are supplied for six focal lengths, namely 8.2 mm, 10.1 mm, 13.6 mm, 18.4 mm, 23.4 mm, 28.3 mm and 31.0 mm. The coefficients `a` and `c` are, for this lens, set to zero, i.e. the distortion is described only by the second-order term `b`. Note that many lens's will also have values for `a` and `c` parameters as well, and these should also be interpolated in a similar way. If we have a photograph `DSCN0001.jpg` taken with a Nikon Coolpix 995 set to the shortest focal length, this photograph could be corrected by ImageMagick via magick DSCN0001.jpg -distort barrel '0.0 -0.019966 0.0' DSCN0001_pt.jpg (The file name extension `_pt` is used by PTlens to mark corrected images.) For the six focal lengths provided, the correction coefficient `b` can be read from the XML file. For other focal lengths, the suitable value can be determined by interpolation between the two neighbouring focal lengths. As an alternative, the dependency of `b` on the focal length `f` can be approximated by the polynomial b = 0.000005142 \* f^3 - 0.000380839 \* f^2 + 0.009606325 \* f - 0.075316854 So the focal length (as read from the EXIF information) is used to calculate the lens correction parameter `b` in the first step, and then, in a second step, the lens correction (i.e. barrel distortion) is performed using this value as the `b` parameter. The Windows section shows a [VBScript Example](../windows/#vb_example) in which the above equations are used, with the focal length being extracted from a Nikon Coolpix 995 photograph via `magick identify`. * * * Calibrating from scratch ------------------------ ### Basic Approach When determining the lens parameters, all programs rely on the same paradigm: the ideal perspective mapping should map real world straight lines to straight lines in the image. So if a set of real-world points P0, P1, ..., Pn is known to lie on a straight line, their images p0, p1, ..., pn must also fall onto a straight line. Any deviation from this rule has to be attributed to lens distortion. We need two points to determine the two parameters defining a straight line (e.g. slope and intersection on the y-axis). Each additional point supplied will provide another equation to determine the lens correction parameters. So if our functional approach has only one free parameter `b` (as for the Nikon Coolpix 995 above), we would have to provide at least three points on a real-world straight line and its image in order to determine the sought lens correction parameter `b`. Putting it more concrete: The distortions model only uses the parameter `b`, i.e. the coordinates of the corrected image `X1, Y1` can be calculated from the coordinates of the digital photograph by r = s \* sqrt(x1^2 + y1^2) X1 = \[(1-b) + b r^2\] \* x1 Y1 = \[(1-b) + b r^2\] \* y1 Y1 = k1 \* X1 + k2 This results in one equation for each point supplied on the same straight line \[(1-b) + b r^2\] \* y1 = k1 \* \[(1-b) + b r^2\] \* x1 + k2 with: r = s \* sqrt(x1^2 + y1^2) Thus three real-world points and their corresponding image points would suffice to determine the parameters describing the straight line and the lens distortion `k1, k2, b`. In practice, the coordinates of the real-world points are rarely known, such that one needs more than just three points to determine the sought parameters. Most calibration software uses a rectangular grid of straight lines (often a chequerboard) to generate a set of equations and then calculate the mapping parameters by a nonlinear least-squares fit. Some programs generate the set of control points on their own, often using pre-defined templates; other programs require the user to select the control points from the calibration image. ### Determining lens parameter sets with Hugin In the following, we will demonstrate how to determine a set of lens correction parameters by the use of Hugin. There is also a ready-made "Simple Lens Calibration Tutorial" on Hugin's Website, but at the time of this writing (2014), it seems to be too simple to provide reliable parameters that can later be used for a multitude of corrections. First of all, you have to get hold of a suitable test pattern. Basically, a checkerboard pattern with about 10 × 7 squares, printed on [ISO 216 A3](http://en.wikipedia.org/wiki/Paper_size#A_series) or alike would do and is often used. Low-cost zoom lenses (so-called [varifocal lenses](http://en.wikipedia.org/wiki/Varifocal_lens) ) should however be set to infinite focus during calibration, as their true focal length might largely differ from that embedded in the EXIF for near focus.For fixed focus lenses you may as well use a checkerboard test pattern, which is especially recommendable when calibrating a fisheye lens, as it may be difficult to find a real-word object large enough to cover its field of view.So especially when calibrating zoom lenses / zoom cameras, you should rather take a photograph of a modern building, as proposed on [PTlens' website](http://epaperpress.com/ptlens/calTargets.html) . Follow the instructions given there. The photographs may show perspective distortion: | | | | --- | --- | | [![[IM Output]](../img_photos/building_1.gif)](../img_photos/building_1.jpg)

perspective | [![[IM Output]](../img_photos/building_2.gif)](../img_photos/building_2.jpg)

non-perspective | Start Hugin, and click the 'Add images ...' button on the first tab and open the calibration image. (See [hugin.sourceforge.net](http://hugin.sourceforge.net/) for a screenshot of Hugin's interface.) At the button of the tab set 'Optimise' to 'Custom parameters' (which will add a new tab named 'Optimiser', you would otherwise not come to see). On the 'Stitcher' tab, set the 'Projection' to 'Rectilinear'. On the 'Control Points' tab, you see your test photograph twice and you can define sets of points that lie on the same straight line by picking these point groups in both versions of the photograph. But do not pick the exact same points in both versions, such that the points are identical in both images, as this would mislead the optimiser to take the easy way and determine the parameters of an one-to-one correspondence. Instead, you should rather choose different points on the same line in both versions of the image. For test purposes, you can define a few of such point sets, at best near the edges of the image, where the straight lines are more distorted. You will find that definining such point sets in Hugin is a rather tedious business (which may be one of the reasons for the lensfun database being so small). Then switch to the 'Optimiser' tab and chose the parameters to optimise by left-clicking them with the ctrl-key pressed. (See hint at the top of the tab.) I would recommend to optimise 'Yaw(y)', 'Pitch (p)' and the lens parameters 'a', 'b' and 'c'. The horizontal field of view 'Hfov (f)' is calculated from the EXIF data in the test image, by use of the FocalLengthIn35mmFilm entry `f`: Hfov = 2 × arctan (18 mm / f) with 18 mm being half of the width of a 35 mm negative (which measures 36 × 24 mm).Then press the button 'Optimize now!'. The resulting parameters 'a', 'b' and 'c' should fall below 0.01 for wide angle lenses and below 0.1 for fisheye lenses. If the values are larger, the optimisation has probably failed. If so, check the point sets on the 'Control Points' tab: the control points are probably out of order or not correctly associated with their corresponding lines. The optimiser also seems to be sensitive to the start set (mathematically speaking: the start vector) provided, i.e. setting all parameters to zero might be the wrong choice. You can edit the start vector by either double-clicking the values on the 'Optimiser' tab or by activating the check box 'Edit script before optimising' at the right buttom of tab page. This will bring up a text box prior to the optimisation, which will allow you to edit the corresponding section of the Hugin project file. Set the start vector a, b, c back to `a0.0 b0.0 c0.0` (or some other suitable values) before re-starting the optimiser. Experience shows that it might help to set 'a' to some positive value, especially for fisheye lenses.For a camera equipped with a fixed lens, one does this calibration once and for all. For a camera with a zoom lens, one has to cover the entire range of focal lengths by calibrating at about five different focal lengths. When having determined such a parameter set, give it a test in ImageMagick via magick calibration\_image.jpg -distort barrel '_a b c_' flat.jpg replacing the values `_a b c_` with the ones just determined. The lines in the output image should be exactly straight, otherwise the optimisation has failed and needs to be performed with a deviating start vector or a corrected control point set. ### Defining point sets For a serious calibration, it is recommendable to manually edit the Hugin project file and define the point coordinates and point sets by other means. The project file is a plain text file with the extension PTO, you can open it with a simple text editor and supply a point list. A single line in its section `# control points` looks like this: c n0 N0 x175.0 y87.8 X1533.3 Y62.6 t3 where `x, y` are the pixel coordinates in the source image (left image on the tab) and `X, Y` are the pixel coordinates in the target image (right image on the tab) – which are actually two versions of the same image in this special case. (Usually these would be two different images lying next to each other in a panorama.) The intro `c n0 N0` is standard code and the trailer `t3` is the numbering of the associated straight line, starting with the index 3. As you can take from the above example, the pixel coordinates may have fractional parts. Of course, `x, y` and `X, Y` have to lie on the same straight line. They must however not be identical, as the optimiser would refuse to work in this case (see above). The easiest approach to garantuee this, is to use the same points in both images but with reverse ordering for the target coordinates,e.g. use p1, p2, p3, p4 in the left image and P4, P3, P2, P1 in the right one.Determine the pixel coordinates in the source image by a point-picking tool. You can use any image viewer to do this, namely one that can store such data. A platform-independent tool for this would be [Fiji](http://fiji.sc/Fiji) . I (working under Windows) used polylines in [WinMorph](http://www.debugmode.com/winmorph) to do so. You should follow a pre-defined strategy when picking the points, e.g. pick the same count of points on each (more or less) horizontal line, going from left to right (i.e. follow a zig-zag line in the entire image, like the cathode ray beem in a tv tube). Such a strategy will simplify the ordering the target point coordinates. The text file lines defining source and target point coordinates can then be established either manually or by means of a software tool. (I use an Excel VBA subroutine to perform this task.) When ready, copy the point list to the corresponding section of the PTO file, save it and re-open it with Hugin. The result should look like this: [![[IM Output]](../img_photos/hugin.jpg)](../img_photos/hugin.jpg) Control point grid in Hugin A ready-made example, both with a calibration image and the corresponding Hugin project is provided in the ZIP file [olympus\_c2500l.zip](olympus_c2500l.zip) . ### Re-engineering from camera created thumbnail There are several cases where we already have an image pair, one being barrel distorted, the other one being already corrected. This correction may have been performed with some other lens-correction software, which doesn't tell us about the correction parameters.Furthermore, a lot of contemporary cameras (2019) offer to perform the lens correction internally for JPEG images. However, this functionality is usually not applied to RAW images. (Well, it's raw.) Nevertheless, the RAW image contains a JPEG preview to which the correction has already been applied by the camera. ImageMagick can read RAW images by the use of dcraw. Thus one may magick the raw image to JPEG without lens correction and compare the result to the internally corrected JPEG thumbnail.In case of such an image pair, the correction parameters can be calculated straightforward. By picking corresponding point pairs in both images, we can directly establish the relationship between `r` and `R`. ![[RAW Image]](raw_marks.jpg) Raw Image (barrel distorted) ![[Corrected Image]](thumb_marks.jpg) Corrected Thumbnail (to re-engineer) | | | | --- | --- | | | | As shown in the above example, we are free of choice which point pairs to choose; these neither have to follow straight lines nor even have to lie on geometrical patterns. We just have to fill a table with corresponding values of `r` and `R` and then calculate a regression curve, for example by means of a [spreadsheet](sorting_for_pto.xls) diagram. | | | | --- | --- | | [![[Calabration]](calibration_points.gif)](calibration_points.gif)

Calibration Points | [![[Regression]](regression_curve.gif)](regression_curve.gif)

Regression (scaled) | Hence the ImageMagick command line is magick barrel.jpg -distort barrel '0.0099 -0.0678 0.0014 1.0511' flat.jpg You can also apply the same command directly to the DNG camera format image "`barrel.dng`" directly too. * * * Examples of Lens Correction --------------------------- ### Camp Mobile | | | | | --- | --- | --- | | [![[IM Output]](../img_photos/campmobile.jpg)](../img_photos/campmobile.jpg)

Original | [![[IM Output]](../img_photos/campmobile_pt.jpg)](../img_photos/campmobile_pt.jpg)

Corrected | [![[IM Output]](../img_photos/campmobile_comp.jpg)](../img_photos/campmobile_comp.jpg)

Difference | The original photograph of the campmobile to the left had to be taken from a rather short distance during dusk, as space was limited due to a steep declivity at the back of the photographer. (The poor lighting conditions explain the blue tint which stems from severe lightening in the post-processing.) The original photograph shows pronounced barrel distortion, visible especially in the horizontal stripe near the top of the image and for the back corner of the build-up. The Nikon Coolpix 995 used for this shot is found in PTlens's database, so the distortion could readily be corrected, as seen in the middle. The image to the right shows the difference between greyscale versions the two photographs, calculated by subtraction of the two, followed by negation and extreme clipping and Gamma correction. Again, the effects of the correction are best illustrated by the horizontal stripe at the top. The white circle (indicating zero difference) results from the non-scaling restriction: the points on a circle with a diameter equal to the smaller dimension of the image remain unaltered. ### GoPro flattening The GoPro camera lens produces a pronounced barrel distortion, which seems to be part of its branding. For instance, the GoPro Hero 3+ silver edition has a fisheye lens with a fixed focal length of 2.77 mm, corresponding to a focal length of 16 mm in 35 mm film, if the entire photosensitive area is used. The GoPro Hero 3+ has three photo modes: * 10 megapixel = 3680 × 2760 pixel wide angle (16 mm in 35 mm film) * 7 megapixel = 3072 × 2304 pixel wide angle (16 mm in 35 mm film) * 5 megapixel = 2624 × 1968 pixel medium angle (23 mm in 35 mm film) The GoPro Hero 3+ is equipped with a 1/2.3" sensor, which has a crop factor of [5.64](http://en.wikipedia.org/wiki/Image_sensor_format) . (Which gives a focal length of only 15.62 mm in 35 mm film, the 16 mm provided by the EXIF information probably being due to rounding.) The first two modes seem to use the entire photosensitive area; the reduced resolution obviously being achieved by sub-sampling. The distortion parameters are therefore the same, as can be proven in practice. The 5-megapixel mode obviously uses only part of the photosensitive area, as 3680 / 2624 × 16 ≈ 23. The lens parameters can be determined to * wide angle: * a = 0.06335 * b = -0.18432 * c = -0.13009 * medium angle: * a = 0.01359 * b = -0.06034 * c = -0.10618 In theory, the parameters of the second mode can be derived from the first, as the radii `ri` and `Ri` are coupled by the scale factor κ = 3680 / 2624 = 1.402, which leads to: * a2 = a1 / κ³ * b2 = b1 / κ² * c2 = c1 / κ The above parameters, resulting from an independent optimisation, differ not much from these theoretical values.Correspondingly, the parameters for the various video modes can be derived either by optimisation or from the part of the sensor area that is used by this mode. For video, the horizontal field of view cannot be derived from the EXIF data. It can be calculated from the photosensitive area used, determined from the video itself (by taking footage under controlled conditions) or just estimated together with the other parameters, i.e. left as a free parameter in the optimisation. The parameters for HD video (1920 × 1080) are: * a = 0.030530 * b = -0.124312 * c = -0.038543 These parameters can be used for a frame-wise correction with ImageMagick. As an alternative, they can be used to "flatten" the entire video by the [AVIsynth](www.avisynth.org) plugin [DeBarrel](http://www.avisynth.nl/users/vcmohan/DeBarrel/DeBarrel.html) , which also uses the Panorama Tools lens correction model. ### Two Keyboards by el\_supremo The photo that I took of my two keyboards has a very obvious barrel distortion in it, because it was taken at a focal length of 17 mm. [![[IM Output]](../img_photos/keyboards.jpg)](../img_photos/keyboards.jpg) This kind of distortion can be corrected with, for example, Canon's Digital Photo Professional (I have a Canon 50D camera). Other manufacturers of SLR cameras usually provide software to do this kind of correction for their lenses but I wanted to see how well the above examples would work on this photo. The first step is to go to the [LensFun WebSite](http://developer.berlios.de/project/showfiles.php?group_id=9034) and download the latest version of their camera database. Unzip the package (winzip can unzip a .tar.gz file in Windows) and then in the "`lensfun/data/db`" directory look for the file which corresponds to your camera manufacturer. In my case I looked at "`slr-canon.xml`" which can be edited with any text editor. Now I find the information for the specific lens I am using which in this case is an "`EF-S 17-85mm`". The information for that lens looks like this: Canon Canon EF-S 17-85mm f/4-5.6 IS USM Canon EF-S 1.6 The calibration entries give distortion values for a range of focal lengths from 17mm up to 85mm. If the focal length I needed was between two of those values, I could either choose whichever was closest or I could interpolate the values. Since the photo I'm correcting was taken at 17mm I need the information from the first line of the calibration information. That gives me the values:  `a="0.021181"  b="-0.055581"  c="0"` These are the three parameters which are used to correct the lens distortion. However for some older versions of IM, The barrel distortion correction requires a fourth parameter d. Fortunately, it is easy to calculate the value of d from the other three using this simple formula:  `d = 1-a-b-c`  That means:  `d="1.0344"`. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _IM will work out the value of 'd' automatically, of it is not provided as a distortion argument, but some older versions of IM did not do this._ | That makes the actual [Barrel Distortion](../distorts/#barrel) , to correct the lens distortion... magick keyboards.jpg \\ -distort barrel "0.021181 -0.055581 0" \\ keyboards\_ptlens.jpg [![[IM Output]](keyboards_ptlens.jpg)](keyboards_ptlens.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Of course you should not save to JPEG until you have finished processing your image completely, due to the JPEG lossy compression._ | In the original photo the distortion is particularly obvious along the bottom of the music stand and along the upper keyboard. These distortions are almost completely gone in the output photo. A visual comparison of this result with that obtained from Canon's software shows essentially the same result. _El-Supremo_ * * * --- # Text Handling -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Text to Image Handling ========================================================================== **Index** | | | | --- | --- | | [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) | | | [![](../img_www/granitesm_right.gif) Text Operators in ImageMagick](#text_operators)
![](../img_www/space.gif)

[![](../img_www/granitesm_right.gif)Label](#label)
![](../img_www/space.gif) \- Simple Text Label

* [Basic Labels](#label)

* [Best Fit Labels](#label_bestfit)

* [Labels over Multiple Lines](#label_lines)

* [Vertical Labels](#label_vertical)


[![](../img_www/granitesm_right.gif)Caption](#caption)
![](../img_www/space.gif) \- Word Wrapped Labels

* [Basic Caption](#caption)

* [Best Fit Captions](#caption_bestfit)

* [Captions with Paragraphs](#caption_paragraphs)


[![](../img_www/granitesm_right.gif)Text Attributes and Settings](#attributes)

* [Text Attributes](#attributes)

* [Pointsize and Density](#pointsize)

* [Label Image Bounds](#bounds)

* [Unicode labels](#unicode)

* [Symbol Fonts](#symbol)

* [Inter-Character Kerning](#kerning)

* [Inter-Word Spacing](#interword-spacing)

* [Inter-Line Spacing](#interline-spacing)


[![](../img_www/granitesm_right.gif)Special Escape Characters in Text Arguments](#escape_chars)

* [Handling Escape Characters](#escape_chars)

* [User defined option escapes](#user_escapes)

* [Escaping Escapes](#escaping_escapes) | [![](../img_www/granitesm_right.gif)Pango](#pango)
![](../img_www/space.gif) \- Basic Formatted Text

* [Pango with Plain Text](#pango)

* [Pango Markup Language](#pango_markup)

* [Pango Notes and Problems](#pango_notes)


[![](../img_www/granitesm_right.gif)Text](#text)
![](../img_www/space.gif) \- Pages of Plain Text

* [Plain Text](#text)

* [Trimming Text Page](#text_trim)


[![](../img_www/granitesm_right.gif)Postscript/PDF](#postscript)
![](../img_www/space.gif) \- documents to images

* [Using Ghostscript Directly](#ghostscript)


[![](../img_www/granitesm_right.gif)Draw](#draw)
![](../img_www/space.gif) \- Draw Text on Existing Canvas

* [Undercolor Box](#box)
,    
* [Bounding Box Overflow](#overflow)


[![](../img_www/granitesm_right.gif)Annotate](#annotate)
![](../img_www/space.gif) \- Better Text Drawing

* [Automatically Sized Annotated Text Canvas](#annotate_size)

* [Autosizing using an Undercolor Box](#autosize_box)

* [Coloring a Gray-scale Text Image](#coloring_text)


[![](../img_www/granitesm_right.gif)Fonts Paths](#font)
(under development) ![](../img_www/space.gif)

[![](../img_www/granitesm_right.gif)Determining Font Metrics](#font_info)
![](../img_www/space.gif)

[![](../img_www/granitesm_right.gif)Creating Lines of Mixed Font Styles](#mixed_font_lines)
![](../img_www/space.gif)

[![](../img_www/granitesm_right.gif)Form Filling](#form_filling)
![](../img_www/space.gif) \- layered text fields on images

[![](../img_www/granitesm_right.gif)Text Processing Alternatives](#tex)
![](../img_www/space.gif) | Creating text labels, or adding text to images is probably one of the most basic and common operations for which ImageMagick is used. It is also one of the most simplest, but with scope for some very fancy results. As such this is a good place to start our exploration of IM's capabilities. * * * Text Operators in ImageMagick ----------------------------- ImageMagick has a lot of different ways in which you can draw text within an image, highlighting the versatility of the image processing library. This page details specific methods and styles of drawing text. What you have to keep in mind as you study these examples is that ImageMagick is primarily an image converter and modifier. As such each of methods provided are simple text drawing operators, such as adding labels and copyright messages to images. See [Annotating Images](../annotating/) . All the text operators also understand and use a set of standard text processing settings such as, the "`[-font](https://imagemagick.org/script/command-line-options.php?#font) `", "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" to use. Also the "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color setting and for more complex text drawing the "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `", "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `" and "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `" colors. In cases where you actually create a new image, such as label and captions, the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color setting is also used. And finally the newer "`[-kerning](https://imagemagick.org/script/command-line-options.php?#kerning) `" and "`[-interword-spacing](https://imagemagick.org/script/command-line-options.php?#interword-spacing) `" modifiers. What ImageMagick is _not_, is a full formatted text and document processor. If you want heavy text processing, you are better off using a full interactive word-processor, or batch text formatter like "`TeX`" (or or one of its flavors (see [A Complete Text Processing System](#tex) below). The output of these programs (generally postscript format) can then be converted into an image and further modified by ImageMagick. That is, use the right tool for the right job. That said some mixed font handling can be done. For a starting point look at [Creating Lines of Mixed Font Styles](#mixed_font_lines) , near the bottom of this page. Now, lets now look at the basic ways you can magick text into images. Later in the next section ([Compound Fonts](../fonts/) we'll look at generating some interesting font effects. * * * Label - Simple Text Label ------------------------- ### Basic Labels Creating a font image using a "`label:`" image, is the more typical way of drawing a font quickly in ImageMagick. The biggest advantage is that generates its own canvas according the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" and "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color settings, which is sized to match the drawn text. For example, here is a typical generated label. magick -background lightblue -fill blue \\ -font Candice -pointsize 72 label:Anthony \\ label.gif [![[IM Output]](label.gif)](label.gif) The above is probably the most typical usage of label, with a font selection and "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" defining the results. But it by far the least interesting way of generating text labels. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The '`label:`' image generated will also have the '`label`' [Image Property](../basics/#set)
meta-data set to the same string. Some file formats, such as MIFF and PNG, will save that specific property and can be used in later image processing programs. For and example of using 'label' meta-data, see [Montage using Saved Meta-Data](../montage/#metadata)
for examples._ | If you also specify a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" then the generated label image will be created at that size. magick -background lightblue -fill blue -font Candice \\ -size 165x70 -pointsize 24 label:Anthony label\_size.gif [![[IM Output]](label_size.gif)](label_size.gif) You can also use "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to set the position of the label within that larger box. magick -background lightblue -fill blue -font Candice \\ -size 165x70 -pointsize 24 -gravity center \\ label:Anthony label\_gravity.gif [![[IM Output]](label_gravity.gif)](label_gravity.gif) Of course if you do not set a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" for the label, no extra space will be available in the generated "`label:`" for "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to use, making it rather useless. The problem with using BOTH "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" and "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" together is that the text could 'overflow' the specified image size. magick -background lightblue -fill blue -font Candice \\ -size 165x70 -pointsize 72 -gravity center \\ label:Anthony label\_overflow.gif [![[IM Output]](label_overflow.gif)](label_overflow.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before version 6.5.2-4, IM would completely ignore the "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" setting if a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting is also given. This causes the text in the above images to be auto-sized according to the 'best fit' handling (see next set of examples)._ | ### Best Fit to Image The biggest trick to using labels to generate images of a specific "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" is NOT to specify a "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" for the label. When this happens IM will have the freedom to try and select a font size that _best fits_ the image size requested. That is, the drawn text will be adjusted to fit the given size! magick -background lightblue -fill blue -font Candice \\ -size 165x70 label:Anthony label\_size\_fit.gif [![[IM Output]](label_size_fit.gif)](label_size_fit.gif) As you can see by setting a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting, you could end up with some extra space to the right or below the image. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _When IM creates a 'bestfit' label, the actual pointsize it used is also saved into the '`label:pointsize`' [Image Property](../basics/#set)
, allowing you you use that information later. This was added to IM v6.6.2-7, during the forum discussion [Pointsize Reporting](https://magick.imagemagick.org/viewtopic.php?t=16449)
_ | You can still adjust the position of the label in that extra space by adjusting the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. magick -background lightblue -fill blue -font Candice \\ -size 165x70 -gravity center label:Anthony label\_size\_gravity.gif [![[IM Output]](label_size_gravity.gif)](label_size_gravity.gif) Of course if you do not set a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" for the label, no extra space will be available in the generated "`label:`" for "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to use, so it only makes sense when you ask for the image to be a specific size. Now for the best news. If the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting you give only contains just width or the height for the label, the font will be adjusted to best fit that given dimension. The other dimension not specified will then be auto-adjusted to fit that text! magick -background lightblue -fill blue -font Candice \\ -size 160x label:Anthony label\_size\_width.gif [![[IM Output]](label_size_width.gif)](label_size_width.gif) Basically that means the above "`label:`" will always be 160 pixels wide, with the largest font size for that width. The height of the label will then be adjusted to suit. The same thing will be done if the height is specified but not the width. magick -background lightblue -fill blue -font Candice \\ -size x40 label:Anthony label\_size\_height.gif [![[IM Output]](label_size_height.gif)](label_size_height.gif) This label is 40 pixels high, the undefined pointsize of the text was adjusted to fit that height, and then the undefined width was set to fit the drawn text. Exacly as you would expect. Of course in this case there will again be little if no extra space for any "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting to play with. ### Labels over Multiple Lines The "`label:`" generator can (as of IM version 6.2.5) generate multi-line labels. magick -background lightblue -fill blue -font Ravie -pointsize 20 \\ label:'ImageMagick\\nRules - OK!' label\_multiline.gif [![[IM Output]](label_multiline.gif)](label_multiline.gif) As you can see "`label:`" understands the use of '`\n`' as representing newlines. This means you may have to pre-process your input text to ensure that any special characters are escaped when placing the data on the command line. See [Special Escape Characters in Text Arguments](#escape_chars) below for more details. As "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" also effects "`label:`" generation (as of IM version 6.2.6), you can use it to 'justify' multi-line labels. magick -background lightblue -fill blue -font Corsiva -pointsize 24 \\ -gravity center label:'ImageMagick\\nExamples\\nby Anthony' \\ label\_centered.gif [![[IM Output]](label_centered.gif)](label_centered.gif) One important feature of IM is that it can read the text data to use from a file. This is done by prefixing the filename with an 'at' character '`@`', and using this as the string argument. For example, here we create a label from my workstations 'message of the day' file... magick -background lightblue -fill blue \\ label:@/etc/motd label\_file.gif [![[IM Output]](label_file.gif)](label_file.gif) You can also read the text for a label from the standard input pipeline. For example here I magick the output of a quote generator to a multi-line label. mesgs ImageResolution |\\ magick -background lightblue -fill blue \\ label:@- label\_file\_multiline.gif [![[IM Output]](label_file_multiline.gif)](label_file_multiline.gif) Notice that the filename I used was just a '`-`' character. This means that the file is to be read from standard input. Remember you can use the '`@_filename_`' to read ANY command line string arguments into IM. This includes all the other text input methods given below. However it can only be used to replace the whole string argument, not a part of a string argument. Note also that in the above examples, an extra blank line was added to the label image. This blank line is caused by a final newline in the input text file. Unless you somehow strip the final newline from the input file (see [caption:](#caption) example below for method to fix this), "`label:`" will always have this blank line from input text files. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Most older versions of IM (before v6.2.5), do not handle multiple line labels. In these versions the lines would have been appended together to form a single, very very long line._ | ### Vertical Labels Of course you can also add newlines to the input text too. For example, here I take a simple word and add a newline between each and every letter, to create some centered vertical text. echo -n "Vertical" | sed 's/./&@/g; s/@$//' | tr '@' '\\012' |\\ magick -background lightblue -fill blue -font Ravie -pointsize 24 \\ -gravity center label:@- label\_vertical.gif Note that the "`sed`" command adds a '@' character after every character, except at the end of the string. The "`tr`" then replaces the '@' characters with newlines. It also assumes the input text does not end with a newline, which would cause an extra blank space to be added at the bottom of the resulting image.[![[IM Output]](label_vertical.gif)](label_vertical.gif) Users running linux, and thus using the GNU version of the "`sed`" command can remove the "`tr`", and replace the '`@`' with '`\n`' in the sed command, so it directly inserts the newlines between each character. See also the special attribute [Inter-Line Spacing](#interline-spacing) which can be used to adjust the space between the characters. * * * Caption - Word Wrapped Label ---------------------------- The "`caption:`" image from text input generator, is in most respects exactly like "`[label:](#label) `" except that instead of expanding the size of the text to fit a specified "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting, it word wraps any long lines that do not fit into the specified "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" width. The "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting is not optional however and must at least specify a maximum width in pixels. For example, here is a caption of a long line that will not fit into the width specified. magick -background lightblue -fill blue -font Corsiva -pointsize 36 \\ -size 320x caption:'This is a very long caption line.' \\ caption.gif [![[IM Output]](caption.gif)](caption.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The '`caption:`' image generated will also have the "`caption`" [Image Property](../basics/#set)
meta-data 'set' to the same string, allowing you to re-use that information later. All the common image file formats will save this information with the image. See [Montage using Saved Meta-Data](../montage/#metadata)
for examples._ | By default the text is all left justified, however as of IM version 6.2.0, "`caption:`" respects "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" for text justification purposes. magick -background lightblue -fill blue -font Candice -pointsize 40 \\ -size 320x -gravity Center caption:'ImageMagick Rules OK!' \\ caption\_centered.gif [![[IM Output]](caption_centered.gif)](caption_centered.gif) If you do provide a height as well as a width to the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting, then the image height will be set to that height as well. You can then also use the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting, to position the text vertically. magick -background lightblue -fill blue -font Gecko -pointsize 32 \\ -size 320x100 -gravity South caption:'Captions at their height!' \\ caption\_height.gif [![[IM Output]](caption_height.gif)](caption_height.gif) Please note however that if the text will not fit (height-wise) into the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" you specified with the given "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `", then the text will overflow the box. The current "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting will naturally determine what part of the text is cut off. For example this is exactly the same as the previous example, but with an image "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" that is too small for the result. magick -background lightblue -fill blue -font Gecko -pointsize 32 \\ -size 320x60 -gravity South caption:'Captions at their height!' \\ caption\_height\_toosmall.gif [![[IM Output]](caption_height_toosmall.gif)](caption_height_toosmall.gif) ### Best Fit Caption As of IM v6.3.2, if you provide both the width and the height of the final image, but do not define the "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" of the font (or turn off the pointsize with "`[+pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `"), IM will attempt to automatically adjust the size of the font so as to best fill the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" of the image you requested. For example, here I ask ImageMagick to fill a fairly large area... magick -background lightblue -fill blue -font Candice -size 320x140 \\ caption:'This text is resized to best fill the space given.' \\ caption\_filled.gif [![[IM Output]](caption_filled.gif)](caption_filled.gif) And now a much smaller thinner area, for the same font and text string. magick -background lightblue -fill blue -font Candice -size 80x110 \\ caption:'This text is resized to best fill the space given.' \\ caption\_filled\_sm.gif [![[IM Output]](caption_filled_sm.gif)](caption_filled_sm.gif) Note that the ONLY difference between the last two examples is the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" of the image generated. IM fitted the text and word wrapping so as to try and best fill the image size specified. This is extremely useful for fitting an unknown bit of text into a given space, without it overflowing the area bounds. However internally it is equivalent to running caption multiple times as IM searches for the right point size to use to best fill the given space. In other words it can often be 10 times or more slower than if you supplied a specific "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" to use. ### Captions with Paragraphs The "`caption:`" image operator (as of IM v6.2.5) understands the use of the '`\n`' shell escape (and thus you need to double backslash '`\\`' to escape backslashes), as meaning a new line or paragraph. Before this version separate paragraphs would have to be processed by separate "`caption:`" operations. magick -background lightblue -fill blue \\ -font Ravie -pointsize 24 -size 360x \\ caption:"Here I use caption to wordwrap.\\nTwo separate lines." \\ caption\_multi\_line.gif [![[IM Output]](caption_multi_line.gif)](caption_multi_line.gif) You can read the text to be drawn from a file, or standard input (from a previous pipeline command), using the '`@`' filename prefix, just as as we can with "`[label:](#label) `". mesgs FilePrivate |\\ magick -background lightblue -fill blue -pointsize 12 \\ -size 320x caption:@- caption\_file.gif [![[IM Output]](caption_file.gif)](caption_file.gif) As you can see newlines in the input text will (as of IM v6.2.5) will be treated as paragraph separators. This includes any final newlines in the input file. Of course "`[label:](#label) `" will not word wrap the lines, but preserve them. If you really want a file to be treated as a single paragraph, then you will need to replace the newline characters with a space character, so your text is all on one line. For example, here we take the same text, but replace the line feeds with spaces, then replace any multiple spaces between the words, with a single space... mesgs FilePrivate | tr '\\012' ' ' | sed 's/ \*/ /g' |\\ magick -background lightblue -fill blue -pointsize 12 \\ -size 320x caption:@- caption\_one\_line.gif [![[IM Output]](caption_one_line.gif)](caption_one_line.gif) As you can see this works a lot better. However often what you want is to treat a blank line as a paragraph break. That means you need to remove all newlines, except those involved with blank lines. Here is a special "`sed`" command to magick such text into the format needed by "`caption:`". In this case the text is the first page of the "`magick`" manpage. man magick | col -b | expand | \\ sed '/^$/d; :loop y/\\n/ /; N; /\\n$/! b loop; s/ \*/ /g; s/^ //' |\\ head -n 7 | magick -size 400x caption:@- caption\_manual.gif [![[IM Output]](caption_manual.gif)](caption_manual.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _There is no 'justified' text option to caption. But the [pango:](#pango)
text formatter (using an external library), does have that feature, and a lot more._ | * * * Text Attributes --------------- Orignal the settings that effect text handling included: "`[-font](https://imagemagick.org/script/command-line-options.php?#font) `", "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `", "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `", "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", and "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `". We have already introduced many of these attribute controls above. But there are other attribute controls that are not used as often, and originally did not effect "`label:`" or "`caption:`" text image generation. As of IM v6.3.2 you can also use the "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `", "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `", and "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `". "`label:`" or "`caption:`". For example, here I make use of a lot of different settings to control the attributes of the IM text image rendering... magick -background white -fill dodgerblue -font Candice \\ -strokewidth 2 -stroke blue -undercolor lightblue \\ -size 165x70 -gravity center label:Anthony label\_color.gif [![[IM Output]](label_color.gif)](label_color.gif) For more details on these settings see [Undercolor Box](#box) below, and [Stroke, StrokeWidth](../draw/#stroke) in the drawing section. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _At this time, you can not use tiling images defined using "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `", "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `", "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `", and "`[-origin](https://imagemagick.org/script/command-line-options.php?#origin) `", with either "`label:`" or "`caption:`". Only solid colors can be used. Attempting to so will just produce an undefined (black) color._ | ### Pointsize, Density and the Actual Font Size Pixels are dots on the display or in an image, and that is what IM works in. On the other hand, images are printed at a specific resolution (specified as 'dots per inch' (dpi) or pixels per inch (ppi)). As such an images resolution effects how other programs will size an image onto a specific media. EG: It effects the images physical size in the real world. The resolution (density or dpi) of an image is irrelevant to the pixel size of an image, and the amount of space an image takes in memory or on disk. It is also, in general, irrelevant to most IM image operations. As such, to ImageMagick, the resolution is just a set of numbers stored with the image, and is normally ignored. The only time the resolution or density of an image becomes relevant is for fonts and for converting vector formats like postscript, pdf, MWF, to the raster image formats IM handles. The "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" setting tells IM how many pixels (dots) per inch (ppi) is present on the output device, which it can then use to adjust the image generation and font sizes to match. For example by default IM works with a "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" setting of 72 ppi, which is a typical setting for displaying images on a monitor or webpage. As a fonts size is specified in 'points' (using "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" and by definition 1 point is 1/72 inches, then a 72 point font should produce text sized to be roughly 1 inch high... magick -pointsize 72 label:Hello pointsize.gif [![[IM Output]](pointsize.gif)](pointsize.gif) However most modern displays have a better resolution than this, typically somewhere between 90 to 120 pixels per inch (ppi). As such... magick -density 90 -pointsize 72 label:Hello density.gif [![[IM Output]](density.gif)](density.gif) Should produce a label that is 1 inch high on a 90 dpi display. It is on my display! You can measure the height of these images on your screen, to check on your displays resolution. As the number of pixels per inch is larger, the drawn font is also naturally larger in terms of the number of pixels in the image, and thus producing a larger image. Different image programs often have a different default density, and this may cause fonts to appear differentially when drawn by different programs, even at the same point size. Note that "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" actually means the **line separation** of a font (actually its drawing area height), and does NOT refer to the actual height of the drawn letters! As such one font can appear larger or smaller than another font, at the same pointsize and density. Only the line spacing of the fonts will actually be the same, anything else is dependant on the font and the font's designer. As such with a default "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" of 72dpi (at which 1 point = 1 pixel) a 12 point font should have 12 pixels separation between the baselines to two lines of text. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Note that the height of a generated "`[label:](#label) `" image is based on the images drawing area or bounding box, which is often, the fonts line spacing and pointsize. This is not always the case, as such just appending lines of text vertically is actually incorrect font handling!_ | Some fonts may even extend well beyond the normal line separation boundaries, extending well above or more commonly below the line spacing. This is especially true of hand script fonts. The **look** of a font is also effected by the fonts "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" and "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `". Doubling a fonts pointsize ("`-pointsize 24`") will also produce a font that looks about the same size as one with doubled density or resolution. However because a font is designed to look a particular way, the thickness of lines in a font may not change much at a larger point size. That is, the larger font size is slightly different.But if you just double the density ("`-density 144`"), a 12 point font will be drawn with its dimensions doubled, should still look like the original 12 point font, just drawn at a larger scale with better smoothing of the edges. However at very low resolutions the physical size limitations of the pixels may also effect the look of a font. This means thin lines may be thickened at lower densities due to the large pixel size the density is defining. The relationship between 'density' and 'pointsize' is all a very complex issue, and one that only a professional font graphic designer can understand fully, and design their fonts to handle correctly. According to _[Lithium](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=11042) _ from the [IM Forums](https://magick.imagemagick.org/viewforum.php?f=1) ... > _I think it is a feature of TrueType font renderer. TrueType glyph is not only a set of curves, it may contain multiple levels of detail and instructions that adjust point coordinates according to output size in pixels, which is more visible for small size in pixels. Because of that, small text looks different (and more clear, one can notice) than shrunk large text._ `FUTURE Example: difference between font at same 'pixel' size, but different density and point size.` Basically increasing one of these factors while decreasing the other by the same amount may _not_ produce the same result. Particularly with regard to line thickness and overall 'style' of the font. You are better off adjusting the right factor for what you are doing. Use "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" when scaling a font for an output device, or later resizing of the font, and use "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" for normal font size changes. If you would like to know more about fonts, then have a look at the document [TrueType Fundamentals (PDF)](http://www.microsoft.com/typography/otspec/TTCH01.htm) , which I found very interesting. ### Label Image Bounds When using some exotic fonts, the font may use extended characters, and in the past IM had lots of trouble creating labels for these fonts. That is, the text overflows the provided canvas. For example, here are two capital letters in a '`LokiCola`' font reminiscent of a certain famous softdrink. magick -background lightblue -fill blue -font LokiCola -pointsize 64 \\ label:HC label\_overflow\_font.gif [![[IM Output]](label_overflow_font.gif)](label_overflow_font.gif) As you can see IM manages to contain this font in a label without cutting of the fonts leader or trailing graphics. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.3.2, "`[label:](#label) `" would have chopped of the 'H' lead-in and parts of the tails from both characters, in the above example._ | The reason this problem existed is because the fonts 'glyphs' or character description draw outside the fonts defined boundaries for specific letters, allowing them to overlap (generally either above or below) the other characters within the font. This is a problem with the way the font itself is designed and defined, and was not the fault of IM, though IM now handles these odd situations in the best interests of the users. In other situations it could still be a problem, and one that can not be solved simply due to multi-line text interactions. For more information see [Bounding Box Overflow](#overflow) examples below, for a more precise description. ### Unicode or UTF8 Format Text This method of supplying string arguments to IM is very important as it allows you to do things which ordinarily could be very difficult to do from the command line. Specifically handling 'unicode text', or selecting specific characters using character codes. Now if you can type unicode characters into commands or scripts you can use them directly.. magick -background lightblue -fill blue -pointsize 32 \\ label:' é è à ù ç Ö ÿ ‘ ’ “ ” ° ² ³ € x ÷ ' label\_i8n.gif [![[IM Output]](label_i8n.gif)](label_i8n.gif) However few people have keyboards or editors properly set up to handle [unicode character input](http://www.cl.cam.ac.uk/~mgk25/unicode.html#input) . Even if you can not directly type unicode characters, one simple solution is to just 'copy-n-paste' the desired characters from some existing UTF-8 text file, or web page. I do! If the UTF-8 text you wanting to draw has already been generated you can read it directly from a file using '`@filename`'. For example here I create a Chinese label from a [UTF-8 encoded Chinese text file](chinese_words.utf8) (without a final newline in the file). magick -background lightblue -fill blue -pointsize 48 \\ -font ZenKaiUni label:@chinese\_words.utf8 label\_utf8.gif [![[IM Output]](label_utf8.gif)](label_utf8.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The font used in the above example is a special one, with the full set of Chinese Glyphs defined, such as the fedora linux fonts '`SimSun`' (or in the font file "`gkai00mp.ttf`"), "`ZenKaiUni`" (in the file "`ukai.ttf`") or "`ShanHeiSunUni`" (in any of the files "`uming.ttf`" or "`zysong.ttf`" or "`bsmi00lp.ttf`").

Note that the windows font '`Mincho`' (used in a later example) also defines many of the Chienese Glyphs but incompletely. If you use it with the above you will get some question marks for undefined glyphs.

The special script "`[imagick_type_gen](../scripts/imagick_type_gen) `" was used to find, extract the fonts proper name, and add the font into an ImageMagick "`type.xml`" configuration file.

_ | We can also generate UTF-8 strings from unicode character codes using the 'GNU' "`printf`" program (on linux systems) to magick unicode numbers to the specific UTF-8 encoded string, in this case proper typeset opening and closing quotes (again no final newline in the UTF-8 input). Here for example I generate the UTF-8 text using unicode character codes, and feed it using a command pipeline (read from 'stdin' using "`@-`"), rather than from an actual file. env LC\_CTYPE=en\_AU.utf8 \\ printf "\\u2018single\\u2019 - \\u201Cdouble\\u201D" | \\ magick -background lightblue -fill blue -pointsize 36 \\ label:@- label\_quotes.gif [![[IM Output]](label_quotes.gif)](label_quotes.gif) On other systems (like Mac OSX and Windows) you can use the perl "`printf`" to output an UTF-8 encoded character string from unicode character codes. perl -e 'binmode(STDOUT, ":utf8"); \\ print "\\x{201C}Unicode \\x{2018}\\x{263A}\\x{2019} Please\\x{201D}";' |\\ magick -background lightblue -fill blue -pointsize 36 \\ label:@- label\_unifun.gif [![[IM Output]](label_unifun.gif)](label_unifun.gif) For more information and to look up the unicode character codes for various languages and symbols see [Unicode Character Code Charts](http://www.unicode.org/charts/) . Not only can unicode characters contain international characters, but with the right font you can also use special 'symbol' sets it defines. The most famous these is the 'DingBats' symbol font. This font has become so common that it is now part of the standard Unicode fontset. For example, here I extract the first 24 characters of the 'DingBats' unicode symbol area using a special "`**[graphics_utf](../scripts/graphics_utf) **`" shell script I wrote to generate a 'block' of unicode characters as UTF-8 text. graphics\_utf -N 2701 2718 |\\ magick -font Mincho -pointsize 32 label:@- label\_dingbats.gif [![[IM Output]](label_dingbats.gif)](label_dingbats.gif) The question marks in the above are specific characters which were not defined by either unicode, or in the windows '`Mincho`' font. More specifically the symbol that was part of the original 'dingbat' font is present in unicode, but using another unicode character code, than the expected dingbat code. See [Dingbats Unicode Specification Chart](http://www.unicode.org/charts/PDF/U2700.pdf) for more detail, and its referal to the correct unicode character to use for the 'missing' dingbat characters. Rather than a question mark, many fonts would just print a box or a blank character for such undefined characters. If you see too many such characters, or missing characters in your output, you probably should be using a different font. Other symbol sets also available as part of the enormous unicode character font include: Tolkan runic symbols, mathematical symbols, roman numerals, arrows, Braile and technical symbols. It is a large set to explore, and the "`**[graphics_utf](../scripts/graphics_utf) **`" shell script can help you explore it. Here is another example of unicode characters which the Microsoft 'Mincho' font can render. In this case from the "[Miscellaneous Symbols](http://www.unicode.org/charts/PDF/U2600.pdf) " section... graphics\_utf -N 2620 2630 |\\ magick -font Mincho -pointsize 40 label:@- label\_misc.gif [![[IM Output]](label_misc.gif)](label_misc.gif) Using unicode within DOS scripts is must harder than under UNIX and LINUX. Special notes on using unicode from that environment has been provided by Wolfgang Hugemann, in [Windows Character Encoding](../windows/#character_encoding) . ### Symbol Fonts More commonly used by people looking for special text images, are special 'symbol fonts'. These are much smaller than the full large Unicode font, as they replace only the normal standard ASCII characters (letters and numbers) with a different set of specific shapes and images, though sometimes (rarely) they also have more symbols in the Latin meta-characters area. The 'DingBat' font symbols started out in this way, but as mentioned above they are now part of the Unicode character set. For example, one symbol I rather like to use comes from the font "WebDings". It is a rather nice 'curvy heart' symbol, which is replaces the normal '`Y`' character in that fonts defintion... magick -size 20x20 -gravity center -font WebDings label:Y label\_heart\_20.gif magick -size 40x40 -gravity center -font WebDings label:Y label\_heart\_40.gif magick -size 60x60 -gravity center -font WebDings label:Y label\_heart\_60.gif magick -size 80x80 -gravity center -font WebDings label:Y label\_heart\_80.gif The important thing to remember is that all truetype fonts are actually a special type of [Vector Image Format](../formats/#vector) . With multiple images (one for each character) in the font. As they are vector images, it means the font should allow you 'draw' a character, shape or symbol at any just about any size (scale), using the controls provided by "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `", and "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `".As you can see above, the 'curvy heart' can be 'rendered' at pretty much any size I desire. Some fonts are very specialized. For example you can get a font file from [IDAutomation](http://www.idautomation.com/fonts/free/) called "`IDAutomationHC39M.ttf`" that can be used to generate barcodes. For example...[![[IM Output]](label_heart_20.gif)](label_heart_20.gif) [![[IM Output]](label_heart_40.gif)](label_heart_40.gif) [![[IM Output]](label_heart_60.gif)](label_heart_60.gif) [![[IM Output]](label_heart_80.gif)](label_heart_80.gif) magick -font IDAutomationHC39M -pointsize 16 label:'\*314-76\*' \\ -bordercolor white -border 5x5 label\_barcode.gif [![[IM Output]](label_barcode.gif)](label_barcode.gif) Here is some other interesting symbols I have found in various symbol fonts I have collected for one reason or another... magick -pointsize 48 -font WebDings label:' " \_ ~ ) - ' label\_webdings.gif magick -pointsize 48 -font LittleGidding label:' x o w ' label\_ltgidding.gif magick -pointsize 48 -font WingDings2 label:'ab' label\_wingdings2.gif magick -pointsize 48 -font Zymbols label:' ? , - I Z ' label\_zymbols.gif magick -pointsize 48 -font TattoEF label:' B Y D I H ' label\_tatooef.gif magick -pointsize 48 -font SoundFX label:' V 3 t f 9 ' label\_soundfx.gif This is only a small sample of what is available. Huge libraries of just about every symbol, shape, or image, imaginable is available on the WWW for you to browse and download. | | | | --- | --- | | [![[IM Output]](label_webdings.gif)](label_webdings.gif)
[![[IM Output]](label_ltgidding.gif)](label_ltgidding.gif)
[![[IM Output]](label_wingdings2.gif)](label_wingdings2.gif)
[![[IM Output]](label_zymbols.gif)](label_zymbols.gif)
[![[IM Output]](label_tatooef.gif)](label_tatooef.gif)
[![[IM Output]](label_soundfx.gif)](label_soundfx.gif) | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Remember that each drawn character has two separate parts that can be drawn: the 'filled' area (which I showed above), and the 'stroke' or outline, which can look very different to the filled area. Each of these areas can be drawn separately, or in different colors, so it may be a good idea to examine a promising symbol or shape more closely, in a number of ways. You may get a very surprising result. See [Compound Fonts, Stroke](../fonts/#stroke)
for some examples of doing this._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Many creators of symbol fonts generate the shapes using a simple scanner and bitmap to vector converter, without any proper design or cleaning of the image or shape. Caution is recommended when looking at such 'scanned' fonts.

The last font shown above is one such example of a 'scanned' font, giving it a poor looking 'dotty' quality, when compared to the other more properly designed fonts._ | ### Inter-character Kerning As of IM v6.4.7-8 you can use "`[-kerning](https://imagemagick.org/script/command-line-options.php?#kerning) `" to insert extra inter-character space between each letter in text strings. For example magick -pointsize 12 label:Anthony label\_kerning\_0.gif magick -pointsize 12 -kerning 1 label:Anthony label\_kerning\_1.gif magick -pointsize 12 -kerning 2.5 label:Anthony label\_kerning\_2.gif magick -pointsize 12 -kerning 5 label:Anthony label\_kerning\_5.gif magick -pointsize 12 -kerning -1 label:Anthony label\_kerning-1.gif [![[IM Output]](label_kerning_0.gif)](label_kerning_0.gif) [![[IM Output]](label_kerning_1.gif)](label_kerning_1.gif) [![[IM Output]](label_kerning_2.gif)](label_kerning_2.gif) [![[IM Output]](label_kerning_5.gif)](label_kerning_5.gif) [![[IM Output]](label_kerning-1.gif)](label_kerning-1.gif) Note that the actual kerning value can be a floating point value, or even a negative value. For another example of using a negative "`[-kerning](https://imagemagick.org/script/command-line-options.php?#kerning) `" value see the [Joined Compound Font](../fonts/#joined) example. ### Inter-Word Spacing Also as of IM v 6.4.8-0 the option "`[-interword-spacing](https://imagemagick.org/script/command-line-options.php?#interword-spacing) `" can be used to modify the size of a space character used between words. For example magick label:'I Love IM!' label\_wspace\_off.gif magick -interword-spacing 1 label:'I Love IM!' label\_wspace\_1.gif magick -interword-spacing 10 label:'I Love IM!' label\_wspace\_10.gif magick -interword-spacing 25 label:'I Love IM!' label\_wspace\_25.gif [![[IM Output]](label_wspace_off.gif)](label_wspace_off.gif) [![[IM Output]](label_wspace_1.gif)](label_wspace_1.gif) [![[IM Output]](label_wspace_10.gif)](label_wspace_10.gif) [![[IM Output]](label_wspace_25.gif)](label_wspace_25.gif) Note how you can not only increase the size of a space character between the words but also decrease the default size. Note however that spaces will cause the words to be re-aligned to pixel boundaries (unlike [Inter-character Kerning](#kerning) above) so the output of a label with spaces set to zero will still be different to a label that does not contain any spaces at all. Both the [Inter-character Kerning](#kerning) and the [Inter-word Spacing](#interword-spacing) will also effect the results of IM's ability to automatically fit a text string to a specific sized image. magick -size 150x label:'I Love IM!' label\_wsize\_of.gif magick -size 150x -interword-spacing 25 label:'I Love IM!' label\_wsize\_25.gif magick -size 150x -interword-spacing 50 label:'I Love IM!' label\_wsize\_50.gif [![[IM Output]](label_wsize_of.gif)](label_wsize_of.gif) [![[IM Output]](label_wsize_25.gif)](label_wsize_25.gif) [![[IM Output]](label_wsize_50.gif)](label_wsize_50.gif) What is happening is that by setting the "`[-interword-spacing](https://imagemagick.org/script/command-line-options.php?#interword-spacing) `" the 'space' character size no longer changes with the rest of the text size. Thus as IM trys to work out the best "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" the amount of space between each word is fixed, and thus play no part in the fitting of the text into the given fixed width. As a consequence the larger the "`[-interword-spacing](https://imagemagick.org/script/command-line-options.php?#interword-spacing) `" the smaller sized font that is needed to actually to fit the line of text into the same specified image width. A negative value can be used, and can in fact to make words overlap, or produce unusual effects using specific characters and fonts. But make it too negative and undefined behaviours can creep in. Caution is advised if you try this. While the above is not an example of text justification (though it looks like it), you can use these options as a starting point to providing proper text justification. If you really need that level of text formating and justification, then you may be better off looking at other methods of generating pre-formated text or [Postscript](#postscript) , such as the command line basied "TeX" or "LaTeX" software. Better still you could use [SVG](../draw/#svg) (rsvg library version), or [Pango Markup Language](#pango) (see below), to generate justified text. ### Inter-Line Spacing As of IM v6.5.5-8 an another option was added "`[-interline-spacing](https://imagemagick.org/script/command-line-options.php?#interword-spacing) `". This was heavilly requested by users in light of the previous settings, and in many ways is much more useful. Basically it will add or subtract this many pixels between the individual lines of text. That is, you can use it to expand or squash together the individual lines of text. For example.... magick label:'First\\nSecond' label\_lspace\_off.gif magick -interline-spacing 5 label:'First\\nSecond' label\_lspace\_5.gif magick -interline-spacing 10 label:'First\\nSecond' label\_lspace\_10.gif magick -interline-spacing 20 label:'First\\nSecond' label\_lspace\_20.gif magick -interline-spacing -5 label:'First\\nSecond' label\_lspace-5.gif magick -interline-spacing -10 label:'First\\nSecond' label\_lspace-10.gif [![[IM Output]](label_lspace_off.gif)](label_lspace_off.gif) [![[IM Output]](label_lspace_5.gif)](label_lspace_5.gif) [![[IM Output]](label_lspace_10.gif)](label_lspace_10.gif) [![[IM Output]](label_lspace_20.gif)](label_lspace_20.gif) [![[IM Output]](label_lspace-5.gif)](label_lspace-5.gif) [![[IM Output]](label_lspace-10.gif)](label_lspace-10.gif) To make best use of this setting you need to be able to calculate the normal line spacing for a specific font. This is the actual definition of "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `", which with the current resolution or "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" setting defines the line spaceing of a font. It does not actually define the fonts actual height or line thickness, though it effects these aspects of a particular font. So taking a "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" of '`72`' dots per inch, and knowning that by defintion there are 72 'points' per inch. you can calculate that a 12 point font will have a line spacing of 12 pixels. With that information you can 'double-space' your 12 point text lines by using a setting of "`-interline-spacing 12`". This will add 12 extra pixels between lines. magick -density 72 -pointsize 12 -interline-spacing 12 -font Arial \\ label:'First\\nSecond\\nThird' label\_lspace\_double.gif [![[IM Output]](label_lspace_double.gif)](label_lspace_double.gif) Of course as previously seen for interword size, adding a constant number of pixels between text elements will tend to make the text smaller when automatic pointsize handling is used. That is, a final image "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" is provided without a "`[-pointsize](https://imagemagick.org/script/command-line-options.php?#pointsize) `" setting. magick -size x70 -interline-spacing 18 -font Arial \\ label:'First\\nSecond\\nThird' label\_lspace\_size.gif [![[IM Output]](label_lspace_size.gif)](label_lspace_size.gif) Using a negtive interline spacing can also be used as a rough and ready method of vertically 'bolding' a line, simply by repeating that line, and subtracting 1 more pixel than the baseline separation. magick -density 72 -pointsize 12 -interline-spacing -13 -font Arial \\ label:'Bolded Word\\nBolded' label\_lspace\_vbold.gif [![[IM Output]](label_lspace_vbold.gif)](label_lspace_vbold.gif) Of course this will not work if you really want two lines, and not just bolding text. It also works better with a fixed width font. * * * Special Escape Characters in Text Arguments ------------------------------------------- We have already introduced the special escape characters used in various text arguments, above. Specifically you can escape special characters like newlines using backslash '`\`', or you can insert extra information into the string using percent '`%`' escapes, as defined on the [Image Properties](https://imagemagick.org/script/escape.php) page. Also there is a special '`@`' escape that if used at the start of a line will use the rest of the text argument as a filename to read the data from the file specified (or STDIN in '`-`' is used). | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Some system (like ubuntu) disable the use of the '@{file}' escape using security policy. Type `magick -list policy` to see what policies and where they are set from are present on your system._ | Not only do these escape characters effect "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `", for use by the "`magick identify`" (as well as "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" and the "`[info:](../files/#info) `"), but they also effect "`[label:](#label) `", and "`[caption:](#caption) `" text to image generators, and control the image meta-data setting options "`[-label](https://imagemagick.org/script/command-line-options.php?#label) `", "`[-comment](https://imagemagick.org/script/command-line-options.php?#comment) `", "`[-caption](https://imagemagick.org/script/command-line-options.php?#caption) `". And finally they are also used by "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `". | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _While backslash '`\`' is used by the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" '`text`' method, the percent '`%`' escapes are **not** as it interferes with ImageMagick's SVG image handling. This was one of the reasons the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operator was created for IM version 6.

_ | The other important point about escape characters is that while they are used for command line text arguments. At no time do they apply within the data being read from a text file (usually read in using the '`@`' escape). This means you do not need to worry about escaping 'escapes' for text file data, but it also means you have to process file data yourself outside of IM if you need to insert information into the text. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Protecting input text file from escape handling was finalised in IM version 6.3.3._ | For example, here I set and the report an images 'label' and 'comment' meta-data using the two methods to set that information from a source text file. The "`info.txt`" file contains the string [![[IM Text]](info.txt.gif)](info.txt) , (no final newline). magick -label @info.txt rose: -format '%l label' info: magick -comment @info.txt rose: -format '%c set "' info: magick rose: -set label @info.txt -format '%l caption' info: magick rose: -set comment @info.txt -format '%c set "' info: [![[IM Text]](file.txt.gif)](file.txt) Notice that IM did _not_ expand any of the escape character sequences that it read in using the '`@`' file read escape. This is important as it means that any time IM reads text from a file, it will _never_ handle any special characters that was present in that file. **IM reads text files, as literal text, without any escapes** Unfortunately this also includes any final newline that may be present in the file (or stream) that is being read! This can result in an extra 'blank' line in the resulting image, when the input text has a newline on the end (a very common practice). For example... echo "Anthony" | magick label:@- label\_stdin.gif [![[IM Output]](label_stdin.gif)](label_stdin.gif) As you can see the label not only contained the input string but also an extra blank line due to the newline character that the "`echo`" command added on the end. If you don't want that final newline, you will need to remove it yourself. This however could be a tricky matter, depending on where and how the text is sourced or created, and what API, you are running IM from. The best way is to try not to generate that final newline to begin with. For example using a '`-n`' flag to "`echo`". echo -n "Anthony" | magick label:@- label\_stdin\_2.gif [![[IM Output]](label_stdin_2.gif)](label_stdin_2.gif) Or using something that does not add extra newlines unless you specifically request it. printf "Anthony" | magick label:@- label\_stdin\_3.gif [![[IM Output]](label_stdin_3.gif)](label_stdin_3.gif) Or you can 'junk' that final newline using a tricky little perl one-liner... echo "Anthony" | perl -0777 -pe 's/\\n$//' |\\ magick label:@- label\_stdin\_4.gif [![[IM Output]](label_stdin_4.gif)](label_stdin_4.gif) In other API's you can look for that final newline before feeding the text to an IM command via a 'piped open'. ### User defined option escapes A major problem is trying to use escaped information from one image, in some other image, such as when generating a separate "`[label:](#label) `", or "`[caption:](#caption) `" image. This is a very difficult problem, and the current solution, (for a single image) is to create a special 'user option', that is attached to an image being processed. This 'setting' can then be looked up by the "`[label:](#label) `", "`[caption:](#caption) `", or "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `", as a percent escape sequence, when needed. For example, here I create a completely new label image using information from the built-in rose image. That information source image is then deleted, though I could just as easily append the new label to the original image. magick rose: \\ -set option:roseinfo 'rose image\\nsize = %w x %h\\nwith %k colors' \\ label:'%\[roseinfo\]' -delete 0 label\_escape.gif [![[IM Output]](label_escape.gif)](label_escape.gif) Yes the above is tricky, but that due to some internal IM core library limitations that are involved. See [Accessing Data from other images](../transform/#fx_other) for more details. ### Escaping Escapes If you must feed a string as an argument to IM (especially as an API call), but don't want IM to expand escapes, you can simply 'escape' all three escapes using an extra backslash '`\`'. Note the '`@`' only needs to be 'escaped' if it is the first character, and for backward compatibility, percent escapes can also be escaped by doubling it. That is, '`%%`' will produce a single percent. For example... magick -background lightblue -fill blue -font Candice -pointsize 48 \\ label:'\\@ \\\\n \\% 5%% ' label\_escapes.gif [![[IM Output]](label_escapes.gif)](label_escapes.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version 6.3.2, you could not use a backslash to escape an initial '`@`' to turn off the 'read from a file' function. In that case the only way to escape an initial '`@`' was to read it from a file. This was not very practical in API's._ | Here is a similar 'escape the escapes' example for "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `"... magick rose: -fill white -stroke black -font Candice -pointsize 20 \\ -gravity center -annotate 0 '\\@ \\\\n 5%%' annotate\_escapes.gif [![[IM Output]](annotate_escapes.gif)](annotate_escapes.gif) Of course as previously shown, reading the text from a file (using the '`@`' escape), will always be treated as literal, without any special meaning. This avoids the need for any pre-processing of the text, just watch out for any final newlines. echo -n '@ \\n 5%' |\\ magick rose: -fill white -stroke black -font Candice -pointsize 20 \\ -gravity center -annotate 0 '@-' annotate\_escapes\_file.gif [![[IM Output]](annotate_escapes_file.gif)](annotate_escapes_file.gif) In other words when reading from a file you don't have to worry about escaping things, but can just write exactly the text you want IM to use. ### Escapes on Older versions of IM The above definitions were only finalised in IM version 6.3.3. Before this escapes were sometimes handled in some options, and sometimes not, according to any requests, problems, and complaints, sent by IM users. This was especially the case with regards to the percent escapes with "`[label:](#label) `" and "`[caption:](#caption) `", which was for a period deemed as 'non-sensible'. For example whether you see a '`%c`' in the following label image is very version dependant (at least before IM v6.3.3). magick -background lightblue -fill blue -font Candice -pointsize 48 \\ label:'ab%cde' label\_percent.gif [![[IM Output]](label_percent.gif)](label_percent.gif) If you see a '`abde`' (percent escape applied) or '`ab%cde`' (percent not applied) depends on exactly what version of IM you are using. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _IM v6.2.4, percent escapes were removed from "`[label:](#label) `" and "`[caption:](#caption) `" as being non-sensible.

However they returned in IM v6.3.2, as a new '`%[fx:...]` construct, which can reference any image, made percent escapes in text to image generators useful again. See [FX Expression Escapes](../transform/#fx_escapes)
._ | This 'what is escaped' was also a problem with regard to the handling of escapes from files. Before IM v6.3.3, the following would have produced two lines, rather than a single line. echo -n ' Love \\n/ Hate ' |\\ magick -background lightblue -fill blue -font Ravie -pointsize 18 \\ label:@- label\_escapes\_file.gif [![[IM Output]](label_escapes_file.gif)](label_escapes_file.gif) As the results of escape handling vary greatly from version to version, in IM's older than v6.3.3, I recommend that scripts test its escape handling, adjust themselves if it is important to the programs correct working. _If anyone like to create an automatic test for IM scripts, please contribute. Or if you find such as test, please let me know._ * * * Pango - Basic Formatted Text ---------------------------- The "`pango:`" text coder (fully working as of IM v6.7.6-3) works in much the same way as the [Label](#label) and [Caption](#caption) coders. It provides a limited text formatting language on systems in which "Pango" is installed. On Linux and MacOSX systems pango is standard, on Windows it is optional. Here is a simple example without using any special pango formatting... magick -background lightblue pango:"Anthony Thyssen" pango.gif [![[IM Output]](pango.gif)](pango.gif) However you should note that some of the previous [Text Attributes](#attributes) will not work with pango, basically due to its text formatting requirements. For example while you can set a "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color, you can not set the default fill, or undercolor, nor the specific font to use. This is because these attributes are selectable via the Pango Markup Language instead (see below).It is recommended that you use "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" to define width and height limits to the output image, to which pango will automatically word wrap (or character wrap, for chinese) the input text. magick -background lightblue -size 150 \\ pango:"Anthony Thyssen is the main author of IM Examples" \\ pango\_size.gif [![[IM Output]](pango_size.gif)](pango_size.gif) And you can even have Pango 'justify' the text properly using the [Define](../basics/#define) , "`pango:justify`"... magick -background lightblue -size 150 -define pango:justify=true \\ pango:"Contributions to IM Examples are welcome via the IM Forum." \\ pango\_justify.gif [![[IM Output]](pango_justify.gif)](pango_justify.gif) Note however that while text can be justified, spaces and newlines are still taken into account by the text formatted. Also pango understands the use of TAB's (unlike label and caption). printf "col1\\tcol2\\nabc\\txyz\\n123\\t789" |\\ magick -background lightblue pango:@- pango\_tabs.gif [![[IM Output]](pango_tabs.gif)](pango_tabs.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that while the "`printf`" command above can generate tab characters, using the '`\t`' escape, IM does not understand the use of such an escape. It does however understand the '`\n`' escape sequence in strings._ | However generating columns using TAB's does not work very well as you can't easily define the 'tab-stops' outside the API. As such using TAB's in this way is _not recommended_, except as line and paragraph indentation . ### Pango Markup language The real power of pango however is in the "Pango Markup" language, which is enabled by default. You can turn off pango markup using "`-define pango:markup=false`", but then you may as well be using [Caption](#caption) instead. The "Pango Markup" is much like HTML, in that you use a set of "`<...>`" markup tags hidden in the text, and which is used to control how the text is to be formatted. Here are some guides on the Markup Language (without the API junk) * [The Pango Markup Language](https://docs.gtk.org/Pango/pango_markup.html) * [Pango Text Attribute Markup Language](https://developer.gnome.org/pango/stable/PangoMarkupFormat.html) (from Gnome)* [Pango Text Attribute Markup Language](https://www.gtk.org/api/2.6/pango/PangoMarkupFormat.html) (From GTK)* [Pango Script Gallery](http://www.pango.org/ScriptGallery) (examples) For example.. magick -background lightblue -gravity center -size 180x \\ pango:"The bold and beautiful" \\ pango\_formatting.gif [![[IM Output]](pango_formatting.gif)](pango_formatting.gif) The "``" tag is the main tag to use in pango mark up. It allows you to control the exact size, color, and position of the contained text. For example.. magick -background lightblue \ pango:' Some Big Red on Blue Text ' \ pango_span.gif [![[IM Output]](pango_span.gif)](pango_span.gif) Note that most numerical values are multiplied by a factor of 1024 as such the the value of "`size="49152"`" in the above example, means a text pointsize of 48 points. While the negative rise ("`rise="-20480"`) means to lower the text position by 20 points (or pixels at 72dpi). But instead of specifing a pointsize for the text I can also use a special size label such as "`size="x-large"`". See the source code of the next example. Watch out for the quotes within quotes in the above. The quotes within the tags are required. However newlines and extra space within tags will take no part in the formatting of the text. As such hiding extra newlines in a markup tags, or in a markup comment "``", can be very useful. Again see the source text of the next example. As a final example of the power of pango formatting here I use it to format a pre-prepared file "`[pango_test.txt](../images/pango_test.txt) `". This contains most of the common pango markup tags you are likely to use. Compare this markup file to the resulting image below. magick -gravity center pango:@pango\_test.txt pango\_test.png [![[IM Output]](pango_test.png)](pango_test.png) ### Pango Notes and Problems **Gravity** I have not been able to get pango to selectively center just a single line of text. You can only center everything, or nothing via the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. The reason for this appears to be because pango is designed to generate separate text labels for applications. That is, titles are usually generated separately to the main body of displayed text. Pango is is not meant to be a whole scale text page formatting engine. **Fonts** Pango can change fonts in the middle of rendering. It already does so easily for bold and italic text. However the font specification is from GTK, and as such uses a different system to ImageMagick in general. You can find out more about fonts using GTK, by running the "gtk-demo" program, and double clicking "Pickers" and the "Text Widget". **Defines** There are lots of special [Defines](../basics/#define) that can be used to globally control various aspects of pango text formatting. These are currently listed on the [Pseudo File Formats](https://imagemagick.org/script/formats.php#pseudo) , though I have not explored all of them myself. These are the ones I have used... `-define pango:markup=false` Turn off the markup language tags. Any tags are then included in the output. No pango formatting within the text is possible. this is especially useful in debugging, letting you see exactly what pango sees for its input. `-define pango:justify=true` Justify text across the width of the image size. That is, add extra intra-word spacing so both left and right edges of a block of text lines up. ### More Information on Pango To see just what is posible see [Pango Script Gallery](http://www.pango.org/ScriptGallery) If you do something interesting with pango, please contribute. Either mail me (Address in page footer), or post it on the [IM Discussion Forum](https://magick.imagemagick.org/viewforum.php?f=1) . | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _On systems with pango installed you can also use the command "`pango-view`" for generate pango formated images. However its default 'density' or 'dpi' setting is your display (IM uses 72 dpi by default) and as such may vary from host to host._ | * * * Text - Pages of Plain Text -------------------------- The "`text:`" input format is designed to magick plain text into images consisting one image per page of text. It is the 'paged text' input operator of ImageMagick. In other words its purpose is to magick the larger preformatted text files into pages in much the same way that printers print plain text onto separate pieces of paper. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Do **not** confuse the "`text:`" file input format with the similar "`[txt:](../files/#txt) `" input format. The latter will first attempt to read the file as a '`IM pixel enumeration`' image format.

That doesn't mean that a plain text file with a "`.txt`" will fail. In fact such a file will probably be converted as you would expect, as the "`[txt:](../files/#txt) `" file format will automatically fall back to the "`text:`" format if an enumerated image is not recognised.

_ | Handling text in this way however had a number of problems. First the text is drawn onto a large canvas, leaving you with the problem of removing the unused space, if such space is not wanted. The other is that lines are not 'word-wrapped' but will overflow canvas and get truncated if they are too long. And finally, for very long text files, multiple pages (images) will be generated unless some extra precautions are taken. On the other hand, "`text:`" will handle just about any text file, without modifying the final image size produced, or word-wrapping very long lines. You also do not need to pre-process and special characters as you would if you used the text on the command line. Finally and more importantly if a fixed width font (like Courier) is used, files with spaced out columns of data, will still have that data in spaced out columns. Basically "`text:`" will magick the input file 'AS IS'. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The input text data read from the file is essentially passed directly to the font library to draw the UTF text. As a consequence of this some control characters may be drawn using unusual 'glyphs'. This includes `TAB` and `FORMFEED` characters, which, at the time of writing, the 'freetype' library gets wrong.

If this is a concern, you may like to pre-process your text file using a filter program, such as "`expand`", to magick `TAB` characters into the appropriate number of spaces._ | When drawing text, a large 'letter' sized page is created (or the page size or type specified with a "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" )at the current resolution (set with "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `"). By default (at 72 dpi) this will be '`612x792`' pixels in size, which for most purposes is very large. For example, here is a direct conversion of the plain text formatted manual for the "`magick`" command, into an image (it is large so to see it select the 'page' image on the right to see it)... man magick | col -b | expand | \\ magick -font CourierNew text:- -delete 1--1 text\_manpage.gif [![[IM Output]](../img_www/doc_page.png)](text_manpage.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The above manual to image conversion however generates multiple pages (images), so I [Deleted](../basics/#delete)
the second and later ones to leave me with just the first page, instead of a GIF animation of all the pages.

I could also have appended a [Read Modifier](../files/#read_mods)
, '`[0]`' input filename, such as "`text:-'[0]'`", to tell IM only to read the first image generated. Though at this time all the page selection is still handled by generating all pages and deleting the unwanted pages._ | I purposely used the 'fixed-width' font '`CourierNew`' in the above so as to preserve the character spaced formatting that is present in the printed page. Note how this output varies from that of [caption:](#caption) above. The overall look of this image can also be improved by using the same techniques given in [Postscript](#ps) section next. If you just want to know how big say a 'A5' page is at 100 dpi, then this command generates a single blank page, of that size and returns its size in pixels. The filename, "`/dev/null`", is a special UNIX file that is always empty. magick -page A5 -density 100 -units PixelsPerInch text:/dev/null \ -format 'Page Size at %x = %w x %h pixels' info: [![[IM Text]](page_size.txt.gif)](page_size.txt) ### Trimming Text Pages Because the text is being 'drawn' onto a large canvas, you will likely want to remove all the unused space produced. This can be done by using the image operations "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `", "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `", then to make it look reasonable, re-adding some edge space using "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `". Of course you will also need to match the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color you used as the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" you are re-adding. Sounds complex? It isn't really, for example... echo " Hello Cruel World " |\\ magick -background lightblue -fill blue -pointsize 18 \\ text:- -trim +repage -bordercolor lightblue -border 3 \\ text\_trimmed.gif [![[IM Output]](text_trimmed.gif)](text_trimmed.gif) In the above example "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" is used to remove the vast amount of extra white space in the "`text:`" page image. This however will also remove any leading spaces in front of a line! There is however an interesting technique which will allow you to "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" the image down to the size of the actual text drawn onto the page, including any leading and trailing spaces in the input. This uses a special "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `" setting (looked at in detail later). echo " Hello Cruel World " |\\ magick -background white -undercolor lightblue -fill blue \\ -pointsize 18 text:- -trim +repage \\ -bordercolor white -border 3 text\_boxed.gif [![[IM Output]](text_boxed.gif)](text_boxed.gif) The extra space at bottom of the text is a result of the last 'newline' character in the text input, creating an extra blank line in the image. But as you can see the leading and trailing spaces of the input text was preserved. If you use a transparent background color in the above, you can then flatten the trimmed image to magick the undrawn areas into the same color as the 'undercolor' used. echo " Hello Cruel World " |\\ magick -background none -undercolor lightblue -fill blue \\ -pointsize 18 text:- -trim +repage \\ -bordercolor lightblue -border 3 \\ -background lightblue -flatten text\_box\_trimmed.gif [![[IM Output]](text_box_trimmed.gif)](text_box_trimmed.gif) The result of the above (except for the added "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" is actually almost exactly what IM now produces using a "`[label:](#label) `" and reading from a '`@`' escaped filename. However "`[label:](#label) `" does it in a faster, and far cleaner way (via the "`freetype`" library rather than a postscript conversion). You can specify a smaller "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" size, either in pixels (see next example), or using a media page size (such as '`A5`'), using the "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" or pixel resolution setting. You can also specify the offset at which to start drawing the text on the page, relative to the top left corner. For example... echo "This is a long line that shows that 'text:' does not word wrap." |\\ magick -background lightblue -pointsize 18 \\ -fill blue -page 320x95+50+10 text:-'\[0\]' +repage text\_page.gif [![[IM Output]](text_page.gif)](text_page.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Almost all other image creation operators use the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" setting to set a larger virtual 'canvas' and an 'offset' for the image on that canvas, generally for the purpose of layering images or generating animations. Because of this it is probably a good idea to reset your page setting using "`[+page](https://imagemagick.org/script/command-line-options.php?#page) `" after any "`text:`" or "`ps:`" operation, or you may get unexpected results for any secondary images you may latter read in on the same command line.

This also is why I added a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator to the above example otherwise the text is offset, and the image generated is also offset!

For more details of using this offset see [Page Image Attributes](../basics/#page)
._ | Note how in the last example, any text line that is too long to fit the width of the page will overflow the page, and not be 'wrapped'. This will effectively crop and junk the end of the lines. Also if there are too many lines, then "`text:`" will generate _multiple pages_ and thus _multiple images_, one for each page generated by the postscript translation of the text file. If you are only interesting in the first page of text, or just want to avoid the possibility of multiple images, add a '`[0]`' to the "`text:`" filename, to tell IM to only read the first page generated _after_ the text has been converted to images (see previous example). Postscript/PDF - Pre-formatted Text and Graphics Input (or other vector image formats) ---------------------------------------------------------------------------------------- The following gives a standard vector image handling technique that can not only be used for "`PS:`" (postscript) images but all other images handled using vector graphics. This includes image formats such as: "`PDF:`" (portable document format), "`[TEXT:](#text) `" (paged plain text), and even "`[SVG:](../draw/#svg) `" (scaled vector graphic) and "`[WMF:](../formats/#wmf) `". This method can be expanded to give you a very fine control of exactly how the text will look as an image. For example with the right 'text to postscript' filter, you can control the word wrapping, justifications, multiple font handling, bolding, borders, titles, filenames, dates, and other fluff in the postscript image. However as this section is about text to image, it means you need to first magick your text to a formatted postscript file. There are lots of external programs that can be used to do this. For example "`a2ps`", "`enscript`" or "`pstext`". Essentially you can use a word processor (like '`OpenOffice`' or '`Word`', or even '`Notepad`'), OR if you want a batch text processing system you could use at '`TeX`' and '`LaTeX`' to generate your pre-formatted text (see [A Complete Text Processing System](#tex) below). These programs are all designed to handle the complexity of mixing plain, bold, different size, and font text together, along with word-wrapping, justification and paragraphing controls. The output from these programs can then be passed to IM to convert it to an image of the size and quality you desire. So lets first generate some postscript (converting text from a personal fortune program). mesgs LN-ManKzinWars | \\ a2ps -q -1 --rows=10 --prologue=bold \\ --center-title="Postscript via 'a2ps'" \\ --header='' --left-footer='' --right-footer='' \\ -o ps\_version.ps [![[IM Output]](../img_www/doc_ps.png)](ps_version.ps) Now we can magick that into an image, trimming the result (as per "`text:`" examples above) to remove the excess blank areas from the default page/canvas generated. magick ps\_version.ps'\[0\]' \\ -trim +repage -bordercolor white -border 3 ps\_version\_raw.gif [![[IM Output]](ps_version_raw.gif)](ps_version_raw.gif) Note the use of '`[0]`' to limit the input to just the first page. If your postscript image generates multiple pages, it will still be completely processed by the "`ghostscript`" delegate, but IM will only read the first image returned, rather than generate multiple images, one image per page. If you postscript is very large, you may like to use other postscript utilities to limit the number of pages before processing it with IM and "`ghostscript`". As you can see postscript converted to the default "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" of 72 dpi, often does not look as good as it should, with only a minimal amount of anti-aliasing. This is particularly the case when dealing with postscript fonts, which are not designed to work at these low-resolutions. To improve this, you can use a [Super Sampling](../distorts/#super_sample) technique to generate a better image. In this case you ask "`ghostscript`" draw the page at a higher resolution (or image "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `"). You can then "`[-resample](https://imagemagick.org/script/command-line-options.php?#resample) `" (a [specalized resize](../resize/#resample) ) to bring this larger image back to a more 'normal' screen resolution density. magick -density 196 ps\_version.ps'\[0\]' -resample 72 \\ -trim +repage -bordercolor white -border 3 ps\_version.gif [![[IM Output]](ps_version.gif)](ps_version.gif) The value '`196`' is 3 times the final 72dpi, which means when "`[-resample](https://imagemagick.org/script/command-line-options.php?#resample) `" is used approximately 3×3 pixels are merged down into each pixel. This produces better anti-aliasing pixels along the edges of the text improving the overall look of the result. Also note that using a larger density or resolution is not quite the same as just enlarging a font. The font definitions could have adjustments for handling low resolution situations. For example compare the hole in the letter '`e`' in the two images. The original version is sharper due to special handling within the font, even though over all the latter super sampled version is clearer. For more information see [Resolution, Pointsize, and Actual Font Size](#pointsize) below. You don't have to use the values above, as sometimes slightly different value may produce a better or more desirable result. Of course having "`ghostscript`" generate an image 2, 3, or even 4 times larger also means IM will take 4, 9 or 16 times longer to generate the image! It will also use that much more memory and temporary disk space! But the results are generally worth it. The best idea is to just try it out for your own document, and see what gives you the best results. Also if you need more anti-aliasing, rather than using an even larger input resolution, you could try blurring the image by a sub-pixel amount (say '`-blur 0x0.7`') before you reduce its size. I have also sometimes found that a very small amount of unsharpening after the resize (a common photoshop technqiue), can improve the overall final result. magick -density 196 ps\_version.ps'\[0\]' \\ -blur 0x0.7 -resample 72 -unsharp 0x0.7 \\ -trim +repage -bordercolor white -border 3 ps\_unsharp.gif [![[IM Output]](ps_unsharp.gif)](ps_unsharp.gif) But I would be careful of these adjustments, as it could make things worse. If you like to have a transparent background instead of white, you can specify a "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting of '`RGBA`', to include the alpha channel in the image. Of course you will need to use an image format that can handle semi-transparent colors. magick -channel RGBA -density 196 ps\_version.ps'\[0\]' -resample 72 \\ -trim +repage -bordercolor none -border 3 ps\_transparent.png [![[IM Output]](ps_transparent.png)](ps_transparent.png) Notice that the banner still uses an off white color for its backgrounds, rather than also being made transparent or semi-transparent. That is, because the postscript generated actually draws that background, replacing the default background of the page (be it white or transparent). Making the background transparent like this will allow you to overlay your postscript image on a specific background color. magick ps\_transparent.png -background skyblue -flatten ps\_bgnd\_color.gif [![[IM Output]](ps_bgnd_color.gif)](ps_bgnd_color.gif) Using a [Alpha Compositing Method](../compose/#compose) you can even overlay it onto a specific background image, or a tiled background. magick composite -tile bg.gif ps\_transparent.png -compose DstOver \\ ps\_bgnd\_tiled.gif [![[IM Output]](ps_bgnd_tiled.gif)](ps_bgnd_tiled.gif) As almost all postscript printers only can darken paper or an overhead transparency, (this includes color printers), when the above is printed the banner would be made semi-transparent automatically. If you also want IM do the same thing, as what a printer would do, you can use a special '`[Multiply](../compose/#multiply) `' alpha composition, to overlay the 'white background' image, onto the desired 'paper' background. magick composite -tile bg.gif ps\_version.gif -compose Multiply ps\_multiply.gif [![[IM Output]](ps_multiply.gif)](ps_multiply.gif) If you have a color postscript image, you also can simulate a pure black and white printer onto colored paper by using the special '`[BumpMap](../compose/#bumpmap) `' compose method. This will grey-scale the source overlay image, before it uses uses multiply to composite the images together. You can also generate the grey-scale image equivalent of an overhead transparency slide. This basically uses the opaque, white background image (from above) as a 'mask' which to set shaped transparent image using the [Alpha Shape Operator](../basics/#alpha_shape) magick ps\_version.gif -negate -background black -alpha shape ps\_overhead.png [![[IM Output]](ps_overhead.png)](ps_overhead.png) Like the "`[text:](#text) `" converter above, the "`ps:`" converter also makes use of the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" setting to set the canvas size of the image 'media' onto which the page is drawn. Though offset supplied will be ignored. However as most postscript files define the drawing media size internally, this is usually not necessary. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Most other image creation operators use the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" setting to set a 'virtual canvas' and an ofset on that virtual canvas (for example to generate GIF animations). As such it is probably a good idea to reset it using "`[+page](https://imagemagick.org/script/command-line-options.php?#page) `" after using it for a "`text:`" or "`ps:`" image read operation, otherwise you may get unexpected results with the later images.

For more details of using this offset see [Page Image Attributes](../basics/#page)
._ | As a final practical example, have a look at my [Ray Traced Tetrahedron](http://www.ict.griffith.edu.au/anthony/graphics/polyhedra/platonic/tetrahedron.jpg) image. Other similar images can be seen in [Studies into Polyhedra](http://www.ict.griffith.edu.au/anthony/graphics/polyhedra/) . The background page was generated from the same data used to produce the displayed 3D mathematical object. The text data was converted using "`a2ps`", then IM was used to magick this to an image. Onto this image other pre-prepared line drawings of the same mathematical object was added to the page. This final image (saved in 'targa' or TGA format) was then passed to the "`[PovRay](http://www.povray.org/) `" ray-tracer for inclusion in the final image or ray traced scene. ### Using GhostScript Directly While this not strictly IM, _Richard Bollinger_ has reported that running the "`ghostscript`" delegate directly is much more efficient, producing an order of magnitude faster processing due to less file handling, by IM.For example instead of running... magick -density 300x300 -compress Group4 file.ps file.tif You can get GhostScript to do it directly. gs -dBATCH -dNOPAUSE -sDEVICE=tiffg4 -r300x300 \\ -sOutputFile=file.tif file.ps This prevents the need for IM to generate a large temporary file (for security and pipelined image handling). As a result of this, direct use of GhostScript can save quite a lot of file handling and IO processing, and can produce a major performance boost when processing postscript and PDF files. However "`ghostscript`" can not resize images, (other than adjust the output density or resolution) and will probably not be able to output the image in the image file format you require, or at the quality you want. But you can always then feed the GhostScript output to ImageMagick to finish the task. That is, especially the case if you want to super-sample the results (higher resolution input, to resized smaller output). GhostScript can be a difficult program to figure out how to use, or fix for specific types of postscript. Cristy constantly battles with these issues on behalf of IM users, and in this he has done a super effort. Unfortunately in dealing with the many things that can (and does) happen, IM can not provide a simplified method for postscript/PDF via GhostScript. Draw - Draw Text on Existing Canvas ----------------------------------- By using the low level "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator to draw the font we get a lot more control, especially as to the exact position of the font, and the size of the image it is drawn into. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill blue -draw "text 25,65 'Anthony'" text\_draw.gif [![[IM Output]](text_draw.gif)](text_draw.gif) However to use it we need to generate a background image of the appropriate size to draw the font, which can be tricky when drawing some unknown text. See [Auto Sizing of Font Images](#size) for ways to solve this problem. A lot of extra options, beyond the standard text options also effect how "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `", actually draws text on an image. Not only can you specify a "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color, but you can also specify a "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `", as well as an edge or "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stroke) `" color, both of which are turned off by default (set to a color of '`none`'. The "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color can also be replaced by a "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" image pattern, while the stroke edge width can be changed using "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `". Then the relative position of the drawn text can be changed a with "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. For example, here I used many of the extra features I just mentioned. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -tile bg.gif -undercolor dodgerblue -stroke navy -strokewidth 2 \\ -gravity center -draw "text 0,0 'Anthony'" text\_options.gif [![[IM Output]](text_options.gif)](text_options.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As of IM version 6.2.4, the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) ` text" operation no longer understands the use of '`\n`' as meaning newline, or the use of percent '`%`' image information escapes. (See [Drawing a Percent Bug](../bugs/draw_percent/)
).

These abilities, and problems, however remain available in the new IM v6 operator "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `". See the [Annotate Text Drawing Operator](#annotate)
below._ | All the above options can also be used within the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" (MVG - Magick Vector Graphic) string. However if you set the above option within the draw argument, that option will only apply to that specific draw MVG string. On top of this the draw MVG format can do much much more, such a text rotation and font 'decorating' and of course you can also draw various shapes like circles onto the image. For example, here we draw underlined, and rotated text, overlaid on a couple of background circles. magick -size 320x120 xc:lightblue \\ -draw "fill tomato circle 250,30 310,30 \\ fill limegreen circle 55,75 15,80 \\ font Candice font-size 72 decorate UnderLine \\ fill dodgerblue stroke navy stroke-width 2 \\ translate 10,110 rotate -15 text 0,0 ' Anthony '" \\ draw\_mvg.gif [![[IM Output]](draw_mvg.gif)](draw_mvg.gif) If you really want to make maximum use of "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" for creating your image, I suggest you look at the [Drawing Examples Page](../draw/) . ### Undercolor Box The "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `" color setting, as demonstrated above, and later below, will color the defined drawing area for that character and font. generally it just fits the drawn character. This is particularly the case the left and right edges of the drawn font, as the top and bottom edges are usually larger enough to accommodate all the characters. The drawing area basically represents the character 'cell' boundaries surrounding the area in which the font is drawn. The major use of using the "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `" option, is as a simple and quick way to clear a 'noisy' background from around the text. For example look at [Annotating on Top Images](../annotating/#anno_on) . However it is recommended you also add an extra space character at the start and end of the string being drawn in that case. ### Bounding Box Overflow One of the biggest problems you will probably come across when drawing text, or just generally handling fonts, is that not all fonts obey the normal rules. A font designer can 'draw' individual characters (or 'glyphs') anywhere relative to the current text position (known as the caret). The font position does not even have to move forward, and in some international fonts could even move backward!. The result of this freedom of design is that some 'glyphs' do not fit inside the defined drawing area which the font declares the character fits into, especially on slanted, or script-like fonts where some parts of the letters extend well outside the bounds and into the areas used by later (or previous) characters. The worst font I have seen in this regards is the '`LokiCola`' font, which draws around half of its capital letters with long wavy tails, well beyond the bounds of the individual character cells. The font basically assumes each capital letter will be followed by 3 or more lowercase letters. To show this I'll draw a number of the font's capital letters separately, allowing you to see just how far the letters could extend beyond the cell 'undercolor' or drawing bounds. I also use a couple of them to form the fonts name, so you can see just as they were designed to be used, and why they overflow their bounding boxes. magick -size 500x200 xc:lightblue \\ -font LokiCola -pointsize 72 -undercolor dodgerblue \\ -draw "text 15,65 'L'" -draw "text 130,65 'C'" \\ -draw "text 245,65 '1'" -draw "text 360,65 'H'" \\ -gravity South -draw "text 0,10 'Loki Cola'" draw\_undercolor.gif [![[IM Output]](draw_undercolor.gif)](draw_undercolor.gif) Also note how the '`H`' actually overflows on the left side as well as the right side of its drawing area. This can make it difficult to use at the beginning of lines. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Remember this problem is NOT a bug in IM, but caused by the interaction of the font library IM uses, and the settings within the font itself, usually on purpose by the font designer. IM just uses the results as they are programmed in the font, which does not always produce what the user intended. Caution is thus advised with unusual fonts._ | Annotate - Text Drawing Operator -------------------------------- With IM version 6, a new font drawing operator, "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `", was made available. This operator is in may ways much simpler that using a "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) ` text" operation, but as it uses the '`annotate()`' API (Application Program Interface), it is also more powerful. While the operator does make use of the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" primitives, it does so in a more complex way, such as expanding special [escape characters](#escape_chars) to add extra image information and even multiple lines, and applying a coordinate system transform to the drawn text to produce slants and rotations. Because of this, the operator is now the preferred text drawing operator for all ImageMagick text drawing and image annotation, and this is now reflected in these example pages. Here is a basic example using this operator. magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -fill blue -annotate +25+70 'Anthony' annotate.gif [![[IM Output]](annotate.gif)](annotate.gif) One of the extra features of the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operator is that it can rotate the X and Y axis of the drawn text completely separately to each other. This is done by providing the angle in which to rotate each axis as a 'image size' in the operators argument. Just to show how complex a single "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operation can be, here is a boxed, stroked, and slanted image... magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -tile bg.gif -undercolor dodgerblue -stroke navy -strokewidth 2 \\ -annotate 0x20+20+67 'Anthony' annotate\_opts.gif [![[IM Output]](annotate_opts.gif)](annotate_opts.gif) In this example all four annotate arguments are given. Specifically, X axis rotation, Y axis rotation, and the fonts X and Y position on the background image. Also note that the fill pattern (set with "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `") is also slanted with the font. That is, because it is drawn using a sheared/rotated coordinate system, which also shears and fill pattern tiled within the drawn text. Further example of this shearing capability is the [Sheared Shadow Font](../fonts/#slewed) example. Compare that with the [Slanted Font](../fonts/#slanted) created with the equivalent "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" MVG string. For a table summarizing the effects of the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" shearing operation, see [Annotate Argument Usage](../misc/#annotate) . For example, here is some slightly rotated text ... magick -size 320x100 xc:lightblue -font Candice -pointsize 72 \\ -annotate 350x350+20+90 'Anthony' annotate\_rotated.gif [![[IM Output]](annotate_rotated.gif)](annotate_rotated.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that the angle given to "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" must be positive for IM to understand it correctly). The exception to this is if a comma-separated 4 number form of [Geometry Argument](../basics/#arg_geometry)
is used. For example "_`-annotate '-10,-10,20,90' 'Anthony'`_", could have been used in the last example._ | This can be used to generate angled condensed labeling. For example... magick -size 100x60 xc:skyblue \\ -annotate 300x300+20+50 "First" \\ -annotate 300x300+35+50 "Second" \\ -annotate 300x300+50+50 "Third" \\ -annotate 300x300+65+50 "Fourth" \\ -annotate 300x300+80+50 "Fifth" \\ annotated\_labels.jpg [![[IM Output]](annotated_labels.jpg)](annotated_labels.jpg) You can also add other information about the current image to the Annotated string using escape characters. For example lets overwrite the built-in "`rose:`" image with information about the images size. To center the text on the image we use a "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting, and turn off any and all rotations and offsets by using an "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" argument of '`0`'. magick rose: -fill white -stroke black -font Candice -pointsize 20 \\ -gravity center -annotate 0 '%wx%h\\nPixels' annotate\_rose.gif [![[IM Output]](annotate_rose.gif)](annotate_rose.gif) For more information see [Special Escape Characters in Text Arguments](#escape_chars) below. For other examples of annotating text onto a larger image in various ways (such as centered on the side, or rotated in the bottom-right corner) see [Practical Text Annotation Examples](../annotating/#practical) . ### Automatically Sized Annotated Text Canvases Often you need much more control than what "`[label:](#label) `" can provide. For example you want to use a tile or gradient image, requiring you to [Annotate](#annotate) the text. Unfortunately you then need to know in advance the size of the canvas you need for your [Annotated Text](#annotate) . Here is a typical example of the problem. When I first set up this command I set my size to the results I wanted, and at first it worked quite well. But then I got this... magick -size 480x80 gradient:yellow-green \\ -font ArialBkI -pointsize 70 -tile gradient:blue-red \\ -annotate +10+65 'Gradient Fun' funfont\_gradients.jpg [![[IM Output]](funfont_gradients.jpg)](funfont_gradients.jpg) Unfortunately when guessing at the canvas size I had miss-spelt the word '`Gradient`' in that above (missing the letter '`i`'). Of course when I fixed that spelling, my image size was now wrong, producing incorrect result shown above. What we need is to be able to use the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operator, but with the canvas sized to fit the [Annotated Text](#annotate) . One solution is to use a much larger canvas, then "`[Trim](../crop/#trim) `" the background to the right size. I also added a "`[Border](../crop/#border) `" to add a little extra space around the font and the final edge of the image, for a better look. magick -size 800x120 xc:black -font Corsiva -pointsize 100 \\ -tile tile\_disks.jpg -annotate +20+80 'Psychedelic!' \\ -trim +repage -bordercolor black -border 10 funfont\_groovy.jpg [![[IM Output]](funfont_groovy.jpg)](funfont_groovy.jpg) This method is much better than trying to make a guess at just how big your final image should be, however "`[Canvas Trim](../crop/#trim) `", will not trim a tiled multi-colored background. The better solution is to create the canvas using "`[label:](#label) `", to generate the canvas of the right size. A [Draw Color Fill](../draw/#color) is then used to tile an image over the canvas (and the label text), and finally we [Annotate](#annotate) our text using another tiling image. magick -font Ravie -pointsize 72 label:'Get Wet!' -border 10 \\ -tile tile\_aqua.jpg -draw "color 0,0 reset" \\ -tile tile\_water.jpg -gravity center -annotate +0+0 'Get Wet!' \\ autosize\_wet.jpg [![[IM Output]](autosize_wet.jpg)](autosize_wet.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that position of the text in a centered "`[label:](#label) `" image may not exactly match the position of a centered "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operation. The two methods follow completely different processing algorithms, and as such may not match. Especially when unusual fonts are involved._ | ### Auto Sized using 'Undercolor Box' Rather than using a "`[label:](#label) `" image, you can draw the font on a large canvas using an [Undercolor Box](#undercolor) and a [large stroke width](../draw/#stroke) , before trimming the canvas to fit. For example magick -size 500x100 xc:lightblue -font SheerBeauty -pointsize 72 \\ -gravity center -undercolor white -stroke none -strokewidth 3 \\ -annotate +0+0 ' Invitation ' -trim +repage -shave 1x1 \\ invitation\_box.jpg [![[IM Output]](invitation_box.jpg)](invitation_box.jpg) The amount of space around the font can be adjusted using the "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `" setting. The only important requirement is that the initial canvas be a color different to the background color, ('`lightblue`' in this case) and is larger than the final result. Just a word of warning, some fonts draw characters well outside the individual character drawing area. (For example see [Undercolor Box](#undercolor) above). In this case the above result will work, but may require you to use a transparent canvas, and then overlay the result over white (using an operation like "`-background white -flatten`" for example), to magick the unused and still transparent areas to white. However that character will likely be touching an edge of the resulting image. Basically you can't really win, in all situations, just try your best. ### Coloring a Gray-scale Text Image I purposefully generated the above image as a grey-scale black and white image, as this can be used as a masking template. From a pure image like this you can then color the background and the foreground of image either separately or both at the same time. Here for example I use the [Level by Colors Operator](../color_mods/#level-colors) , "`[+level-color](https://imagemagick.org/script/command-line-options.php?#level-color) `", to globally modify the image colors so as to assign the foreground and background colors with specific values. magick invitation_box.jpg -colorspace sRGB \ +level-colors navy,lightblue invitation_colored.jpg [![[IM Output]](invitation_colored.jpg)](invitation_colored.jpg) For example, here I use [Composite Masking](../compose/#mask) to replace background and foreground with pattern images. magick invitation_box.jpg -colorspace sRGB \ \( +clone -size 300x150 -tile gradient:LightYellow \ -draw "color 0,0 reset" \) \ \( +clone -size 300x150 -tile plasma:tomato \ -draw "color 0,0 reset" \) \ -reverse -composite invitation_rose.jpg [![[IM Output]](invitation_rose.jpg)](invitation_rose.jpg) The [Reverse Operator](../basics/#reverse) in the above is used to reorder the images, so the first image becomes the third 'masking' image of the composition. The foreground ("`plasma:`") image then becomes first, and the background in the middle. For other techniques of coloring a gray-scale image like this, see [Using a Mask to Limit the Composed Area](../compose/#mask) . And more generally [Using Masks with Images](../masking/#masks) . For other methods of generating gradients for tiling see [Gradients of Color](../canvas/#gradient) , [Sparse Points of Color](../canvas/#sparse-color) , and [Randomized Canvases](../canvas/#plasma) . * * * Fonts ----- **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** As for ordering the font paths, that is simply ordering the fonts specified in the XML files. The start point is the system fonts, followed by the system installed "type.xml" file, on my system this is "/etc/ImageMagick-6/type.xml". This system installed "type.xml" file is typically just a list of 'include' other type-\* files. And the order of the includes will specify the order of Extra System Fonts, verses Ghostscript Fonts. After that file other "type.xml" files are looked for, such as in 'home' directories, or even current directory. Later fonts will NOT replace earlier fonts, as such if two fonts have that same name, only the first one will be noted by IM. (a security measure). To see the fonts loaded use magick -list font It lists "Path:" of the type file each font list was found in, but the paths are listed in REVERSE order, with system fonts at the end. I have for example a personal Font named "Courier", but it is not listed in the above list as it was defined after the "Courier" that was found in the "System Fonts" area, (which is listed at the end of the above output). On the other hand my own personal font "CourierNew", is listed, as it does not clash with any system or system config defined font. To see what font glyph file is selected for soem specific request use... magick -debug annotate xc: -font Courier \\ -annotate 0 'Test' null: 2>&1 | grep '^ \*Font ' Determining Font Metrics, without using an API ---------------------------------------------- ![[diagram]](../img_diagrams/glyph_metrics.gif) A particular font and its individual characters contain a lot of information. Such information can be very useful to have, especially if you are wanting to use IM for piecing together the text of many different fonts. It is also important to remember that most fonts are proportional fonts, meaning that each individual character will have a different width, and a different 'natural' advance of the caret (or origin). As such each specific 'string' of characters will be rendered (drawn) a different length without any real regard to the actual number of characters used in the string. The exception to this are 'Fixed-Width' fonts, such as "`Courier`", "`Typewriter`", or "`Terminal`" fonts, in which all characters have the same width, allowing you to generate columns of text easily. The [Debugging Setting](../basics/#debug) "`[-debug](https://imagemagick.org/script/command-line-options.php?#debug) annotate`" can be used to get IM to directly report a TTF font's metrics, for a specific string. For example... magick -debug annotate xc: -font Candice -pointsize 24 \ -annotate 0 'Test' null: 2>&1 |\ grep Metrics: | fmt -w80 [![[IM Text]](font_metrics.txt.gif)](font_metrics.txt) As you can see you get a mixed bag of information you can use: from the declared bounds of the drawn string (which is not nessarilly the strings actual bounds), relative to the origin; to the amount the 'carat' (origin) should advance before drawing the next string. The full debug output (which is rather verbose, and not shown in the above) also reports the actual font file used (twice) so you can also use it to check that you have the right font too. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The "`[-debug](https://imagemagick.org/script/command-line-options.php?#debug) annotate`" method was added to IM v6.3.9-2_ | ### Older techniques This debug output however may not be convenient, or you may have to handle IM's that are older than this version. The following are older examples where the text is actually drawn in various ways and colors, and then information (as integers) extracted from the resulting image. For example lets find out the dimensions of the '`Ravie`' font relative to a fixed baseline, at 72 point.Here is the image we will be studying, as a reference. You don't actually need to drawn and save it as an image, as we are only extracting data, not an image. the colors of this image will be modified so we can look at the white and black parts separately using "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" to extract the metrics used. magick -size 100x150 xc:lightblue -font Ravie -pointsize 72 \\ -fill black -undercolor white -annotate +20+100 'A' font\_drawn.gif [![[IM Output]](font_drawn.gif)](font_drawn.gif) For the basic basic font metrics, we first draw the font itself with a transparent color ('`None`'), so that we can measure find the size and location of the bounding box or drawing area of this specific character, for this font. Note that for height information you can just draw anything. magick -size 100x150 xc:lightblue -font Ravie -pointsize 72 \ -fill none -undercolor white -annotate +20+100 'A' -trim info: [![[IM Text]](font_boxinfo.txt.gif)](font_boxinfo.txt) From the results above we can see that a '`Ravie`' font at 72 points, will have a total bounding box height of 74 pixels. The top of the box is 42 pixels from the top of the image, as the baseline which was positioned at a 100 pixels y coordinate, the box starts is 100 - 42 or 58 pixels above the baseline. That leaves 74 - 58 or 16 pixels for the bounding box below the baseline for the descenders. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Note that not all fonts limit their drawing to within their defined drawing bounding box! However some letters can extend far outside those boundaries. That is, why the above example sets a "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color of '`none`'. That way ill behaved fonts will not effect the above measurements._ | Also note that the distance separating lines (baselines actually) should be purely determined by the point size of the font, and has nothing to do with how the font is drawn. In out example, as the font has a point size of 72 points, and a point is defined as 1/72th of an inch, then the baselines should be 1 inch apart. With a current output resolution (density) of 72 pixels per inch, that means the baselines will be 72 pixels apart. Interestingly enough that means that for this font, with a 74 pixel bounding box, the font has a two pixel overlap for the drawing area between the lines of properly single spaced text! Also from the above measurements we can see that in drawing the string "`A`" in this font at this point size, the next character should be drawn 66 pixels to the right of the starting point (known as the caret). This is the strings 'logical' length. That is, the 'caret' or start point for the next character should start at 20 + 66, or at '`+86+100`' (the baseline does not change vertically). Be warned that some Arabic fonts can in fact draw right to left, so the 'caret' offset will be negative. That gives use the font metrics for the character 'A' but what about physical dimensions of drawn 'A' relative to the 'caret' or start point. Well just swap the two color settings... magick -size 100x150 xc:lightblue -font Ravie -pointsize 72 \ -fill black -undercolor none -annotate +20+100 'A' -trim info: [![[IM Text]](font_drawn.txt.gif)](font_drawn.txt) Height-wise the character was within its defined drawing boundaries, with its height going from 100 - 43 or 57 pixels above the baseline (hard against its bounding box) to 60 - 57 or only 3 pixels below the fonts baseline. In other words this letter does not have a 'descender' drawn in area below the baseline. From this we can see that the 'A' draws from 3 pixels _before_ the caret (positioned at +20, but final image is at +17), to 70 - 3 or 67 pixels after the caret position. In other words this font is slightly wider than its horizontal bonding box, when drawn. Note that while this gives you the actual drawn string length, this is different to the caret offset needed when appending text, (which is defined by the strings bounding box, and not its drawn length). In other words text should be appended together using their bounding boxes, and not their actual drawn length size as we have do in other examples. Of course if you get a very ill-behaved font, you may like to check how far a specific string draws beyond its bounds so that you can still provide space for it, say at the end of a line. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The dimensions extracted from a font will also vary with the current "`[-strokewidth](https://imagemagick.org/script/command-line-options.php?#strokewidth) `" used for drawing the font. If you increase the size of the outline stroke, then the dimensions (and bounding box size) needed to draw the font is also expanded by the same amount to accommodate the thicker outline._ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Dimensions also vary with the operating system, (type and version) and the version of the delegate font drawing library IM is using on that system, even when the exact same font library and IM version has not changed. Caution is recommended when different computers could be used for text drawing, as results can vary even for the same font._ | For more information see the document [TrueType Fundamentals (PDF)](http://www.microsoft.com/typography/otspec/TTCH01.htm) . This shows that even my generalizations above may not always hold true, though is generally the case. Note the above examples will only return dimensions in whole pixels, where all the dimensions used by fonts are floating point numbers. In fact whether a font is even drawn from a whole pixel (caret) starting point, can be application dependant, and effect the resulting look of the font. * * * Creating Lines of Mixed Font Styles ----------------------------------- Creating a single line using multiple fonts, point sizes, and styles is not something IM is really designed to do. It gets even worse when you also start to consider things like text justification, word wrapping, and wrapping around images and other things. This is the sort of thing that programs like Word Processors, Web Browsers, Document Printers do very well, usually under user interaction, but few can do so well under program control. One exception to this is "`TeX`", and its family of programs (see [A Complete Text Processing System](#tex) below), so if you are serious about processing text graphically, I suggest you look at this program family. Another alternative is to look at various document 'pretty' printing programs such as a HTML converter. You can use these to magick program generated documents into postscript which IM can then happily post-process into whatever image format or style you want. An API solution (using the C MagickWand API interface) has been created by "El Supremo" (from the IM discussion forums) in his [FontMetrics](http://members.shaw.ca/el.supremo/MagickWand/fontmetrics.htm) program. and here is [Example Output of "FontMetrics"](http://members.shaw.ca/el.supremo/MagickWand/metric1.htm) . Now while IM command-line is not designed for 'word processing', it does not mean you can't use it for such. It is just more difficult. Here I will give some examples of mixing text in different fonts and styles, to give people a starting point. The simplest solution people usually think of is to just append "`[label:](../fonts/#label) `" images together... magick -font LokiCola -pointsize 36 label:'LokiCola ' \\ -font Candice -pointsize 24 label:'Candice ' \\ -font SheerBeauty -pointsize 48 label:'SheerBeauty' \\ +append wp\_label\_append.jpg [![[IM Output]](wp_label_append.jpg)](wp_label_append.jpg) However as you can see all the images are vertically aligned to the top of the image, and unless you use similar fonts, will not look very good. Alternatively, you can use an append justification trick to align them along the bottom. magick -size 1x50 xc:none +size \\ \\( -background white -font LokiCola -pointsize 36 \\ label:'LokiCola ' \\ -clone 0 +swap -background none -append \\) \\ \\( -background white -font Candice -pointsize 24 \\ label:'Candice ' \\ -clone 0 +swap -background none -append \\) \\ \\( -background white -font SheerBeauty -pointsize 48 \\ label:'SheerBeauty' \\ -clone 0 +swap -background none -append \\) \\ -delete 0 -gravity South -crop 0x50+0+0 +append \\ -bordercolor none -border 1 -trim +repage \\ -background white -flatten wp\_label\_bottom.jpg [![[IM Output]](wp_label_bottom.jpg)](wp_label_bottom.jpg) What this did was to add some extra padding to the top of each label, and cropping them all to the same height before appending them horizontally. After that a simple "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" and a "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" was used to set the height of the line to the highest label, and fill in the background. As you can see this produces a better job, but a small font tends to produce subscript like behaviour, rather than properly aligned text. What we really need to do is align all the text strings by their 'baselines' and that is very difficult without access to more textual information. This information is easily obtainable under a program API, but much more difficult from the command line. One method is shown in the previous example section. However it is possible to align words by their baseline without actually collecting baseline information. While "`[label:](../fonts/#label) `" text images do not provide any clue as to the images baseline, you can specifically draw images at a fixed baseline. Without an API you also can not directly find out how long or high drawn text is, so you first need to use a canvas that is large enough to ensure that we don't loose any information about text image. Then to preserve trailing spaces and text height you also have to make good use of the ("`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `") feature available to text annotation and provide a boundary for image trimming. So lets see how you can do it from the command line. magick -size 500x100 xc:none -fill blue -draw 'line 15,0 15,99' \\ -undercolor white -fill black \\ \\( -clone 0 -font LokiCola -pointsize 36 \\ -annotate +5+60 'Loki Cola ' \\) \\ \\( -clone 0 -font Candice -pointsize 24 \\ -annotate +5+60 'Candice ' \\) \\ \\( -clone 0 -font SheerBeauty -pointsize 48 \\ -annotate +5+60 'Sheer Beauty' \\) \\ -delete 0 -trim +repage +append \\ -transparent blue -trim +repage \\ -background white -flatten wp\_draw\_baseline.jpg [![[IM Output]](wp_draw_baseline.jpg)](wp_draw_baseline.jpg) As before the trimming of the images is done in two steps. First draw the text on a base image which contains a vertical blue line. Thus when we trim the text, only the width of the text image will be trimmed, leaving all the words at the same baseline height. After appending them together, we can now remove the blue construction line by making it fully-transparent. If you are generating just a black and white image, the better way would be to just extract one of the non-blue channels instead, which ensures you really do get all of the construction line. A second trim will then trim the top and bottom sections, shrinking it to the largest bounding box. A final flatten to the same color as the as the bounding box then removes all evidence of its use in constructing the line. As you can see all the text is now properly baseline aligned, regardless of the font or the pointsize used. Of course in these examples I only used black on white text. Other colors can be used, as long at they don't interfere with the construction line and transparent background used for text alignment. With this technique you can now generate mixed font text lines, and vertically append them all together into a larger document. You can also see that doing all this is a lot of work, work that is normally hidden from the user by word processors and web browsers. If you do plan to do a lot of this sort of stuff, I do suggest you look into the alternatives I previously mentioned. * * * Form Filling ------------ You have an image of some standard fill in form and you want to fill in the fields which are in well known positions. So you have a data file such as "`[text_data.txt](../images/text_data.txt) `" shown here... [![[IM Text]](text_data.txt.gif)](../images/text_data.txt) The fields are text width, gravity (justification), color, position x, y and the actual text to place for this field. Now you can use a simple looped shell script to generate a text label as described by the above, assigning the appropriate text in the defined text positions in a form (background) image. cat text_data.txt | while read width gravity color pointsize x y text do magick -size ${width}x -gravity $gravity -fill $color -background wheat \ -pointsize $pointsize -page +${x}+${y} label:"${text}" miff:- done | magick -size 200x100 xc: - -flatten text_layered.jpg [![[IM Output]](text_layered.jpg)](text_layered.jpg) The 'form image' in this case is just a blank image, but really could be anything. I also set the background color of the labels to 'wheat' so the area filled in is visible, but you would normally set this to none. The above does not use temporary files, but instead uses a pipeline of [MIFF](../files/#miff) format images. This is an example of using a [Image Streaming Format](../files/#miff_stream) , in which individual images are simply appended together, on after the other in a file or pipeline. This is only a starting point. The form fields can come from some definition file, while the text to fill in from a database or other data source. Other attributes can also be set such as the font to use, text rotations and so on. You could also include both width and height, or if the text should be word-wrapped using [Caption](#caption) should be used rather than a [Label](#label) . See also [Pins in a Map](../layers/#layer_pins) for another example of this technique, much like the above. * * * Text Processing Alternatives ---------------------------- The ideal way of generating fully formatted text files and documents is to use ImageMagick as part of a larger image and text processing system. | | | | --- | --- | | **Tool** | **used for...** | | ImageMagick | Image batch processing and preparations | | Gimp | GUI image editing for one off problem fixing | | | | LyX | GUI word processing, built to generate... | | LaTeX | Text processor for documents, and books... | | [TeX](http://en.wikipedia.org/wiki/TeX) | Underlying Text format
(positions symbols and fonts on pages) | | Metafont | TeX Font generator | Basically ImageMagick can do a lot of things, that does not mean it is the best tool for those things. For larger document preparations you are better off treating it as only one part of a larger whole. The various 'TeX' tools given above are usually a standard install for most Linux systems, and can combine text and images into an unified whole. More importantly it keeps text as text, and formats the text appropriately, as you specify, doing almost all the hard work of word and page wrapping, and arrangement with the images. But without filling a 'doc' file with useless formatting garbage. You have full control, or can leave it to make the decisions. They provides a way of generating any type of document, from a simple page, newsletter or even a full book If you are serious about document generation, then these tools are well worth looking at and learning. Pango (Linux and MacOSX only) also provides an alternative. It provides many text to image processing features not available in ImageMagick. For example TABs, justification, margins, headers, and so on. It even has a markup language of some kind to allow font changes in the middle of text. Other solutions also include the many text to postscript conversion programs, such as "a2ps" which I demonstrate in generating an example postscript file in [Postscript Handling](#postscript) above. This converts and formats may different types of text files, with word wrapping, bolding and tab control, as well as a reasonably nice header, footer, border, and multi-page options. Of course this is indirect image processing via a [Postscript or PDF](../formats/#ps) intermediate language. Another is to layout the text using SVG, or the ImageMagick [Drawing Command](../draw/#draw) , though you will then need to deal with the layout. There are lots of tools out there to magick text into images, and most can be combined with ImageMagick to post-process the text image and merge it into your image. This lets ImageMagick get on with what it does best, image processing. * * * --- # Animation Optimization -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Animation Optimization ========================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Introduction to Optimization](#intro) [![](../img_www/granitesm_right.gif)General Purpose GIF Optimizer of ImageMagick](#optimize) [![](../img_www/granitesm_right.gif) Frame Optimization](#frame_opt) * [Basic Frame Optimization](#optframe) * [No Pixel Overlay](#repeated_frame) - repeated image every second frame * [Moving Hole Animation](#hole) - a difficult to frame optimize animation * [Frame Doubling](#doubling) * [Layer Optimize Plus](#optimizeplus) * [Remove Duplicate Frames](#removedups) * [Splitting Frame Updates](#splitting) * [Remove Zero Delay Frames](#removezero) * [Frame Optimization Results and Summary](#frame_results) [![](../img_www/granitesm_right.gif) Semi-Transparency Handling](#semitrans_opt) [![](../img_www/granitesm_right.gif) Color Optimization](#color_opt) * [GIF Color Problem](#color_problem) * [Speed Animation](#speed) - an animation with too many colors * [Frame Opt Before Color Opt?](#color_frame_first) * [Fuzzy Color Optimization](#color_fuzz) * [Single Global Color Table](#colortables) * [Dithering Colors](#dithering) [![](../img_www/granitesm_right.gif) Compression Optimization](#compress_opt) * [Transparency Optimization](#opt_trans) * [LZW Optimization](#opt_lzw) * [Lossy LZW Optimization \- (non-IM)](#opt_lzw_lossy) * [Ordered Dithered LZW Optimization](#opt_lzw_dithered) [![](../img_www/granitesm_right.gif) Minor Optimizations](#minor_opt) [![](../img_www/granitesm_right.gif)Other Sources of Information on GIF Optimization](#gif_links) These examples start to make use of the [Basic Animation Handling](../anim_basics/) , to try to optimize the final display and file size of an animation. This is especially important for complex GIF animations where smaller sub-frame overlays can be used, as well as three types of disposal methods controlling how an animation is handled. * * * Introduction to Animation Optimization -------------------------------------- Optimizing an animation is not easy, especially a GIF animation that has color restrictions, as well as a choice of different frame disposal techniques, and the ability to use smaller 'sub-frame' overlays from one frame to the next. When optimizing animation you should try to optimize them in the following order. * [Minor Optimizations](#minor_opt) * [Semi-Transparency Handling](#semitrans_opt) * [Color Optimizations](#color_opt) * [Frame Optimizations](#frame_opt) * [Compression Optimizations](#compress_opt) * [Single Global Color Table](#colortables) That however is not the order we will look at these optimization techniques. For GIF animations [Frame Optimization](#frame_opt) is the most basic optimization technique, and where the most gains can be made. As such it will be looked at first. Probably the hardest aspect of optimization that users have trouble with is [Color Optimizations](#color_opt) caused by the color limitations of the GIF animations. One aspect of this [Single Global Color Table](#colortables) has to be done as a the last step before saving to GIF or you may loose the operators effect on the final GIF file save. * * * General Purpose GIF Optimizer of ImageMagick -------------------------------------------- The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`**Optimize**`' will use a number of the techniques, that we will discuss in detail below, to attempt to optimize a GIF animation in a single reasonable step. Currently this option is equivalent to (in order)... * A [Coalesce](../anim_basics/#coalesce) the Animation. * Basic [Frame Optimization](#optframe) * and [Transparency Optimization](#opt_trans) At which point you can immediately save the GIF animation. These are reasonably safe optimization steps that can be applied to most animation sequences, however there is no guarantee, that it will result in a smaller GIF animation. This is particularly true of an raw video sequence where a [Transparency Optimization](#opt_trans) will generally result in a worsening of the LZW compression ratio. However for most GIF animations, involving cartoon like images, the '`Optimize`' operator should produce a good well optimized animation. The operator however is still in development, and in future is likely to also include extra standard optimization steps, such as... * A 50% Threshold of the alpha channel, just as the IM does normally does when saving to the GIF file format, to remove semi-transparent pixels. You can still do the semi-transparency handling yourself before hand to override this, if you like. See [GIF Boolean Transparency](../formats/#boolean_trans) for more detail. * Some type of [Color Optimization](#color_opt) technique. Exactly what, is still to be decided, and may be selected depending on the animation and the number of colors involved. _Suggestions Welcome_. * A [Single Global Color Table](#colortables) , "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" operation. In other words, it is hoped that '`Optimize`' will eventually become the IM generic GIF animation optimizer, for quick and easy use by IM users. Until then be careful of its use, especially in scripts as it will change. Of course as many optimization steps may not be worth the effort for a specific animation. This option will also likely become quite slow. This is the plan, and the goal that this IM Examples section, was looking toward. * * * Frame Optimizations ------------------- Frame optimization is based on overlaying a smaller sub-image rather than a complete overlay of the whole image. This obviously produces a smaller number of pixels and thus a smaller file on disk, to being sent across the network. Also overlaying a smaller frame means the client computer does not have to do as much work in changing pixels on screen. However there are different disposal methods available in the GIF format to handle the last frame displayed, and that can result in different size overlays. Not only that but it is possible to split up the overlays into multiple parts, or update actions, bring about a more complex but more optimized animation. Because of the complexity of doing frame optimizations, any existing frame optimizations are typically always removed first by using "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operation. See [Coalesce Examples](../anim_basics/#coalesce) . Naturally that means any hand optimizations that may have existed are also removed, so some caution is advised. ### Basic Frame Optimization The "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" method will produce a basic frame optimization for a GIF animation. However as was shown in the [Deconstruct Examples](../anim_basics/#deconstruct) of the previous section, this operator does not work with all GIF animations when transparent pixels are involved. Specifically when an animation clears any colored pixel to transparency. That is, it will only work with [Overlay Animations](#overlay) . The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`**OptimizeFrame**`' is designed to be a GIF Frame Optimizer, which will try to find the smallest sub-frames overlay images, using any GIF disposal method. The result is generally a [Mixed Disposal Animation](#mixed) though often it will also generate a [Cleared Frame Animations](#clear) or [Pure Overlay Animations](#overlay) , if that was determined to be the best solution for the specific animation. Remember the input animation must be a '_coalesced animation_', so it consists of a sequence of complete image frames, all the same size, without any canvas offsets. Of course any existing dispose methods in coalesced animation is completely irrelevant, and will be ignored by the '`OptimizeFrame`' method. For example, lets try this with a [Dispose Previous Animation](../anim_basics/#previous) , created in the previous section. magick canvas\_prev.gif -coalesce -layers OptimizeFrame optframe.gif gif\_anim\_montage optframe.gif optframe\_frames.gif [![[IM Output]](optframe.gif)](optframe.gif) [![[IM Output]](../anim_basics/coalesce_frames.gif)](../anim_basics/coalesce_frames.gif) ![==>](../img_www/space.gif) ![==>](../img_www/right.gif) [![[IM Output]](optframe_frames.gif)](optframe_frames.gif) As you can see "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) OptimizeFrame`' correctly returned our animation back into its original frame optimized form, using [Previous Disposal](../anim_basics/#previous) . This optimization even works properly for the trickier to handle [Background Dispose Animations](../anim_basics/#background) ... magick canvas\_bgnd.gif -coalesce -layers OptimizeFrame optframe\_bgnd.gif gif\_anim\_montage optframe\_bgnd.gif optframe\_bgnd\_frames.gif [![[IM Output]](optframe_bgnd.gif)](optframe_bgnd.gif) [![[IM Output]](optframe_bgnd_frames.gif)](optframe_bgnd_frames.gif) The animation is perfectly frame optimized using [Background Disposal](../anim_basics/#background) . This operator will work correctly for all GIF animations, and will generally return the best possible simple 'dispose and frame optimization' possible. Now for some bad news about any type of simple frame optimization, such as what IM provides... While '`[OptimizeFrame](#optframe) `' returns the best possible frame optimization for a given animation that IM can figure out, there are is a number of special cases where it does not do well. These include... * Animations where pixel clearing (returning to transparency) is needed, but the frame overlays are too large to efficiently clear the small areas of pixels that needs to be cleared (see the [move hole animation](#hole) below). * Animations involving two or more small areas of change that are distantly separated. These are actually quite common, and horrible to frame optimize. (See [Splitting Frame Updates](#splitting) below) * Animations with very complex backgrounds that remain static for long periods (more than 3 frames), but then change slightly before remain static for another long period, etc., etc., etc... Or a static background that becomes greatly obscured for a very short period. It can be near impossible for any computer algorithm to figure out the 'best' frame optimization in this complex situation (IE: What should be regarded as a static background?). Only humans with their intuitive grasp on what they see, can generate a good optimally frame overlay sequence in these cases. _Examples of difficult to optimize animations wanted, please contribute._ If you find an example of an animation which IM fails to produce a good optimization, please mail it to me for further study. This is how new techniques and possible automatic solutions can be developed. I will naturally publish your name as a contributor. ### No Pixel Overlay \- repeated image every second frame [![[animation]](../images/paddleball.gif)](../images/paddleball.gif) Sometimes the best optimization for an image involves not overlaying any pixels at all! For example to the right is a simple animation, contributed by nixscripter. If we look at its frames you can see it is not very optimized. But notice that every second frame of the animation is simply repeated. gif\_anim\_montage paddleball.gif paddleball\_frames.gif [![[IM Output]](paddleball_frames.gif)](paddleball_frames.gif) After frame optimizing it we get a very special GIF disposal sequence. magick paddleball.gif -coalesce -layers OptimizeFrame paddleball\_opt.gif gif\_anim\_montage paddleball\_opt.gif paddleball\_opt\_frames.gif [![[IM Output]](paddleball_opt.gif)](paddleball_opt.gif) [![[IM Output]](paddleball_opt_frames.gif)](paddleball_opt_frames.gif) What is happening is that rather than overlaying the original frame IM chose to recover the first image using a '[Previous](../anim_basics/#previous) GIF disposal. As that recovered frame is left as is, there are no changed pixels. So the sub-frame overlay gets reduced nothing. Unfortunately, neither IM or the GIF format allow you have a zero sized image, so a special one transparent pixel minimal image is used instead. This image is known as a [Missed Image](../crop/#crop_missed) as it is also extensively used when "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" 'misses' the actual image data, producing the same result. This image, in effect, only preserves the frames meta-data, such as: [Dispose Method](../anim_basics/#dispose) , [Time Delay](../anim_basics/#delay) , and [Loop Iterations](../anim_basics/#loop) . As such it is an essential part of the animation, even though it is 'empty'. So by overylaying a bare minimal single transparent pixel, IM saved a huge amount of space (and time) in this animation. ### Moving Hole Animation \- difficult to frame optimize Here is one extreme case of GIF animation that does not frame optimize very well by any normal optimization method. This animation basically consists of a simple unchanging background image but with a transparent 'hole' through that background that changed position from frame to frame. To create it I need to make a coalesced image sequence, where I cut up a hole in a fixed background image, using [Layer Alpha Composition](../anim_mods/#compose) . I also used a "`[+antialias](https://imagemagick.org/script/command-line-options.php?#antialias) `" switch to ensure only four colors are used three blues and the transparency. So we don't need to deal with [Color Optimization Problems](#colors) . magick +antialias -size 100x100 -delay 100 xc:SkyBlue -loop 0 \\ -fill DodgerBlue -draw 'circle 50,50 15,25' \\ -fill RoyalBlue -draw 'circle 50,50 30,25' \\ null: \\( -size 100x100 xc:none -draw 'circle 40,25 27,22' \\) \\ \\( +clone -rotate 90 \\) \\( +clone -rotate 90 \\) \\ \\( +clone -rotate 90 \\) -compose DstOut -layers Composite \\ -set dispose background moving\_hole.gif gif\_anim\_montage moving\_hole.gif moving\_hole\_frames.gif [![[IM Output]](moving_hole.gif)](moving_hole.gif) [![[IM Output]](moving_hole_frames.gif)](moving_hole_frames.gif) As you can see the animation works, with a round 'hole' showing the background color of this page, producing an animation file of [![[IM Text]](moving_hole_size.txt.gif)](moving_hole_size.txt) bytes in size. So lets try a straight-forward frame optimization for this animation. magick moving\_hole.gif -layers OptimizeFrame moving\_hole\_opt.gif gif\_anim\_montage moving\_hole\_opt.gif moving\_hole\_opt\_frames.gif [![[IM Output]](moving_hole_opt.gif)](moving_hole_opt.gif) [![[IM Output]](moving_hole_opt_frames.gif)](moving_hole_opt_frames.gif) Hang on, nothing happened! The best optimization IM could achieve was no change at all! Is the above coalesced version of this animation its most optimal? Well for the animation as it stands... Yes, this really is the best simple optimization that can be achieved by pure frame disposal optimization! Not good. The problem is that for a GIF animation to 'clear' or 'erase' the pixels drawn by previous frames, it needs to use a '[Background](../anim_basics/#background) ' dispose method. Though in some special situations a '[Previous](../anim_basics/#previous) ' dispose method can also be used. However '[Background](../anim_basics/#background) ' dispose only can clear areas that were just overlaid. As the first frame was a complete overlay of the whole image, the whole image will be cleared. Even though only a small section of the animation needs to have its pixels cleared. As a consequence the whole of the second frame needs to be overlaid, even though most of that frame was just previously displayed! This horrible catch-22 situation continues all the way across the rest of the animation, producing no basic frame optimizations. I did say this animation would be difficult to frame optimize. ### Frame Doubling \- a method to frame optimize 'holes' All is not lost however. By adding some extra frames to the animation, you can give the '`[OptimizeFrame](#optframe) `' method some room in which to make better use of the GIF disposal methods available. Here for example we add an extra frame by doubling up the first image, but giving it a zero time delay so as not to change the overall timings of the animation. magick moving\_hole.gif\[0\] -set delay 0 moving\_hole.gif \\ -layers OptimizeFrame moving\_hole\_dup.gif gif\_anim\_montage moving\_hole\_dup.gif moving\_hole\_dup\_frames.gif [![[IM Output]](moving_hole_dup.gif)](moving_hole_dup.gif) [![[IM Output]](moving_hole_dup_frames.gif)](moving_hole_dup_frames.gif) By doubling the first frame the animation was now reduced from [![[IM Text]](moving_hole_size.txt.gif)](moving_hole_size.txt) bytes down to [![[IM Text]](moving_hole_dup_size.txt.gif)](moving_hole_dup_size.txt) bytes in size. So even though the animation now has five frames, it is now much smaller in overall size, because of the massive reduction in the size of the sub-frame image overlays. Doubling essentially separates the pixel clearing function of the dispose method, from the pixel overlaying function performed by the next frame. Both the dispose and the overlay are done as part of the same frame update by GIF animation programs, so no loss of speed or quality should be noticeable. This is a complex and tricky technique, and one that is rarely seen or understood by GIF animation designers or GIF optimization programs, but its benefits are well worth it then it is needed. However the reduction in sub-frame image sizes only lasts for a short time, as later frames having to also clear out pixel for the next frame, so the frames become large again to continue to clear out later pixels. That is, because pixel clearing always result in larger frames, never smaller. So lets try and double _all_ the frames (except the last which never needs doubling) to see how that affects the final image... magick moving\_hole.gif \\( -clone 0--1 -set delay 0 \\) \\ +delete -insert 2 -insert 1 -insert 0 \\ -layers OptimizeFrame moving\_hole\_double.gif gif\_anim\_montage x2 moving\_hole\_double.gif moving\_hole\_double\_frames.gif [![[IM Output]](moving_hole_double.gif)](moving_hole_double.gif) [![[IM Output]](moving_hole_double_frames.gif)](moving_hole_double_frames.gif) As you can see while we have almost twice as many frames, all the image sizes are much smaller, producing an animation that is [![[IM Text]](moving_hole_double_size.txt.gif)](moving_hole_double_size.txt) bytes in size, a smaller result, though not nearly as big a saving as the first single frame doubling we performed. So that you can follow what is happening, the '`[Background](../anim_basics/#background) `' frame is an exact duplicate of the previous frame, making no change to what is being displayed. However, it defines the area of the animation that needs to cleared before the next frame image is overlaid. The following '`[None](../anim_basics/#none) `' frame then fills in the pixels that need to be changed, as well as the pixels that the previous frames disposal also cleared. In the above animation that means the pixels that was needed to shape the new hole, and well as the pixels that was used to fill-in the previous 'hole'. The result is smaller but not nearly as much, as adding extra frames does have its own cost. At least each of the added frames also does not have its own color table, or this animation would have in fact become larger, due to the size of the extra color tables! ### Layer Optimize Plus \- Automatic frame doubling Optimization I am please to say that as of version 6.2.7, IM can now do frame doubling optimization automatically, as part of its normal frame optimization handling. However as adding frames to make an animation smaller is so radical a move, it was given its own separate "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`**OptimizePlus**`'. For example, lets get IM to do the frame doubling optimization... magick moving\_hole.gif -layers OptimizePlus moving\_hole\_oplus.gif gif\_anim\_montage x2 moving\_hole\_oplus.gif moving\_hole\_oplus\_frames.gif [![[IM Output]](moving_hole_oplus.gif)](moving_hole_oplus.gif) [![[IM Output]](moving_hole_oplus_frames.gif)](moving_hole_oplus_frames.gif) That is, IM gave you the same result as our previous frame doubling example. Thus the GIF file is still [![[IM Text]](moving_hole_oplus_size.txt.gif)](moving_hole_oplus_size.txt) bytes in size. However '`OptimizePlus`' will only frame double if the number of pixels in the current and next frame of the resulting animation (3 frames) is reduced, so we can let IM decide whether to frame double or not. As "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`[OptimizePlus](#optimizeplus) `' adds extra frames as it creates an frame optimized GIF animation, it also will remove any unneeded or extra frames that make no change to the final animation (merging delay times as appropriate). That is, it will also do an automatic '`[RemoveDups](#removedups) `' (see next). The '`[OptimizeFrame](#optframe) `' method will not do this. ### Remove Duplicate Frames \- merging consecutive duplicate images Unfortunately if you [coalesce](../anim_basics/#coalesce) " this animation, you will also get all the extra frames that the above added. magick moving\_hole\_oplus.gif -coalesce gif:- |\\ gif\_anim\_montage x2 - moving\_hole\_oplus\_cframes.gif [![[IM Output]](moving_hole_oplus_cframes.gif)](moving_hole_oplus_cframes.gif) To let you remove such useless duplicate frames from a coalesced animation, a '`**RemoveDups**`' method has been provided. This compares each frame with the next frame in the animation, and removes the first frame if they are identical (with color similarity set by the current [Fuzz Factor](../color_basics/#fuzz) ). Also to ensure that any timings in the animation are not lost, the [Timing Delays](../anim_basics/#delay) of the two frames are also merged. For example.. magick moving\_hole\_oplus.gif -coalesce -layers RemoveDups gif:- |\\ gif\_anim\_montage - moving\_hole\_oplus\_rmdups\_frames.gif [![[IM Output]](moving_hole_oplus_rmdups_frames.gif)](moving_hole_oplus_rmdups_frames.gif) And we now have our original coalesced form of the animation. For another method of removing the extra frames see the '`[RemoveZero](#removezero) `' method below. ### Splitting Frame Updates \- separately updating two distant changes As you have seen with frame doubling, by separating the 'clearing of pixels' from the overlaying of new pixels, we can reduce the overall size of a single frame overlay. However this animation still produces some very large overlays, which mostly consist of pixels that don't actually change from one frame to the next. That is, the main overlay frame is only updating two rather small areas that are quite distant from each other thereby producing a single large overlay image. Rather than trying to update both changes simultaneously while will also includiing all those the unchanged pixels in-between the two area, we instead update each area separatally. That is, we _split the frame update into two phases_, one for each of the separated areas that changed. In this case we can fill in the hole first, then create the new hole as a separate update.It does not actually matter (except with possible regard to disposals) which of the two separate changes happen in which order, but you should try to be logical about it. It may also be that one change is easier to create than another. For example, here I insert extra frames to fill in the old hole as a separate update to the 'digging' of the new hole. This is the easier intermediate frame to generate as well as the most logical ordering of actions. Of course you do not need to do this for the last frame, as that frame is just junked before the animation loops. magick moving\_hole.gif \\ \\( +antialias -size 100x100 -delay 0 xc:SkyBlue \\ -fill DodgerBlue -draw 'circle 50,50 15,25' \\ -fill RoyalBlue -draw 'circle 50,50 30,25' \\) \\ \\( +clone \\) -insert 1 \\( +clone \\) -insert 3 +swap \\ -set dispose background moving\_hole\_split.gif gif\_anim\_montage x2 moving\_hole\_split.gif moving\_hole\_split\_frames.gif [![[IM Output]](moving_hole_split.gif)](moving_hole_split.gif) [![[IM Output]](moving_hole_split_frames.gif)](moving_hole_split_frames.gif) Remember the added intermediate frame is different from the surrounding user displayed frames (the ones with a non-zero time delay). This is not simple 'frame doubling', but the separating two distant small changes. This addition of intermediate frames is not a simple step that can be automated. Although it is possible that a smart heuristic could be developed to generate these intermediate frames, it is not always obvious what should be done, let alone if it should be done. _If you like to try to generate such an heuristic, please mail me._ So lets try a standard frame optimization after adding these extra frames... magick moving\_hole\_split.gif \\ -layers OptimizeFrame moving\_hole\_split\_opt.gif gif\_anim\_montage x2 moving\_hole\_split\_opt.gif \\ moving\_hole\_split\_opt\_frames.gif [![[IM Output]](moving_hole_split_opt.gif)](moving_hole_split_opt.gif) [![[IM Output]](moving_hole_split_opt_frames.gif)](moving_hole_split_opt_frames.gif) The addition of these 'zero delay intermediate frames', allows this animation frame optimize better than the original unoptimized animation, producing a [![[IM Text]](moving_hole_split_opt_size.txt.gif)](moving_hole_split_opt_size.txt) byte animation. However for this specific case it isn't as good as using an automated [Frame Doubling](#double) technique (See the '[OptimizePlus](#optimizeplus) ' layers method above). However adding 'zero delay intermediate frames' does not stop you from also doing that 'frame doubling' technique as well... magick moving\_hole\_split.gif \\ -layers OptimizePlus moving\_hole\_split\_oplus.gif gif\_anim\_montage x2 moving\_hole\_split\_oplus.gif \\ moving\_hole\_split\_oplus\_frames.gif [![[IM Output]](moving_hole_split_oplus.gif)](moving_hole_split_oplus.gif) [![[IM Output]](moving_hole_split_oplus_frames.gif)](moving_hole_split_oplus_frames.gif) This animation now has two extra 'zero delay intermediate frames' per frame update. The first fills in the old hole, the second clearing an area that will contain transparent pixels, before finally the pixels that should not have been cleared is restored. The result is the most optimal frame optimization possible for this specific problem animation, resulting in [![[IM Text]](moving_hole_split_oplus_size.txt.gif)](moving_hole_split_oplus_size.txt) bytes in the final file size. That is, our 4 frame animation was made smaller, by adding 6 extra zero time delay frames! More than double the original number of frames. Weird but true! Of course it would also be nice if GIF animation programs actually recognise [Zero Delay Intermediate Frames](../anim_basics/#zero) for what they are, namely, intermediate updates between the real frames of the animation. But even so when the updates are highly separated, and very small, the slight pause caused by the extra frames is rarely visible. Of course, if the two separated parts of the animation are not actually related, then they do not need to be time synchronized. Another alternative is that instead of adding extra frames, to split the animation to two completely separate animations that you can displaying together on a web page. See [Splitting up an Animation](../anim_mods/#split) . This particular animation however cannot be split up into separate time disjoint animations. First the distant changes need to be time synchronised. and second the four areas that do change, overlap in both the horizontal and vertical directions. This means a simple HTML 'table' cannot rejoin the sub-animations into a complete whole, without some type of CSS trickery. _Can you prove me wrong?_ _FUTURE: reference to a better example of animating 'two distant objects'. in 'Animation Handling', say involving two separately moving objects._ ### Remove Zero Delay Frames \- removing intermediate updates Of course sometimes you are not interested or want to remove these added intermediate frames from an animation, leaving just the frames that will actually be shown to an user for some period of time. You can't just [coalesce](../anim_basics/#coalesce") the animation and use the '`[RemoveDups](#removedups) `' method as not all 'Intermediate Frames' are similar to the surounding frames, and are thus not duplicates. However as these types of frame have a [Zero Time Delay](../anim_basics/#zero) you can use another special "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method, '`**RemoveZero**`' which will remove any frame that has a zero time delay. This same method will also remove the frames added using [Frame Doubling](#double) and '`[OptimizePlus](#optimizeplus) `' techniques as well. For example... magick moving\_hole\_split\_oplus.gif -coalesce -layers RemoveZero gif:- |\\ gif\_anim\_montage - moving\_hole\_split\_rmzero\_frames.gif [![[IM Output]](moving_hole_split_rmzero_frames.gif)](moving_hole_split_rmzero_frames.gif) Which again returns the animation back to just the user viewable frames, simplifying the animation. Of course after removing [Zero Delay Intermediate Frames](../anim_basics/#zero) , it is very difficult to re-add them as the change information is contained is lost. Consequentially the animation may not frame optimize very well afterward. Optimization is one of the main purposes of such frames after all. ### Frame Optimization Results and Summary Lets summarize our optimizations of the moving hole animation... [![[IM Text]](moving_hole_sizes.txt.gif)](moving_hole_sizes.txt) As you can see by using some complex frame handling, with the help of IM and some human intervention, we were able to frame optimize the 'moving hole' animation to almost half its original size, though with just under three times the number of frames of the original. Of course results can vary greatly from animation to animation, but the techniques we used for frame optimization are the same. It just needs a little care and fore-thought, which humans are good at, and computers are not. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _There is the point, that IM should not only account for the number of pixels in current set of frames being looked at, but also the overall size of the extra frame added, and perhaps the overall compression results obtained, when making the decision about how to frame optimize the image.

On the other hand IM also does not look at the resulting savings in the number of pixels that may result, beyond the frames that are directly involved. That is, later frames sizes may also be smaller as a result of frame doubling, or the disposal method used. This is especially true when the choice is whether to use 'previous image dispose' method, which can have substantial pixel count reductions later in an animation sequence, rather than immediately in the very next frame. A good choice here often requires human input.

As such I can make no guarantee that IM will produce the best optimization choices, for a specific animation. However it certainly gives it a good try, without the use of recursion, to make that choice. That is, only using immediate pixel counts for its decision.

A recursive algorithm, one that makes a choice, then see what the best final size of the animation that results from that choice, (including recursive choices further along) can produce a guaranteed best optimization. However it could also be an extremely slow operator, and for a large animation could take years to make the final decision. It would also need to include [compression optimization](#compress_opt")
choices, as these could effect the final outcome. In other words, while such an algorithm could guarantee the best optimization, it does so at a heavy computational cost.

Of course a human being with an intimate knowledge of what the animation is trying to achieve, will generally do better in complex animations, as you saw above with [splitting frame updates](#splitting)
.

If you would like to try an create a recursive GIF optimization operator please do. I will help in any way I can. It would beat just about every other GIF optimization program on the market. Also most GIF animation developers will probably be very grateful of your efforts (money-wise)._ | * * * Semi-Transparency Handling -------------------------- The GIF file format does not allow the use of semi-transparent pixels (See [GIF Boolean Transparency](../formats/#boolean_trans) ). This is a fact, and before you can properly optimize an animation, or even save it to GIF format, you need to handle any semi-transparent pixels that may be present, in a way that is suitable for the animation. By default if you don't handle these pixels, IM will use a 50% threshold to magick these pixels into either fully-transparent or fully-opaque. However that may not be the best way to handle the problem, particularly in images that contain large areas of semi-transparent pixels, such as shadow effects. For example, I wanted to create a Stargate Asgard Teleport animation that could take just about any sub-image as the object being teleported. magick -channel RGBA -fill white \\ \\( medical.gif -repage 100x100+34+65 -coalesce -set delay 200 \\) \\ \\( +clone -motion-blur 0x20+90 -blur 0x3 -colorize 100% \\ +clone -colorize 30% +swap -composite -set delay 10 \\) \\ \\( +clone -roll +0-20 -blur 0x3 -colorize 30% \\ -motion-blur 0x15+90 -motion-blur 0x15-90 -set delay 10 \\) \\ \\( +clone -colorize 30% \\ -motion-blur 0x30+90 -blur 0x5 -crop +0+10\\! \\) \\ \\( +clone -motion-blur 0x50+90 -blur 0x2 -crop +0+20\\! \\) \\ \\( +page -size 100x100 xc:none -set delay 200 \\) \\ -set dispose background -coalesce -loop 0 teleport.miff gif\_anim\_montage teleport.miff teleport\_frames.png [![[IM Output]](teleport_frames.png)](teleport_frames.png) I purposely left the animation in the IM internal MIFF: file format as this ensures that the original image is preserved without modification, and used a PNG: file format to display the frames so that you can see all the semi-transparent pixels contained in it! This is not only important for animations with semi-transparent pixels, but also ones with lots of colors. Once the image sequence has been saves into GIF, your chances of generating a good color optimization goes from good, to difficult.Okay I have an animation sequence. If I attempt to save this directly as GIF, IM will just threshold all those semi-transparent pixels. magick teleport.miff teleport\_thres.gif gif\_anim\_montage teleport\_thres.gif teleport\_thres\_frames.gif [![[IM Output]](teleport_thres.gif)](teleport_thres.gif) [![[IM Output]](teleport_thres_frames.gif)](teleport_thres_frames.gif) The result doesn't really look anything like what we wanted. The default 50% transparency handling makes the animation look like a look like a shrinking 'egg'. Definitely not what I want to achieve with this animation.. If this type of transparency handling is acceptable this is the way to apply it, before continuing with your other optimizations... magick teleport.miff -channel A -threshold 50% +channel \\ ...do further processing now... teleport.gif An extra advantage of using the above DIY, is that you can control the threshold level. Say '`10%`' to remove almost every semi-transparent pixel present, to '`90%`' to make them all opaque. magick teleport.miff -channel A -threshold 90% +channel teleport\_thres90.gif gif\_anim\_montage teleport\_thres90.gif teleport\_thres90\_frames.gif [![[IM Output]](teleport_thres90.gif)](teleport_thres90.gif) [![[IM Output]](teleport_thres90_frames.gif)](teleport_thres90_frames.gif) But applying a threshold for animations, like this one, is not a good solution, as it really spoils the transparency effect I am trying to achieve.The best overall solution to preserving all the special effects in the above animation is to just [Add a Solid Color Background](../anim_mods/#flatten) . magick teleport.miff -bordercolor skyblue \\ -coalesce -border 0 teleport\_bgnd.gif gif\_anim\_montage teleport\_bgnd.gif teleport\_bgnd\_frames.gif [![[IM Output]](teleport_bgnd.gif)](teleport_bgnd.gif) [![[IM Output]](teleport_bgnd_frames.gif)](teleport_bgnd_frames.gif) This removes ALL the transparency from the animation, but at the cost of only allowing the animation to work on specific background color. But if you are creating the animation for a specific web page, that may be quite acceptable. Note however for images with sharp outlines, using a dither pattern like this can produce a 'dotty' outline to the sharp edges. As such, it is not recommended for the general case. The other solution is to try and generate some pattern of transparent and opaque pixels so as to try and preserve the images semi-transparency. And for this IM offers a large range of dithering options that can solve this problem. _FUTURE: some link to a to be created section on transparency dithering, such as [Quantization and Dithering](../quantize/#color_trans) ._ Note that the obvious first solution of using a [Monochrome Dithering](../quantize/#monochrome) of the alpha channel is not simple, probably requiring some advance [Multi-Image Composition](../anim_mods/#composite) to do correctly.A simple solution is to use a [Diffused Pixel Ordered Dither](../quantize/#ordered-dither) technique, which can be restricted to just the alpha channel, to remove the semi-transparent pixels. magick teleport.miff -channel A -ordered-dither o8x8 teleport\_od.gif gif\_anim\_montage teleport\_od.gif teleport\_od\_frames.gif [![[IM Output]](teleport_od.gif)](teleport_od.gif) [![[IM Output]](teleport_od_frames.gif)](teleport_od_frames.gif) The result is reasonable, but looks like a dissolving object than teleporting.Using a [Halftone](../quantize/#halftone) will produce a much nicer effect by making the transparency pattern bolder. magick teleport.miff -channel A -ordered-dither h8x8a teleport\_htone.gif gif\_anim\_montage teleport\_htone.gif teleport\_htone\_frames.gif [![[IM Output]](teleport_htone.gif)](teleport_htone.gif) [![[IM Output]](teleport_htone_frames.gif)](teleport_htone_frames.gif) But for this specific animation, I found that using a [User Designed Dither Map](../quantize/#thresholds_xml) to produce vertical lines (from a horizontal line dither pattern) produces an effect that enhances the teleporting animation while removing semi-transparent pixels. magick teleport.miff -rotate 90 \\ -channel A -ordered-dither hlines -rotate -90 teleport\_lines.gif gif\_anim\_montage teleport\_lines.gif teleport\_lines\_frames.gif [![[IM Output]](teleport_lines.gif)](teleport_lines.gif) [![[IM Output]](teleport_lines_frames.gif)](teleport_lines_frames.gif) So as you can see there are quite a number of possibilities to handling the semi-transparency in a GIF animation. * * * Color Optimization ------------------ Handling semi-transparent pixels is only the first limitation of the GIF file format. The next one is a 256 color limit for each color table in the animation. You are allowed to have a separate color table for each frame. This means a single animation can have more than 256 colors. However, even that may not always be a good idea. If you just like a quick summary of the color optimization options available, I suggest you jump to the examples on [Video to GIF](../video/#gif) conversion where the color problems of an animation is at its worst. ### GIF Color Problem GIF animations in particular have problems in handling colors, as you it first does not allow semi-transparent colors, then has a 256 color limit per frame, or a 256 global color limit. Finally your best frame optimization will not work very well unless the colors used for a pixel in one frame also match the same color, in the next frame, when that part of the image did NOT change! This may seem like an easy problem but [Color Reduction](../quantize/#intro) is itself an extremely complex field, which required its own full section in IM Examples. Color problems are actually why most GIF animations you find on the World Wide Web are of the cartoon variety, or are very bad looking. Especially if resized from a larger version of the animation. In [Resizing Animations](../anim_mods/#resize) will probably require more effort in color optimization, than in the actual resize process itself. Here I will assume you have the original source of the animation. But that is not always possible, so if you are optimizing a modified GIF animation, some extra caution may be needed. However if you have an animation with to many colors, the first thing you need to remember is... **Do not save directly to GIF format, use the MIFF file format,   OR   separate PNG images.** As soon as you save to GIF, you have lost control of your GIF color optimization efforts, and you probably have a very bad looking GIF animation that will not optimize very well using various [Frame Optimization](#frame_opt) techniques. ### Speed Animation \- an Animation with too many colors First we need to generate a GIF animation with a vast number of colors, so that we can really test out the problems involved in color optimization. magick -dispose none -channel RGBA \\ \\( medical.gif -repage 100x60+5+14 -coalesce -set delay 100 \\) \\ \\( medical.gif -repage 100x44+34+6 -coalesce -set delay 10 \\ -motion-blur 0x12+0 -motion-blur 0x12+180 -wave -8x200 \\) \\ \\( medical.gif -repage 100x60+63+14 -coalesce -set delay 100 \\) \\ \\( medical.gif -repage 100x44+34+6 -coalesce -set delay 10 \\ -motion-blur 0x12+0 -motion-blur 0x12+180 -wave +8x200 \\) \\ null: \\( +page -size 120x15 xc:SkyBlue xc:RoyalBlue \\ -size 120x70 gradient:SkyBlue-RoyalBlue \\ +swap -append -blur 0x3 -background white -rotate -25 \\ \\) -gravity center -compose DstOver -layers Composite \\ -loop 0 speed.miff magick speed.miff speed.gif gif\_anim\_montage speed.gif speed\_frames.gif [![[IM Output]](speed.gif)](speed.gif) [![[IM Output]](speed_frames.gif)](speed_frames.gif) Note that I did not save the animation directly to the GIF format but saved it in a MIFF format file, "`[speed.miff](speed.miff) `" first. This preserves all aspects of the originally created (or modified) animation, including GIF meta-data, timing delays, as well as all the colors of the image without distortion. Only after preserving the original animation, did I directly convert the original animation to GIF format. That way I could show what the above code is meant to achieve, and why I called it 'speed'. This was done also to provide a base line GIF animation for study and later comparison. So lets look at various details of our original animation.. magick identify -format "Number of Frames: %n\n" speed.miff | head -1 [![[IM Text]](speed_nframes.txt.gif)](speed_nframes.txt) magick identify -format "Colors in Frame %p: %k\n" speed.miff [![[IM Text]](speed_ncf.txt.gif)](speed_ncf.txt) magick speed.miff +append -format "Total Number of Colors: %k" info: [![[IM Text]](speed_ncolors.txt.gif)](speed_ncolors.txt) As you can see, each image in the animation has a very large number of colors. Not only does each frame have a different number of colors, but the first and third frames are very similar color-wise, though not quite exactly the same. However the GIF file format can only save a maximum of 256 color per frame, the ImageMagick saved this to GIF format it did so in the fastest, and dumbest way possible... It reduced the number of colors of each frame in the animation (a process called [Color Quantization](../quantize/#colors) )... magick identify -format "Colors in Frame %p: %k\n" speed.gif magick speed.gif +append -format "Total Number of Colors: %k" info: [![[IM Text]](speed_ncolors2.txt.gif)](speed_ncolors2.txt) Because the reduced number of colors in each frame is slightly different, IM also needed to supply a separate colormap for each frame in the animation. This means that the GIF file has one 'Global Color Table' and it always does, but also three separate 'Local Color Tables'. The "`magick identify`" command cannot tell you how many such local color tables a GIF file has, as the information is too format specific, and not important to the image processing IM normally does. However the more specific "`[Giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans) `" program can tell you how many low level local color tables were used... giftrans -L speed.gif 2>&1 | grep -c "Local Color Table:" [![[IM Text]](speed_ctables.txt.gif)](speed_ctables.txt) As you can see this animation has [![[IM Text]](speed_ctables.txt.gif)](speed_ctables.txt) local color tables, one less than the number of frames present in the image, just as I predicted. Not only does each frame have a different set of colors, but also a slightly different pattern of colors (the image dither pattern), as described in [Problems with Error Correction Dithers](../quantize/#dither_sensitive) . Normally this default operation of IM [Color Quantization and Dithering](../quantize/) is very good, and perfectly suited for pictures, especially real life photos. In fact the individual frames of an animation will generally look great. All the problems are when we try to later string those individually color reduced frames into an single animation sequence. ### Frame Opt before Color Opt? As you saw above saving an animation directly to a GIF format, works, but you will get quite a lot of color differences from one frame to the next, which s bad for later [Frame Optimization](#optframe) (as you will see later). To prevent color differences causing such problems you can do the [Frame Optimization](#optframe) before saving the animation, and thus avoiding the introduced color differences from one frame to another. However be warned that doing frame optimization before color reducing however change the dynamics of the color reduction. Often less of the static unmoving areas will appear in the optimized sub-frame, which means that the color quantization for that frame can give those colors less importance, and therefor less colors. ### Fuzzy Color Optimization However sometimes you don't have access to the original animation before it was saved to GIF format. This is especially true if you downloaded the original animation from the WWW. That means you already have an animation with all those GIF color distortions already present, producing problems with later optimizations. Now because a slightly different set of colors are used from one frame to the next, and a different pattern of pixels are used for each frame in the animation, each frame can be regarded as a completely different image. For example lets compare the first and third frames, which share large amount of the same background image.... magick compare speed.gif'\[0,2\]' speed\_compare.gif [![[IM Output]](speed_compare.gif)](speed_compare.gif) The red areas of the above example shows two solid square areas of the areas that are different, just as you would expect. But it also shows bands of color differences outlining the background of the two frames. These represent the 'churning' dither pattern along the edges of the background gradient where different color pixels were used to represent the exact same background. This was also the frame pair showing least background disturbances caused by using different sets of colors, and dither patterns. The actual consecutive frame differences are far worse, producing near a near solid red difference. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Image differences like this are also a problem if your source images were stored using the JPEG image format. This format uses a lossy-compression method that (even at 100% quality) causes slight color differences, in the images. However the differences are generally confined to a halo around the actual areas of difference, rather that throughout the image.

All I can say is, avoid JPEG images for use in animations unless you plan to use one single image as a static background image for ALL your frames._ | As so many pixels in the animation are different from one frame to the next it is not surprising then that when we try to [Frame Optimize](#frame_opt) the animation, we get no optimization at all... magick speed.gif -layers OptimizeFrame speed\_opt2.gif gif\_anim\_montage speed\_opt2.gif speed\_opt2\_frames.gif [![[IM Output]](speed_opt2_frames.gif)](speed_opt2_frames.gif) However most the pixel color differences between unchanging parts of the animation frames are actually rather small. It wouldn't have been a very good [Color reduction](../quantize/#intro) , if this wasn't the case. That means that by asking IM to relax its color comparisons a little, you can ask it to ignore minor color differences. This is done by setting an appropriate [Fuzz Factor](../color_basics/#fuzz) . magick speed.gif -fuzz 5% -layers OptimizeFrame speed\_opt3.gif gif\_anim\_montage speed\_opt3.gif speed\_opt3\_frames.gif [![[IM Output]](speed_opt3_frames.gif)](speed_opt3_frames.gif) As you can see with the addition of a small [Fuzz Factor](../color_basics/#fuzz) , IM will now ignore the pixels that are only slightly different, producing a reasonable [Frame Optimization](#frame_opt) . How much of a fuzz factor you need depend on just how much trouble IM had in color reducing the original images. In this case not a lot, so only a very small factor was needed. If a small fuzz factor produces an acceptable result, then just set it for your [Frame Optimization](#optframe) and [Transparency Optimization](#trans_opt) . Just remember you still have a separate color table for each frame to take care of, which is the next point of discussion. Note also that the [Frame Optimization](#frame_opt) decided to use a '[Previous Disposal](../anim_basics/#previous) for the second frame. That is, after displaying the second frame return the image to the previous frame disposal (the first image) before overlaying. This resulted in a smaller overlay image size, than if no disposal was used thoughout. If you wanted just a simple [Overlay Animation](../anim_basics/#overlay) , only using [None Disposal](../anim_basics/#none) thoughout, you could have used the old [Deconstruct](../anim_basics/#deconstruct) operator (also known as [Layers CompareAny](../anim_basics/#compareany) ) to generate it instead. magick speed.gif -fuzz 5% -deconstruct speed\_opt4.gif gif\_anim\_montage speed\_opt4.gif speed\_opt4\_frames.gif [![[IM Output]](speed_opt4_frames.gif)](speed_opt4_frames.gif) ### Generating a Single Global Color Table Now as each and every frame has a different set of colors, IM was forced to save the image, with a separate color table for every frame: one global one for the first frame, and 3 local color tables for the later frames. For example, here I used the very simple program "`[Giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans) `" program to report how many frame color tables were created. giftrans -L speed.gif 2>&1 | grep -c "Local Color Table:" [![[IM Text]](speed_ctables.txt.gif)](speed_ctables.txt) For a fully-coalesced (or film strip like) animation, having separate color tables for each frame is perfectly fine and reasonable, and in such situations this is not a problem. That is, for slide shows of very different images, separate color tables will produce the best looking result. As such this is the normal working behaviour of IM. All these extra color tables is however very costly as each colortable can use a lot of space. Up to 768 bytes (256 colors × 3 bytes per color or 3/4 kilobytes) for each frame in the image. Not only that, but the GIF compression does not compress these color tables, only pixel data! If having this much file space for separate color tables is a problem, especially for an image that doesn't change color a lot, as is the case with most GIF animations, then you can get IM to only use the requires global color table, and not add any local color tables. ---To remove local color maps all the image must become type palette and all use the same palette, For the command line you can do this by setting a "-map image" to define the command palette, You cannot use -colors as that works of individual images. The command line solution is a special "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" option, that does a global color reduction to a common palette that is added to all images. NOTE any change to the image will likely invalidate the palette, so while color reduction should be done BEFORE you do GIF frame and/or compression optimizations, the common palette needs to be last, just before saving. If "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" does not need to reduce the number of colors in an image it will not do it or dither colors, just add a common palette across all images. --- IM can generate a single global color table, if all the frames use the same color palette. In IM color palettes are only assigned to an image either by reading them in from an image format that is using such a palette, or by assigning it one using the "`[-map](https://imagemagick.org/script/command-line-options.php?#map) `" color reduction operator. See [Dither with Pre-defined Colormap](../quantize/#map) for more details. One way to generate this single color table is to simply "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" all the frames together, then using the "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" command to reduce the number of colors to a minimal set (less than 256, or smaller if you want an even smaller color table). The resulting color table can then be applied to the original image using "`[-map](https://imagemagick.org/script/command-line-options.php?#map) `". For example, here reduce the image to a single set of 64 colors. This uses the special [MPR in-memory register](../files/#mpr) to assign the generated color map to the "`[-map](https://imagemagick.org/script/command-line-options.php?#map) `" command. magick speed.gif \\ \\( -clone 0--1 -background none +append \\ -quantize transparent -colors 63 -unique-colors \\ -write mpr:cmap +delete \\) \\ -map mpr:cmap speed\_cmap.gif [![[IM Output]](speed_cmap.gif)](speed_cmap.gif) Now if you examine the resulting animation using "`[Giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans) `" you will find that the image now uses a single 'global' color table, rather than a separate color table for each frame. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _I use a "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color of '`None`' before appending the images together, allowing you to use this on un-coalesced animations, and not have the possibility adding extra unneeded colors.

The special "`[-quantize](https://imagemagick.org/script/command-line-options.php?#quantize) `" setting of '`transparent`' colorspace was used to ensure that IM does not attempt to generate semi-transparent colors in its colormap. An useless thing as we are saving the result to GIF which cannot handle semi-transparency.

Finally I color reduce to 63 colors, to leave space for a transparent color. Some animations need transparency, while others (like this one) may still need it later for [Compression Optimization](#compress_opt)
._ | To make this easier, IM also provides a special option "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" which will generate a common color map (of 256 colors) over all the frames, applying it globally. This is a lot simpler than the DIY method above. magick speed.miff -alpha off +map speed\_map.gif [![[IM Output]](speed_map.gif)](speed_map.gif) This resulted in [![[IM Text]](speed_map_ctables.txt.gif)](speed_map_ctables.txt) 'local' (or extra unwanted) color tables in the resulting image. I will be using the single color table version of the animation for the next optimization sections, though you could actually do this at any point in your animation optimizations and especially before the final save. As a result of color table optimization, the animation which was [![[IM Text]](speed_size.txt.gif)](speed_size.txt) bytes for our directly converted GIF, is now [![[IM Text]](speed_map_size.txt.gif)](speed_map_size.txt) bytes, after using the "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" operator. The more frames (and 'local color tables') an animation has, the larger the saving. Now as any modification to an animation will generally remove the saved palette for each of the images, it is important that the "`[+map](https://imagemagick.org/script/command-line-options.php?#map) `" operator be the last operation before saving the animation to GIF. Remember **Removal of local color maps should be the last optimization, before saving to GIF format.** ### Ordered Dither, removing the 'static' **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Note however that in all the techniques we have looked at so far all can have a dither pattern that changes from one overlay to another. A churning of the pixels that can look like TV static. ... small number of colors ... With a frame optimization of a smaller unmoving area, you can even get a rectangular areas of static that looks even worse. ... Ordered Dither ... For now refer to the more practical and less detailed [Video to GIF, Optimization Summary](../video/#gif) . * * * Compression Optimization ------------------------ Once you have your animation saved into a GIF format, by handling semi-transparent pixels and using color and frame optimizations, you are also able to get some smaller file size reductions by catering to the GIF compression algorithm. The LZW compression or Run-length Compression that the GIF file format can use will compress better if it finds larger areas of constant color, or pixel sequences that repeat over and over. ### Transparency Optimization As you saw in [Frame Optimization](#frame_opt) an overlaid image will often be just repeating what is already being displayed. That is, it is overlaying the same colored pixels that is already present after the GIF disposal methods have been applied. But why bother repeating those pixels. If you are already using transparency in an image, you have a transparent pixel color available. But converting those areas into transparency, get larger areas of uniform transparent pixels. That can compress better, than using a mix of different colors, needed to match the same area being overlaid. For example, here is a simple [Frame Optimized](#frame_opt) , [Overlay Animation](../anim_basics/#overlay) ... | | | | | --- | --- | --- | | | [![[IM Output]](../anim_basics/bunny_bgnd_frames.gif)](../anim_basics/bunny_bgnd_frames.gif) | [![[IM Output]](../anim_basics/bunny_bgnd.gif)](../anim_basics/bunny_bgnd.gif) | Lets now use the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `", method '`**OptimizeTransparency**`' (Added IM v6.3.4-4) to replace any pixel that does change the displayed result with transparency. magick bunny\_bgnd.gif -layers OptimizeTransparency \\ +map bunny\_bgnd\_opttrans.gif gif\_anim\_montage bunny\_bgnd\_opttrans.gif bunny\_bgnd\_opttrans\_frames.gif [![[IM Output]](bunny_bgnd_opttrans.gif)](bunny_bgnd_opttrans.gif) [![[IM Output]](bunny_bgnd_opttrans_frames.gif)](bunny_bgnd_opttrans_frames.gif) As you can see the sub-frames now have large transparent areas, which do not effect the final resulting animation. Areas that need the pixels changed are still overlaid, but the areas that does not change have been made transparent. That includes within the object being animated as well, leaving rather horible looking 'holes'. As the larger constant transparent colored areas will (in theory) compress better, the resulting 'messy' animation is a lot smaller, reducing the file size from the frame optimized result of [![[IM Text]](bunny_bgnd_size.txt.gif)](bunny_bgnd_size.txt) bytes down to [![[IM Text]](bunny_bgnd_opttrans_size.txt.gif)](bunny_bgnd_opttrans_size.txt) bytes. This is quite a big savings for a very small effort. Note that the optimization method did not need to be a [Coalesced Animation](../anim_basics/#coalesced) , and that the size of the sub-frames is left unchanged, so as to preserve the disposal needs of this and later frames. As such any savings is just in terms of improved compression ratios for the same number of pixels in the animation, and not in that actual number of pixels saved into the file. It should thus be done after you have completed any [Frame Optimization](#frame_opt) needed, as one of your final optimization steps. FUTURE: link to a 'remove background' from animation Of course like most of the other "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" methods (comparison or optimization) you can specify a [Fuzz Factor](../color_basics/#fuzz) to adjust, 'how similar' colors are thought to be. That lets you handle animations that were badly color dithered, though if you had studied the [Color Optimization](#color_opt) above you should not have that problem. The free animated GIF tool "`**[InterGIF](http://utter.chaos.org.uk/~pdh/software/intergif.htm) **`" also provides this same type of transparency compression optimization shown above, but without the ability to also support a 'fuzz factor' to also make 'close' color changes transparent. I do not recommend it, except as an alternative when IM is not available. ### LZW Optimization \- (non-IM) Some applications can further optimise the compression ratio of the images in an animation to make it them even smaller. However to do this requires a specialized knowledge of the LZW compression that the GIF image file format typically uses. Basically, if a specific sequence of pixels has already been handled by the LZW compression algorithm, it will not bother to magick them into transparent pixels as doing so will not improve the images compression. It sounds weird but it works. Unfortunately _ImageMagick will not do this_, as it is such a complex process that takes a great deal of skill and resources to get a reasonably good heuristic to produce a good result in the general case. I can however give you a practical example of this technique using the "`[Gifsicle](http://www.lcdf.org/gifsicle/) `" application at its highest '`-O2`' optimization level. gifsicle -O2 bunny\_bgnd.gif -o bunny\_bgnd\_lzw\_gifsicle.gif gif\_anim\_montage bunny\_bgnd\_lzw\_gifsicle.gif bunny\_bgnd\_lzw\_frames.gif [![[IM Output]](bunny_bgnd_lzw_gifsicle.gif)](bunny_bgnd_lzw_gifsicle.gif) [![[IM Output]](bunny_bgnd_lzw_frames.gif)](bunny_bgnd_lzw_frames.gif) LZW compression optimization reduced the image from [![[IM Text]](bunny_bgnd_opttrans_size.txt.gif)](bunny_bgnd_opttrans_size.txt) bytes with simple transparency optimization, to [![[IM Text]](bunny_bgnd_lzw_gifsicle_size.txt.gif)](bunny_bgnd_lzw_gifsicle_size.txt) bytes for "Gifsicle". Not a large improvement. The more important aspect however is that while LZW optimization converted unchanged pixel to transparency (as we did using [Transparency Optimization](#opt_trans) above), it did not change a sequence of pixels that had already been seen. That is, only groups of pixels that have _not_ already been repeated within the animation were changed, as those pixel would (presumably) already compress well using LZW compression patterns. Note that the selection of what pixels should be made transparent, to generate repeated pixel patterns, is very complex and difficult, and can even depend on the exact LZW implementation as well. It is a heuristic, not a perfectly predictable algorithm. As such different programs will generally produce different results depending on the specific image being compressed. One program may produce a better compression ratio for one image, and another may be better for a different image. ### Lossy LZW Optimization \- (non-IM) Another compression improvement method involved the slight modification of the pixel colors themselves to 'close color matches' so as to increase the repetition of the color references in the image. A repeated pattern naturally compresses better, and as such can produce a higher compression ratios. A fork of the previous "Gifsicle" application, known as [giflossy](https://kornel.ski/lossygif) , also generats a '`gifsicle`' program, but one with the option to modify the image in minor ways (it is 'lossy') to reduce the size of GIF images, especially in animation, much further. gifsicle -O3 --lossy=80 bunny\_bgnd.gif -o bunny\_bgnd\_giflossy.gif gif\_anim\_montage bunny\_bgnd\_giflossy.gif bunny\_bgnd\_lossy\_frames.gif [![[IM Output]](bunny_bgnd_giflossy.gif)](bunny_bgnd_giflossy.gif) [![[IM Output]](bunny_bgnd_lossy_frames.gif)](bunny_bgnd_lossy_frames.gif) * * * This resulted in a size of [![[IM Text]](bunny_bgnd_giflossy_size.txt.gif)](bunny_bgnd_giflossy_size.txt) , which is amazing 1/3 reduction in size. Unfortunately this method involved changing the resulting image, and as such the optimization is lossy, as it can loose subtle color information. On the plus side it allows you to compress the individual frames, rather than the frame-to-frame optimization. Here for example I generated a difference image of the previous non-lossy LWZ compression against a lossy LWZ compression. magick compare bunny\_bgnd\_lossy\_frames.gif bunny\_bgnd\_lzw\_frames.gif \\ bunny\_bgnd\_diff\_frames.gif [![[IM Output]](bunny_bgnd_diff_frames.gif)](bunny_bgnd_diff_frames.gif) As you can see almost all the color modifications was in the original 'grass' background image, rather than the cartoon bunny. Basically it slightly modified things just enough to make a huge difference, and for this image not a real noticable difference in look. Of course [Color Quantization and Dithering](../quantize/) is itself a lossy operation and is usually needed anyway, so using a lossy compression method for GIF images, and GIF animations is not regarded as very bad. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Another example of such an algorithm that was patented for use by Photoshop see [US Patent 7031540 - Transformation to increase the lempel-ziv compressibility of images with minimal visual distortion](http://www.patentstorm.us/patents/7031540-fulltext.html)
. It is heavy reading but details the methods it uses to achieve better compression._ | ### Ordered Dithered LZW Optimization As the dithering process is usually a more lossy process than LZW optimizations, a better solution may be to try to introduce the repeatable patterns as part of the dithering process. That can be achieved by using [Ordered Dithering](../quantize/#ordered-dither) to produce such patterns, and thus much stronger LZW compression savings than all the previous LZW Optimization method. As a bonus it can also improve the [Frame Optimization](#frame_opt) of real life animations with static backgrounds. That would be especially true if you artificially clean up the background so it does become a static unchanging background. Of course Ordered Dither Compression Optimization only works for images that have not previously been dithered or otherwise color optimized. As such it only works for animations that have yet to be optimized for the GIF image format. Also currently IM Ordered dither only works for an uniform color palette. IM has yet to have a 'best color' or 'user supplied' palette implementation of ordered dither, though I have seen programs that use such an algorithm for very limited (and fixed) color pallets. _Do you know of such an algorithm?_ For a practical example of using ordered dither for improved LZW compression optimization, see [Ordered Dithered Video](../video/#gif_ordered_dither) . ### Other LZW Optimization Other improvements in LZW optimization can also be achieved by other re-arragements of the 'dither pattern' in the image. And some GIF tools can do exactly that. However any such optimization should always be checked by a human eye before being approved, as sometimes a subtile but bad color changes can result. ### Compression Optimization Summary Here is a complete summary of the final file sizes achieved using compression optimizations. [![[IM Text]](bunny_bgnd_compress_sizes.txt.gif)](bunny_bgnd_compress_sizes.txt) As you can see only slight improvements in final animation size was achieved by using the very complex [LZW Optimization](#lwz_opt) , over the built-in [Transparency Optimization](#trans_opt) . However the results are also highly variable between the many GIF optimization application programs available, and the specific animation that is being optimized. If you really need to get the very last byte from a file size, then a [LZW Optimization](#lwz_opt) may be just what you need. And if you really need the very best results, you should try a number of different programs (and thus heuristic implementations) to see which one compresses your specific animation better, including what other optimization features they provide. Typically a [Transparency Optimization](#trans_opt) is good enough for most purposes. With [LZW Optimization](#lwz_opt) only producing a slightly better result, producing a very minor saving for network transmission sizes, rather than disk storage size, as the latter uses larger 'chunks' or 'blocks' of storage. Because of this I feel the [LZW Optimization](#lwz_opt) , overkill, and I don't think it is worth the effort, or the money (most of these tools are commercially sold). | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Unfortunately I have found that these GIF optimizers do not handle ALL types of pre-optimized animations very well.

For example, my tests show that "`[Gifsicle](http://www.lcdf.org/gifsicle/) `" fails to handle an animation that was already optimized using a 'background disposal' technique.

On the other hand I found that "`[InterGIF](http://www.chaos.org.uk/~pdh/software/intergif.htm) `" will not handle animations that have already been optimized to use an initial canvas and 'previous disposals' technique. It also is limited to the use of [Transparency Optimization](#trans_opt)
, which IM now provides.

I thus recommend you do not mix GIF optimization utilities by feeding one utilities output into another. At least not without first coalescing the animation to remove any previous frame optimizations.

IM, Gifsicle and InterGIF, all provide such coalescing options to remove their own optimizations, though I cannot guarantee the non-IM applications will coalesce ALL animations correctly. IM will.

_ | Because you can't use these programs reliably with IM's advanced [Frame Optimization](#frame_opt) techniques (which selects and switches to using different GIF disposal techniques automatically), I have often found that IM will often produce an overall better result that just using these LZW compression optimizers. I also suggest you also [Coalesce](../anim_basics/#coalesce) the result again afterward and compare its frames against the original un-optimized animation, to ensure that the non-IM program did not somehow stuff up the animation entirely (see note above). Believe me I have seen it happen, and scripts should double check animations remain valid. Another tutorial (using windows tools) about this type of optimization is [WebReference Frame Optimation](http://www.webreference.com/dev/gifanim/frame.html) . Note that the site is mis-named as it is about compression optimization. * * * Minor Optimizations ------------------- There are a few other optimization techniques that you can use with GIF animations that are often so obvious that they are overlooked. * **Remove GIF comments.** Many GIF animations have a large text comment added. Often these were added automatically by graphical editors as a form of advertising. For example, "`Gimp`" by default adds "`Created with The GIMP`" to images. If the comment is not needed, it is a waste of space. Remove them by adding a "`[+set](https://imagemagick.org/script/command-line-options.php?#set) comment`" operator to the IM "`magick`" command before the GIF is saved. Please note however that if the comment is a copyright notice, it may not be a good idea to remove it for legal reasons. * **Reduce the number of colors.** If animation looks okay with fewer colors, use a smaller color table. The color tables are always a power of two, so if you can use less than 32 colors, that is a lot smaller than using 256 colors. This is especially magick important as color tables are not compressed by the LZW compression used for the GIF image data. Also using fewer colors will generally produce better LZW compression as more common pixel sequences are found. This is not always the case however as color dithering (due to the color reduction) can also make the compression worse. Turning of dithering or using an ordered dither can be magick important here. * **Half the number of user visible frames.** If you can handle a less smooth animation, then halving the total number frames can produce a good improvement in the final file size. Of course you don't get a file half the size, and the animation quality is reduced. But it can produce a very large file size reduction. * **Crop/Resize the animation.** A smaller image size means a smaller file size. So if you don't need a big animation, don't use a big animation. A small thumbnail to represent a larger animation or video, is often preferable in a listing that the real thing. * **Alternative Compressions.** If you do not plan to use the animation as an animation, that is you just want to store it, turn off the LZW compression, and "gzip" or "bzip2" compress the WHOLE file for storage! The result is a lot smaller, though it requires web servers to give the right 'content' and 'compression' hints to browsers for it to be directly usable by client browsers. The "`Apache`" web server, doesn't do this by default, but can be made to do so. Better still, archive the whole directory of uncompressed animations into a single file, for even better storage compression. If you have any other optimization ideas, please let me know. * * * Other Sources of Information on GIF Optimization ------------------------------------------------ The above completes the various basic methods and techniques for handling animations. However to form a complete picture. You should continue into the next IM examples page, detailing techniques for handling actual problems with real [Animations of Images](../anim_mods/) . Also many of the above techniques are demonstrated in the practical examples of [Video to GIF Optimization](../video/#gif) . I also recommend you thoroughly read about [Color Quantization](../quantize/) , if you are really serious about dealing with GIF animations, as color reduction is often the key to good GIF animation handling. Other useful sources for GIF Animation Optimization techniques that I have found on the WWW include... * [Dr Dobb's - Optimizing GIF Animations](http://www.ddj.com/documents/s=2904/nam1012433888/index.html) * [Optimizing Animated GIFs](http://www.webreference.com/dev/gifanim/) Mail me if you think you have a page I should list here. I will only add pages of useful content, so no guarantees about adding your link. --- # Unknown Author: [Anthony Thyssen](http://www.ict.griffith.edu.au/anthony/anthony.html) , Annotating -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Annotating Images ===================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Labeling Images](#annotating) ![](../img_www/space.gif) (techniques for labeling images) * [Labeling below (or above) an Image](#anno_below) * [Labeling on top of the Image Itself](#anno_on) [![](../img_www/granitesm_right.gif) Overlaying Images](#overlay) ![](../img_www/space.gif) (overlaying and merging images on top of each other) [![](../img_www/granitesm_right.gif) Watermarking](#watermarking) ![](../img_www/space.gif) (annotating for copy protection) * [Watermarking with Symbols](#wmark_symbol) * [Watermarking with Text](#wmark_text) * [Watermarking with Images](#wmark_image) [![](../img_www/granitesm_right.gif) Text and Image Positioning Methods](#text_position) * [The 'Gravity' of the Situation](#gravity) * [Image Positioning using Gravity](#gravity_image) * [Text Positioning using Gravity](#gravity_text) * [Text on Left Edge using Gravity](#gravity_left) * [Text Positioning using Draw](#draw) * [Text Positioning using Distort](#distort) This document presents various ways of annotating a large image with either text or some other image. The annotation may be bold and highly visible, or subtle and hidden. Reasons for annotating images are varied, but are usually either to * Mark the image with information about what the image is about. * Point out or highlight some aspect of the image. * Add copyright or logos to the image as a form of copy protection. [ImageMagick](https://imagemagick.org/) provides a lot of ways to do these things, but not all are easy to discover from the manuals on your own. This page tries to present the common methods used. Many of the specific methods are discussed more fully on other example pages. If you are interested in annotating or watermarking a GIF animation, I suggest you first look though this document, then jump to [Annotating GIF Animations](../anim_mods/#annotating) , to start you off. * * * Annotating Images ----------------- The basic problem with labeling an image is doing so the text is readable no matter what the image. The following show many methods, show of which can be expanded to do more complex tasks. In these examples, I am limiting myself to the default font of ImageMagick. You are encouraged to use different fonts and point sizes appropriate to what you want to achieve. ### Labeling Below (or Above) an Image **Append a Label** with centering is now possible, from IM v6.4.7-1, as [Image Appending](../layers/#append) now follows the gravity setting, for alignment purposes. magick dragon.gif -background Khaki label:'Faerie Dragon' \\ -gravity Center -append anno\_label.jpg [![[IM Output]](anno_label.jpg)](anno_label_append.jpg) By reordering the images you can append the label above the image. magick dragon.gif -background Orange label:'Faerie Dragon' \\ +swap -gravity Center -append anno\_label2.jpg [![[IM Output]](anno_label2.jpg)](anno_label2.jpg) **Splice and Draw** is very simple way of adding extra space to an image to allow us to draw/annotate the label into the image. magick dragon.gif \\ -gravity South -background Plum -splice 0x18 \\ -annotate +0+2 'Faerie Dragon' anno\_splice.gif [![[IM Output]](anno_splice.gif)](anno_splice.gif) The same method can be used to draw a label above the image, just replace the gravity setting of '`South`' with '`North`'. Easy! magick dragon.gif \\ -gravity North -background YellowGreen -splice 0x18 \\ -annotate +0+2 'Faerie Dragon' anno\_splice2.gif [![[IM Output]](anno_splice2.gif)](anno_splice2.gif) The "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator is no longer recommended for direct drawing onto images, unless part of more complex drawing functions. See the section on [Text to Image Handling](../text/) for more details of other text drawing methods and techniques.**Label using Montage** The montage command in ImageMagick is often overlooked by users as only useful for creating a display of a whole directory of images. It does provide a very simple way to add labels an image. montage -label "Faerie Dragon" dragon.gif \\ -geometry +0+0 -background Gold anno\_montage.jpg [![[IM Output]](anno_montage.jpg)](anno_montage.jpg) Montage can also add a frame and other things to the image for you, so this form of labeling has a lot of extra possibilities beyond that of simple labeling of the image. montage -label "Faerie Dragon" dragon.gif \\ -font Candice -pointsize 15 \\ -frame 5 -geometry +0+0 anno\_montage2.jpg For more info about using montage see [Montage, Arrays of Images](../montage/) .[![[IM Output]](anno_montage2.jpg)](anno_montage2.jpg) **Label using Polaroid** An alternative to using montage, is to use the [Polaroid Image Transformation](../transform/#polaroid) , to generate a rather fancy commented image. magick -caption "Faerie Dragon" dragon.gif -gravity center \\ -background black +polaroid anno\_polaroid.png Warning this image is distorted, (curved and rotated) with some randomization, as such the final image size can vary, unless rotation is disabled. It also contains complex shadow and transparency effects, so a PNG format image was used to save the resulting image.[![[IM Output]](anno_polaroid.png)](anno_polaroid.png) You can reduce the 'fuzziness' in the resulting image caused by the rotation by using a 'Super Sampling' technique. See [Polaroid Image Transformation](../transform/#polaroid) for an example of this. ### Labeling on top of the Image itself... The problem with writing text directly on a picture is that you can't be sure the text will be readable in the color you have chosen. The image being drawn onto could be black, white or a rainbow of colors.**Outlined Label**: The simplest method is to draw the string with a outline to separate the text from the image. However as the "`[-stroke](https://imagemagick.org/script/command-line-options.php?#stoke) `" font setting adds thickness to a font both inward and outward, reducing its effectiveness (See [Stroke and StrokeWidth](../draw/#stroke) for more information. The better way to draw an font with a background outline is to draw the text twice. magick dragon.gif -gravity south \\ -stroke '#000C' -strokewidth 2 -annotate 0 'Faerie Dragon' \\ -stroke none -fill white -annotate 0 'Faerie Dragon' \\ anno\_outline.jpg [![[IM Output]](anno_outline.jpg)](anno_outline.jpg) As you can see it works, but not very well. It does work better with a thicker font, than the default '`Times`' or '`Arial`' font. For more details of this technique see [Thick Stroke Compound Font](../fonts/#thick_stroke) .**Draw Dim Box**: The more classical method of making the annotated text more visible is to 'dim" the image in the area the text will be added, then draw the text in the opposite color. For example... magick dragon.gif \\ -fill '#0008' -draw 'rectangle 5,128,114,145' \\ -fill white -annotate +10+141 'Faerie Dragon' \\ anno\_dim\_draw.jpg [![[IM Output]](anno_dim_draw.jpg)](anno_dim_draw.jpg) This method works well, but as you can see I decided not to use "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" in this example to place the text, as the darkened rectangle cannot be positioned with gravity (this may change in the future). Also its size and position can depend on the image and final text size, which may require some extra math calculations.**Undercolor Box**: Instead of trying to draw the background box yourself, you can get ImageMagick to use an 'undercolor' on the box. See [Text Undercolor Box](../text/#box) . The text 'undercolor' (as used in the library API), can be specified on the command line using the "`[-undercolor](https://imagemagick.org/script/command-line-options.php?#undercolor) `" option. magick dragon.gif -fill white -undercolor '#00000080' -gravity South \\ -annotate +0+5 ' Faerie Dragon ' anno\_undercolor.jpg [![[IM Output]](anno_undercolor.jpg)](anno_undercolor.jpg) As you can see it is a lot simpler that drawing the dimmed box yourself, though an extra space at the start and end of the drawn text is recommended, to pad out the box slightly.**Composited Label**: The more ideal solution is to prepare a text image before-hand and then overlay it as an image. Here we create a simple label on a semi-transparent background, and overlay it. magick -background '#00000080' -fill white label:'Faerie Dragon' miff:- |\\ magick composite -gravity south -geometry +0+3 \\ - dragon.gif anno\_composite.jpg [![[IM Output]](anno_composite.jpg)](anno_composite.jpg) This last technique has very some distinct advantages. The dimmed box can be sized to fit the label, and it can be position with "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to position it correctly, without needing any specific knowledge of the image it is being added to, or of the drawn font being used. Also you are not limited to using just a simple dimmed box. Instead you can prepare very complex font image, either before-hand, so you can apply it many times, or on the fly on a per image basis. Just about all the [Compound Font Effects](../fonts/) styles are also available to you, allowing you to make your text additions very exciting and professional looking. **Auto-Sized Caption**: With the release of IM v6.3.2, the "`[caption:](../text/#caption) `" can now automatically adjust the size of text to best fit a box of a particular size.But to make proper use of this for an overlay you really need to know how wide the image being annotated is. Here I gather that info then create and overlay a caption such that the text is automatically sized to best fit the space provided, with word wrapping. width=\`identify -format %w dragon.gif\`; \\ magick -background '#0008' -fill white -gravity center -size ${width}x30 \\ caption:"Faerie Dragons love hot apple pies\\!" \\ dragon.gif +swap -gravity south -composite anno\_caption.jpg [![[IM Output]](anno_caption.jpg)](anno_caption.jpg) This technique is ideal for overlaying image comments onto an image, though doing so on the command line has its own problems as you are creating a new image, not annotating an old image. See [User defined option escapes](../text/#user_escapes) for a solution to this problem. **Fancy Label**: As a final example I will overlay a text string created using a fancy [soft outlined font](../fonts/#denser_soft_outline) to make sure it remains visible, but without creating a rectangular box for the annotation. magick -size 100x14 xc:none -gravity center \\ -stroke black -strokewidth 2 -annotate 0 'Faerie Dragon' \\ -background none -shadow 100x3+0+0 +repage \\ -stroke none -fill white -annotate 0 'Faerie Dragon' \\ dragon.gif +swap -gravity south -geometry +0-3 \\ -composite anno\_fancy.jpg [![[IM Output]](anno_fancy.jpg)](anno_fancy.jpg) If you are planning to composite the same label (say a copyright message) onto a lot of images, it would probably be better to generate your label separately and compose that label onto each image using the "[mogrify](../basics/#mogrify) " command. The "`-geometry +0-3`" offset in the above is used to position the composite overlay closer to the edge, as the soft fuzzy outline of this image is often larger that is necessary. All the above examples should of course be adjusted to suit your own requirements. Don't be a sheep and follow what everyone else does. Experiment, and give your own web site or program a distinct flavor from everyone else. And more importantly tell the IM community about it. FUTURE: select the black or white color based on the images relative intensity. This uses a number if very advanced techniques. magick input.jpg -font myfont -pointsize 25 \\ \\( +clone -resize 1x1 -fx 1-intensity -threshold 50% \\ -scale 32x32 -write mpr:color +delete \\) -tile mpr:color \\ -annotate +10+26 'My Text' output.jpg Explanation: Copy of image is resized to 1 pixel to find the images average color. This is then inverted and greyscaled using -fx, then thresholded to either black or white, (as appropriate). This single color pixel is now scaled to a larger tiling image, and saved into a named memory register (mpr:). The image is then used to set the fill tile, for the annotated text. Their is however no simple method (at this time) to set the outline -stroke color of the draw text to its inverse. Other techniques are to use some text as a 'negate image' mask, or even a color burn or color dodge compose operation, to distort the image with the text. * * * Overlaying Images ----------------- The "`magick composite`" command and the "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" image operator in ImageMagick provides the primary means to place image on top of other images in various ways. The details of these methods are given in [Alpha Compositing](../compose/) Examples Page. However there are more higher level operators that also make use of alpha compositing of images. These include [Image Layering](../layers/) , as well as [Positioning Images with Gravity](#image_gravity) , further down this examples page. The default compose method of compose is "`Over`" which just overlays the overlay image onto the background image, handling transparencies just as you would expect. The background image also determines the final size of the result, regardless of where the overlay is placed (using the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" option). It doesn't matter if the overlay is in the middle, halfway off the background image, or far far away, the output image is the same size as the background image. The geometry position of the image is also effected by "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", so the positioning of the overlaid image can be defined relative to any of nine (9) different locations. See "[Positioning Images and Text](#gravity) " below. On top of "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" of the compose overlay, individual images can also have a page or canvas information (set using "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" and "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" options), that can effect the final position of the images. This image specific information is however not effected by "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `". On with the examples...**Overlaying** is probably the most common form of image annotation, and is very simple to do. Here I overlay a 32x32 icon of a castle in the middle of a prepared button frame. magick composite -gravity center castle.gif frame.gif castle\_button.gif [![[IM Output]](../images/castle.gif)](../images/castle.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/frame.gif)](../images/frame.gif) ![==>](../img_www/right.gif) [![[IM Output]](castle_button.gif)](castle_button.gif) You can also position the sub-images exactly. Here we set a hand to point out the small craws of the faerie dragon. magick composite -geometry +31+105 hand\_point.gif dragon.gif \\ dragon\_claw\_pointed.jpg [![[IM Output]](../images/hand_point.gif)](../images/hand_point.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/dragon.gif)](../images/dragon.gif) ![==>](../img_www/right.gif) [![[IM Output]](dragon_claw_pointed.jpg)](dragon_claw_pointed.jpg) Exactly how an image is drawn on the background is controlled by the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting. The default as used above is "`-compose over`" which just overlays the image on the background. Most of the other compose methods provided are not very usable except in very specific situations, but here are some of them. For more details of this setting and its effects see [Alpha Compositing](../compose/) . **Bumpmap** is a tricky compose method and basically darkens the background image in accordance to the brightness of the overlay image. Anything that is white in the overlay is handled like it is transparent, while anything black becomes black on the output image. It is a bit like using the overlay as an ink stamp and that is a good way of picturing this operation. As a hint, overlaying with a bumpmap works best with light colored images. So you may need to prepare the bumpmap image before using. Here we resize our dragon image before using "`-compose bumpmap`" to draw it on a paper scroll image. magick composite \\( dragon.gif -resize 50% \\) scroll.gif \\ -compose bumpmap -gravity center dragon\_scroll.gif [![[IM Output]](../images/dragon.gif)](../images/dragon.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/scroll.gif)](../images/scroll.gif) ![==>](../img_www/right.gif) [![[IM Output]](dragon_scroll.gif)](dragon_scroll.gif) Bumpmaps can also be used to set an overall effect on an image, in this case we tile a light colored background pattern over our dragon. Remember that a bumpmap image is treated as a grey-scale image, so any color in our overlay image is lost. magick composite -compose bumpmap -tile rings.jpg \\ dragon.gif dragon\_rings.jpg [![[IM Output]](../images/rings.jpg)](../images/rings.jpg) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/dragon.gif)](../images/dragon.gif) ![==>](../img_www/right.gif) [![[IM Output]](dragon_rings.jpg)](dragon_rings.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" option above only works for compose operations using the "`magick composite`" command. In "`magick`" you will have to use the "`[tile:](../canvas/#tile) `" image generator with a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" to specify the extent. You can of course make your source image overlay larger than the background image you are overlaying, as the result will be the size of the background or destination image._ | **Multiply** compose method is best known for its ability to merge two images with white backgrounds (like onto a page of text). Unlike the '`bumpmap`' compose method, it does not pre-magick the overlaid image into grey-scale. mesgs PictureWords |\\ magick -pointsize 18 text:- -trim +repage \\ -bordercolor white -border 10x5 text.gif magick composite -compose multiply -geometry +400+3 \\ paint\_brush.gif text.gif text\_multiply.gif [![[IM Output]](../images/paint_brush.gif)](../images/paint_brush.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](text.gif)](text.gif) ![==>](../img_www/right.gif) [![[IM Output]](text_multiply.gif)](text_multiply.gif) ASIDE: The complex command to generate "`text.gif`" above is just to create a typical text only image, the "`mesgs`" command just outputs a specific quotation, like "`fortune`" does but with more control. This method works very well in a lot of situations, but generally only if one (either) image is basically black (or greyscale) on a mostly white background. If both images contain regions of color, then you may get unusual results. In other words, this technique is perfect for overlaying line drawings, diagrams or images of text, on white (or reasonably light colored) images, such as images of printed or scanned pages. * * * Water Marking ------------- Watermarking is an important job, as it provides a way of marking an image as belonging to some company or web site. Unfortunately this involves trashing the image in some way, to the detriment of the image itself. The basic goals of watermarking is * The mark should be clearly visible regardless of whether the image is light or dark in color. * It should be difficult to erase. * and it shouldn't be too annoying to viewers. All these factors are in conflict, and this is one reason why watermarking is so difficult to do well. ### Watermarking with Symbols One of the simplest, and most annoying forms of watermarking is to just to place a very small but specific image somewhere on the image being watermarked. Here we generated an image (using "`logo:`") that we want to watermark, using a small 'eyes' symbol. magick logo: -resize x180 -gravity center -crop 180x180+0+0 logo.jpg magick composite -geometry +160+13 eyes.gif logo.jpg wmark\_symbol.jpg [![[IM Output]](logo.jpg)](logo.jpg) ![ + ](../img_www/plus.gif) [![[IM Output]](../images/eyes.gif)](../images/eyes.gif) ![==>](../img_www/right.gif) [![[IM Output]](wmark_symbol.jpg)](wmark_symbol.jpg) The best idea for the placement of the small image is to add it so it looks to be actually part of the original image. In the above I added the "eyes" image so it looks almost like it is part of the wizards hat, (you don't want it to become too integrated into the image either). Consequently, this technique requires the human touch, which makes it impossible to fully automate. The small image can also be very difficult to remove, as it destroys completely the part of the image it overlaid. And if done well, is hardly noticeable, unless you are specifically looking for it. I have seen it used to good effect in many places on the web. One web site used a small dagger-like symbol. Images stolen from that website became very obvious when I spotted that same dagger symbol on images I found on other web sites. ### Watermarking with Text Just drawing text on an image is also a simple way of watermarking, and any of the [label on image](#anno_on) examples above can be used as a type of wartermark. However to do this properly you should use two different colors to prevent the text from disappearing when drawn on different colored backgrounds. As such some sort of [Compound Font Effects](../fonts/) should be used. magick logo.jpg -font Arial -pointsize 20 \\ -draw "gravity south \\ fill black text 0,12 'Copyright' \\ fill white text 1,11 'Copyright' " \\ wmark\_text\_drawn.jpg This works well and can be automated, but it is too bold to be used as a good watermark as it stands out too well from the image.[![[IM Output]](wmark_text_drawn.jpg)](wmark_text_drawn.jpg) But by doing some preparation, an image with transparent background can be created that will be less evasive. For details of the steps being used to generate the watermark text, see [Font Masking](../fonts/#mask) . Also the mask examples of [Masking Images](../masking/#masks) may be useful for you understanding. magick -size 300x50 xc:grey30 -font Arial -pointsize 20 -gravity center \ -draw "fill grey70 text 0,0 'Copyright'" \ stamp_fgnd.png magick -size 300x50 xc:black -font Arial -pointsize 20 -gravity center \ -draw "fill white text 1,1 'Copyright' \ text 0,0 'Copyright' \ fill black text -1,-1 'Copyright'" \ -alpha off stamp_mask.png magick composite -compose CopyOpacity stamp_mask.png stamp_fgnd.png stamp.png magick mogrify -trim +repage stamp.png [![[IM Output]](stamp.png)](stamp.png) Now we have a watermark font we can apply it to our image... magick composite -gravity south -geometry +0+10 stamp.png logo.jpg \\ wmark\_text\_stamped.jpg As you can see the watermark is not as bold as before, and even uses shades of grey rather the pure white and black. Even so it is still highly visible no matter what the background. The [Compound Font Effects](../fonts/) page details a lot of font styles that can be used in this way without overwhelming the image being watermarked.[![[IM Output]](wmark_text_stamped.jpg)](wmark_text_stamped.jpg) You can also tile the text over the whole image. Here we also avoid the need for an intermediate image by using a 'pipeline' of commands, with the output of one, feeding the next. magick -size 140x80 xc:none -fill grey \\ -gravity NorthWest -draw "text 10,10 'Copyright'" \\ -gravity SouthEast -draw "text 5,15 'Copyright'" \\ miff:- |\\ magick composite -tile - logo.jpg wmark\_text\_tiled.jpg This takes advantage of the fact that an image (like a photograph, not a diagram) will generally have some areas in which the tiled test string will be visible. You might like to make the text semi-transparent for your own watermarking (using say a half transparent grey such as "`'#80808080'`"). You may also like to keep this tiling technique in mind with the following proper watermarking techniques.[![[IM Output]](wmark_text_tiled.jpg)](wmark_text_tiled.jpg) ### Watermarking with Images | | | | --- | --- | | ImageMagick also provides a number of options that are specifically useful for more subtle watermarking, over a larger area. This is usually what is more commonly referred to, when you 'watermark' an image. To the right is a "water dragon" image I will use for these demonstrations. It has some transparency, which I used to check that IM is doing the right thing with respect to transparency, avoiding any horrible 'square' look to the results. | [![[IM Output]](../images/wmark_image.png)](../images/wmark_image.png) | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version 6, the options "[`-watermark`](https://imagemagick.org/script/command-line-options.php?#watermark)
" and "[`-dissolve`](https://imagemagick.org/script/command-line-options.php?#dissolve)
" were broken with their handling of the alpha channel (transparency) for the overlaying image, producing some very strange effects._ | **Watermark** compositing was meant to watermark images, and while it works, it tends only to work with pure white and black overlay images, producing ugly edge artifacts. magick composite -watermark 30% -gravity south \\ wmark\_image.png logo.jpg wmark\_watermark.jpg For more detailed information on this option see the [Watermark Option Usage](../compose/#watermark) page.[![[IM Output]](wmark_watermark.jpg)](wmark_watermark.jpg) **Dissolve** was found by me and others to work better. magick composite -dissolve 25% -gravity south \\ wmark\_image.png logo.jpg wmark\_dissolve.jpg This works very well, but parts of the watermark will disappear on images with pure white and black pixels. That is, dissolving white on white and black on black will not be visible in the final image. As these two colors are very common, it is better to do some extra pre-processing of the watermark so that is uses various shades of grey rather than pure white and black. (See "Greyed Dissolve" below)[![[IM Output]](wmark_dissolve.jpg)](wmark_dissolve.jpg) For more detailed information on this option see the [Dissolve Option Usage](../compose/#dissolve) page.**Tiled:** You can also tile the watermark across the background image instead of just adding it in one location. Just replace your gravity position with "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" instead. Of course in that case you may want to make the watermark even less intrusive. magick composite -dissolve 15 -tile \\ wmark\_image.png logo.jpg wmark\_tiled.jpg [![[IM Output]](wmark_tiled.jpg)](wmark_tiled.jpg) **Greyed Bumpmap:** To use bumpmap properly as a watermark the image needs some preparation to make both white and black a lighter grey color range, using a [Grey-Scale Adjustment](../color_basics/#greying) technique. If this is not done the result would be very very bold. magick wmark\_image.png -fill Gray91 -colorize 80 miff:- |\\ magick composite -compose bumpmap -gravity south \\ - logo.jpg wmark\_bumpmap.jpg [![[IM Output]](wmark_bumpmap.jpg)](wmark_bumpmap.jpg) The biggest problem with bumpmap as a watermark is that the operation will only darken an image. As such this technique is fairly useless for very dark images.**Greyed Dissolve:** The same preprocessing technique can also be useful with dissolve method so the white parts of the watermark image darken slightly on white background, and ditto also to lighten black areas of the watermark on black parts of the image. magick wmark\_image.png -fill grey50 -colorize 40 miff:- |\\ magick composite -dissolve 30 -gravity south - logo.jpg wmark\_dissolve\_grey.jpg [![[IM Output]](wmark_dissolve_grey.jpg)](wmark_dissolve_grey.jpg) This I'd say is just about ideal as a watermark, satisfying all the requirements. I would however further adjust the final dissolve to make the watermark even less noticeable.**Tiled Greyed Dissolve:** This is exactly as above but tiled over the image with an even lower dissolve value. magick wmark\_image.png -fill grey50 -colorize 40 miff:- |\\ magick composite -dissolve 15 -tile - logo.jpg wmark\_dissolve\_tile.jpg [![[IM Output]](wmark_dissolve_tile.jpg)](wmark_dissolve_tile.jpg) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The "`magick composite`" command does not know how to handle multi-image files such as animations. However other methods do allow you to do this. See [Modifying Animations, Annotating](../anim_mods/#annotating)
for examples of annotating and overlaying multi-image files._ | * * * Positioning Images and Text with Gravity ---------------------------------------- ### The 'Gravity' of the Situation As you can see above, being able to position images and text in a larger image can be just as important as anything else. Naturally the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting is one of the most important aspects of this. On the ImageMagick Mailing list, Tim Hunter declared _“ Gravity will make you crazy until you get the hang of it. ”_ This is a sentiment to which I agree wholeheartedly. Gravity will only be applied in the following situations... * Any operation that involves a 'geometry' like setting, like "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" and "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" positioning of images for [Alpha Composition](../compose/) , including [Multi-image Layered Composition](../anim_mods/#composite) . * It is also used, as means of specifying the text justification by the various text to image generators such as "`[label:](../text/#label) `" and the text justification by the various text to image generators such as "`[caption:](../text/#caption) `". * The "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" text drawing operator also uses it for text positioning as well as justification. * And finally it is used by the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" method for its '`text`' and "`image`' methods, and ONLY those methods. However "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" is **NOT** used for * Any image list or layer operators, such as "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `", "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" and most "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" methods, and especially not in GIF animations. All of these operations uses image offsets on a larger virtual canvas (set using the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `", "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" meta-data settings) to position images. Such offsets are always relative to the top-left corner of the images virtual canvas. No understanding of "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" is used in this methodology. * Any other "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" method does not use "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" for positioning. It is also unlikely to do so as "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" is not defined under the SVG draft which IM follows for these low level functions. What does all this this mean? First and most importantly it defines the origin point that "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" uses to position overlay text and images relative to the images edges, sides and center, without the user needing to know the actual size of the image. This is its primary function. Secondly it defines horizontal and vertical justification of the overlaid object (text or image) relative to that defined point of gravity. For example, with '`East`' gravity the text or image will be placed to the right (right justification) of the defined point. Justification should technically be a separate setting to "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", though closely related, however IM currently combines both into a single setting. There is a push to separate the two aspects such if a "`justification`" setting is undefined it falls back to using the current "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. If you find you need this, request it from Cristy (via the mail list). If enough users ask for it I am sure it will eventually be implemented. ### Image Positioning using Gravity Here is an example of using gravity to position images on a background. magick composite label:Default rings.jpg gravity\_default.jpg magick composite label:Center -gravity center rings.jpg gravity\_center.jpg magick composite label:South -gravity south rings.jpg gravity\_south.jpg magick composite label:East -gravity east rings.jpg gravity\_east.jpg magick composite label:NorthEast -gravity northeast rings.jpg gravity\_northeast.jpg [![[IM Output]](gravity_default.jpg)](gravity_default.jpg) [![[IM Output]](gravity_center.jpg)](gravity_center.jpg) [![[IM Output]](gravity_south.jpg)](gravity_south.jpg) [![[IM Output]](gravity_east.jpg)](gravity_east.jpg) [![[IM Output]](gravity_northeast.jpg)](gravity_northeast.jpg) Note that the actual position of the image is also justified according to the the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. That is, a gravity of "`South`" will center the image at the bottom of the larger image, but above that gravity point. This will become more important later with text rotation. The other thing to remember is that the position specified by any "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" setting is relative to the position gravity places the image. Not only that the direction of the position is also modified so that a position direction is inward. For example the "`-gravity South -geometry +10+10`" will move the label image further into the background. That is, the Y direction of the geometry position has been reversed, while the X direction was left alone. magick composite label:Default -geometry +10+10 \\ rings.jpg gravity\_default\_pos.jpg magick composite label:South -geometry +10+10 -gravity south \\ rings.jpg gravity\_south\_pos.jpg magick composite label:NorthEast -geometry +10+10 -gravity northeast \\ rings.jpg gravity\_northeast\_pos.jpg [![[IM Output]](gravity_default_pos.jpg)](gravity_default_pos.jpg) [![[IM Output]](gravity_northeast_pos.jpg)](gravity_northeast_pos.jpg) [![[IM Output]](gravity_south_pos.jpg)](gravity_south_pos.jpg) You can also use "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" with "`-draw image`", to multiple images with a single command. magick rings.jpg \\ -gravity Center -draw "image Over 0,0 0,0 'castle.gif'" \\ -gravity NorthEast -draw "image Bumpmap 0,0 0,0 'castle.gif'" \\ -gravity SouthWest -draw "image Multiply 0,0 0,0 'castle.gif'" \\ gravity\_image.jpg [![[IM Output]](gravity_image.jpg)](gravity_image.jpg) And you can also now use "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" to overlay images onto the background as well... magick rings.jpg \\ -gravity Center castle.gif -compose Over -composite \\ -gravity NorthWest castle.gif -compose Bumpmap -composite \\ -gravity SouthEast castle.gif -compose Multiply -composite \\ gravity\_image2.jpg [![[IM Output]](gravity_image2.jpg)](gravity_image2.jpg) For more detail of about the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" settings used above see [Alpha Composition](../compose/) . For other methods of overlaying combining and overlaying multiple images into one single image, see The IM Examples section [Layers of Multiple Images](../layers/) . ### Text Positioning with Gravity That is, all well and good for images but what about drawing text directly on images. Well the same basic effects as for images apply. As mentioned above gravity will also effect the positioning of text using either the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" '`text`' method, or the better "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" text drawing operator. magick rings.jpg -resize 120x120 \\ -gravity northwest -annotate 0 'NorthWest' \\ -gravity east -annotate 0 'East' \\ -gravity center -annotate 0 'Center' \\ -gravity south -annotate 0 'South' \\ -gravity northeast -annotate 0 'NorthEast' \\ gravity\_text.jpg [![[IM Output]](gravity_text.jpg)](gravity_text.jpg) There is one very important difference between positioning images and text. If you draw a text string, without defining any form of "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", the string will be drawn relative to the 'baseline' of the font.For example, lets actually do this... magick rings.jpg -annotate 0 'String' gravity\_text\_none.jpg [![[IM Output]](gravity_text_none.jpg)](gravity_text_none.jpg) If you look carefully you will only see the small loop tail of the 'g' in 'String' was visible at the top edge of the resulting image. The rest of the string has been drawn outside the background image. However if you set "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to '`NorthWest`' the text will be positioned as if it was an image. That is, relative to its [bounding or undercolor box](../text/#box) as defined by the font.For example... magick rings.jpg -gravity NorthWest -annotate 0 'String' gravity\_text\_nw.jpg [![[IM Output]](gravity_text_nw.jpg)](gravity_text_nw.jpg) The reason for the distinction is to ensure that IM text drawing remains compatible with other vector drawing image formats like the "SVG". These formats do not use gravity, so turning on gravity tells IM to follow the same rules as image placement when doing text drawing, rather than the vector graphics rules, involving the font 'baseline' and 'start' point of the text. If you do turn on gravity and then want to later turn it off, you can use either "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) none`" or "`[+gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to reset it back to the default 'no gravity' setting.Lets apply a text offset and draw both the default '`None`' and '`NorthWest`' arguments for "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", just so you can see how closely the two forms are related. magick rings.jpg \\ -gravity NorthWest -annotate +10+20 'NorthWest' \\ -gravity None -annotate +10+20 'None' \\ gravity\_text\_pos.jpg [![[IM Output]](gravity_text_pos.jpg)](gravity_text_pos.jpg) While it may not look it in this example, these two strings can overlap, particularly with regard to descenders on letters such as '`g`', and '`p`'. That this the two string are not properly separated by 'pointsize' units, but only by the fonts baseline height. The best idea is not to mix the two modes in your own image processing. Either use gravity, or don't. The choice is yours. #### Text on Left Edge using Gravity As a final example here is the way to actually annotate centered along the left edge of an image. The problem here is that when you rotate text, it rotates around the text 'handle'. Unfortunatally this handle is set by gravity BEFORE the text is rotated, and as such does not work very well, unless you use restrict yourself to 'centered text'. ![[IM Output]](gravity_text_left_fail.jpg)For example, here is a typical 'first try' to positioning text so that it is positioned along the center of the left edge of the image. Of course it fails rather unexpectally! magick rings.jpg \\ -gravity West -annotate 90x90+10+0 'String' \\ gravity\_text\_left\_fail.jpg As you can see the text was positioned on the left edge, but only so that start (where the pre-rotated 'handle' is) is centered. The cause of this problem is that in IMv7 the "[\-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) " setting is also directly used to set the text 'justification' (which sets the 'handle' used to position the text). There is some animated demos of gravity effects on rotated text written in PerlMagick API (Download "`[**im_annotation.pl**](../scripts/im_annotation.pl) `". I also created a shell script version of the same program, "`[**im_annotation**](../scripts/im_annotation) `", and "`[**im_annotation_2**](../scripts/im_annotation_2) `".A trick to making this work to rotate the whole image first then use center south! It is a non-sensical solution, but it works. magick rings.jpg -rotate -90 \\ -gravity South -annotate +0+2 'String' \\ -rotate 90 gravity\_text\_left.jpg [![[IM Output]](gravity_text_left.jpg)](gravity_text_left.jpg) An alternative method is shown below in [Text Positioning using Distort](#distort) . ### Text Positioning using Draw While in the above I used a 'text offset' to position the text relative to the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" point, it is not the only way to do so. The other method is to use a "-draw translate" option to position the text. This has the advantage in that you can arrange to position text without gravity effects, while still using gravity to 'justify' the positioning 'handle' within the text. In these examples I added some extra construction lines (which are also not gravity effected) to show how the position is applied from the center point of the image. Text with an offset... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 70,70' \\ -fill red -draw 'line 68,70 72,70 line 70,68 70,72' \\ -fill blue -draw "text 20,20 'Offset'" \\ text\_offset.jpg [![[IM Output]](text_offset.jpg)](text_offset.jpg) Text with a translation... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 70,70' \\ -fill red -draw 'line 68,70 72,70 line 70,68 70,72' \\ -fill blue -draw "translate 20,20 text 0,0 'Translate'" \\ text\_translate.jpg [![[IM Output]](text_translate.jpg)](text_translate.jpg) As you can see both produce the same effective result. But as the "`-draw text`" requires you to give an offset that was part of its arguments, it is more commonly used to position the drawn text from the command line. However while both of these methods produce the same result, they will produce completely different results when text rotation is also applied. Basically due to the order in which the actions are being applied. #### Draw Rotated Text There are two separate ways of positioning drawn text: use a 'text offset', or 'translate' the text to the final position. The effects of these two positioning methods produce very different results when rotation is also applied. The reason for this is complex, but essentially involves how IM does [Drawing Surface Warps](../draw/#transform) . Having said that lets look at what happens if you rotate some text using the two different positions. Just an offset, without rotation... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 70,70' \\ -fill red -draw 'line 68,70 72,70 line 70,68 70,72' \\ -fill blue -draw "text 20,20 'None'" \\ rotate\_none.jpg [![[IM Output]](rotate_none.jpg)](rotate_none.jpg) Rotating Text with an offset... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 50,78' \\ -fill red -draw 'line 48,78 52,78 line 50,76 50,80' \\ -fill blue -draw "rotate 45 text 20,20 'Offset'" \\ rotate\_offset.jpg [![[IM Output]](rotate_offset.jpg)](rotate_offset.jpg) Rotating Text with translation... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 70,70' \\ -fill red -draw 'line 68,70 72,70 line 70,68 70,72' \\ -fill blue -draw "translate 20,20 rotate 45 text 0,0 'Translate'" \\ rotate\_translate.jpg [![[IM Output]](rotate_translate.jpg)](rotate_translate.jpg) This is actually what most people want. Though the offset rotation can be useful for some special effects. Note how order of these [Drawing Surface Warps](../draw/#transform) are reversed to the order they are given. The rotation is performed first, and the translation is performed second. If you reverse the 'rotate' and 'translate' methods you will get the same result as an ordinary 'text offset', a rotated offset. The "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operator was designed specifically to make positioning rotated text easier, by specifically asking IM to draw the text with rotation, instead of 'doing surface warping'. Annotate with rotate and offset... magick -size 100x100 xc:white -gravity Center \\ -fill cyan -draw 'line 50,50 70,70' \\ -fill red -draw 'line 68,70 72,70 line 70,68 70,72' \\ -fill blue -annotate 45x45+20+20 'Annotate' \\ rotate\_annotate.jpg [![[IM Output]](rotate_annotate.jpg)](rotate_annotate.jpg) The problem with the above examples is that the IMv7 "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting not only refers to the position on the background image, but also the position in the overlay image that is to be drawn. IMv7 will be adding 'Text Justification', which refers to the overlay position, as a separate (but related) setting to gravity (background position). #### Text Positioning using Distort Using [SRT Distortion](../distorts/#srt) with [Layering Images](../layers/#flatten) , is particularly good method for placing images (or text in images). Basically it allows you complete low level control over both the point at which the image is placed, as well as how the image is to be arranged at relative to that point. To start with here we create a 'text image' with a transparent background and simply 'layer' the image onto the background image. magick rings.jpg -background none label:'Some Text' \\ -flatten layer\_simple.jpg [![[IM Output]](layer_simple.jpg)](layer_simple.jpg) As you can see the text simply added to image at top left corner. Lets rotate it using distort (layers variant) -- Not the use of parenthesis to limit what image we distort! magick rings.jpg \\( -background none label:'Some Text' \\ +distort SRT 70 \\ \\) -flatten layer\_rotate.jpg [![[IM Output]](layer_rotate.jpg)](layer_rotate.jpg) Note that the text position was NOT changed! All that happens was that the distort rotated the text around the center point (the handle), but so that relative to the 'virtual canvas' that point did not move. Thus when the now larger image is [Flattened](../layers/#flatten) its point of rotation 'the center of the text image' did not move. The next step is to move that handle, but for this we need to use almost the full set of [SRT Distortion](../distorts/#srt) arguments. Because we want to continue to use the 'center handle' as well we need to use some [Image Property Percent Escapes](http://imagemagick.org/script/escape.php) , or more specifically [FX Percent Escapes](../transform/#fx_escapes) . So lets place the center at '`+60+60`' in the background image magick rings.jpg \\( -background none label:'Some Text' \\ +distort SRT '%\[fx:w/2\],%\[fx:h/2\] 1 70 60,60' \\ \\) -flatten layer\_translate.jpg [![[IM Output]](layer_translate.jpg)](layer_translate.jpg) Another way of moving a 'layer image' is using the [Repage Operator](../basics/#page) . Especially a relative move using a '`!`' flag. The 'handle' for this is by the nature of layer images, the top left corner. The [SRT Distortion Operator](../distorts/#srt) will not only translate the image using the handle specified, but can use sub-pixel (floating point) positions for both of those handles. That is, it can distort the text by sub-pixel increments to any location, without the integer restrictions most other operations have. The final example is placing the 90 degree rotated text on the left edge. The handle of the text to rotate around and position will this time be at the be the center bottom of the text, before it was rotated. That is, a calculated position of '`%[fx:w/2],%h`'. Position on the background image must also now be calculated to be the center left edge, ('`0,%[fx:h/2]`'). The problem is the [SRT Distortion Operator](../distorts/#srt) does not have access to the background image when it is distorting the text image. The solution is to do this position calculation when the background image available, and save it into some 'personal setting' which can then be added to the distort arguments. This technique is looked more closely in [Extract Information from Other Images](../transform/#fx_other) . So here is the result. First calculate the position on the background image. Then distort the text image so its 'handle' is also moved to that pre-calculated position. magick rings.jpg -set option:my:left\_edge '0,%\[fx:h/2\]' \\ \\( -background none label:'Some Text' \\ +distort SRT '%\[fx:w/2\],%h 1 90 %\[my:left\_edge\]' \\ \\) -flatten layer\_on\_left.jpg [![[IM Output]](layer_on_left.jpg)](layer_on_left.jpg) The '`my:`' string can be anything that does not clash with existing prefixes. That is, I use it to hold MY settings, separate to any other settings ImageMagick may use for coders or specific options. Prefixing '`my:`' is a good choice for this. Percent escapes are handled purely as string substitutions, and in fact we could generate the whole Distort option as a string. The only problem is you can not do math on your '`my:`' settings, after they have been set. So any mathematics must be done before hand. This is something that will be looked at for IMv7, so that FX expresions use % escape variables. * * * --- # File Handling -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Image File Handling ======================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Image Formats Summary](#summary) [![](../img_www/granitesm_right.gif) Reading Images](#read) * [Read Modifiers](#read_mods) * [Input Filename Meta-character Handling](#read_meta) * [Compressed Images](#read_compressed) [![](../img_www/granitesm_right.gif) Saving Images](#save) * [Filename Percent Escapes](#save_escapes) * [GZipped Compressed Images](#save_gzip) * [Saved Attributes](#save_attributes) * [Encrypted Images](#save_encrypted) * [Writing a Multiple Images (adjoin)](#adjoin) * [Starting Sequence (Scene) Number](#scene) * [Writing an Image, Multiple Times](#write) [![](../img_www/granitesm_right.gif) Special Output File Formats](#special_formats) (Specific to IM) [`miff:`](#miff)    [`info:`](#info)    [`null:`](#null)    [`txt:`](#txt)    [`sparse-color:`](#sparse-color)    [`histogram:`](#histogram)    [`mpr:`](#mpr)    [`mpc:`](#mpc)    [`fd:`](#fd)    [`inline:`](#inline)    [`clipboard:`](#clipboard) -- Read/Write to/from windows clipboard [`ephemeral:`](#ephemeral) -- Auto-delete after read [`show:`, `win:`, and `x:`](#show) -- Display Images Directly [`x:` (as input)](#x) -- Display Capture and Re-draw [![](../img_www/granitesm_right.gif) Delegates and Coders for Image Formats](#delegates) * [Input Delegate Example](#delegate_input) * [Output Delegate Example](#delegate_output) * [Listing Delegates and Source Files](#delegate_list) * [Printing Delegate](#delegate_print) * [Spawning External Commands](#delegate_spawn) * [Postscript and PDF Delegates](#delegate_postscript) * [Direct Delegate Format Conversion (taint)](#delegate_direct) * [Other Delegate Examples](#delegate_other) [![](../img_www/granitesm_right.gif) Really Massive Image Handling](#massive) [![](../img_www/granitesm_right.gif) Long Streams of Lots of Images, Video sequences](#image_streams) To process an image, you not only need operators to work on the images, but you also need ways to read in and write out the image in as many different file formats as possible. In this section we look at IM file formats in general. * * * Image Formats Summary --------------------- One of the most common uses of ImageMagick is not to modify images at all, but only to magick an image from one image format to another. In fact this was the original reason for IM's creation was this sort of image format conversion. This is why the primary IM command is call "`magick`". To this end, ImageMagick can handle a bewildering array of image and file formats. Added to this array are a large number of special input and output formats for built-in test images, simple image creation, and image formats specific for programming shell scripts, and programs. For a complete list, see [IM Image Formats Page](https://imagemagick.org/script/formats.php) on the IM web site. All this can be daunting for a new user of ImageMagick. My best advise is to ignore most of the file formats, as you will probably never need them. Instead concentrate on what you want to do, and try to do it. If you don't know how, try to look for an example in these pages and across the web. For image formats demonstrated in IM Examples, see [Reference Index, File Formats](../reference.html#formats) . * * * Reading Images -------------- IM by default will attempt to determine the image format type by the 'magic' file identification codes within the file itself. If this fails however you will need to specify the images file format using with the files suffix, or by adding a prefix format. Some formats will not read any files and ignore any given filename. These are some of the common built-in images... logo: granite: rose: Some of them will generate images based on arguments given as a filename and perhaps an extra "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" controlling the final image size... -size 30x30 canvas:red -size 30x30 gradient:yellow-lime -size 30x30 pattern:fishscales magick import: In some cases you can even use multiple formats... -size 30x30 tile:pattern:gray95 This is however overkill in this case as the '`pattern:`' format coder has the '`tile:`' coder built into it. But it does make it clear what you were intending to do. IM can also download an image that is published on the 'world wide web' by specifying that images URL. This basically provides a '`http:`' image coder, which is why it works. magick http://www.ict.griffith.edu.au/anthony/images/anthony\_castle.gif \\ -resize 100x100 castle\_logo.png [![[IM Output]](castle_logo.png)](castle_logo.png) As you can see this command reads the image from the WWW and resizes it before finally saving the result to disk. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _When a prefix file format is given, any suffix given as part of the filename does not have any bearing on the way the file is read. This is in fact vital when reading some file formats such as the "`[text:](../text/#text) `" verses the "`[txt:](#txt) `" file format handling. Of course if an image generator actually reads in an image file to process it in a special way (for example "`[tile:](../canvas/#tile) `") then the suffix (or prefix) file formats will again become important, as it was in the last example_ | A special coder prefix "`implicit::`" can be used to 'turn-off' any use of coders, allowing use of ':' in the filename. Filename can have the special 'file meta-characters', such as '`*`' and '`?`' embedded in them. IM will expand these characters to generate a list of filenames to be read in, avoiding the need for an external shell to do this, or problems with command line length limits. For example... magick montage '\*.jpg' -geometry 50x50+2+2 image\_index.gif This will produce a single montage index image of all the JPEG files in the current directory. Note however that I needed to quote the argument to prevent my UNIX shell from expanding the file names rather than ImageMagick. See below for a more complete "`magick montage`" specification. Of course the linux shells can also expand '`*`' and '`?`' characters passed to them unquoted. However in some cases you may find yourself hitting 'command line limits' if the file list expands to a very large number of filenames. Here are other examples of using a linux shell to expand the filename... magick image\_\[0-9\].gif image\_\[1-9\]\[0-9\].gif animation.gif magick image\_?.gif image\_??.gif image\_???.gif animation.gif magick image\_(?|??|???|????).gif animation.gif Also see the [Read Frames, Read Modifier](#read_frames) below, for an formated incrementing number in the filename. If the filename is simply the single character string '`-`' IM reads the image from standard input. cat tree.gif | magick - -frame 5x5+2+2 read_stdin.gif [![[IM Output]](read_stdin.gif)](read_stdin.gif) Note that some image file formats allow you to simple append multiple image files together in one long multi-image stream. These formats include the simple [PbmPlus/NetPBM](../formats/#pbmplus) image formats, as well as IM's own special file format [MIFF:](#miff) for image in eye.gif news.gif storm.gif do magick $image miff:- done | magick - -frame 5x5+2+2 +append read_multiple_stdin.gif [![[IM Output]](read_multiple_stdin.gif)](read_multiple_stdin.gif) The special character '`@`' at the start of a filename, means replace the filename, with contents of the given file. That is, you can read a file containing a list of files! echo "eye.gif news.gif storm.gif" > filelist.txt magick @filelist.txt -frame 5x5+2+2 +append filelist.gif [![[IM Output]](filelist.gif)](filelist.gif) You can also use '`@`' with the special filename '`-`' to read the filenames from standard input. echo "eye.gif news.gif storm.gif" |\\ magick @- -frame 5x5+2+2 +append filelist\_stdin.gif [![[IM Output]](filelist_stdin.gif)](filelist_stdin.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Reading a list of filenames from a file using the '@' syntax was added in IM v6.5.2-1._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As a security precaution this only works with actual image files. It does not work with image generators such as "`rose:`" or "`label:string`". It also can not be used to 'include' command line options from a file._ | ### Read Modifiers or Extract Setting Image can be modified immediatally they have been read into memory, but before the image(s) are actually added to the current image sequence. You can specify a "`[-extract](https://imagemagick.org/script/command-line-options.php?#extract) `" setting. For example, here I crop the rose image... magick -extract 32x32+20+5 rose: +repage rose\_extract.gif [![[IM Output]](rose_extract.gif)](rose_extract.gif) Or you can append a read modifier to the end of the filename using square brackets '`[...]`'. For example... magick 'rose:\[32x32+20+5\]' +repage rose\_read\_modifier.gif [![[IM Output]](rose_read_modifier.gif)](rose_read_modifier.gif) Note however that '`[]`' characters are usually also special shell meta-characters, so if you use them it is a good idea to quote the additional modifier, to stop UNIX shells interpreting it. Both the "`[-extract](https://imagemagick.org/script/command-line-options.php?#extract) `" setting and the read modifer does the same job, though the latter will override the former. Also when you use a modifier, you must let IM handle any special file expansion meta-characters, such as '`*`' and '`?`', as an UNIX shell will not 'find' the requested files due to the modifier. What it actually does in that case is shell dependant. As such the whole filename should be quoted when using read modifiers. The real purpose of these read modifiers is to limit the amount of memory needed, by removing unwanted images or making images smaller, while images are still being read into memory. For example when readin a whole directory of large JPEG images. Here is the list of all the special read modifiers (and "`[-extract](https://imagemagick.org/script/command-line-options.php?#extract) `" settings ) and their effects. A '`#`' represent some number. '`[#]`' '`[#-#]`' '`[#,#,#]`' `[#,#-#,#]`'. **Read Frames** Will select specific sub-frames from a multi-image file format from the image that has been read in. The given number '`#`' index specifies the frame number to read. Multiple indexes can be specified in either comma order or as an index range. The image index start at zero for the first image, 1 for the second and so on. If you specify a negative index then the count is from the end of the image sequence, in reverse order, -1 for the last image, -2 for the second last image. This is exactly the same convention as used for the [Image Lists Operators](../basics/#list_ops) . For example magick document.pdf'\[0\]' first\_page\_of\_pdf.gif magick animation.gif'\[1-3\]' second\_to\_fourth\_frames.gif magick animation.gif'\[-1,2\]' last\_then\_the\_third\_frame.gif You can also get IM to read images based on a list of numbers. For example.. magick 'image\_%03d.png\[5-7\]' ... will read in the files "`image_005.png`", "`image_006.png`", and "`image_007.png`". With this method you can not use a negative index. '`[#x#]`' **Read Resize** From IM version 6.2.6-2 a new modifier was added to help IM users to handle very very large images. This modifier will resize the image that was just read in, immediately before that image is added to the other images already in memory.This can both shrink images, or enlarge images. For example... magick pattern:gray95'\[60x60\]' enlarged\_dots.gif [![[IM Output]](enlarged_dots.gif)](enlarged_dots.gif) Warning, the read modifier does not currently use any of the resize flags, such as `'!'` (no aspect preserve) or `'>'` (only shrink larger images. (perhaps if you put in a request?) You can also use it as an alternative way of specifying the size of a solid color canvas. Actually what is happening is that it is resizing the default single pixel image. For example... magick 'canvas:DodgerBlue\[50x50\]' canvas\_size.gif [![[IM Output]](canvas_size.gif)](canvas_size.gif) The modifier is most important when you are attempting to read in lots of very very large images, as each image will be resized before the next image is read, producing a substantial saving in total memory needed to handle those images. For example instead of... magick montage '\*.tiff' -geometry 100x100+5+5 -frame 4 index.jpg which reads all the tiff files in first, then resizes them. You can instead do... magick montage '\*.tiff\[100x100\]' -geometry 100x100+5+5 -frame 4 index.jpg This will read each image in, and resize them, before proceeding to the next image. Resulting in far less memory usage, and possibly prevent disk swapping ([thrashing](http://en.wikipedia.org/wiki/Thrash_(computer_science)) ), when memory limits are reached.For JPEG images I also recommend you use the special "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" setting instead, producing something like... magick montage -define jpeg:size=200x200 '\*.jpg\[100x100\]' -strip \\ -geometry 100x100+5+5 -frame 4 index.png The special setting is passed to the JPEG library and is used to limit the size the JPEG image during the reading process. However it is not exact, with the resulting image being somewhere between that size or double that size with the aspect ratio preserved. See [Reading JPEG Images](../formats/#jpg_read) for more details. The result of the combination is a much faster reading and even lower memory usage for JPEG images. Especially when generating lots of small thumbnails. See [General Thumbnail Creation](../thumbnails/#creation) . '`[#x#+#+#]`' **Read Crop** From IM v6.3.1 if you also add an offset the above becomes a crop of the image being read in. For example, To get a smaller 600x400 pixel sub-section from a much larger image. magick 'image.png\[600x400+1900+2900\]' tileimage.png This however will read in the entire image into memory then crop it before it is finally added to the current image sequence. If you want to handle really large images I suggest you look at the "`[stream](../basics/#stream) `" command and pipe you image into the "`magick`" command for further processing. See [Massive Image Handling](#massive) below. If the image is "`gzip`"ed, IM will automatically uncompress it, into a temporary file before attempting to figure out the image format and decode the image file format. As such you can not only save images in gzip compressed format, but use them directly in later IM processing. For large text based images this can result in enormous disk space savings. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The PNG format includes "`gzip`" compression as part of its format specification. In this case the first digit of the two digit PNG "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" setting defines the level of compression. For more detail see [PNG Image File Format](../formats/#png)
examples._ | The above is only a short summary of the special input options available when reading images into ImageMagick. A full summary is given on the [The Anatomy of the Command Line](https://imagemagick.org/script/command-line-processing.php) page on the [ImageMagick Website](https://imagemagick.org/) . As shown previously the image input can be modified by some IM settings such as "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" for image creation and "`[-define](https://imagemagick.org/script/command-line-options.php?#define) jpeg:size=??`" for JPEG reading. Other options also effect image input creation, including, "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `", "`[-type](https://imagemagick.org/script/command-line-options.php?#type) `", "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `", "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `". See [Setting/Changing Image Meta-Data](../basics/#meta-data) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Be very careful when passing an user provided argument to IM in a script, insuring that the argument is what you expect. You do not want to let a web image processing script return an image of the system password file for example._ | ### Input Filename Meta-Character Handling **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Not only does the shell handle meta-characters (unless that argument is quoted) but IM also does its own form of meta-character handling in filenames. For example magick \*.jpg .... is expanded by the shell BEFORE passing the filenames to IM, while magick '\*.jpg' .... will have the shell pass "\*.jpg" to ImageMagick, which then expands into an internal list of filenames! This was provided for Windows Dos support, and as a method to preventing command line limit overflows in command such as "magick mogrify" and "magick montage", which typically process long lists of images. As such to actually get IM to read a file names literially named on disk as '\*.jpg' you need to use any of the following forms... magick '\\\*.jpg' .... magick "\\\*.jpg" .... magick "\\\\\*.jpg" .... magick \\\\\\\*.jpg .... NOTE; the second line is NOT recommended as some shells (not bash) and some APIs (C programs, possibly PHP) may actually remove the single backslash, and pass '\*.jpg' to IM which it will again expand! On top of '?' and '\*', IM also adds the meta-character handling of ':', '%' and '\[...\]' for read modifier handling. These however have a different meaning (codec specification, scene number inclusion, and read modifiers) to normal shell syntax of those meta-characters. For example DOS uses will need to escape a 'drive-letter' in filename paths being passed to ImageMagick. For example... magick C\\:\\path\\to\\image.jpg .... Another example is when loading an image containg a time code. For example.. magick "time\_10\\:30.jpg" .... will read the filename "time\_10:30.jpg" from disk. Without the backslash, IM may think that the image should be read with a non-existant image file format (or delegate) "time\_10:", and fail in an unexpected way. An alternative is to use a question mark... magick "time\_10?30.jpg" ... However that may also match another file such as "time\_10\_30.jpg" as well! ### Compressing Images **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** IM will also read files that have been compressed, and given the appropriate suffix, or image format specification. That is, an image saved as "image.gif.gz" will first be uncomressed, before being decoded from its GIF image format. Gzipped XPixmap (xpm) and NetPbm/PbmPlus (ppm) images is also automatically handled, both by Imagemagick, and the formats normal delegate library. As such you can use the compressed forms directly either in IM, or in other programs that understand these file formats. See [Saving Compressed Images](#save_gzip) below. * * * Saving Images ------------- Processing images is well and good but it can be just as important to save the results in the right way. The last argument of the "`magick`", "`magick montage`" and "`magick composite`" defines a filename, and image format for a final write of the image (defailt image output). Though you can also save an image in the middle of an image sequence using "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `" (see below). To specify what file format you want to save your image, or images, you can either use a filename suffix, such as I use in just about all these examples, or prefix the filename with the string "`{format}:`". For example... magick tree.gif GIF:tree\_image [![[IM Output]](tree_image)](tree_image) If you check the resulting image you will find that a GIF image file was actually created, even though the filename itself does not have a "`.gif`" filename suffix. The case of the format is not sensitive, so you can use either lowercase or uppercase. This image format specification becomes particularly important when you want to save the image to the standard output of the command (using a "`-`" filename). This special filename does not have a suffix, so you _must_ tell ImageMagick what format to use. If you don't, the image will default to the original image format that the image came from (if known). For example, here we write an IM pixel enumeration to the screen using a "`-`" to output the result to the standard output. magick tree.gif -resize 1x3\! txt:- [![[IM Text]](write_stdout.txt.gif)](write_stdout.txt) It is also used to pass the image, on to another command such as "`magick identify`" though a shell 'pipeline', without saving it to a temporary file. magick tree.gif -resize 200% miff:- | identify - [![[IM Text]](write_identify.txt.gif)](write_identify.txt) In this case you can also see that the special "`-`" filename is also used to denote reading an image from standard input by the "`magick identify`" command. For more information see the offical guide at [The Anatomy of the Command Line, Output Filenames](https://imagemagick.org/script/command-line-processing.php#output) . ### Filename Percent Escapes The save filename can contain a few special percent escape (`%`) sequences. Specifically, '`%d`', '`%x`', and '`%o`'. These inserts the images 'scene number' into the file name using the C '`printf()`' formats. For more information see [Writing a Multi-Image Sequence](#adjoin) below. Of course this means that if you want to insert a percent character into the filename you will need to double it ('`%%`'). As of IM v6.4.8-4 you can now also insert special pre-prepared setting (must start with '`filename:`' into the final filename. For example... magick rose: -set filename:mysize "%wx%h" 'rose_%[filename:mysize].png' [![[IM Output]](rose_70x46.png)](rose_70x46.png) This saves the built-in rose image into a file containing that images size in pixels. Specifically, the filename "`rose_70x46.gif`". This will let you (with a little indirection) use any [Image Property Percent Escape](http://imagemagick.org/script/escape.php) as part of your output filename. Note that only a '`%[filename:_label_]`' image [Property](../basics/#property) can be used within the output filename (along with the normal '`%d`' escape. This restriction is for security reasons and the fact that legitimate image filenames could include '`%` and '`[]`'. Warning, do not include the file suffix in the filename setting! IM will not see it, and save the image using the original file format, rather than the one that was included in filename setting. That is, the filename will have the suffix you specify, but the image format may different! The '`filename:`' setting does not need to be the same for every image. You can generate or even calculate or set a different setting for each image being used. Here is another example where I modify an image, and write it to a new filename, that was built using each individual images original filename. magick eye.gif news.gif storm.gif -scale 200% \ -set filename:f '%t_magnify.%e' +adjoin '%[filename:f]' [![[IM Output]](eye_magnify.gif)](eye_magnify.gif) [![[IM Output]](news_magnify.gif)](news_magnify.gif) [![[IM Output]](storm_magnify.gif)](storm_magnify.gif) This magnifies each image such as "`eye.gif`" and saves it in the file "`eye_magnify.gif`" in the current directory. However all three images are read into memory, and then modified by the one command. This is not a recommended solution for a number of large images, or very large numbers of images, due to the posibilty of reaching memory limits and thus going to disk swapping (thrashing). Note that the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" in this case is vital to prevent IM saving all the images into a mutli-image GIF animation, using just the filename of the first image. I also ensured I preserved the original suffix of the filename using the "`%e`" escape sequence. Normally including the suffix in the filename setting is a bad idea, as IM does not see it when it comes from an escape sequence, for determining the output file format. In this case however the format is not changing so there is no problem. Caution is needed. To get the exact original filename of the image use '`%d/%f`' or '`%d/%t.%e`'. You can also use '`%m`' instead of '`%e`' which is the actual format (in capitals) that IM found in the original images file (which may not match the original images filename suffix). Note that for built-in images, many of these escape sequence strings are blank. Also if there is no directory the '`%d` will be blank. This is a known problem for IMv7 Another example of using 'Filename Escape Sequence' is in [Tile Cropping Images](../crop/#crop_tile) , where the technique it is used to generate a filename basied on a calculated tile position for each of the resulting images. Also see the example in [Using Convert Instead of Morgify](../basics/#mogrify_convert) . ### Automatic GZip Suffix IM will also automatically "`gzip`" images if a "`.gz`" suffix is given. For example, here I save the built-in "`rose:`" image as a "`gzip`"ed, uncompressed GIF file. I turn off the normal LZW compression of GIF, as it would prevent "`gzip`" compression from achieving its best compression. magick rose: -compress none rose.gif.gz [![[IM Output]](../img_www/doc_art.png)](rose.gif.gz) How browsers handle a gzipped image depends on the file type returned by the web server and how your browser handled compressed images. Because of this I did not directly display the above image. Click on the 'art' icon to see what your browser does, with such an image from this web server. Compare the size of this to a normal saved LZW compressed GIF image... magick rose: rose.gif [![[IM Output]](rose.gif)](rose.gif) The "`gzip`"ed rose is [![[IM Text]](rose_gz_size.txt.gif)](rose_gz_size.txt) bytes in size, while a normal LZW compressed rose is [![[IM Text]](rose_size.txt.gif)](rose_size.txt) bytes. As you can see GZIP compression is actually slightly better than the LZW compression that the GIF format uses, so may be better for archiving purposes. GZipped image files are more commonly used for longer term storage of image file formats that do not have any compression by default. This includes the IM File format "[MIFF:](#miff) " and the simpler [NetPBM](../formats/#netpbm) image file formats. ### Saved Attributes **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Other Settings specific to image writing.... -depth -quality -compress -type -loop -set label -set comment Also see [Image Depth](../basics/#depth) , [Image Type](../basics/#type) , [JPEG Quality](../formats/#jpg_write) , [PNG Quality](../formats/#png_quality) . [GIF loop](../anim_basics/#loop) . Talk about file compressions, which are part of various image formats. Different compressions are used for different image formats. Especially the JPEG to TIFF compression change needed. Using or "[\-compress](https://imagemagick.org/script/command-line-options.php?#compress) None" and "[\-compress](https://imagemagick.org/script/command-line-options.php?#compress) " NetPBM text/binary format selection. The GIF compression and the copyright patent. Other than using IM to reduce -quality or changing the format to something else the -compression option is rarely used. Often it is only used internally by IM to save images using the same compression the image was read with. ### Encrypted Images IM also allows you save sensitive images with encrypted with a pass phrase using the options "`[-encipher](https://imagemagick.org/script/command-line-options.php?#encipher) `" and "`[-decipher](https://imagemagick.org/script/command-line-options.php?#decipher) `". See [Encrypting Images](../transform/#encipher) ### Writing a Multiple Images - Adjoin Techniques A major problem with saving images, is that ImageMagick works with an ordered sequence (list) of images, not just one image at a time. Because of this IM will attempt to write ALL the images in the current image sequence into the filename given. If the file format allows multiple images IM will by default save all the images in the current image sequence into that image file. For example if you look at the [GIF Animation Basics](../anim_basics/) examples page you will see that it will save multiple image frames into a single image file format to produce an animation. If the output format does not allow you to save multiple images into the one file, IM will instead generate multiple files. For example, when saving to image formats like `JPEG` and `PNG` and so on. You can also force this behavior on image formats that do allow multiple images per file, such as `GIF` and `PS` by using the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" output file handling setting. magick eye.gif news.gif storm.gif +adjoin image.gif [![[IM Output]](image-0.gif)](image-0.gif) [![[IM Output]](image-1.gif)](image-1.gif) [![[IM Output]](image-2.gif)](image-2.gif) If you look closely at the filenames of the three images generated above, you will see that IM generated images named "`image-0.gif`" to "`image-2.gif`". | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Previous to ImageMagick version 6.2.0 the output filename of the above would have been "`image.gif.0`" to "`image.gif.2`". This resulted in many problems due to the loss of the filename suffix, so was changed to add the image number, before the filename suffix._ | An alternative is to add a 'C language printf()' construct "`%d`" to the output filename. This special string will be replaced by the current image number of each image in sequence. magick eye.gif news.gif storm.gif +adjoin image\_%d.gif [![[IM Output]](image_0.gif)](image_0.gif) [![[IM Output]](image_1.gif)](image_1.gif) [![[IM Output]](image_2.gif)](image_2.gif) Here we generated the images "`image_0.gif`" to "`image_2.gif`", using an underscore rather that the IM default of a dash. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Not only can you use '`%d`' for a decimal number, but you can use '`%x`' for a hexadecimal number (lowercase), '`%X`' for a hexadecimal number (uppercase), or '`%o`' for an octal number.

_ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _If you really want a percent character which is followed by one of these letters, then you will need to double the percent character to escape its meaning. That is, you will need to use '`%%`' to ensure you actually generate a percent symbol.

_ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The '`%d`' in the output filename actually enables the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" setting of ImageMagick, automatically.
However while I don't actually need the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" in the above, it is probably a good idea to provide it anyway, just so it is clear that you are generating separate images._ | This works well for a small number of images, but if you have more than ten images you will get a mix of image with one digit and two digit numbers. And if you have more than a hundred, you get three digit numbers too. When that happens, directory listings will no longer list the saved images in sequence, since "`image_15.gif`" would alphabetically appear before "`image_5.gif`". Of course there are ways to fix this. For example using a command line shell expressions like.. magick image\_\[0-9\].gif image\_\[1-9\]\[0-9\].gif animation.gif magick image\_?.gif image\_??.gif image\_???.gif animation.gif magick image\_(?|??|???|????).gif animation.gif magick 'image\_%d.gif\[0-123\]' animation.gif The last method is the proper IM way of handling a sequence of files, though you need to know the range of number you want to use. The '`%d`' formats each number to match the filename (see next)In any case, this is awkward and prone to mistakes, can produce errors if files are missing, and can be dependant on what type of computer system you are using. Better to avoid this problem altogether. If you are familiar with the 'C' language (look up the UNIX system man page for '`printf`') then you will probably know that if you use something like "`%03d`" you will always get 3 digit numbers (with leading zeros) for the image sequence frame number. The image names would in that case be "`images_000.gif`", "`images_001.gif`" and so on. magick eye.gif news.gif storm.gif +adjoin image\_%03d.gif [![[IM Output]](image_000.gif)](image_000.gif) [![[IM Output]](image_001.gif)](image_001.gif) [![[IM Output]](image_002.gif)](image_002.gif) Using this method, the images will not only be numbered, but will also list alphabetically correctly, making image file handling a whole lot easier. I thus recommended you add a '`%03d`' or whatever is appropriate, to the output filename whenever you plan on writing multiple images, as separate image files. ### Written Scene Numbers If you want the image sequence to start at '`1`', instead of '`0`', and don't want to rename all the resultant image files, the simplest solution is to prepend a 'junk' image on the front of the sequence to be written. magick null: eye.gif news.gif storm.gif +adjoin image_%01d_of_3.gif rm image_0_of_3.gif [![[IM Output]](image_1_of_3.gif)](image_1_of_3.gif) [![[IM Output]](image_2_of_3.gif)](image_2_of_3.gif) [![[IM Output]](image_3_of_3.gif)](image_3_of_3.gif) You can, of course, use "`[+insert](https://imagemagick.org/script/command-line-options.php?#insert) `" to do this after your image processing. This is not a particularly nice solution, but works, and is simple, and backward compatible with the older major versions of IM. As of IM version 6.2 you can use the "`[-scene](https://imagemagick.org/script/command-line-options.php?#scene) `" setting to set the starting number for the current image sequence. magick eye.gif news.gif storm.gif +adjoin -scene 101 image\_%03d.gif [![[IM Output]](image_101.gif)](image_101.gif) [![[IM Output]](image_102.gif)](image_102.gif) [![[IM Output]](image_103.gif)](image_103.gif) Which produced the image files "`image_101.gif`" to "`image_103.gif`". ### Writing an Image, Multiple Times While on the subject of writing images, it is possible to write an image from the middle of a sequence of image operations, using the special "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `" image operator. This is very useful when you like to output an image multiple times at various points during image processing. For example, see [Complex Image Processing with Debugging](../basics/#complex) . Here is an example where I have a [Photo of some Parrots](../img_photos/parrots_orig.png) , curtisy of the [Kodak Lossless True Color Image Suite](http://r0k.us/graphics/kodak/) (image 23), but I want to save them in a range of different sizes, using one command... magick parrots\_orig.png \\ \\( +clone -resize x128 -write parrots\_lrg.jpg +delete \\) \\ \\( +clone -resize x96 -write parrots\_big.jpg +delete \\) \\ \\( +clone -resize x64 -write parrots\_med.jpg +delete \\) \\ -resize x32 parrots\_sml.jpg [![[IM Output]](parrots_lrg.jpg)](parrots_lrg.jpg) [![[IM Output]](parrots_big.jpg)](parrots_big.jpg) [![[IM Output]](parrots_med.jpg)](parrots_med.jpg) [![[IM Output]](parrots_sml.jpg)](parrots_sml.jpg) As you can see we can use the [Image List Operators](../basics/#list_ops) to process a 'clone' of an image, write out the result, then delete and backtrack back to the original source image, repeating the process as many times as you need. In this particular case it means I did not end up resizing the same image over and over, and thus accumulating resize errors. It also meant I could have just as easily generate the smaller images first, then the larger images after that, without problems, or modify the image in many different ways for each image file generated. That is, the order and modification of each image is irrelevent! Note that "`[+clone](https://imagemagick.org/script/command-line-options.php?#clone) `" does not actually duplicate the image data! IM uses a reference-counted cloning process which only copies the image pixels when they are updated. As such only enough memory to hold the original image and the new image that is generated is actually used, in the above process. It also makes "`[+clone](https://imagemagick.org/script/command-line-options.php?#clone) `" very fast, and memory efficient. Here is another technique of doing the same thing, but saving the original image in a named image register using "`[MPR:](#mpr) `" (see below), instead of "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `". magick scroll.gif -background lightsteelblue -flatten -alpha off \\ -write mpr:scroll -resize x128 -write scroll\_lrg.jpg +delete \\ mpr:scroll -resize x96 -write scroll\_big.jpg +delete \\ mpr:scroll -resize x64 -write scroll\_med.jpg +delete \\ mpr:scroll -resize x32 scroll\_sml.jpg [![[IM Output]](scroll_lrg.jpg)](scroll_lrg.jpg) [![[IM Output]](scroll_big.jpg)](scroll_big.jpg) [![[IM Output]](scroll_med.jpg)](scroll_med.jpg) [![[IM Output]](scroll_sml.jpg)](scroll_sml.jpg) Here we save one copy of the original image into the "`mpr:scroll`" image register, before modifying the image still in memory after the write. Note that a MPR register can actually hold a whole sequence of images. Once the results of that operation is written and deleted from memory, the original image (or image sequence) is recovered, and the process repeated as many times as needed. Of course as previously there is no need to use "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `" on the final image, as we can just output it as normal. If you did use a "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `", you can instead just junk the final image using another special file format "`[NULL:](#null) `" (see below).**A word of warning about "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `"**: Because some file formats require images to be in a special format for writing, the "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `" operator could modify images. GIF images for example may be color reduced (see [Quantization and Dithering](../quantize) ). However other formats will leave the source image as is (see [MIFF](#miff) and [MPC](#mpc) below). If you need protect yourself from these changes (as you are not simply deleting the image afterward), you can use "`[+write](https://imagemagick.org/script/command-line-options.php?#write) `" which will make an internal clone of the image for writing, then delete it afterwards. However remember that this can result in a doubling of memory use to hold the write modified copy of the image. At least for a moment. * * * Special File Formats (specific to IM) ------------------------------------- As you saw above (and will explore in the next section [Common Image File Formats](../formats/) ), ImageMagick understands a huge number of well known image file formats. It also includes a good number of special image generators (as exampled in [Canvas Creation](../canvas/) ). On top of these there are also some very special file formats, which allow some very special handling of images. **`miff:`** Is the ImageMagick File Format. The whole image sequence and _all_ the attributes associated with the images are saved in this file format. Of course only ImageMagick commands will read this format, so it is not suitable for transferring between different image processing packages. The "`miff:`" file formats primary purpose is as an intermediate save format, when processing images in long an complex ways. It is also suitable for 'pipelining' an image from one IM command to another, while passing image meta-data and other attributes assocated with the image. I recommend when writing "`miff:`" that you include a "`[+depth](https://imagemagick.org/script/command-line-options.php?#depth) `" option. This will reset the 'input depth' of the image to the IM memory quality so as to use the best posible quality for the intermediate image save. Of course you can 'clip' the save image depth using "`-depth 8`" so as to reduce the image size on disk, however that will also force [Quantum Rounding](../basics/#quantum_effects) effects as well (unless [HDRI floating-point save](../basics/#hdri_formats) is also enabled). For those interested in parsing this format, it starts with a plain text header of all the image attributes. The header end in a line containing a single formfeed character. This header is itself an useful way of extracting basic image information in various image processing processing scripts. For example, here are I use a GNU-sed command to list the "`miff:`" header up to the formfeed separator, showing all the attributes of the built-in "`rose:`" image. magick rose: miff:- | sed -n '/^\f$/q; p' [![[IM Text]](write_miff_info.txt.gif)](write_miff_info.txt) This is actually quite useful as it reveals all the current settings flags and meta data that IM knows about the image. However there is also statistics, as these are generated by either the "`magick identify`" command, the "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" operator or the special "`info:`" format; if requested with a "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" option. (see next) The image file format has very low parsing requirements, and while not compressed, can handle ANY type image IM knows about. It is almost the most ideal format to use for temporary images, and pipelined image commands you can use, though ImageMagick programs is the only one that can read it. See also the "`[MPR](#mpr) `" image memory register, and "`[MPC](#mpc) `" memory disk mapping formats below. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The raw image data (binary) is actually prefixed by the four character sequence "\\n\\f\\n:", (formfeed on a line by itself, and a colon). How this data should be read is encoded in the header data, but tyically consists of binary integers in RGB turples. But can have more channels, and could even consist of floats or even double data values.

In may ways it is practically identical to a binery [PbmPlus](../formats/#pbmplus)
Image file format,with a greatly expanded header to hold image meta-data, and more variations in number of channels and data types._ | **MIFF Image Streaming** The "`miff:`" format is a 'streaming' image file format. That is to say multiple images are handled simply by appending or concatenating the images together, one after the other. This means you can generate a 'stream' of multiple images, simply by writing the images to the same destination, such as a pipeline. Even if the individual images were generated by different commands. For example you can have a loop of image processing commands, each command simply outputs a 'streaming' MIFF image. After the loop you can pipe the 'stream' of images into an into a single command to generate montages, collages, animations, or something else. For example the following generates a list of colors starting with the letter 'b', then uses a loop of "`magick`" commands to generate a labeled color patch, one color at a time. These are then 'piped' into a "`magick montage`" to generate a simple color table. magick -list color | egrep '^b' | \\ while read color junk; do \\ magick -label $color -size 70x20 xc:$color +depth miff:-; \\ done |\\ magick montage - -frame 5 -tile 6x -geometry +2+2 \\ -background none color\_table.png [![[IM Text]](color_table.png)](color_table.png) The above specific example was programmed into a script "**[show\_colors](../scripts/show_colors) **" which you can use to search for, find and display colors, for use in your image processing. The above is an example of a '**Pipeline of Streaming Images** that is very useful for generating multi-image sequences. Other examples of this technique include [Programmed Positioning of Layered Images](../layers/#layer_prog) , [Pins in a Map](../layers/#layer_pins) , the 'Named Colors Image' in [Colors by Name](../color_basics/#color_names) , and the animations such as shown in [Random Ripples](../canvas/#random_ripples) . This technique can also be used with operations like "`-write miff:-`", so as to output a miff format image from multiple places in a single command. Each image will be automatically append together in the final output stream. This can be especially useful for debugging complex image processing commands.The alternative method (commonly using in PHP scripts) is to use a 'generated command' technique, that uses a shell script to generate a long "`magick`" comamnd to be run. The scripts in [Image Warping Animations](../warping/#animations) use this technique. **`info:`** The "`info:`" file format (added in IM v6.2.4) does _NOT_ output an actual image! This format basically outputs the same information that the ImageMagick "`magick identify`" command will output. Like "`magick identify`" this output format is controlled by the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" and "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" options allowing you to output just the specific information you are interested in, as defined by the [Image Property Escapes](https://imagemagick.org/script/escape.php) page.For example instead of piping a MIFF image to "`magick identify`" as we did above (see [Saving Images](#saving_images) ), we could have used the following, to retrieve the single line identification of the resulting image format. magick granite: info:- [![[IM Text]](info_image.txt.gif)](info_image.txt) Of course you can use a "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting to output the desired information in a specific and more parsable way. What is so useful about "`info:`" is that you can now produce your image, while extracting extra information about it, at the same time. This is done by using the "`[-write](https://imagemagick.org/script/command-line-options.php?#write) `" operator to save this special image format to a file (or the commands normal standard output). magick rose: -shave 12x0 -repage 64x64+9+9 \ -format '%wx%h %g' -write info:info_paged.txt paged.gif [![[IM Output]](paged.gif)](paged.gif) [![[IM Text]](info_paged.txt.gif)](info_paged.txt) There is also a "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" operator that is equivalent using "`[-write](https://imagemagick.org/script/command-line-options.php?#write) info:`" to output image identification information to standard output. This make it even easier to monitor what is happening to your images when debugging your IM commands. For example... magick logo: -identify \ -trim -identify \ +repage -identify \ -resize 80x80\! -identify \ logo_thumbnail.gif [![[IM Output]](logo_thumbnail.gif)](logo_thumbnail.gif) [![[IM Text]](info_thumbnail.txt.gif)](info_thumbnail.txt) Here you can see how "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" reduced the size of the image but preserves the 'crop' information of what part of the image was trimmed, then the "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" removing that extra 'canvas' or 'page' information. And so on. Also like the "`magick identify`" command, both "`[info:](#info) `" and "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `", will become much more verbose if the "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" setting is turned on. Here I limit the long output to just the first few lines, just so you can get a bit of an idea about it. magick rose: -verbose info: | head [![[IM Text]](info_verbose.txt.gif)](info_verbose.txt) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" setting will also cause extra information about images being read in or out, to be printed to the standard error (with the exception of the "`info:`" format). It also causes some operators like "`[-colors](https://imagemagick.org/script/command-line-options.php?#colors) `" to output additional information. As such you may like to turn it off again after using it with either "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `" or the "`info:`" format.

For example_    "`-verbose -write info:image_info.txt +verbose`"    _or_    "`-verbose -identify +verbose`" _._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Scripted reading of the output from any form of "`[identify](../basics/#identify) `", should do so in a case in-sensitive way. This insures better backward compatibility between different versions of ImageMagick._ | NOTE: "`info:`" (and "`[-identify](https://imagemagick.org/script/command-line-options.php?#identify) `") is only an output format, producing the same output as the "`[identify](../basics/#identify) `" command. You can not read, or create an image using the "`info:`" file format. You can also use "`[-print](https://imagemagick.org/script/command-line-options.php?#print) `" to print information, but that is applied only once against the whole image sequence. That means you can use this operator to calculate much more complex '`%[fx:...]`' expressions involving multiple images. But remember unlike the other methods above, it is only applied once accross all images. **`null:`** As an output format, this will just 'junk' the image results. As such if used as the final argument in a "`magick`", "`magick montage`", or "`magick composite`" command the final result will not be saved! Why? Well it may be that you are more interested in specific images, generated during image processing rather than the overall result, especially when debugging. For example, here we extract and save one image, from an image sequence, then junk all the other images using "`null:`". magick eye.gif news.gif storm.gif tree.gif rose: logo: \\ \\( -clone 2 -write write\_storm.gif \\) null: [![[IM Output]](write_storm.gif)](write_storm.gif) This is a lot simpler than attempting to delete all the other images one at a time. As an input image format however, "`null:`" will generate a special placeholder image of a single transparent pixel, with with a special 'null source' flag, in the current image sequence. This special image is especially important to [Leave Gaps in a Montage](../montage/#null) , and as a list separator for multi-image [Layer Composition](../anim_mods/#composite) . It is closely related to another special image format known as a '[missed image](../crop/#crop_missed) ', that can be generated for operations like "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `". This image format is produced when an operation produces an empty or non-sensible result. Both images are a single transparent pixel, and as such "`null:`" images will also be treated as if it is a '[missed image](../crop/#crop_missed) '. At this time there is no method to remove any "`null:`" or even '[missed image](../crop/#crop_missed) ', from the current image sequence. However such a method has been proposed. Mail me if you find you need such a method. **`txt:`** This is a simple ASCII text file, which basically lists each pixel in the image, one per line. It is not a general text to image converter, for that see [Multi-line Text Files Examples](../text/#text) . If the 'pixel enumeration' is not reconised, the image will be passed to the "`[text:](../text/#text) `" format coder, for rendering as a plain text file. For example, here is a "`netscape:`" image scale to a 2x2 pixel image, then listed using a "`txt:`" image format. magick netscape: -scale 2x2\\! txt\_netscape.txt [![[IM Text]](txt_netscape.txt.gif)](txt_netscape.txt) The first line (header) of the image is packed with the basic information about the image. The information consists of... _File Magic:_ The image header defines this file as a the special IM text image format (EG a "ImageMagick pixel enumeration" file), this is known in computing circles as the files 'magic' or the code string which identifies this file as being this specific file format. _Image Size:_ The next two numbers define the size of the image contained in this file. Multiplying these numbers together will also tell you how many lines should follow the header to fully define the image. IM will always output this many lines, though as you will see later when reading you do NOT need to define ALL the pixels. _MaxValue:_ The last number in the header defines the 'maximum value' of the image data that is possible. In the above examples this was '`255`' which is a result of using a 8 bit depth. The reason it output the built-in "`netscape:`" image at this depth is because it was defined internally using 8-bit values, and as such IM preserved this depth level for the image. See the section on the [Depth Setting](../basics/#depth) for more information. But you can override the depth setting (up to the limit of your IM's Q or [Compile-time Quality](../basics/#quality) setting, by changing the images "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `". For example, here I output the color values as 16 bit values (from 0 to 65535)... magick netscape: -scale 2x2\\! -depth 16 txt\_netscape\_16.txt [![[IM Text]](txt_netscape_16.txt.gif)](txt_netscape_16.txt) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _At this time you can not set a specific 'Maximum Value' to use in the output file format. You can only define a different value in terms of the current "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting, making the maximum value equal to `2^depth-1`._ | _Colorspace:_ The last item in the header defines the [colorspace](../color_basics/#colorspace) of the data that follows. If the image contained any transparency, a final letter '`a`' (for alpha) is also appended to the colorspace name, and an extra column of numbers added between parenthesis. Grayscale images will output an image as '`grey`', but will define at least three numbers, which will be the same value for each pixel. For example, here is the same image using a [colorspace](../color_basics/#colorspace) of '`LAB`' with an alpha channel added! magick netscape: -scale 2x2\\! -colorspace LAB -alpha set txt\_cspace\_lab.txt [![[IM Text]](txt_cspace_lab.txt.gif)](txt_cspace_lab.txt) After the initial header are the _Pixel Data_ lines, one per pixel in the image. _Coordinates:_ The first two numbers up to the colon '`:`' is the pixel position, starting from 0. _Color Values:_ After this the color values for the pixel (from 0 to the _MaxValue_ given in the header) is given in parenthesis, with anywhere from 3 to 5 numbers depending on the current colorspace for the image. Spaces are optional so caution is advised when parsing the numbers in parenthesis. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The values are normally intergers. However as of IM v6.9.2-1, if the special define "`[-define](https://imagemagick.org/script/command-line-options.php?#define) txt:compliance=css`" is given with "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) 16`" the values will be represented as percentage values with '`%`' signs. This is part of SVG, CSS compliance._ | _Color Comments:_ Anything that follows the numbers in parenthesis, is regarded as comment. IM will fill in extra information on the pixel color using formats that it can parse as a color argument (See "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" manual entry for details of these color specifications). The color comments are however variable, though typically it will start with a hash ('`#`') hexidecimal color value, after which it may output RGB() values, or color names depending of the pixel data given. These colornames should be understood by ImageMagick, but are meant as a referance only, as it is purely a comment. Exactly what colors is provided is highly dependant on the IM version you are using, especially in early IM v6 versions and before. There is no guarantee that this comment area will not change again in the future, so it is best not to rely on it. IM doesn't when reading a Pixel Enumeration Image. Here is an example of correctly reading a Pixel Enumeration in a shell script. The exact format of the TXT image is defined by the convert command, then '`tail`' is used to junk the header, '`tr`' to character replace every non-number character with a single space, so that the later '`while`' can read the numbers easily, junking any later comment numbers that may have been left over. magick rose: -resize 3x2\! -depth 8 -colorspace RGB -alpha off txt:- | tail -n +2 | tr -cs '0-9.\n' ' ' | while read x y r g b junk; do echo "$x,$y = rgb($r,$g,$b)" done [![[IM Text]](txt_shell_read.txt.gif)](txt_shell_read.txt) **Reading TXT images** is also valid. You do not need to define ALL the pixels in the image. In fact you do not even need to have the pixels in the correct order! ImageMagick will just read each pixel defining line in turn, and 'draw' it onto a blank image canvas. Only the numbers in the parenthesis on each line is used for this, not the color names. The initial blank canvas, is cleared and set to the current background color. As such any pixel not provided by a "`txt:`" image, will be left as this color. For interesting use of "`txt:`" images, look at [Forward Pixel Mapping](../distorts/#forward_mapping) where I output an Enumerated Pixel Image, then change each of the pixel locations so as to rotate (distort) the image, before reading the Enumerated Pixel Image, back into IM again. In the resulting image some pixel locations were not defined, while other locations had multiple pixels added. IM handled this without problems. The "`txt:`" format is especially useful with the "`[-unique-colors](https://imagemagick.org/script/command-line-options.php?#unique-colors) `" operator, which replaces each image in the current image sequence with a new image containing one pixel for each unique color found. When this is output to a "`txt:`" format file, you get a basic summary of the colors contained in an image (though not their counts, or histogram). For example, here are the colors used by the tree image. As GIF can only use 8 bit numbers, the colors is also output at the same [Depth](../basics/#depth) . magick tree.gif -unique-colors txt:- [![[IM Output]](../images/tree.gif)](../images/tree.gif) [![[IM Text]](tree_colors.txt.gif)](tree_colors.txt) There is another alternative to using the IM "`txt:`" format using the various [NetPBM image file formats](../formats/#netpbm) . IM by default outputs this format as binary, but you can turn off "`[-compress](https://imagemagick.org/script/command-line-options.php?#compress) `" to output an ASCII text version of the NetPBM format. For example. magick tree.gif -unique-colors -compress None -depth 8 tree_netpbm.ppm [![[IM Text]](tree_netpbm.ppm.gif)](tree_netpbm.ppm) You may notice that the numbers in the above matches the number in the IM's Enumerated Pixel ("`txt:`") format. See [Resized Gradient](../canvas/#gradient_resize) for some examples of generating a NetPBM format image for IM to read. If you just want the color of a specific pixel you can crop the image down to one pixel, and output it as a "`txt:`" image. magick rose: -crop 1x1+12+26 txt: [![[IM Text]](rose_one.txt.gif)](rose_one.txt) Or you can use a special [FX Escape Format](../transform/#fx_escapes) to output the color in a form directly usable by IM. magick rose: -format '%[pixel:u.p{12,26}]' info: [![[IM Text]](rose_pixel.txt.gif)](rose_pixel.txt) See also [Extracting Image Colors](../quantize/#extract) . **`sparse-color:`** This is a special output image format that will return a simple comma separated list of coordinates and colors for each pixel that is not transparent. The output string is suitable for direct input into the [Sparse Color Operator](../canvas/#sparse-color) . For example this finds the few pixels 'closest' to a pure red color in the "`rose:`" image. magick rose: -alpha set -fuzz 13% +transparent red sparse-color: [![[IM Text]](rose_sparse.txt.gif)](rose_sparse.txt) In many ways this is more useful that the "`[txt:](#txt) `" format shown above, but only if a couple of pixels are involved. Be warned however that at the time of writing, the output is all one line. Shell scripts may like to magick the spaces in the output to newlines. **`histogram:`** This is actually the "`[miff:](#miff) `" image format, but with a very large image comment that contains a complete count of all the colors within the image. That is, in the "`[miff:](#miff) `" text header '`Comment={...}`' attribute. For example, here we again list the colors present in the "tree" image, but this time including the pixel count for each color. The text histogram comment is extracted from the "`histogram:`" image using a secondary "`[info:](#info) `" formatted magick identify. magick tree.gif -define histogram:unique-colors=true \ -format %c histogram:info:- [![[IM Output]](../images/tree.gif)](../images/tree.gif) [![[IM Text]](tree_histogram.txt.gif)](tree_histogram.txt) ![](../img_www/warning.gif)![](../img_www/space.gif)_The "`info:`" output format was added to IM v6.2.4. For IM versions before this use.._ magick tree.gif histogram:- | identify -format %c - You will note that the format is almost exactly the same as that of the previous TXT, or IM Pixel Enumeration Image format, including the comments on the color values. The only difference is that the X,Y location has been replaced by a count of the number of pixels. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _This comment can take a very long time to create. As of IM v6.6.1-5, you can add the special setting "`[-define](https://imagemagick.org/script/command-line-options.php?#define) histogram:unique-colors=false`" which will turn off this comment generation if you do not need it._ | The image itself is a histogram graph, 256x200 pixels in size. The x-axis is color value (0-255) and the y-axis is pixel count (normalized to the number of pixels). The histogram for each channel is displayed in the color it represents, and added together. Thus, red and blue overlap to make magenta. In other words with color channel has its own separate histogram.If you want the image converted to some other format, just save it into that format. "`histogram:`" is a special image processing format. It will magick the image, then output in the format specified by the filename suffix or further "`_format_:`" codes. magick rose: \\ -define histogram:unique-colors=false \\ histogram:histogram.gif [![[IM Output]](histogram.gif)](histogram.gif) An image that is very dark will be heavily weighted to the left, while a light image will be heavily weighted to the right. Mid-tones, likewise, are represented in the middle. To see this better here I separate the histograms for each of the color channels. I also strip the histogram text comment (if still present), and resize the image for display. magick histogram.gif -strip -resize 50% -separate histogram-%d.gif | | | | | --- | --- | --- | | | | [![[IM Output]](histogram-0.gif)](histogram-0.gif)

Red | [![[IM Output]](histogram-1.gif)](histogram-1.gif)

Green | [![[IM Output]](histogram-2.gif)](histogram-2.gif)

Blue | For the "`rose:`" image above you will see that red is spread more showing its vital importance in the image. On the other hand green and blue spikes on the left, showing that is has very little influence on the image at all.If you are more interesting in the brightness of an image rather than its colors, magick the image to a gray-scale before generating a "`histogram:`" image. magick rose: -colorspace Gray \\ -define histogram:unique-colors=false \\ histogram:histogram\_gray.gif [![[IM Output]](histogram_gray.gif)](histogram_gray.gif) As you can see the histogram of a gray-scale image is a little different. As the predominate red color become more of a mid-tone grey color, producing a spike in the center of the histogram. Also the small area of off-white in the image now produces a distinct spike at the extreme right of the graph. The completely empty space at the extreme left also shows that there are no dark patches in the image at all.On the other hand a better 'global' histogram can be generated by simply separating all the color channels in the original image and appending. The resulting histogram is a representation of all the color values regardless of which channel that value is from. magick rose: -separate -append \\ -define histogram:unique-colors=false \\ histogram:histogram\_values.gif [![[IM Output]](histogram_values.gif)](histogram_values.gif) Unfortunately as "`histogram:`" is an output format, you will either need to 'pipe' the image into another command, save it to disk, or use the special "`[mpr:](#mpr) `" save/read, if you want to process the image further. See example in "`[mpr:](#mpr) `" below. It would good if some method of generating histograms (and other graphs) became available as operators rather than a special output format. **`mpr:_{label}_`** (Memory Program Register) will save the whole image sequence into a named memory register, from which you can later read the image data. As such if you want to save an image for use latter, in a complex image operation you can do so. Writing to a "`mpr:`" at the end of processing is useless, as the program memory is returned back to the system when the program finishes. As such you will want to use a [Write](#write) operation to save the images to a file in the middle of your processing steps, if you need it in a different process. The '_label_' given to "`mpr:`" can be anything you like, it is only a label on where the image was saved in memory. It can even be just a simple number for people who do scripting and don't want to deal with names, though names could make your script easier to follow. After you have saved an image see below), you can then read in the image again, from the same 'labelled' memory location, as many times as you like. For example... magick tree.gif -write mpr:tree +delete \\ \\ mpr:tree mpr:tree mpr:tree +append mpr.gif [![[IM Output]](mpr.gif)](mpr.gif) Note the use of "`[+delete](https://imagemagick.org/script/command-line-options.php?#delete) `" in the above image processing. In the above it is not necessary (just re-read the "`mpr:tree`" two times instead of three), but it is very common to [Delete](../basics/#delete) all images from the current image sequence after saving the images in a "`mpr:`" register. Basically the two lines in the above can be thought of as two completely separate "`magick`" commands, but using a named memory register for the intermediate image rather than disk space. In many ways using "`mpr:`" is like using [Clone](../basics/#clone) or [Duplicate](../basics/#duplicate) (which we could have used in the above example), but using "`mpr:`" allows use to completely remove all the images, to clear the current image list for other work. The best feature of this method is that it also allows you to use settings and operations that only work on image input. For example, using it with the input image "`[tile:](../canvas/#tile) `" operator to tile an image over a larger area. magick tree.gif -flip -write mpr:tree +delete \\ -size 64x64 tile:mpr:tree mpr\_tile.gif [![[IM Output]](mpr_tile.gif)](mpr_tile.gif) You can also use "`mpr:`" to grab the output of some of the special output image format filters for further processing. For example here we save the output image from "`[histogram:](#histogram) `" and then read it back in continue to processing it in the same command, magick rose: -define histogram:unique-colors=false \\ -write histogram:mpr:hgram +delete \\ mpr:hgram -strip -resize 50% histogram\_resized.gif [![[IM Output]](histogram_resized.gif)](histogram_resized.gif) The "`mpr:`" in-memory save is actually the only way you can re-use images already in-memory through special I/O filters such as an output file format like "`[histogram:](#histogram) `" or an input file format like "`[tile:](../canvas/#tile_memory) `". The same is true for the special options that take an actual input image, such as "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" or for "`[Color Mapping](https://imagemagick.org/script/command-line-options.php?#map) `" images using another image as a source. See [Multi-image Color Maps](../quantize/#map_common) . NOTE that such options are being replaced in IMv7 with versions that do not need the image to be read from a file. It is also the only way to use the [\-draw 'image'](../draw/#image) method to overlay images using a generated in-memory image, though there are lots of other techniques to do this. The "`mpr:`" image actually saves the _whole image sequence_ and not just one image. It is a bit like taking a snapshot of the current image sequence so you can reload it later on for further processing. This for example allow you to take copies of a whole animation sequence, for duplicating or cloning, without needing to know how many images are actually involved. See [Layers Composition](../anim_mods/#composite) for an example of doing this. When you do have multiple images in "`mpr:`" you can actually still extract individual images from that sequence! Using "`mpr:image'[2]'`" will pull the third image from a multi-image sequence saved using "`-write mpr:image`". For example, here I extract the 'storm' image from a set of four images. magick eye.gif news.gif storm.gif tree.gif \\ -write mpr:images -delete 0--1 \\ \\ mpr:images'\[2\]' mpr\_extract.gif [![[IM Output]](mpr_extract.gif)](mpr_extract.gif) The [Image Cloning](../basics/#clone) operator cannot generally handle an unknown variable number of images, and in fact before the [Clone](../basics/#clone) operator was added "`mpr:`" was the only method available for duplicating in-memory images, without using intermediate disk files. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As of IM v6.8.2 you can also store images in a remote IM caching daemon process. This allows images (and there meta-data) to be passed between separately running IM commands, without needed disk space. See [Distributed Pixel Cache Daemon](https://imagemagick.org/script/distribute-pixel-cache.php)
_ | **`mpc:`** Is a special IM specific disk save format that was originally designed with really large images in mind. Basically is is a memory-mapped disk file of program memory, saved to disk as **two** binary files, a "`.mpc`" holding the meta-data of the image, and a "`.cache`" holding the images pixel-cache. **The "`MPC:`" format creates two files to save one image** Such files will not work after IM is recompiled or upgraded, and only for the IM compiled for a specific machine. As such it is only good for temporary 'quick read' files, such as in holding temporary images used by scripted image processing, and not long term storage. For example... magick very_big_image.tif very_big_image.mpc will create two files on disk. A small "`very_big_image.mpc`" file and a special memory dump file called "`very_big_image.cache`". The second file size will likely be very much larger that any other image file format as it is just a raw, uncompressed memory dump. However the file does not need to be 'read in' or 'decoded' but can be directly 'paged' into computer memory, and used exactly as-is, without any processing overhead. Only lots of disk space and disk IO. In other words it only needs disk access time to read, without any file format processing. That is, no decoding of the data needed. Because the image is 'memory-ready' it is especially useful for temporary images of all sizes as it will be usable immediately by the next IM command you issue. But remember, two files are generated and they will be larger than a normal image filesize, so be careful of your disk usage, and script cleanup. My own IM scripts make good use of this feature. For example see the scripts "[de-pixelate](../scripts/de-pixelate) ", and "[divide\_vert](../scripts/divide_vert) ", which make use of quite a large number temporary image files for image processing operations. This can be extremely useful for scripts or [Mogrify Alpha Compositing](../basics/#mogrify_compose) that needs to be able to read the same image, over and over and over again, as IM does not have to decode the image, or use up lots of memory just to store it. This is also very useful for processing a very large image, where you must extract or [Crop](../crop/#crop) a smaller section of the image for the for actual processing. However as most image operations actually make clone copies of images during processing, a new in-memory copy, could still be made. As such some care is still needed. A [Crop](../crop/#crop) or [Resize](../resize/#resize) to much smaller image sizes are the safest operations for MPC large image handling. For more information see [Really Massive Image Handling](#massive) below. **`fd:{file_descriptor}`** This special file name which allows you to specify a specific '_file descriptor_' the image is to read from or written to. The name '`fd:0`' is the '_standard input_' and '`fd:1`' is the '_standard output_' of the program. These are equivalent to using a '`-`' as a file name. However you can specify any '_file descriptor_' to with to read/write the image. Including '`fd:2`' for '_standard error_', or whatever other previously opened file handle the parent program may have arranged. The most common use for this is in very advanced shell scripting, where you may have multiple file streams of images. Or for network daemons that may have multiple file streams open simultaneously. **`inline:{base64_file|data:base64_data}`** Inline images let you read an image defined in a special base64 encoding. For example to read a base64 encoded image use... `inline:base64_image.txt` This encoding could be from a file, but it is more typically given directly as the read argument instead of as a file name from some external image source. This is more typically used an alternative to 'blobs' on the command line, or in API image processing. Or put the image data directly on the command line... `inline:data:mime-type;base64,/9j/4AAQSk...knrn//2Q==` For example lets base64 encode a very small image (there are many programs that will let you do this conversion)... openssl enc -base64 -in noseguy.gif [![[IM Text]](b64_image.txt.gif)](b64_image.txt) Note base64 data can contain any amount of white space such as returns and newlines. It is simply ignored by the format. It also only uses normal ASCII characters, which is why it is used to encode binary data for email and web pages. It also allows binary data to be stored in programs and scripts without problems. For example I could have the following command in a shell script so the script itself has the image built into it, and thus does not need a separate external image source. magick 'inline:data:image/gif;base64, R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs= ' b64_noseguy.gif [![[IM Output]](b64_noseguy.gif)](b64_noseguy.gif) Remember with this the image could be used in your script (shell or API). You do not needing to have a separate external image file, making installation of an otherwise simple script more complicated. _So why does "`[inline:](#inline) `" have this rather complicated form?_ Basically because this is the format used for inline images in HTML web pages. For example in the following the image on the right was included directly inline on the web page, and not as a separate external file, using HTML tag of the form... Nose Guy ![Nose Guy](data:image/gif;base64,%20R0lGODlhIAAgAPIEAAAAAB6Q/76+vvXes////wAAAAAAAAAAACH5BAEAAAUALAAA%20AAAgACAAAAOBWLrc/jDKCYG1NBcwegeaxHkeGD4j+Z1OWl4Yu6mAYAu1ebpwL/OE%20YCDA0YWAQuJqRwsSeEyaRTUwTlxUqjUymmZpmeI3u62Mv+XWmUzBrpeit7YtB1/r%20pTAefv942UcXVX9+MjNVfheGCl18i4ddjwwpPjEslFKDUWeRGj2fnw0JADs=)_This will not work with all web browsers, for example it will not work with IE7 and earlier, but will work with IE8. Basically the most modern web browsers understand it._The same type inline data format is also used for 'face' images in EMail headers, and probably many other file types. ASIDE: Thanks to the 'magic' part of ImageMagick, most image file formats do not need to have the mime-type (the '`image/gif`' part of the long string) included. And in actual fact it is completely ignored by IM in any case). However the comma '`,`' is still required to mark the end of that part of the inline image data string. magick 'inline:data:,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//U b//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ek yky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguW w6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7 ' b64_folder.gif [![[IM Output]](b64_folder.gif)](b64_folder.gif) WARNING: Command line option input is restricted to 5000 characters. Also many shells (and particularly PC-DOS input) has total command line length limits. As such this is not suitable for very large base64 images. **`clipboard:`** Read or Write the image to or from the Windows Clipboard. (Windows only). **`ephemeral:{image_file}`** Read and then Delete this image file. This is a special image reading file format which will cause IM to delete the given image file after that file has been read into memory. Note that the image in memory will not have been processed or even saved when the read file has been removed. This is very dangerous and should be used with extreme caution. It is mostly used in [Delegate Spawning](#delegate_spawn) . Here the background delegate will read the input image, then deletes it when it has the data. This in turn notifies the foreground 'parent' process, that the 'child' is ready to proceed on its own, as it has finished reading the image provided. The main program can then clean-up and continue its image processing separately, or simply exit, as the case may be. The "`show:`" image output delegate uses this with the "`magick display`" command, to automatically background an image magick display before the main command continues or exits. (see below) For example I used this in a shell script that calls "`[flicker_cmp](../scripts/flicker_cmp) `" to display some intermediate results, but then automatically continues (or exit) when the IM has signaled that the program has finished reading its input image by deleting the second image given. If you need that feedback but also need to preserve the image being read, then make a copy, hard link, or symbolic link to the original image, and pass that file as "`ephemeral:`". that way when it is deleted the orignal image is preserved. NOTE: There is currently no way to get "animate" or "display" to signal when it has finished an animation, or has actually put the image up for magick display. :-( However you can have "magick" read a separate "ephemeral:" image, to notify a controling script that it has reached a specific point in its image processing. # Blur an image, and show an on screen comparision before # auto-deleting and exiting. magick rose: input_image.png magick input_image.png -blur 0x5 blurred.png flicker_cmp input_image.png ephemeral:blurred.png & # wait for the second image to have been read and deleted! while [ -f blurred.png ]; do usleep 100; done # At this point we can continue (or exit) without problems. # while the on screen display continues in background. rm -f input_image.png I have also used this in other background programs, as a signal that that background program is ready to continue. **`show:`, `win:` and `x:`** -- Display images directly on screen These are special output formats that will which will directly display the image result to your screen. Instead of saving the image into a file, it just displays the result. This is very useful for quick testing IM commands to see what the results will be, and is highly recommended for this purpose. However they are only very simple versions of the "`[display](../basics/#display) `" and "`[animate](../basics/#animate) `" command. For example, get a fast summary of images in a directory... magick montage *.jpg show: See the areas that are different between two images... magick compare image1.png image2.png show: All the formats listed here, actually call on the "`[display](../basics/#display) `" program to perform their task. However they each handled the job in different ways. For example '`show:`' will use a [Spawning Delegate](../files/#delegate_spawn) to run a separate "`[display](../basics/#display) `" program. This means that once the image has been displayed, the original command will continue its processing (typically exiting, unless you use "`-write show:`" ). On the other hand, using '`x:`' or '`win:`' will wait for you to quit the display window before allowing the original command to continue (and exit). Unfortunately none of these methods will display animations very well. For that you are better off piping the animation (in MIFF format) into the "`[animate](../basics/#animate) `" command. **`x:` (as input)** - Reading an X Window Display You can also read the current X window display using the "`x:`" operator, in much the same way as you can with the "[import](../basics/#import) command. In fact without options it acts exactly like the "import" command. Use the left button to select the window to grab a copy of, or mark out an area using the middle button. For example, to select a window using your mouse, then display the window just grabbed in another window (exit when grabbed window is displayed)... magick x: show: WARNING. if you grab a window that is unmapped (iconized), or has another window over it, the image contents will contain either a blank area, or the contents of the overlapping window!!! So make sure when grabbing a window that window fully visible on screen. To grab the whole display use '`root`' for the window name. magick x:'root' full_screen_dump.jpg Or use the [Read Modifiers](#read_mods) to grab a specific area of the display. magick x:'root[300x400+879+122]' part_screen_dump.jpg Providing a window name you can grab a specific window. For example this will grab the window titled '`MailEd`'... magick x:'MailEd' window.jpg However that does really not work well, as often you have multiple windows with the same name, or the name of the window just can't be determined. The better way is to tell IM the exact window wanted using a "X Window ID" which is the number that the X display uses to uniquely identify a specific window (or child window). The X Window ID is typicaly looked up using the "`xwininfo`" command, but other programs such as "`xdotool`", and "`xwit`" as well as other tools like "`xprop`" can be used to find information about the windows. For example things like, window class, name, title, its size and placement, child windows, and window manager decoration. For example, find all windows with "Mozilla Firefox" in the title or name... xwininfo -root -all | grep "Mozilla Firefox" I can then extract the X Window ID of the window I want from the output of the above. Here is a little more complex bash script I have in my window manager. When I press a button, it looks up the ID of the window with the current 'focus', captures it, then names the file as a PNG in my current directory using the next capture number, according to any previous captures made. bash -c " id=$(xprop -root _NET_ACTIVE_WINDOW | sed 's/.* //') magick x:$id capture-tmp-$$.png num=$( ls capture-[0-9]*.png 2>/dev/null | sed -n '$ s/[^0-9]//gp' ) num=$( printf %03d $(expr $num + 1) ) mv capture-tmp-$$.png capture-$num.png " Most terminal programs will tell you the X Window ID they are using to magick display text in the environment variable "WINDOWID". As such if you run this from a command line of a XTerm, or Gnome Terminal, you will grab a copy of the current terminal window. magick x:$WINDOWID this_terminal.png Now for some fun... Here I grab the contents of my current terminal, draw some stuff into it, and then use the "`[display](../basics/#display) `" to draw it back into the same terminal window! window=`xwininfo -children -id $WINDOWID |\ sed -n 's/^ *\(0x[^ ]*\).*/\1/p'`; \ window="${window:-$WINDOWID}"; \ magick x:$window -background black \ -draw 'fill black rectangle 40,40 160,160' \ -draw 'stroke red line 50,50 50,150 line 50,150 150,150' \ -draw 'fill lime circle 110,100 80,100' \ -draw 'stroke dodgerblue line 50,150 150,50' \ rose: -geometry +180+60 -composite \ png:- |\ magick display -window $window - The first command in the above is designed for an "XTerm" window, which requires that the window you "`magick display`" into, be the child window of the provided "WINDOWID". The second line falls back to original value of "WINDOWID" if no 'child' window is found, as is the case for a "Gnome-Terminal" window. Once the window to use is worked out, it is grabbed, drawn on, and restored into the terminal window! And presto you have instant graphical output directly into the current terminal window. Here is a simpler example, this darkens the window contents each time you run it. Try running this a few times in an actual "xterm" window, and you find the older the command in the terminal window the darker it gets! window=`xwininfo -children -id $WINDOWID |\ sed -n 's/^ *\(0x[^ ]*\).*/\1/p'`; \ window="${window:-$WINDOWID}"; \ magick x:$window -background black -colorize 20% png:- |\ magick display -window $window - And here is a 'screen capture' showing what happened as I repeated the above in my own "xterm" window... [![[snapshot]](../img_diagrams/xterm_darken.png)](../img_diagrams/xterm_darken.png) Be warned that while the contents of the terminal are modified, it is only temporary. If you iconify, obscure, or change desktop screens, then go back to the terminal, the modifications will be lost as the terminal program re-draws the window, and wipe out your own 'drawing'. The above does not work nearly as well for a "Gnome-Terminal" as for "XTerm"s because the former likes to 're-draw' its window every time it scrolls, where a "XTerm" does not. Imagine IM scripts that display the results of graphs and other things directly in various windows as part of a larger client program. This is in fact how many postscript viewers, and even many web browsers display output from special sub-programs. That is, they have that sub-program take over and directly draw into a provided sub-window. Experiment, and please let me (and others) know what you come up with, either via email or the [IM Users Forum](https://magick.imagemagick.org/viewforum.php?f=1) . * * * Coders and Delegates for Image Formats -------------------------------------- **Coders** are dynamic library modules (usually written in the C programming language) that handle the "format:" aspect of image input and output. They can also be used by users to create special purpose filters. They may require the installation of extra external libraries to be installed, which are often called 'delegate libraries'. They are loaded as dynamic modules only as needed, which means the associated libraries used by a coder does not need to be installed, unless you want to actually make use of that coder. These examples will not go into the C programing required for writing coders, but there is an example coder in the source that can be used to create your own coder modules. A **Delegate** is simply a command that IM knows that will allow it to magick between different formats. This allows IM to use that 'simpler' and pre-written command, rather than requiring a more complex binary coder to handle some image file format. To get a list of what delegates are available use the special command... magick -list delegate The most well known 'delegate' program Im makes use of is "`ghostscript`" which will allow IM to read, and magick the very complex Postscript and PDF format vector images into some other raster image file format that IM can read. However '**Delegate Commands**' are very useful for users too, as it allows you to expand IM so that it can handle special types of images, or to provide alternative methods to read and write those images. The 'commands' themselves are listed in a file named "`delegates.xml`", and which is located in IM's system configuration directory. But it will also read a "`delegates.xml`" located in the users personal "`.magick`" sub-directory of there Linux/UNIX home directory. And it is in this second file that users should place their 'command delegates'. ### Input Delegate Command Example For example I can create a personal "`delegates.xml`" file in the "`.magick`" sub-directory of my Linux/UNIX home directory, of the form... ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) This is a complete 'delegate' configuration file, but only the middle line is an actual delegate. A very simple one that tells IM that if it sees an image with either a '`.flip`' suffix or a '`flip:`' format prefix, it should call the above command, to read the 'flip' format image. For example.. magick flip:tree.gif delegate\_tree\_flip.gif [![[IM Output]](delegate_tree_flip.gif)](delegate_tree_flip.gif) In this case all the delegate command does is use a separate IM "`magick`" command to 'flip' the image upside down, before the original IM command even reads and processes the image! The delegate assumes the command will understand the image file format given and that it will return ANY image file format that IM itself can understand and process (a [MIFF](#miff) image file format in this case). The '`%i`' and the '`%o`' parts of the delegate represent temporary filenames the command is the provided input and outptu filenames the delegate should use. These filename are generated by IM, and will be located in a temporary directory. These temporary filenames also do NOT have any image suffixes, so it is important that you prefix the image format type desired, if necessary. It is done this way for security reasons, and because IM itself may only be reading a stream of data, and not an actual file. It also means the delegate command does not have to deal with things like clean up of those files when finished. There are other '%' substitutions for things like a second temporary filename for intermediate temporary files, image density, size, and so on. More detail about these escapes and other delegate options are provided in the comments at the top of the IM installed 'system' "`delegate.xml`" file. Now this may seem like a rather silly and trivial example, but it basically means you can now use a secondary command to magick ANY data file into ANY image IM understands. IM will then know how to handle that data type automatically given the image suffix, or a format prefix, without you needing to remember all the details. Lots of delegates of this type has already been added to the system file, so it is worth a look. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _For security reasons delegates in a personal "`delegates.xml`" file will not override the delegates defined in the system installed "`delegates.xml`" file. You can only add new unique delegate formats in ".magick/delegates.xml" in your home directory, later duplicate delegates will be ignored.

Of course if the input format is already known internally then of course system delegates are not looked at.

Also as always, sanitise any user (especially web user) input, as you don't want the user to make use of a delegate without you knowing about it.

_ | For example as of IM v6.4.2-6, a "`autotrace:`' delegate was added to the system delegates file, which will run the "`[AutoTrace](http://autotrace.sourceforge.net/) `" command while reading ANY input image. IM converts the input image to the required PNG image format needed by the delegate program, filters it though the delegate, then reads the resulting SVG (typically via an external RSVG library), to generate a smooth edged version of the original input bitmap image. See [Raster to Vector Converter Example](../transform/#edge_vector) . If a converter generates multiple image files (such a PNG), you will need to merge all those separate images into a single multi-image format such as MIFF, so that IM can read the multiple images from the one output file. Sometimes IM will string together multiple delegate programs to read in an image. For example to read a 'HTML' page as an image, it first calls the delegate "`html2ps`" to magick it to postscript. Then it converts the generated postscript file into a set of multiple images using the special "`ghostscript`" program delegate. Of course using two, or more delegates like this can produce other problems due to the complex interactions, miss-installations, and bugs that may be present in the delegate programs. But in general it works, and is a key aspect of what make ImageMagick, magical. ### Output Delegate Example Similar things are done when saving to specific image file formats that IM does not directly understand. For example by adding this delegate to your personal "`.magick/delegates.xml`" file, you can tell IM how to create a '`.xyzzy`' image file. ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) Of course this just quickly copies a GIF file format image as a TMP file format, but the command can be any type of image converter, script or shell command sequence you like. With that personal delegate, IM can now create your '`.xyzzy`' images, having been provided at least one method of going so. magick rose: -negate rose.xyzzy magick identify rose.xyzzy Note that the identify in the above does not understand the '`.xyzzy`' suffix (no input delegate has been provided). However as no specific delegate is provided, the file 'magic' (an identification string inside the file itself) tells IM that it is in reality a GIF image format, so IM handles it correctly anyway, without needing a special input delegate or coder. This is actually the the 'MAGIC' part of 'ImageMagick'. ### Delegate Listings A full list of external delegates that IM can use for converting image formats is read from a special system file called "`delegates.xml`" as well as a personal "`delegates.xml`" file (see below). If you can find this file it makes interesting reading. The format of this file however is too complex to do into here, though it is explained in both the system file and the manuals provided both online and with your ImageMagick installation (docs area). A simplified summary of the delegates and conversions that IM is reading from these files can be printed using the "`[-list delegate](../basics/#list) `" option... magick -list delegate However please note that delegated declared with '`stealth="True"`' will not be listed, by the "`[-list delegate](../basics/#list) `" option. All delegates are optional, and more than one can be created for a specific conversion. If one delegate is not available (or it errors and image is not created), then IM will try the next delegate, until one is found that does work, or it runs out of delegates to try, at which point an error will be produced indicating it can not read that image. ### Printing Delegate One of the most useful delegates I have ever created was to let me easily print images to a postscript printer. The printer was already set up using the linux "`lpr`" command and it could accept either a PNG format image, or a postscript file. Here is the simple "`PRT:`delegate I decided to create.[![[IM Output]](delegate_rose_xyzzy.txt.gif)](delegate_rose_xyzzy.txt) ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) Notice I decided to use postscript format ("`decode="ps"`") for the image being passed to the "`lpr`" command on my system. I chose that as I can then use options such as "`-density`" to adjust the size of the output image. For example I can create a command to grab a window form my screen, modify the image, so as to fit on printed page (as I want it) then print it. magick x:Loopy -shave 6 -chop 0x24 -modulate 220,0 \ -bordercolor white -border 50x150 -density 130 prt: I could have also used "`decode="png"`", however my system would then enlarge or shrink the image to always completely fill the A4 page. You however may like this. ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) ### Spawning External Commands External command delegates does not have to just be for converting images to/from files, but can be used as a quick way to run (or 'spawn') complex commands in the background. Such a delegate will have the attribute '`spawn="True"`' added to it, and will launch the command, wait for it to delete its input image, then IM will continue as normal, leaving the command running in the background. For example two output delegates "`show`" and "`win`" both provide simple ways to display the result of a command in the IM "`[display](../basics/#display) `" program. For example.. magick rose: label:rose -append show: This will append a label to the built-in 'rose' image and just display it on the screen. When the spawning delegate has read its input image and deleted it (typically using the special "`[ephemeral:](#ephemeral) `" input format, see above), the launching IM will continue (and exit), leaving the 'display' program running in the background to show the results. Here is the "`show`" spawning delegate, showing the use of "`[ephemeral:](#ephemeral) `" in the "`[display](../basics/#display_script) `" command. magick -list delegate | grep show Unfortunatally the "`[list](../basics/#list) `" option does not show the '`spawn="True"`' flag of the delegate, but it is defined for this delegate. This is a lot more convenient that trying to remember all the special options that a scripted "`[display](../basics/#display_script) `" command needs. Perhaps you have some complex command that you run all the time. ### Postscript and PDF Delegate By using delegates ImageMagick can make use of external programs to do some of the more complex and specialised image format conversions.For example, while Postscript (PS:), and Encapsulated Postscript (EPS:) can be written directly by ImageMagick. These file formats can not be read by IM. Postscript is a full computer language and requires a very complex interpreter to create images from it. As such it is far beyond the scope of IM to handle the reading of this file format. To solve this IM looks for an external delegate program called "`ghostscript`" to do the work of converting an PS or EPS format file to some other image format that IM can read easily. Of course that means that if you get an error like... **convert: no decode delegate for this image format \`...'** Basically means that IM was unable to find the appropriate external program to magick your given image format into an image format that IM itself can handle. For Postscript images, that usually means "`ghostscript`" is not installed, mis-configured, or in an unknown location on your system.[![[IM Output]](delegate_show.txt.gif)](delegate_show.txt) ![](../img_www/expert.gif)![](../img_www/space.gif)_The PDF/PS "`ghostscript`" delegates are in a special format used internally. IM internally examines postscript format images to attempt to determine exactly how to rasterize the file via the given delegates. In fact, multiple PS delegates are present and selected by IM depending on the situation. For example the ghostscript device used ('`bmpsep8`' verses '`pngalpha`') is selected depending on if "`-colorspace RGB`" had previously been set or not. For PDF we use the '`ps:color`' delegate rather than '`ps:alpha`' because the '`pngalpha`' ghostscript device only supports an one-to-one page-to-image conversion and PDF's generally are multi-page._ ### Direct Delegate Format Conversion (Taint) The delegate system also allows IM to call an external program to convert an image from one format to another format, without any processing of the image by ImageMagick itself. But only if the destination image is readable by IM as an image and the final result of the "`magick`" was an 'untainted' copy of the image. For example if you try this comamnd to magick a 'Adobe Illustrator' file ("`.ai`") (which is a type of Postscript), to EPS (encapsulated postscript)... magick -density 300 map.ai map.eps Then IM will magick the "`map.ai`" to an EPS file (in "`/tmp`"), a format it understands. Then after reading into memory (after using the 'eps' delegate), it will then find that it does not actually need to modify it (it remains 'untainted'). Because no change was made to the image, and the image was already converted to a 'eps' file file format, IM will short-circuit itself and directly copy the 'eps' file it generated to "`map.eps`". That is, the EPS file will be just a copy of the original unchanged Adobe Illustrator file! In otherwords IM only used its internal delegates to magick the file (actually just rename it). It never actually processes the image itself, and as such the image remains a pure vector image. This is actually the original purpose of "`magick`" as a program back in version 1 of ImageMagick. All the other operations and settings were added later over a very long period of time. You can however force IM to actually read-in and write-out the image, as a raster, by using the special "`[-taint](https://imagemagick.org/script/command-line-options.php?#taint) `" operator to mark it as being modified, without actually modifying it. magick -density 300 map.ai -taint map.eps Here the image IM reads does become 'modified' or 'tainted' so it will write out the version of the image in memory to the final EPS file, rather than simply copy the input file. ### Other Delegate Examples #### Modifying Postscript Delegate for CMYK postscript See [Blog of John](http://blog.digitaljohn.co.uk/2007/06/19/imagemagick-cmyk-to-rgb/) , #### DCRaw 8-bit processed camera image Delegate An alternative delegate for reading 8-bit fully processed 'raw' digital camera images (CRW, CR2, NEF, etc) is... ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) This will read the 'raw' camera image, and magick it to a PNG file format (though you can also just as easily add a '`-T`' flag and use a TIFF image format). That output image turn is readable by ImageMagick. By adding this delegate can then use it simply, for any ImageMagick image read operation (any API, not just command line), and IM will handle all the file IO and cleanup. For example... magick dcraw8:image.crw image.png If you do not define the filepath of the "`dcraw`" executable, IM will search the for the program along the users current PATH environment variable, however allowing this could represent a security problem. System installed delegates generally define the command path fully. See comments in this [IM Users Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=15605) . #### Video decoder delegate using 'ffmpeg' For example, here is a delegate published by Mikko Koppanen, on his [Mikko’s blog](http://valokuva.org/) site. Add this to your personal "`delegates.xml`" file in "`.magick`" directory of your home... ![](../img_www/text_top.gif) ![](../img_www/text_bot.gif) IM can now use the "`ffmpeg`" program to decode the frames from an MPEG video image. For example. magick "ffmpeg:test1.mpg[40]" frame_40.png * * * Really Massive Image Handling ----------------------------- For handling any sort of large image it would probably be better for you to use a Q8 version of ImageMagick, which has half the memory requirements of the higher quality Q16 version. Check your IM's compiled Q level using "`identify -version`". For medium sized images you can attempt to use "`[-limit](https://imagemagick.org/script/command-line-options.php?#limit) `" to increase the processing limits (for example processing "`-limit area 8192 -limit memory 8192`"), so as to try to avoid IM caching the image data to disk. However your system may reject large memory requests and still force IM to cache the image to disk (about 1000 times slower). To see if IM is using disk cache for the image processing, you can use "`[-debug](https://imagemagick.org/script/command-line-options.php?#debug) cache`" to monitor that action. Also see [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?f=3&t=19642) . ### Memory/Disk Management If you are planing to process really large images you may want to make sure IM does not use up all the computers memory, and slowing down the processing of other programs (by spending all its to shuffling between memory and disk swap) simply by asking it to immediately use temporary swap disk files. For example this is a _nice_ way of processing a very large image over a long period of time without stopping you from using your computer for other things. Basically it forces IM to cache everything to disk. env MAGICK\_TMPDIR=/data nice -5 \\ magick -limit memory 32 -limit map 32 \\ huge\_9Gb\_file.psd -scene 1 +adjoin layer\_%d.png Of course this assumes that "`/data`" has enough file and disk space to handle the images memory requirements. ### Memory Mapped Disk Files If you have many operations to perform on the same source image and you have plenty of disk space you can use the [MPC image format](#mpc) which is expensive to create but has near zero overhead when loading... magick mybigassimage.jpg mybigassimage.mpc magick mybigassimage.mpc -resize 50% resized.jpg magick mybigassimage.mpc -rotate 90 rotated.jpg ...etc... rm -f mybigassimage.mpc mybigassimage.cache This will let you read a very large image multiple times with a minimal cost, and memory usage. An example of a scripted for of tiling using this method was presented in an IM Forum Discussion [Cut large image on tiles](https://magick.imagemagick.org/viewtopic.php?t=18315) and revisited in [Cropping very very large images](https://magick.imagemagick.org/viewtopic.php?f=1&t=20982) . Basically the MPC image format file consists of two actual files, an informational "`.mpc`" file, and a direct memory paged copy of the image in a "`.cache`". Of course you need to clean up both files when you are finished. This method is designed so that IM does not have to re-parse the image format and cache it to disk, every time you run a new "`magick`" command. Also if you are accessing only sections of the input image, each command does not need to process the whole image, but can now read just that smaller section from the cahced disk file as needed. If you plan to process a very large MPC copy of the image, it is a good idea to extract or [crop](../crop/#crop) a smaller section of the image for actual processing. This is because just about any operation performed on an image, will generally result in a new in-memory copy being made of the result, so an initial crop is a very good idea. If you have the memory you can also try to use a 'memory disk' such as a 'TMPFS' or RamDisk type filesystem. Be warned however that filling that type of disk also directly fills your computers memory. So really you are just swapping one use of memory for another. ### Processing Images in small sections While you can use the MPC method above to crop out various sections from a source image for further processing, you still need to read in and write out the the whole image, and for a massive image that can still take a lot of time. IM has also evolved a simpler pipeline processor for images called "`[stream](../basics/#stream) `". This program has a limited set of image operations that are designed to only process images one scan line (row of pixels) at a time. As such only enough memory to hold a single line of pixels is used when processing images in this way. For example this allows you to extract a smaller area of a very large image for further processing, without needing to read in the whole image into memory first. However the output of "`[stream](../basics/#stream) `" is raw RGB image values, so some post-processing is recommended. magick stream -map rgb -storage-type char -extract 600x400+1900+2900 image.png - |\\ magick -depth 8 -size 600x400 rgb:- tileimage.png You don't have the save the output to a file but can continue processing the smaller image directly. For example... magick stream -map rgb -storage-type char -extract 600x400+1900+2900 image.png - |\\ magick -depth 8 -size 600x400 rgb:- ...more\_processing\_here... tile.png This will only process the `600x400` pixel image extracted without reading in the whole larger image first. **Speed concerns...**Peter V noted... In my experience is the approach of using "`[stream](../basics/#stream) `" for cutting 800MB PNM files the fastest compared to use of MPC files, or using "`magick -crop`". **What formats work...**Paul Heckbert (of image distortion fame) noted that the "stream" command works well for certain file formats (in particular, JPEG), but does not work well for other types like PSB, which may be interleaved. I believe it would depend on if the 'coder' for a particular file format provides support for line by line streams of pixels. This may be because the programmer that generated the file format 'coder' just did not get round to, or need 'streaming'. In this case some more work by a programmer familiar with that image file format maybe needed to complete the 'coder' module. Also a vector image file format like SVG or WMV, or an image that is pre-processed by some 'delegate', like digital camera image file formats, could not possibly be 'streamed' because, there are no actual rows of pixels in the image, only drawn objects (lines, polygons and gradient shades). **JPEG images sections**As per the IM forum discussion [Extract a region of an huge jpeg](https://magick.imagemagick.org/viewtopic.php?t=18268) you can use specialized JPEG programs such as the special "`jpegtran`" and "`jpegcrop`" developed by [JPEG Club](http://jpegclub.org/jpegtran/) , can extract a regions from a JPEG image without actually decoding the data. That is, a lossless crop of a JPEG to another JPEG image. For example.. jpegtran -crop 100x100+0+0 -copy none huge.jpeg crop.jpg However there an few cavats. The top-left starting point will be moved to the smaller 8 or 16 multiple, with an appropriate increase in the final image size. That is, because JPEG images uses 'frequency encoded blocks' which are typically either 8x8 pixel or 16x16 pixels in size (determined by the JPEG sampling factor, 1 = 8 pixels, 2 = 16 pixels). These blocks need to be preserved if lossless copies are to be made. For a '`+0+0`' offset, it is already at an appropriate boundary, so the above should produce an exact 100x100 pixel crop. But for other offsets you will need to so some final cleanup of the extracted region. For example... jpegtran -crop 100x100+123+425 -copy none huge.jpeg crop.jpg magick crop.jpg -gravity SouthEast -crop 100x100+0+0 +repage crop\_fixed.png ### Processing Images in Tiles (PbmPlus) To process an massive image in tiles, without ever holding the whole image in memory is a much harder problem. Basically while you are breaking up an image you will need to either hold a whole row of images, or have multiple streams (one for each column of images) open, while the massive image is being broken up, or later being put back together. Most common technique is simply save the each image tile as separate image files on disk. In fact this is often the better way of storing ultra large images as programs can then just read the 'tiles' needed at any given moment for processing, producing a sort of 'disk based' random access image. This type of massive image storage, combined with a pyramid type multiple-resolution structure is actually how "google image maps" work. While IM does not have anything to break breakup (tile crop) massive images using a small amount of memory, the [PbmPlus/NetPBM](../formats/#pbmplus) can do this. **Pbmpus processing of a small section** For example, here I use PbmPlus tools to cut (crop) out a small section of the large image, process it, then compose that piece back into the original image. tifftopnm INPUT.tif input.pam pamcut {left} {top} {width} {height} input.pam part.pam # process smaller "part.pam" image here pamcomp -xoff={left} -yoff={top} - input.pam output.pam pamtotiff output.pam OUTPUT.tif The "`tifftopnm`" does a conversion to an image data stream, and performs a similar job to ImageMagick "`[stream](../basics/#stream) `" command. The "`pamcut`" is the equivalent of a [Crop Operation](../crop/#crop) , and will extract a smaller area from the input image. Instead of _width_ or _height_. You can also specify _right_ or _bottom_ bounds of the crop. You could substitute a "`magick stream`" command with "`magick` The central part, can be processed using normal ImageMagick, or if you like pain, a chain PbmPlus equivalent tools. The "`pamcomp`" should overlay the modified part of the image back into the PbmPlus version of the original image. Other possible alternative to "`pamcomp`", is "`pnmpaste`", but this has not transparency handling, for pixel bleading. Note that by using composition with pieces it should be posible to distort small tiles and re-join them into a larger image afterwards. **Pbmpus diced (tile crop) processing** We may be able to use "`pamdice`" and "`pamundice`", or other alternatives to generate and merge smaller image tiles that can be processed individually, however this must save files into separate disk files (or named pipes) due to the 'multiple images per row tile problem'. An example script, "`[pam_diced_flip.pl](../scripts/pam_diced_flip.pl) `" of doing this has been provided by [bugbear](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=17875") , to 'flip' or 'rotate' (90 degree only) very large PbmPlus images using smaller tiles. Something that normally requires you to read the whole image into memory. Note that it does use a lot of temporary files, but it has a very small memory footprint. ### VIPS and NIP, a Massive Image TIFF handler Jenny Drake < jennydrake @ lineone.net > reports... You may also like to look at the non-IM alternative of "`[Vips](http://www.vips.ecs.soton.ac.uk/index.php) `" and "`nip`", developed by the National Portrait Gallery in London, which is designed to work on very large image files (generally TIFF) with low specification computers. "`Vips`" is the underlying engine and "`nip`" is the gui. Works on Linux, Windows and sometimes on Mac. * * * Long Streams of Lots of Images, Video sequences ----------------------------------------------- Streams of images is another problem area. Here it isn't the size of the image that is of concern, but the shear number of images involved. So many you generally do not want to load them all into memory, or even save them individually to disk, as normal images. The biggest cultript of such images is of course, video handling, and animations The key to handling such images are the streaming image file formats where images can be simply concatanated together, one after another, into the one file stream. We touched on this briefly above in [MIFF Image Streaming](#miff_stream) . Like ImageMagick's own [MIFF](#miff) format, the [PbmPlus/NetPBM](../formats/#pbmplus) is also a streaming format (almost the same just simpler) but is much more well know and commonly used in video image stream processing. In a forum discussion, [Reading Multiple Images](https://magick.imagemagick.org/viewtopic.php?f=2&t=18320) , an user wanted to process a 'stream' of multiple PPM images, generated by a "`ffmpeg`" video processing program. [Pbmplus](../formats/#pbmplus) images (like [MIFF](#miff) images, can be simply concatenated together to generate a multi-image stream. At this time IM does not allow you to just read one image from such a stream, process it, and then read another single image. All IM commands will always read the whole stream, and then close it. This is being fixed as part of IMv7 scripted processing. One solution is a small perl script, "`[process_ppm_pipeline](../scripts/process_ppm_pipeline) `", that will accept a stream of PPM images, and run a separate "`magick`" command on each image, as it arrives. The output is also a series of PPM images that produces a new stream of images. For example read a video, and 'flip' every frame, one by one... ffmpeg input.mpg -f image2pipe -vcodec ppm | pnmtopnm -plain | process\_ppm\_pipeline -flip | ffmpeg -f image2pipe -vcodec jpeg output.mpg The "`pnmtopnm -plain`" is vital, as the script currently only handles a stream of ascii-PPM images, though with some more smarts it could also be made to handle any binary (raw) [Pbmplus](../formats/#pbmplus) image stream, or even a [MIFF](#miff) image stream. Such a tool might be even used for processing a multiple streams (columns) of massively large images too. Though this may require a lot more in-depth knownlege in internal processing of the commands incolved. if a way can be found to sub-divide such images into a stream of tiles, and then re-construct the large image again at the end. Eventually I hope to include some mechanism by which you can ask a coder to read and return just one image from a multi-image file stream without closing that stream, so that another image can be read in again later. In this way Im can then process a stream of images, one image at a time. _UPDATE: IMv7 can read one image at a time from a stream. With a loop, or using the pipelined commands, it should be posible to generate streaming image filters. More experimentation needed._ * * * --- # Animation Basics -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Animation Basics ==================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) GIF Animations and Animation Meta-data](#gif_anim) [![](../img_www/granitesm_right.gif) Frame Disposal Methods](#dispose) * [Dispose None](#none) - overlay each frame in sequence * [Dispose Previous](#previous) - preserve background canvas * [Dispose Background](#background) - clear to background [![](../img_www/granitesm_right.gif) Studying Animations](#study) * [Identify](#identify) - information about an animation * [Adjoin](#adjoin) - splitting into individual frame images * [Coalesce](#coalesce) - fill out frames completely * [Frame Montage](#montage) - the "gif\_anim\_montage" script * [List Information](#list_info) - rebuild an existing animation * [Disposal Images](#dispose_images) - the GIF dispose form of the frames * [Deconstruct](#deconstruct) - report areas of frame differences * [Frame Comparisons](#compare) - more detailed frame differences [Compare\_Any](#compareany) ,  [Compare\_Clear](#compareclear) ,  [Compare\_Overlay](#compareoverlay) [![](../img_www/granitesm_right.gif) Types of Animations](#types) * [Coalesced Animations](#coalesced) * [Overlay Animations](#overlay) * [Cleared Frame Animations](#cleared) * [Mixed Disposal Animations](#mixed) [![](../img_www/granitesm_right.gif) The End of the Loop](#loop) - when an animation stops running [![](../img_www/granitesm_right.gif) Zero Delay Intermediate Frames](#zero) These examples continue the previous example page on [Layers of Multiple Images](../layers/) but instead of layering multiple images on top of each other to produce a single image, here we display each image for a short period of time so as to produce an animation of images. The following section provides a basic understanding of the complexities of animations and specifically GIF animations. It looks at the basic methods used to generate animations, and how you can study existing animations to get an understanding of how they work. This is recommended reading before going further in any of the later animation sections. * * * GIF Animations and Animation Meta-data -------------------------------------- The default way ImageMagick handles the output of an image list is to generate a multi-page image. For the GIF image format, however, this takes the special form of a 'GIF animation'. magick -delay 100 -size 100x100 xc:SkyBlue \\ -page +5+10 balloon.gif -page +35+30 medical.gif \\ -page +62+50 present.gif -page +10+55 shading.gif \\ -loop 0 animation.gif [![[IM Output]](animation.gif)](animation.gif) Here is a more advanced 'sparkle' example that uses a shell script "**`[star_field](../scripts/star_field) `**". This script was developed from my experiments in generating [random star fields](../advanced/#stars) . star_field 70x46 stars1.gif star_field 70x46 stars2.gif star_field 70x46 stars3.gif magick rose: -compose Screen \ \( -clone 0 stars1.gif -composite \) \ \( -clone 0 stars2.gif -composite \) \ \( -clone 0 stars3.gif -composite \) \ -delete 0 -set delay 25 -layers Optimize rose_sparkle.gif rm stars[123].gif [![[IM Output]](rose_sparkle.gif)](rose_sparkle.gif) Basically three random star fields are generated, at the right size, then overlaid onto our image, the IM built-in "`rose:`", using a '`[Screen](../compose/#screen) `' alpha composition to brighten the image with the given star patterns. The whole thing is then run though the IM general GIF animation optimizer. The above may seem complex as it is using some advanced IM features I have yet to introduce, but the result is a relatively simple, but well optimized three frame animation. You can also look at some of the more complex animations that were created using simple shell scripts for [Distortion Animations](../warping/#animations) . There are a few extra IM settings which were created specifically for use in GIF animations, and knowing about these is the first step into the world of GIF animations...`[**-dispose**](https://imagemagick.org/script/command-line-options.php?#dispose) {method}`What the following images should do with the previous results of the GIF animation. Valid options are '`Undefined`', '`[None](#none) `', '`[Previous](#previous) `', and '`[Background](#background) `. (See below for explanation of the settings)`[**-loop**](https://imagemagick.org/script/command-line-options.php?#loop) {number}`Number of times the GIF animation is to cycle though the image sequence before stopping. It is an output 'image write' setting, so can be set anywhere on the command line, though only the last such setting will be used. Usually this set by default, to zero (infinite loop), however if any image read in has a different value, then this setting will be set to that images value. As such I recommend that you always set "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" when creating a GIF animation, after all the images has been read in. For more information see [The End of the Loop](#loop) below.`[**-delay**](https://imagemagick.org/script/command-line-options.php?#delay) {time}`  Set the time delay (in 1/100th of a second) to pause after drawing the images that are read in or created after this setting has been defined. You can specify a different scale for the time delay by specifying a '`x`' scaling (giving in ticks per second). For example '`10x1`' is 10, 1 second ticks, while '`10x100`' is 10, one hundredth of a second ticks. Basically the '`x`' is equivalent to a fraction '`/`' sign. For example if you specify '`1x160`' will set a delay that is appropriate for 160 frames per second. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _GIF animation delays must be specified in hundredths of a second for correct working, which is why that is the default time unit. The '`x`' factor is used more for generating other more movie like formats, such a MNG's, and AVI's._ | `[**-set**](https://imagemagick.org/script/command-line-options.php?#set) dispose {method} [**-set**](https://imagemagick.org/script/command-line-options.php?#set) delay {time}`While the previous option settings will set image attributes on newly created, or image that are read in, _after_ that option is given, the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" option is an operator, that will allow you set image attributes on all images that have _already_ in the current image sequence. This allows you to change the setting over a whole animation, or just a single frame, after the images have been loaded or modified.`[**-page**](https://imagemagick.org/script/command-line-options.php?#page) {w}x{h}+{x}+{y}`This lets you set the offset position of the image about to be read in. As this is a setting option, it only applies the geometry you give to images that follow the setting. It does not effect images already read into memory. If not given, or turned off using "`[+page](https://imagemagick.org/script/command-line-options.php?#page) `" the offset for the image read will be preserved. If the image does not have an offset it will be positioned at '`+0+0`' or the top left corner of the working canvas or 'page'. It can also be used to define a larger working canvas, by specifying a width '`x`' height. Only the width and height page setting of the first image in the sequence will be used to set the overall GIF animation canvas size, all other page size settings will be ignored when the animation is finally written. When a GIF animation is read in the canvas size is set on all the frames in the animation. MNG animations can save frame offsets, but does not save canvas sizes. The size of the first image defines the canvas size of the whole animation. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The GIF image format can not specify a negative offset for images on a canvas. If you try to use a negative offset IM will reset it to zero when that image (or animation frame) is written to a GIF file.

Positive offsets larger than the image canvas are quite acceptable but may result in the image not appearing in the canvas drawing area when magick displayed. How a GIF animation display program handles this is undefined. Caution is advised._ | `[**-repage**](https://imagemagick.org/script/command-line-options.php?#repage) {w}x{h}+{x}+{y}`This is exactly like "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" except that it is an image operator instead of a setting. That means you can use this to change or reset the 'page geometry' of an image or animation frame that has already being read into memory. The simpler "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" form, just resets the 'page geometry' of all images to the actual image in each frame in the current image sequence to a zero offset, and the images actual size. This operation is vital when you are extracting the individual frames from an animation, (See the [Adjoin Examples](#adjoin) below). However "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" will destroy a lot of positioning information stored in each image, as such you should also probably extract this information into a separate file for later re-use. See [Animation List Information](#list_info) below. ### Important Point DO NOT save the intermediate, animations which you are not finished processing, directly to GIF. You can use the IM internal format MIFF, as a temporary file format, if you want to work on an animation in series of separate processing steps. I repeat... **Do not use GIF as an intermediate file format, use MIFF instead** If you made the big mistake of saving to GIF you would have just made the resulting animation worse, as IM would have now performed an automatic [Color Quantization](../quantize/#colors) , to reduce the number of colors present. Not only that but it did so on each frame completely independently to every other frame, making any further processing, particularly any GIF optimizations just that much harder. Solving this is a complex, multi-level problem, which is looked at in the next section [Animation Optimization](../anim_opt/) . * * * Frame Disposal Methods ---------------------- The first thing people creating GIF animation have trouble with is the "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting. This is not surprising as it is a complex setting. Worse still a lot of animation programs, including many web browsers, don't always handle the GIF disposal meta-data setting correctly. However using the right disposal can make a big difference to how well your animation works and optimizes. The first thing to remember in ImageMagick is that almost all the special animation options, are settings for image reading. That is, they are applied to images that are read in, after, the setting has been given. The "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" setting is the only one typically used after the animation has been completed, just before the the animation is saved. The basic task of the "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" defines how an image is to be removed, _after_ it has been displayed for its "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" time period. That is, you need to give an image's "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" and "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" settings _before_ reading the image for that frame. But the action is applied after that image is displayed. This is a little counter intuitive but does make sense in the way IM operates on images. If you remember this, you should have no problems. The 'plus' forms of these options, like most other settings in IM stops the setting being applied to any images being read in. That means if you don't specify a setting, the frame image will continue to use the setting that was read in with the image (if any). This can be important later when you want to read in a GIF animation for further processing. Or when merging one GIF animation into another (the most difficult animation technique). ### Dispose None \- each frame overlaid in sequence The default "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting for GIF animations is '`**Undefined**`' which most animation programs treats the same as a '`**None**`' disposal setting. Basically this tells the computer to just leave whatever is overlaid by this specific frame. Or more precisely, 'do nothing'. However please note that the whole canvas is always cleared at the end of the animation sequence, before it loops and repeats. Here for example is a standard 'None dispose' animation... magick -delay 100 -dispose None \\ -page 100x100+5+10 balloon.gif \\ -page +35+30 medical.gif \\ -page +62+50 present.gif \\ -page +10+55 shading.gif \\ -loop 0 anim\_none.gif [![[IM Output]](anim_none.gif)](anim_none.gif) This disposal technique is ideal for animations which involve no form of transparency, such as animations drawn on a solid, or patterned background. magick -dispose none -delay 100 \\ -size 100x100 xc:SkyBlue +antialias \\ -fill DodgerBlue -draw 'circle 50,50 15,25' \\ -page +5+10 balloon.gif \\ -page +35+30 medical.gif \\ -page +62+50 present.gif \\ -page +10+55 shading.gif \\ -loop 0 canvas\_none.gif [![[IM Output]](canvas_none.gif)](canvas_none.gif) Note that this technique can only add visible colors to an animation. It can never actually make any part of an animation transparent again. (See [Overlay Animations](#overlay) below). To also handle transparency need to use one of the other sorts of disposal methods. ### Dispose Previous \- preserve background canvas The '`**Previous**`' disposal method is relatively simple. When the current image is finished, return the canvas to what it looked like before the image was overlaid. If the previous frame image also used a '`Previous`' disposal method, then the result will be that same as what it was before that frame.. etc.. etc.. etc... For example in this animation each of the later frames will return to the very first frame of the image, which has a '`[None](#none) ` disposal setting, before overlaying the image associated with that frame. The result is a background canvas that has just each frame image overlaid for just the duration of that image... magick -dispose none -delay 0 \\ -size 100x100 xc:SkyBlue +antialias \\ -fill DodgerBlue -draw 'circle 50,50 15,25' \\ -dispose previous -delay 100 \\ -page +5+10 balloon.gif \\ -page +35+30 medical.gif \\ -page +62+50 present.gif \\ -page +10+55 shading.gif \\ -loop 0 canvas\_prev.gif [![[IM Output]](canvas_prev.gif)](canvas_prev.gif) Note the "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" method '`[None](#none) `' used for the first image. This is important, otherwise the 'previous' frame will go all the way back to the original empty canvas that was present before the first frame. Also note that I used a "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" of '`0`' in the above animation. This says not to wait before overlaying the first frame onto this 'background canvas'. Without it you will see a short delay, showing just the canvas image with nothing on top of it. Of course I need to still set a longer "`[-delay](https://imagemagick.org/script/command-line-options.php?#delay) `" for the later images, or they will appear and disappear in the wink of an eye, and incidentally use up a lot of the viewers CPU cycles. The use of the '`Previous`' disposal method can be prone to a slight flickering, or pause in some web browsers, especially on slower machines. Though that is quite rarely seen these days, the flicker itself is still present, and something I consider to be a bug. See [Zero Delay Frames](#zero) below for more specifics. Few animations make use of a dispose previous style of animation, the reason is that it is very difficult for computers to optimise. The problem is just what frame should the computer pick to become the background image? Simple for us humans to figure out the best image to use, but difficult for a computer decide. The best background image to use in an animation may not even be meant to be displayed, such as in the current example, and as such may not exist in an un-optimized version of that animation. ### Dispose Background \- clear to background While the first two "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" methods are relatively simple, the '`**Background**`' is probably the hardest to understand. When the time delay is finished for a particular frame, the area that was overlaid by that frame is cleared. Not the whole canvas, just the area that was overlaid. Once that is done then the resulting canvas is what is passed to the next frame of the animation, to be overlaid by that frames image. Here for example we just replace each frame with the next frame. magick -delay 100 -dispose Background \\ -page 100x100+5+10 balloon.gif \\ -page +35+30 medical.gif \\ -page +62+50 present.gif \\ -page +10+55 shading.gif \\ -loop 0 anim\_bgnd.gif [![[IM Output]](anim_bgnd.gif)](anim_bgnd.gif) So you can see exactly what is going on, lets add an initial canvas image to the animation, so you can see how a '`Background`' actually 'disposes' that frame from the animation display. magick -delay 100 -dispose none \\ -size 100x100 xc:SkyBlue +antialias \\ -fill DodgerBlue -draw 'circle 50,50 15,25' \\ -dispose background \\ -page +5+10 balloon.gif \\ -page +35+30 medical.gif \\ -page +62+50 present.gif \\ -page +10+55 shading.gif \\ -loop 0 canvas\_bgnd.gif [![[IM Output]](canvas_bgnd.gif)](canvas_bgnd.gif) As you can see as each overlaid frame is disposed of, that frames area is cleared to transparency, before the next image is overlaid. This is the importance of this GIF disposal method as it is the only way GIF animations can clear any pixel regardless of an animations frame history. The only other way to clear pixels is to use '`[Previous](#previous) `' to go back to a frame in which those pixels were clear. But that relies on knowing the history of the animation sequence which makes it much more difficult for computers to optimize. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _There is some thinking that rather than clearing the overlaid area to the transparent color, this disposal should clear it to the 'background' color meta-data setting stored in the GIF animation. In fact the old "`Netscape`" browser (version 2 and 3), did exactly that. But then it also failed to implement the '`Previous`' dispose method correctly.

On the other hand the initial canvas should also be set from the formats 'background' color too, and that is also not done. However all modern web browsers clear just the area that was last overlaid to transparency, as such this is now accepted practice, and what IM now follows._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version 6.2.6-1, the IM "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" and "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" operations did not handle animations that used '`Background`' disposal to make pixels transparent, as per all the major web browsers. See [Animation Bugs](../bugs/animation_bgnd/)
for examples and details.

These functions however did work fine when no pixel clearing was applied or intended. This has now been fixed for "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" and the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers)  [OptimizeFrame](../anim_opt/#optframe) `' method was created to replace the use of "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" as a GIF animation frame optimizing function._ | * * * Studying Animations ------------------- Before we can continue with the basics of GIF animation, their types, optimizations, and handling techniques, we need some techniques for studying existing animations. ### Identify \- information about and animation Now an animation consists of a lot of information packed into each individual frame. You can see some of this information using the default IM "`[identify](../basics/#identify) `" command. magick identify canvas_prev.gif [![[IM Text]](identify_prev.txt.gif)](identify_prev.txt) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _If you did not see output like the above your IM is a little old, and you really should upgrade your installed version of ImageMagick, to the latest version. If you don't you will be missing out on a lot of the new advances in IM's handling and control of GIF animations._ | As you can see the actual image saved for the second and later frames is only 32x32 pixels, but all the frames sits on a 100x100 pixel 'virtual canvas' with a 'virtual offset' on that larger canvas. To see more of the various bits of meta-data that is present you need to use some of the more specialzed [percent Escape Formats](http://imagemagick.org/script/escape.php) to get IM to output it. magick identify -format "%f canvas=%Wx%H size=%wx%h offset=%X%Y %D %Tcs\n" \ canvas_prev.gif [![[IM Text]](identify_prev_more.txt.gif)](identify_prev_more.txt) Which clearly shows not only the canvas size, image size and offset, but also the disposal and time delays used for each individual frame. Note how the first frame has the different disposal and time delay that was needed for proper use of the later '[Previous](#previous) ' disposal method. ### Adjoin \- splitting an animation into frames Now as you saw above, ImageMagick will by default try to save multiple images into one file if that file format allows it. However as discussed in [Writing a Multi-Image List](../files/#write_list) IM will let you use the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" setting to tell it to save each image to disk as a separate individual image. For example, here we read in one of the GIF animations and output the individual frame images in the animation sequence. magick canvas\_prev.gif -scene 1 +adjoin frame\_%03d.gif [![[IM Output]](frame_001.gif)](frame_001.gif) [![[IM Output]](frame_002.gif)](frame_002.gif) [![[IM Output]](frame_003.gif)](frame_003.gif) [![[IM Output]](frame_004.gif)](frame_004.gif) [![[IM Output]](frame_005.gif)](frame_005.gif) If you were to examine the actual images above you will find that although most web browsers show a larger 100x100 area, on which each sub-frame appears. In fact most of the actual images show are really only just 32x32 pixels, just as show in the previous 'identify' commands above. That is, most of the area is just a canvas on which nothing is drawn, known as the images 'page geometry' or 'virtual canvas'. The first image of the animation defines that larger 'canvas' and every other frame defines an 'offset' position on this larger canvas. This extra information is preserved in the frames that was saved by the "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" setting. As as such you can easilly re-build the GIF animation. Not only is the page information preserved in each separate frame image, but also any delay, looping and GIF dispose settings, is also preserved.This means that to rebuild the animation you only need to read all the images in. magick frame\_???.gif anim\_rebuilt.gif [![[IM Output]](anim_rebuilt.gif)](anim_rebuilt.gif) Sometimes however you don't want to preserve this page geometry information. For example if you want to use the individual frames for other projects. You can reset the page size and offset using the "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" option, to remove the 'virtual canvas' information, leaving just the actual image. Normally when extracting animation sub-images you also generally reset the images delay and dispose settings too to ensure they don't interfer with the editing and display. For example here I remove the unwanted virtual canvas and offset and reset the timing delays and disposals. magick canvas\_prev.gif +repage -set delay 0 -set dispose None \\ +adjoin repage\_%03d.gif [![[IM Output]](repage_000.gif)](repage_000.gif) [![[IM Output]](repage_001.gif)](repage_001.gif) [![[IM Output]](repage_002.gif)](repage_002.gif) [![[IM Output]](repage_003.gif)](repage_003.gif) [![[IM Output]](repage_004.gif)](repage_004.gif) Of course if you junk that meta-data, you need some way of recording and editing that data. See [Animation List Information](#list_info) (below) for a script that extracts both the sub-images and saves the animation meta-data, in a form that can be used to re-build the animation. ### Coalesce \- fill out frames completely Viewing an animation in the form of the sub-frames, however is usually not very useful, in a typical animation. For one thing, a highly optimized animation can consist of lots of very small parts, without any visual indication of how they fit together. It can also have a lot of other 'noise' that was added for [Compression Optimization](../anim_opt/#compress_opt) to reduce the overall file size of the animation. For example, it is very difficult to figure out what this animation actually did, just by looking at the individual sub-frames of the animation. magick script\_k.gif +repage +adjoin script\_k\_%02d.gif [![[IM Output]](script_k_00.gif)](script_k_00.gif) [![[IM Output]](script_k_01.gif)](script_k_01.gif) [![[IM Output]](script_k_02.gif)](script_k_02.gif) [![[IM Output]](script_k_03.gif)](script_k_03.gif) [![[IM Output]](script_k_04.gif)](script_k_04.gif) [![[IM Output]](script_k_05.gif)](script_k_05.gif) [![[IM Output]](script_k_06.gif)](script_k_06.gif) [![[IM Output]](script_k_07.gif)](script_k_07.gif) [![[IM Output]](script_k_08.gif)](script_k_08.gif) [![[IM Output]](script_k_09.gif)](script_k_09.gif) [![[IM Output]](script_k_10.gif)](script_k_10.gif) The "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operation basically converts an image into exactly what the animation should look like after the previous frame has been correctly [disposed](#dispose) , and the next sub-frame overlaid. That is, instead of an animation sequence where each frame only represents the overlaid changes to the previous 'disposed' frame. This operator creates a complete view of the animation at each point, a bit like a true film strip, rather than an animation sequence. Such a sequence, known as a [Coalesced Animation](#coalesced) is much easier to study, edit, modify and re-optimize. Here for example will generate a montage of the same 'confusing' animation sequence I showed above, but this time we'll "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" the sequences, so you can see what is really happening. montage script\_k.gif -coalesce \\ -tile x1 -frame 4 -geometry '+2+2' \\ -background none -bordercolor none coalesce\_k\_montage.gif [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) [![[IM Output]](coalesce_k_montage.gif)](coalesce_k_montage.gif) As you can see the result is like a film strip of the animation, allowing you to clearly see how the previous pieces fit together to form a hand drawn letter 'K'. As of IM version 6.2.6, the "`magick montage`" command understood the use of "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `", allowing you to create 'film strip' like image of the animation frames, exactly as shown above. This version also contained fixes for coalesce, and any GIF animation work should be at least this version (or better still the latest version). | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _An even better montage technique for examining animations is given in the next example section._ | The "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting of a _coalesced image sequence_ is actually irrelevant, in a [Coalesced Animation](#coalesced) . However for users piece of mind the "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator will set the "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting of each frame to either '`[None](#none) `' or '`[Background](#background) `' as appropriate, so that the coalesced image sequence will continue to animate correctly (as shown above). | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _A frame with a '`[Background](#background) `' disposal means the next frame needed to clear at least one or more pixels, to be displayed correctly.

As such animations in which "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" added a '`[Background](#background) `' dispose, means that the animation can not be saved as a simple [Overlay Animation](#overlay)
(see below).

Technically, you can set all dispose settings of a coalesced image sequence to either '`[Background](#background) `' or '`[Previous](#previous) `' to generate a [Cleared Frame Animation](#cleared)
(see below). Though not all animations will optimize well in that form._ | Their are also some non-animation uses of the "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator. See [Coalesce, and Progressive Flattening](../layers/#coalesce) examples of these uses. ### Animation Frame Montage \- the "gif\_anim\_montage" script While "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" operator will let you extract the actual images from an animation and "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" will let you see the resulting frames of the animation, both methods leave out a lot of information about the animation. By using some very careful manipulation of the animation images, you can display the frames so as to show not only the actual frames, but also the placement of those frames on the larger canvas. Here is one such method of displaying an animation. magick -dispose Background script\_k.gif -alpha set \\ -compose Copy -bordercolor black -border 1x1 -compose Over \\ -coalesce -bordercolor none -frame 4x4+2+2 \\ -bordercolor none -border 2x2 +append script\_k\_parts.gif [![[IM Output]](script_k_parts.gif)](script_k_parts.gif) Here you can clearly see how the animation works. Each sub-frame image is positioned so as to add to all the previous overlays. The result is a slowly growing picture. Each frame is also a lot smaller than the 'virtual canvas' on which it is positioned. I use this display technique a lot during the development and debugging of GIF animations, as such I converted it into a shell script "**`[gif_anim_montage](../scripts/gif_anim_montage) `**", and expanded it to also list some of the details above each frame in the animation. gif\_anim\_montage script\_k.gif script\_k\_frames.gif [![[IM Output]](script_k_frames.gif)](script_k_frames.gif) Note the variations in the timings used in various frames, to pause as if the pen is being lifted from the page and repositioned. Animations with variable timing can be some of the most interesting, but also more difficult to handle, as you will see in later IM Example pages. The "`[gif_anim_montage](../scripts/gif_anim_montage) `" script also the special option '`-u`' which will also underlay a semi-transparent copy of the coalesced animation. This lets you see how the new sub-frames modifies the displayed animation. gif\_anim\_montage -u script\_k.gif script\_k\_frames.png [![[IM Output]](script_k_frames.png)](script_k_frames.png) Of course this has semi-transparent pixels so a 'PNG' image format was needed, OR you could use one of the many 'background' options that script also provides, allowing you to use GIF or even JPEG formats for the resulting summery image of the animation. Other options, lets you define the number of rows or columns to use, as well as set various non-transparent backgrounds, or use a red box rather than the default black. This script will be used a lot during the next few pages of IM Examples. Suggestions and comments are welcome. ### Animation List Information \- options used to build an animation As I noted, using "`[+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" and "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `", as well as "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `", are all useful methods of extracting and looking at GIF animations. However they all destroy information about the original animation in the process. You can see this extra information on framing, time delays, frame dispose, etc., using the IM "`magick identify`" command with a "`[-verbose](https://imagemagick.org/script/command-line-options.php?#verbose) `" option. However I, and probably most other users, find the output from this command, overwhelming and not really directly usable. This is where another special shell script I wrote comes in. The "**`[gif2anim](../scripts/gif2anim) `**" script will separate the individual frames of the animation, but will also figure out exactly what IM "`magick`" options you would need in order to re-build the animation from those images. You can think of "`[gif2anim](../scripts/gif2anim) `" as an animation disassembler, producing a summary of the animation in terms of IM options. For example, lets decode the animation example we have been using to recover the original "`magick`" settings used to create it, as well as individual images used... gif2anim canvas\_prev.gif [![[IM Text]](canvas_prev.anim.gif)](canvas_prev.anim) [![[IM Output]](canvas_prev_001.gif)](canvas_prev_001.gif) [![[IM Output]](canvas_prev_002.gif)](canvas_prev_002.gif) [![[IM Output]](canvas_prev_003.gif)](canvas_prev_003.gif) [![[IM Output]](canvas_prev_004.gif)](canvas_prev_004.gif) [![[IM Output]](canvas_prev_005.gif)](canvas_prev_005.gif) By default the "`[gif2anim](../scripts/gif2anim) `" script uses the same base file name for the individual images and "`.anim`" options file. As such the animation sequence file generated by the above command is named "`[canvas_prev.anim](canvas_prev.anim) `", with the individual frame images "`[canvas_prev_001.gif](canvas_prev_001.gif) `" to "`[canvas_prev_005.gif](canvas_prev_005.gif) `". If you examine the results more closely you will see that it actually did manage to re-create the original options I used when I first created this GIF animation (See [Dispose Previous Animation](#previous) ). Also while it is not important to actually generating an animation, the size, and timings of the overlaid frames is also listed as a comment, to make it easier to study. Rather than save the results to a file you can just list the animation sequence options to the screen using a "`-l`" flag. That is, just output the animation sequence file, rather than save it, or the individual frame images of the animation. gif2anim -l canvas\_prev.gif Given a "`.anim`" file and the individual framing images, a complementary script "**`[anim2gif](../scripts/anim2gif) `**" can be used to re-build the animation. anim2gif canvas\_prev.anim [![[IM Output]](canvas_prev_anim.gif)](canvas_prev_anim.gif) The "`[anim2gif](../scripts/anim2gif) `" by default will re-create the GIF animation with a "`_anim.gif`" suffix. You can see that the resulting "`[canvas_prev_anim.gif](canvas_prev_anim.gif) `" animation generated, looks and works exactly like the original animation. This script simply replaces the special string "`BASENAME`" used in the "animation sequence file", strips all comments, then just pass the convert options that is left into the "`magick`" command. In other words it treats the above file as a type of 'convert' script with comments. The reason a special string was used, is because this then allows you to specify a different base filename than the name of the "`.anim`" file itself. That way you can use a completely different set of frame images, such as modified versions of the original, to recreate a different animation from the old one. This is very useful feature, which will used in more complex animation processing. (See [Appending Animations Side-By-Side](../anim_mods/#append) for an example). Like "`[gif2anim](../scripts/gif2anim) `", the "`[anim2gif](../scripts/anim2gif) `" script has quite a number of useful options, to help you process and modify animations. Some of these options will be used later. For example see [Appending Animations](../anim_mods/#append) . Also as the "`.anim`" file is plain text you can use it take the decoded images of an animation to adjust the GIF's meta-data, such as the timings, positions, repeating sections of an animation, or adding new frames and images to an animation. This was after all why I originally wrote the scripts, long before I got involved with IM examples. For now the "`[gif2anim](../scripts/gif2anim) `" will be most useful for examining an animation sequence to see just what is happening, and the timings that is being applied between frames. ### Dispose Images \- the GIF dispose form of the frames This special "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method, '`**Dispose**`' shows what the frame should look like _after_ the time delay is finished, and the GIF dispose method has been applied, but _before_ the next frames image is overlaid. In other words this show exactly what the GIF "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" method setting actually does to the frame, allowing you figure out exactly what is going wrong with your animation. For example, here is how each of our three [Dispose Method Example Animations](#dispose) look like after the individual frame dispose method was applied. Remember each of these animations consist of a 'canvas image' that was set with a '`[None](#none) `' "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" setting, then followed by four smaller images overlaid then disposed of by the various GIF dispose methods. '`[None](#none) `' dispose animation... magick canvas\_none.gif -layers Dispose canvas\_none\_dispose.gif gif\_anim\_montage canvas\_none\_dispose.gif canvas\_none\_dispose\_frames.gif [![[IM Output]](canvas_none_dispose_frames.gif)](canvas_none_dispose_frames.gif) '`[Previous](#previous) `' dispose animation... magick canvas\_prev.gif -layers Dispose canvas\_prev\_dispose.gif gif\_anim\_montage canvas\_prev\_dispose.gif canvas\_prev\_dispose\_frames.gif [![[IM Output]](canvas_prev_dispose_frames.gif)](canvas_prev_dispose_frames.gif) '`[Background](#background) `' dispose animation... magick canvas\_bgnd.gif -layers Dispose canvas\_bgnd\_dispose.gif gif\_anim\_montage canvas\_bgnd\_dispose.gif canvas\_bgnd\_dispose\_frames.gif [![[IM Output]](canvas_bgnd_dispose_frames.gif)](canvas_bgnd_dispose_frames.gif) If you study the above you can see exactly how each of the three GIF dispose methods clear the animation of that frames overlaid image. Note that the first frame of these three animations is always set to a dispose of '`None`' so will remain unchanged. It is the effect of the dispose method in the later frames that is imporant. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "`-layers Dispose`" operation only generates the 'coalesced' sequence of the disposal frames. It does not reset the disposal setting itself, and as such the result may not animate properly. To make the above animate correctly set all disposal methods to '`previous`' or '`background`' or you can optimize the animation, before saving._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The look of the final frame after the GIF dispose method is normally of no consequence to a GIF animation, as the whole canvas is completely cleared before the animation repeats (loops). If it does not 'loop' but stops at the end of the animation sequence, then the final frames disposal is not applied.

In other words the appearance of the last frame (after disposal) as shown above, or even the actual dispose setting of the last frame, does have any effect on a GIF animation. IM generally sets this to same as the previous frame when it trys to work out an appropriate disposal method, during a [Frame Optimize](../anim_opt/#optframe)
an animation._ | ### Deconstruct \- report areas of frame differences The traditional way in ImageMagick to optimize an animation, making the result smaller and faster to download and animate, is to "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" its "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" form. _This is no longer recommended_. Instead you use should use the [General GIF Optimizer](../anim_opt/#optimize) . This operator will take a coalesced sequence of images (the animation frames as they actually appear when displayed), and compare the second and later images with that of the previous image. It then replaces that image with the smallest rectangular area of the pixels that had changed. Any pixel change, will count, regardless of if it is a color change (overlay) or cleared (erased). This is quite simple, and for a typical [Overlay Animations](#overlay) will generate an optimal [Frame Optimization](../anim_opt/#frame_opt) for that animation. An [Overlay Animations](#overlay) animation however only use a '`[None](#none) `' dispose method only. For example lets take the [coalesce previous animation](#coalesce) we generated above, which happens to form a [Overlay Animation](#overlay) , and run it though the "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" operator. magick canvas\_prev.gif -coalesce coalesce.gif magick coalesce.gif -deconstruct deconstruct.gif gif\_anim\_montage coalesce.gif coalesce\_frames.gif gif\_anim\_montage deconstruct.gif deconstruct\_frames.gif [![[IM Output]](deconstruct.gif)](deconstruct.gif) [![[IM Output]](coalesce_frames.gif)](coalesce_frames.gif) ![==>](../img_www/space.gif) ![==>](../img_www/right.gif) [![[IM Output]](deconstruct_frames.gif)](deconstruct_frames.gif) A 'previous dispose animation' if you remember clears each frame to the last non-previous disposed frame, in this case the initial background canvas. As you can see "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" returned the area that changed from one coalesced frame to the next. Resulting in an optimized [Overlay Animation](#overlay) , that requires no special dispose setting. This is nowhere near as optimal as the original hand generated animation I started with, but is useful in itself. | | | | --- | --- | | Unfortunately "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" has absolutely no understanding of the GIF animation "`[-dispose](https://imagemagick.org/script/command-line-options.php?#dispose) `" settings. Consequently if you try this on an animation that clears pixels from one frame to the next, such as the '[background disposed](#background)
' animation we created above (and shown left), it will fail badly. | [![[IM Output]](canvas_bgnd.gif)](canvas_bgnd.gif) | Here we take the just shown animation, and run it though a "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" and "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" cycle. magick canvas\_bgnd.gif -coalesce -deconstruct deconstruct\_erase.gif [![[IM Output]](deconstruct_erase.gif)](deconstruct_erase.gif) As you can see "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `", slowly destroys the animation. Basically "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" is designed to simply find the differences between image layers. It was never designed to correctly optimize animations, and will fail for animations that need to use various disposal techniques to clear (erase or make transparent) previously overlaid pixels. ### Frame Comparisons \- more detailed comparing of frames With IM v6.2.6-2, a number of extra GIF frame comparison methods were added. These were needed internally for proper optimization of animations, but was deems useful enough to make them available to the command line and other API interfaces. #### Compare\_Any The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`**CompareAny**`' is actually exactly the same as "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `". In fact the "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" operator is only a functional alias for the '`CompareAny`' method. Again lets look at the actual image results of a 'deconstruct' or '`CompareAny`' of the '[background disposed](#background) ' animation. magick canvas\_bgnd.gif -coalesce canvas\_bgnd\_coal.gif gif\_anim\_montage canvas\_bgnd\_coal.gif canvas\_bgnd\_coal\_frames.gif magick canvas\_bgnd\_coal.gif -layers CompareAny magick compare\_any.gif gif\_anim\_montage compare\_any.gif compare\_any\_frames.gif [![[IM Output]](canvas_bgnd_coal_frames.gif)](canvas_bgnd_coal_frames.gif) ![==>](../img_www/space.gif) ![==>](../img_www/right.gif) [![[IM Output]](compare_any_frames.gif)](compare_any_frames.gif) As you can see the second and later images, is the minimal rectangular area that contains all the pixels that have changed, whether it is an overlay of a new pixel color, or a clearing of an old pixel to transparency. #### Compare\_Clear The "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`**CompareClear**`' will show the smallest rectangular area that contains all the pixels that needed to be cleared from one frame to the next. magick canvas_bgnd_coal.gif -quiet -layers CompareClear compare_clear.gif gif_anim_montage compare_clear.gif compare_clear_frames.gif [![[IM Output]](compare_clear_frames.gif)](compare_clear_frames.gif) Notice that as no pixels were cleared between the first and second frame, a special [Missed Image](../crop/#crop_missed) was generated. The "`[-quiet](https://imagemagick.org/script/command-line-options.php?#quiet) `" setting was used to tell IM not to give any warning about this image. If all the later frames all become 'missed' images, then the GIF animation never clears pixels, and the animation can be classed as a [Overlay Animation](#overlay) . #### Compare\_Overlay The last "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" comparison method, '`**CompareOverlay**`', returns the area of pixels that were overlaid (added or changed in color, but not cleared) since the previous frame. magick canvas\_bgnd\_coal.gif -layers CompareOverlay magick compare\_overlay.gif gif\_anim\_montage compare\_overlay.gif compare\_overlay\_frames.gif [![[IM Output]](compare_overlay_frames.gif)](compare_overlay_frames.gif) This is similar to the special IM specific '[ChangeMask](../compose/#changemask) " Alpha Composition Method. However, that returns just the pixels that change the image, rather than the rectangular area that was changed. See also [Transparency Optimization](../anim_opt/#opt_trans) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _None of the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" comparison methods, nor the "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" operator, look at or modify the image GIF dispose method that is used. The results is just a list of images, and not expected to be used as animations themselves._ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _While the operators are designed to work with a coalesced image sequence, they will accept a non-coalesced sequence of image layers, without producing an error.

In this case each frame is overlaid onto the previous overlaid frames using a '`[Copy](../compose/#copy) `' alpha composition method, before the frames are compared. This alpha composition method ensures that any transparency in a layer will also be added to the destination image. Without this the above would not find pixels that get cleared to transparency in a coalesced image sequence.

Note that this is different to the more normal '`[Over](../compose/#over) `' composition method that the "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator would use for handling the 'dispose/overlay' cycle needed to display a GIF animation.

_ | * * * Types of Animations ------------------- Most GIF animations you find fall into some basic types of animation. Knowing about these types allows you understand how that animation is being displayed from one frame to another, and can allow you to take shortcuts in how you handle and modify the animation. ### Coalesced Animations A '**Coalesced Animation**' is basically an image sequence that shows what an animation should look like when displayed to an user after each 'dispose/overlay' cycle. The images are basically as you would see them if you were looking at an actual 'film strip' of the animation. It is the simplified and completely un-optimized form of any animation. This naming convention is from the name of the IM "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator that is used to magick GIF disposal animations, into an un-optimized 'Coalesced Animation'. Most video formats (MPEG, AVI etc) are actually also 'Coalesced Animations' by their very nature. However these also tend not to have any transparent pixels, and generally have a constant time delay between the frames of the animation. A coalesced GIF animation however can have transparent pixels, and widely varying time delays from immediate '0' delays, to very fast, or very very very slow. Any GIF disposal setting in a coalesced animation does not have any meaning, however the "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operator will set the disposal appropriately so the resulting image sequence can still work as a valid GIF animation. Video formats which always replaces every pixel from one frame to the next can generally just use a '`[None](#none) `' or '`[Undefined](#none) `' GIF disposal setting. Here is an example of an animation that is also by its nature a Coalesced Animation, plus a "`[gif_anim_montage](../scripts/gif_anim_montage) `" display of the animations individual frames. | | | | | --- | --- | --- | | | [![[IM Output]](../images/smoke_skull_frames.gif)](../images/smoke_skull_frames.gif) | [![[IM Output]](../images/smoke_skull_anim.gif)](../images/smoke_skull_anim.gif) | Most animations that do not contain, or use, transparency, and which animate the entire canvas, are usually saved and distributed as Coalesced Animations. ### Overlay Animations An '**Overlay Animation**' is one in which each frame of an animation only overlays new pixels to the animation currently displayed. In other words at no point in the animation does it need to clear a pixel to transparency. The individual frames can contain transparency, either as a background, or as part of its optimization, but it never clears a pixel back to transparency. Of course if no transparency is used at all, then the animation is guaranteed to be able to be turned into a simple Overlay Animation. This is probably the simplest type of [Frame Optimized](#frame_opt) animation, and one that requires no special handling by clients. Each frame that is shown to the user can be viewed as simply as 'flattened' image of all the previous frames. Any animation that only uses a '`[None](#none) `' GIF disposal method is an 'Overlay Animation'. The last example for instance is not only a '[Fully Coalesced Animation](#coalesced) ' but also a 'Overlay Animation', though not all such 'Fully Coalesced Animations' are 'Overlay Animations'. You can test if an animation can become an overlay animation by using the '`[CompareClear](#compareclear) `' layers method on a [Coalesced](#coalesce) animation, and checking if all the second and later images are 'missed images'. That is, no pixel needed to be cleared or erased from one frame to the next. In fact if an animation can become an overlay animation, without modification, then the IM "`[coalesce](#coalesce) `" operator will only use '`[None](#none) `' disposal methods for all the frames. If this is not the case then "`[coalesce](#coalesce) `" will have used '`[Background](#background) `' disposal for at least some of the frames. This then gives you with another test for 'overlay only' capability. Overlay animations can use transparency, but they do not have any moving parts on a transparent background. For example, the animation of a hand drawn letter 'K', is an overlay animation, as each part only adds or changes existing parts on a transparent background. It never adds new transparency to the resulting image (except as part of the first frame). | | | | | --- | --- | --- | | | [![[IM Output]](script_k_frames.gif)](script_k_frames.gif) | [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) | [![[IM Output]](../images/dl_world_anim.gif)](../images/dl_world_anim.gif) That is, not to say an moving object can't be handled by an overlay animation, it just means you need a non-transparent background so you can also 'erase' the old positions of the moving parts without needing transparency. For example look at the frames of this "download the world into a folder" animation... [![[IM Output]](../images/dl_world_frames.gif)](../images/dl_world_frames.gif) Of course by needing to 'erase' old parts by overlay the original background means that overlaid sub-images are generally bigger, and hence a generally larger GIF animation file size. Unfortunately using the IM's [Optimize Frame](../anim_opt/#optframe) operator, can, and most probably will, turn a 'Coalesced Overlay Animation' into into something that is not a 'Overlay Animation', in its attempt to find smaller GIF file size. However by using [Deconstruct](#deconstruct) on the animation instead of using [Optimize Frame](../anim_opt/#optframe) , you can ensure the animation remains a simple 'Overlay Animation', but only if the animation is really a 'Overlay Animation'. If the animation isn't a 'Overlay Animation', then [Deconstruct](#deconstruct) operation can go badly wrong (See [Deconstruct](#deconstruct) above). With some human skill you can still optimize an overlay animation better, for example using [Split Frame Updates](../anim_opt/#splitting) , and applying some form of [Compression Optimization](../anim_opt/#compress_opt) without destroying the 'Overlay Only' requirement of the animation. Typically 'Overlay Animations' display no transparency at all (they can use it as part of optimization, but they don't display it). And if no transparency is displayed, then the animation is guaranteed to be a 'Overlay Animation'. Why is 'Overlay Animations' so important? Because there is software out there that are limited to this type of animation. It is much simplier to handle as only overlay is performed without need to handle transparency, or save the previous frame to handle GIF disposal methods. Such software is rare but does exist. ### Cleared Frame Animations When an animation only uses just '[Previous](#previous) ' or '[Background](#background) ' GIF disposal, you get a very special type of animation. Note that if only '[Background](#background) ' disposals is used, all the frames of an animation are displayed then cleared before the next frame is displayed. Also when only '`[Previous](#previous) `' are used, the animation is always returned to the initial cleared canvas before the next frame is displayed, resulting in the same effect. Same happens if you only use a mix of those two disposal settings. That is, animations that only uses these disposal methods will have frames that are complete copies of what is to be displayed. That is, the frame contains everything that will be displayed to the user at that point in time. That is, not to say that the animation is a '[Fully Coalesced Animation](#coalesced) '. As the sub-frame may be a lot smaller than the virtual canvas area of the animation, but everything outside that frame will be regarded as transparent (or background), containing nothing of importance. For example take a look at this running bunny animation... | | | | | --- | --- | --- | | | [![[IM Output]](../images/bunny_frames.gif)](../images/bunny_frames.gif) | [![[IM Output]](../images/bunny_anim.gif)](../images/bunny_anim.gif) | Note that each and every sub-frame is the complete image that is displayed. No more, no less. Also notice that none of the frames actually needs to use the whole virtual canvas of the animation. And finally note how all the frame disposals are set to '`[Previous](#previous) `', which for reasons you will see below is the more logical disposal setting to use. All the disposal settings could however have been set to '`[Background](#background) `' disposal or any mix of the two without changing the final result.For want of a better name I call such an animation a '**Cleared Frame Animation**', but I have also seen it called a 'Previous or Background Disposal Animation'. The only time that an animation is not of this type is if at least one non-blank frame in the animation used a '`[None](#none) `' or '`Undefined`' (same thing) disposal method. This animation is very special, as it can handle any amount of transparency clearing, anywhere within the animation sequence, unlike a [Overlay Animation](#overlay) . But it can also be overlaid onto ANY static background image really quickly. To do this we need to tighten the definition of a 'Cleared Frame Animation' slightly. Specifically we need to make sure all the disposals are set to '`[Previous](#previous) `' (which is already the case in our example). If that is done, then you can just pre-pend an image (with a zero delay) to underlay a background.For example lets place our bunny on some grass.... magick bunny\_grass.gif bunny\_anim.gif -loop 0 bunny\_on\_grass.gif [![[IM Output]](bunny_on_grass.gif)](bunny_on_grass.gif) As you can see this is so simple that many applications use these types of GIF animations to add symbols or other indicators (file locks, smileys, stars, etc) to larger objects. Animating such a GIF animation is also easy, as the application can just clear the area to some simple constant background image, and overlay the next frame in the sequence. No need to calculate disposals, or keep track of a 'previous' display, other than the static unchanging background display. This is also the reason why a '`[Previous](#previous) `' disposal is the preferred disposal for a [Cleared Frame Animation](#cleared) . Unlike a [Overlay Animation](#overlay) which are only a special sub-set of GIF animations, ALL animations can be saved as a [Cleared Frame Animation](#cleared) . Just [coalesce](#coalesce) the animation, and optionally [trim](../crop/#trim) any surrounding transparent edges to frame optimize it, and reset the disposals. magick any\_animation.gif -coalesce -trim \\ -set dispose previous cleared\_frame\_animation.gif You can even re-position the animation on that background... magick bunny\_grass.gif \\( bunny\_anim.gif -repage 0x0+5+15\\! \\) \\ -loop 0 bunny\_on\_grass2.gif [![[IM Output]](bunny_on_grass2.gif)](bunny_on_grass2.gif) As such a [Cleared Frame Animation](#cleared) typically consists of a small, constantly changing or moving object on a transparent background. These are directly usable on web pages, or as animated symbols, or can be merged with other animations to produce much more complex animations. In summery this type of animation is a good style to use in a library of animated parts, for use in creating larger more complex animations. There is however a problem with adding background like this for GIF animations. If you look at the previous examples, you would probably have notice a significant and disturbing pause in the fast moving animation. That is, the bunny vanished for a moment, when the animation looped, and the background image is re-loaded. (See notes in [Zero Delay Frames](#zero) )Though this is not a problem for applications that use this technique, for adding animated symbols to displayed objects, as they just don't display that 'intermediate' frame, anyway. As such if are adding a non-transparent background to the GIF animation, then it is generally a good idea to magick the simple [Cleared Frame Animation](#cleared) into a [Overlay Animation](#overlay) . That is add that background to every frame of the animation, rather than give an initial canvas. You can do that by either, [Coalescing](#coalesce) the above animation, then deleting the [Zero Delay](#zero) Background frame, OR [Layer Composite](../anim_mods/#composite) the original animation onto a [Static Background](../anim_mods/#background) . For example... magick bunny\_grass.gif \\( bunny\_anim.gif -repage 0x0+5+15\\! \\) \\ -coalesce -delete 0 -deconstruct -loop 0 bunny\_bgnd.gif gif\_anim\_montage bunny\_bgnd.gif bunny\_bgnd\_frames.gif [![[IM Output]](bunny_bgnd.gif)](bunny_bgnd.gif) [![[IM Output]](bunny_bgnd_frames.gif)](bunny_bgnd_frames.gif) Now that all the frames are displayed equally well, no pause can be seen as the background is reset. The animation however is now an [Overlay Animation](#overlay) with background being 're-drawn' due to the movement of the animation object, as such it is probably a bit larger in file size. See [Transparency Optimization](../anim_opt/#opt_trans) for a continuation of the optimization of the above result. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The IM forum member [el\_supremo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=3499)
, Pete, has contributed a MagickWand equivelent script, [Cleared Frame onto Background example](http://members.shaw.ca/el.supremo/MagickWand/bunny.htm)
.

This example is also discussed in detail in the IM Forum [Creating a Cleared Frame GIF Animation in the MagickWand](https://magick.imagemagick.org/viewtopic.php?f=6&t=20472)
.

_ | ### Mixed Disposal Animations \- multi-background animations There is nothing preventing you from mixing the various disposal methods in a single GIF animation. If fact adding a background to a [Cleared Frame Animation](#cleared) , does exactly that. Using mixing disposal methods not so simple for us humans, but doing so can allow you to generate some very complex animated displays. In general they are created as part of automatic [Frame Optimization](../anim_opt/#frame_opt) for a particular animation. Just remember the result will not be directly usable as the previous animation types for specific purposes. In fact do not be surprised if some GIF handling programs, just do not handle a 'Mixed Disposal Animation' properly. That includes some of the GIF optimizers available. A typical example of a 'Mixed Disposal Animation' is a small moving object that causes some semi-permanent but temporarilly static change in the animations background. A ball hitting a lever would be one example. _Simple Example wanted_ Similarly animations involving two very small moving objects on a larger transparent display can only be optimized well by mixing up the disposal techniques, so that each object is moved using separate animation frames. FUTURE, A more complex animation for study. \* Start with a semi-transparent canvas \* run a little 'previous' disposal \* leave one frame as a new 'canvas' \* more previous animations \* erase that 'addition' using a 'background' disposal set as new canvas \* continue back to start point. This animation should thoroughly test out not only IM disposal methods but also various browser disposal methods. _If you like to contribute an IM example of such an animation you can get your name, and home page link here!_ * * * The End of the Loop \- when an animation stops ---------------------------------------------- It is often regarded as a good idea not to make animations loop forever, as client machines have to continually work while the animation is still animating. As such it is a good idea to think about how many times your animation actually loops. Basically.. **Add a loop limit to your animations (if practical)** This is especially the case for large animations used as a logo at the top of a web page. Depending on the overall time for which an animation runs, 10 to 30 loops is usually enough for large logos. And you should add a loop limit for all such animations, to be kind to your users. A "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" save setting of 0, means to loop forever. This is typically what is used, and that is okay, for small animations. Some browsers however enforce a stop when an animation reaches some internal loop limit (often 256 loops). For IM Examples I have generally used a '0' "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" save setting, meaning 'loop forever', because the animations can appear anywhere on a page. That means it may be some time between when the user loaded a page to when they finally look at and read about a particular GIF animation. If I did use a smaller number of 'loops', the animation would no longer be doing what it should be demonstrating, loosing its effectiveness. For large animations on top level flash pages, a "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" of '1', the normal GIF animation default, can be used. This means run though the animation once only and then stop. Which brings us to an all important question.. **Stop where?** Some browsers, like the old "`Netscape`" browser, re-displayed the first frame of the animation. Most modern browsers however will just stop on the last frame, ignoring that frames useless [dispose](#dispose) setting. What a specific application does however is up to the application as there is no true standard. Actually even the use of the 'loop' meta-data, is itself non-standard, just something that the old "`Netscape`" browser implemented, and all later browsers copied. Because of this, if there is some specific frame that you want your animation to stop on, say the frame with your company name or logo on it, then it is a good idea to make that frame both the first and last frame of an animation One of those frames however should be given a 'zero delay', so as not to effect the overall loop time length of the animation. So just to summarize... **If loop limited, add the 'stop' frame as BOTH first and last frames.** * * * Zero Delay Intermediate Frames ------------------------------ We have already seen use of a frame that has a 'zero delay', with regard to a [Cleared Frame Animations](#cleared) . I also used them to explain [Previous and Background Disposals](#previous) . These special frames are actually a lot more common then people would probably think. They represent not only methods to prepend a background 'canvas' to an animation (such as I have used them for above). But they are also a must for some of the more complex [Frame Optimization](../anim_opt/#opt_frame) techniques, such as [Frame Doubling](../anim_opt/#doubling) and [Splitting Frame Updates](../anim_opt/#splitting) . Another (very old pre-PNG format) usage was to allow you to create static GIF images that contained more than the 256 color limit! That is, each frame provides 256 colors, and the next frame the next set of 256 colors, all with zero delay and no looping at the end. Thanks to [TLUL](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=23894) in the discussion [Creating unquantized GIFs](https://magick.imagemagick.org/viewtopic.php?f=1&t=22855) for pointing this out. These '_zero delay intermediate frames_' are not meant to be displayed to an user. They are just used to create special effects in GIF images that are otherwise not posible or better optimized than you would get without them. In summary... **Zero Delay Frames are Intermediate Frames, They are not meant to be visible to users.** ImageMagick not only will create such frame in animations as part of its automatic '[OptimizePlus](../anim_opt/#optimizeplus) ', but also provides a way to remove them using the '[RemoveZero](../anim_opt/#removezero) ' layers method. Watch out for them, as they will often complicate your handling of Animations. Okay so they are important, what of it? Because many applications don't like them, or incorrectly handle them. They consider 'Zero Delay Frames' as a bad thing, even when you purposely add them to animations, for some reason or another. Here is summary of applications that I know about or have been told, 'do the wrong thing'... | | | | --- | --- | | **Gimp** | Will not save a 'Zero Delay Frame', they always add a minimal time delay to any frame that has a zero time delay. :-( | | **FireFox** | Will give a slight non-zero pause on such frames. This presumably is so that animations that have no time delays at all, do use up all the computers CPU cycles. But "`firefox`" still doesn't relax that restriction if an animation has an overall non-zero display time. | | **Internet Explorer** | Has a minimum time delay of 6 centi-seconds, and ignores any delay smaller than this. Internet Explorer version 8 also fails (immediately restarts the loop) if any image frame extends beyond the animation bounds set by the first frame. This I would class as a major bug. | On the other hand ImageMagick '[RemoveZero](../anim_opt/#removezero) ' layers method does do the right thing and will NOT remove any frame if ALL the images have a 'zero time delay'. In fact this layers method will give a warning if it sees an animation with no time delays at all. This brings us to another rule-of-thumb... **Never save a GIF (looping) animation that has no 'delays' at all** Doing so is very bad practice, and the reason most of the above 'buggy' applications, do what they do, rather than what they should. Complain to the owners if you see them. Also complain to application developers, so that they handle Zero delay frames correctly. Even if it means not displaying that frame at all, just using them as preparation for the next frame to display. They are after all on screen for _ZERO_ time! * * * --- # Thumbnails -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Creating Thumbnails and Framing =================================================================================== | | | | | --- | --- | --- | | [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) | | | | [![](../img_www/granitesm_right.gif) Thumbnail Storage](#storage)

* [Image Format Choice](#formats)

* [Profiles, and JPEG Images](#profiles)


[![](../img_www/granitesm_right.gif) General Thumbnail Creation](#creation)

* [**Thumbnails of Specific Height**](#height)

* [Resize Thumbnail to Fit](#fit)

* [Pad Out Thumbnail](#pad)

* [Cut the Thumbnail to Fit](#cut)

* [Area Fit Thumbnail Size](#areafit)

* [**Fit to a Given Space Summary**](#fit_summery)

* [Square Padding or Cropping](#square)

* [Manual Cropping](#manual)

* [HTML thumbnail pages](#html)

* [FavIcon Web Page Link Thumbnail](#favicon)


[![](../img_www/granitesm_right.gif) Other Non-IM Techniques](#non-im) | [![](../img_www/granitesm_right.gif) Adding Fluff](#fluff)

* [Adding Image Labels](#labels)

* [Raised Button](#button)

* [Bubble Button](#bubble)

* [Adding Borders](#border)

* [Simple Frame](#frame)

* [Montage Framing](#montage)

* [Soft and Blurred Edges](#soft_edges)

* [Rounded and Shaped Corners](#rounded)

* [Torn Paper Edge](#torn)

* [Adding a Shadow](#shadow)

* [Adding Some Thickness](#thickness)

* [Polaroid-like Thumbnails](#polaroid) | [![](../img_www/granitesm_right.gif) Framing Techniques](#framing)

* [**Self Framing** (External)](#self_frame)

* [Self Framing (Internal)](#self_frame_inside)

* [**Simple Border Overlay**](#border_overlay)

* [Badge using Overlay](#badge_overlay)

* [**Mask 'n' Paint Technique**](#mask_paint)

* [Rounded Border](#rounded_border)

* [Badge using Mask 'n' Paint](#badge_mask_paint)

* [**Paint 'n' Mask Technique**](#paint_mask)

* [Page Curl Corners](#pagecurl)

* [Fancy Corner Overlay](#fancy)

* [Badge using Paint 'n' Mask](#badge_paint_mask)

* [**Lighting Mask Technique**](#lighting_mask)

* [Glass Bubble](#glass_bubble)

* [Badge with Lighting Mask](#badge_lighting)


[![](../img_www/granitesm_right.gif)Framing using Edge Images](#frame_edge)

* [Over-simplistic Append](#frame_append)

* [Extended Overlay Framing](#frame_extended)

* [45 degree corner joints](#frame_joints) | 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 far better to re-use your original source than to re-do it from a already degraded copy 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... * Save the main photo image in the lossy JPEG format at the size you want or need, then use the same name for the generated thumbnail but using the GIF image format. EG Same filename but a different format and suffix. Main Image: `photo_name.jpg` ![](../img_www/space.gif) Thumbnail: `photo_name.gif` * Store the thumbnails with the same name in a sub-directory called for example "`thumbs`" or whatever is convenient for you. Main Image: `photo_name.jpg` ![](../img_www/space.gif) Thumbnail: `thumbs/photo_name.jpg` * Use the same format as the original image, but with an extra string added to the file name. Typical string additions include "`_tn`", "`_small`", "`_thumb`", etc... Main Image: `photo_name.jpg` ![](../img_www/space.gif) Thumbnail: `photo_name_tn.jpg` * Some combination of the above. There is no reason why you cannot save thumbnails in different image format, with an extra image suffix appended to the filename, and saved in a subdirectory! Main Image: `images/photo_name.jpg` ![](../img_www/space.gif) Thumbnail: `thumbs/photo_name.jpg.gif` This is actually quite common on the WWW, and I have even seen the the two directories stored on completely separate machines! The first scheme can use "`magick mogrify`" to generate all your thumbnails, without destroying the original image, by using a "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting to specify the output image format. As of IM v3.2.0, the second scheme is now also possible to do with "`magick mogrify`" thanks to the addition of a special "`[-path](https://imagemagick.org/script/command-line-options.php?#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 magick 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 "`magick 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 "`magick mogrify`"](../basics/#mogrify_not) . 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](../formats/#summary) . 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](https://imagemagick.org/script/command-line-options.php?#quality) `" percentage (say 50 or even 30%), though it will not look very good. It has also been suggested that using "`[-sampling-factor](https://imagemagick.org/script/command-line-options.php?#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](../formats/#bgnd) . **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](https://imagemagick.org/script/command-line-options.php?#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](../formats/#png_non-im) ) 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 an 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](../formats/#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... magick input.jpg -strip output.jpg magick mogrify -strip \*.jpg You can also use the option "`[-profile](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#resize) `" and "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" were combined into a new operation, just for this very purpose. Naturally enough this resize operation is called "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `". For example... magick -define jpeg:size=240x180 image.jpg -thumbnail 120x90 thumbs/image.gif magick mogrify -path thumbs -format gif -define jpeg:size=240x180 -thumbnail 120x90 '\*.jpg' | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.5.4-7 the "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `" would strip ALL profiles from the image, including the ICC color profiles. From this version onward the color profiles will be preserved. If the color profile is not wanted then "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" all profiles._ | The "`[magick mogrify](../basics/#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](../basics/#mogrify_not) . For very large images the "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#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, an 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 "`[-define](https://imagemagick.org/script/command-line-options.php?#define) jpeg: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](../formats/#jpg_read) . | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.5.6-0 this coder setting was extracted from the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting. This caused problems when users used "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" for image creation but then had JPEG reading produce unexpected results. As such this was changed to be a special coder setting instead.

In older versions of IM you may need to reset the setting using "`[+size](https://imagemagick.org/script/command-line-options.php?#size) ` before reading JPEG images, because of this 'dual' role._ | From IM version 6.2.6-2, a new [Read Image Modifier](../files/#read_mods) 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 "`[-define](https://imagemagick.org/script/command-line-options.php?#define) jpeg:size=`" setting for JPEG images. As such the recommended way of resizing ANY input image format is now... magick -define jpeg: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 magick a [large sample JPEG image](../img_photos/hatching_orig.jpg) to a GIF thumbnail 90 pixels high with the width automatically adjusted (within the 250 pixel width limit) to preserve the aspect ratio of the image. magick -define jpeg:size=500x180 hatching\_orig.jpg -auto-orient \\ -thumbnail 250x90 -unsharp 0x.5 thumbnail.gif [![[IM Output]](thumbnail.gif)](thumbnail.gif) Note that I used the "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#sample) `" resize operator for the initial downsizing of the image, it is faster, while producing reasonable results for small thumbnails. I also set a minimum "`[-define](https://imagemagick.org/script/command-line-options.php?#define) jpeg: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 JPEG size hint I use is at least double that of the final thumbnail so that resize will still generate a reasonable looking result. The "`[-auto-orient](https://imagemagick.org/script/command-line-options.php?#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. Note however that orientation can still go wrong, especially for photos viewing directly down or up, such as when taking photos of documents.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, (EG: using "`-thumbnail x90`" ) IM would could have problems when generating thumbnails of very long thin images such as those shown in [Web Line Images](http://www.ict.griffith.edu.au/images/FancyLines/Images.html) . The result in that case would be very very long, _enlargement_ of the image, instead of a small thumbnail. Some people (including myself) find that while IM's resize is one of the best implementations (See [IM Resize vs Other Programs](../filter/#photoshop) ), the result is still a little blurry. As such you can improve the above result by sharpening the image slightly (using "`[-unsharp](https://imagemagick.org/script/command-line-options.php?#auto-orient) `") after the "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `" resize operation. For more information see [Sharpen Resized Images -- Photoshop Resize Technique](../resize/#resize_unsharp) , But really it all comes down to a matter of personal taste. The "`magick mogrify`" version is the same as the "`magick`" 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. magick mogrify -format gif -define jpeg:size=500x180 -auto-orient \\ -thumbnail 250x90 -unsharp 0x.5 '\*.jpg' | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that "`magick 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._ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Instead of specifying a different format (using "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `") so as to prevent "`magick mogrify`" from overwriting the original source images, you can use a "`[-path](https://imagemagick.org/script/command-line-options.php?#path) `" setting to define a separate thumbnail directory. You can use both output options._ | While "`magick mogrify`" can output the new images with a different suffix ("`[-format](https://imagemagick.org/script/command-line-options.php?#format) `") or directory ("`[-path](https://imagemagick.org/script/command-line-options.php?#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 "`magick`".     _I wrote such a script to do this, while simultaneously generating HTML indexes at the same time._ ### Resize Thumbnail to Fit 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. magick -define jpeg:size=200x200 hatching\_orig.jpg \\ -thumbnail '100x100>' rectangle.gif [![[IM Output]](rectangle.gif)](rectangle.gif) 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 Thumbnail 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 exactly 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 Operator](../crop/#extent) . magick -define jpeg:size=200x200 hatching\_orig.jpg -thumbnail '100x100>' \\ -background skyblue -gravity center -extent 100x100 pad\_extent.gif [![[IM Output]](pad_extent.gif)](pad_extent.gif) As of IM version 6.2.5, you can also use a [Viewport Crop](../crop/#crop_viewport) , and flatten the result onto a background color. magick -define jpeg:size=200x200 hatching\_orig.jpg -thumbnail '100x100>' \\ -gravity center -crop 120x120+0+0\\! \\ -background skyblue -flatten pad\_view.gif [![[IM Output]](pad_view.gif)](pad_view.gif) The key difference between using[Extent](../crop/#extent) and a [Viewport Crop](../crop/#crop_viewport) is weather you want a minimal [Virtual Canvas](../basics/#virtual_canvas) or have the whole area 'padded out'. 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. magick -define jpeg:size=200x200 hatching\_orig.jpg -thumbnail '100x100>' \\ granite: +swap -gravity center -composite pad\_compose.gif [![[IM Output]](pad_compose.gif)](pad_compose.gif) This method is probably the best method to use with older versions of IM (such as IM v5), though the "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" operation will need to be done by the separate "`[composite](../basics/#composite) `" command, rather than the above single command method. However an image processing point of view all the above are actually doing the same thing. ### Cut the Thumbnail 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 an 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. magick -define jpeg:size=200x200 hatching\_orig.jpg -thumbnail 100x100^ \\ -gravity center -extent 100x100 cut\_to\_fit.gif [![[IM Output]](cut_to_fit.gif)](cut_to_fit.gif) 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](../resize/#fill) . | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _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](../resize/#space_fill)
for details._ | ### Area Fit Thumbnail 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 two 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](../resize/#pixel) ), 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... magick -define jpeg:size=200x200 hatching\_orig.jpg -thumbnail 10000@ \\ -gravity center -background skyblue -extent 100x100 area\_fit.gif [![[IM Output]](area_fit.gif)](area_fit.gif) 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 a Given Space Summary In summary, here are the results of the three methods for thumbnailing an image to a specific sized area. All three methods use exactly the same code, with just with a slight change in the resize argument/flag used. | | | | | --- | --- | --- | | [![[IM Output]](pad_extent.gif)](pad_extent.gif)

Padded Fit
resize, no flag | [![[IM Output]](area_fit.gif)](area_fit.gif)

Area Fit
resize, '@' flag | [![[IM Output]](cut_to_fit.gif)](cut_to_fit.gif)

Cut to Fit
resize, '^' flag | ### Square Padding and Cropping The above padding and cropping methods assume you know the final size of the area in which you want the image to fit. But that is not always the case. Sometimes you want to simply 'square an image', either by 'padding' it out (external square), or 'shaving' the edges (internal square). From the IM Discussion Forums on [Squaring Images](https://magick.imagemagick.org/viewtopic.php?f=1&t=20601) a number of methods were developed.External Squaring can be done using [Mosaic](../layers/#mosaic) to create a larger background canvas using a rotated copy of the image. magick thumbnail.gif \\ \\( +clone -rotate 90 +clone -mosaic +level-colors white \\) \\ +swap -gravity center -composite square\_padded.gif [![[IM Output]](square_padded.gif)](square_padded.gif) Internal Squaring on the other hand is a little harder and requires more work to achieve. This one uses some heavy mask handling to generate a smaller canvas. magick thumbnail.gif \\ \\( +clone +level-colors white \\ \\( +clone -rotate 90 +level-colors black \\) \\ -composite -bordercolor white -border 1 -trim +repage \\) \\ +swap -compose Src -gravity center -composite \\ square\_cropped.gif [![[IM Output]](square_cropped.gif)](square_cropped.gif) An alturnative way is to use a no-op distort using a distort viewport crop/pad the image (See [Distort Viewport Centered Square Crop](../distorts/#centered_square) ). Essentually it uses a 'percent escapes' to do the calculations needed for an [Extent](../crop/#extent) type of operation. External (padding) square... magick thumbnail.gif -virtual-pixel white -set option:distort:viewport \\ "%\[fx:max(w,h)\]x%\[fx:max(w,h)\]-%\[fx:max((h-w)/2,0)\]-%\[fx:max((w-h)/2,0)\]" \\ -filter point -distort SRT 0 +repage square\_external.gif [![[IM Output]](square_external.gif)](square_external.gif) The [Virtual Pixel](../misc/#virtual) setting is used to specify the padding color. Internal (cropped) square... magick thumbnail.gif -set option:distort:viewport \\ "%\[fx:min(w,h)\]x%\[fx:min(w,h)\]+%\[fx:max((w-h)/2,0)\]+%\[fx:max((h-w)/2,0)\]" \\ -filter point -distort SRT 0 +repage square\_internal.gif [![[IM Output]](square_internal.gif)](square_internal.gif) Curtisy of [Fred Weinhaus's Tidbits Page](http://www.fmwconcepts.com/imagemagick/tidbits/image.php#pad_crop_square) . This is a simplier version, but will lose any meta-data (like comment strings or profiles) the image may have. magick thumbnail.gif -set option:size '%\[fx:min(w,h)\]x%\[fx:min(w,h)\]' \\ xc:none +swap -gravity center -composite square\_internal\_2.gif [![[IM Output]](square_internal_2.gif)](square_internal_2.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _IMv7 will allow you to do the above mathematics directly as part of a crop or extent argument, which will prevent loss of image meta-data._ | ### 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 use a PNG or TIFF for the original ,VERY large, scan of the photo. OR the original JPEG image downloaded from a digital camera. Basically for the unmodified original source image, for archiving. I also now like to include the string "`_orig`" in this images filename. * A smaller JPEG image format for a web viewable image when the thumbnail is clicked or selected. This image is resized to fit a 800x800 pixel box, which is a size suitable for viewing by most web users. I typically add a "`_md`" for medium sized image, in the filename. * And lastly a GIF thumbnail resized to a fixed 90 pixel high, and variable width. This allows centered rows of thumbnails on web pages to look reasonable neat and tidy, but which automatically fills the browser windows width, no matter what size browser they are using. Again I typically now include a "`_tn`" in the images filename, to denote that it is a thumbnail. I first generate the web viewable JPEG images (medium size) using "`magick 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 an initial set of thumbnails, again using "`magick 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 "`magick -thumbnail`", or more often in the same graphic program I am viewing and cropping the images with (usually "`XV`", see below). So instead of a thumbnail where the people in the photo are hardly visible (left), I have manually cropping around the subject, highlighting the main point of the photo (right), before thumbnailing. 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]](../img_photos/kiteflyers_auto.gif)](../img_photos/kiteflyers_orig.jpg)

Automatically
Generated
Thumbnail | ![](../img_www/space.gif) | [![[IM Output]](../img_photos/kiteflyers_man.gif)](../img_photos/kiteflyers_orig.jpg)

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. Also I only do this for images I am putting the web. Of course as "`magick mogrify`" will overwrite any existing, possibly hand generated thumbnails, you cannot use it again after you perform any manual thumbnail generation. The "`magick mogrify`" command is useful, but also very dangerous as it overwrites lots of images. Always think before you run "`magick 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](https://antofthy.gitlab.io/info/art/) . For a quick example and starting point for generating such links look at the examples of using the [identify command](../basics/#identify) . ### FavIcon Web Page Link Thumbnail The "`favion.ico`" icon often looked for by web browsers on the top level web page of a web site, for that whole site. That image is a special multi-resolution image format and can be created as follows. magick image.png -alpha off -resize 256x256 \\ -define icon:auto-resize="256,128,96,64,48,32,16" \\ favicon.ico The '`image.png`' can be anything you like, but should be square. If it isn't that should also be the first step in the above. You can also include larger resolutions such as 128 or 256 pixels, but few browsers would make use of them. The 16 and 32 pixel sizes are much more commonly used in such ICO files so special emphesis on those my be useful. Also remember that many browsers will color reduce the images so are to reduce the space used to store it in an users bookmarks file. This brings us to one other point. As only the smallest of images are typically used, with further color reduction, it is recommented to keep the images as small and as well defined as posible. Here is an example of manually resizing images for an ICO file format. magick image.png -background white \\ \\( -clone 0 -resize 16x16 -extent 16x16 \\) \\ \\( -clone 0 -resize 32x32 -extent 32x32 \\) \\ \\( -clone 0 -resize 48x48 -extent 48x48 \\) \\ \\( -clone 0 -resize 64x64 -extent 64x64 \\) \\ -delete 0 -alpha off -colors 256 favicon.ico As mentioned only the "`favion.ico`" image found on the top level directory of a web site is generally used, however you can also specify the location of the link thumbnail image by adding the following HTML tag to the headers of your pages... The "`/path/to/favicon.ico`" can be an absolute or partical URL/URI to the location from which the browser should pick up the web pages thumbnail image. The use of '`REL="shortcut"`' is specific to Internet Explorer (before IE9), and not offically part of the HTML specification. It is posible to merge the two HTML tags together using '`REL="shortcut icon"`' however by keeping the tags separate you can make use of a non-ICO image file format (such as SVG) for non-IE browsers, such as firefox. Remember if this html element is not used the "`favicon.ico`" file found on the top level directory of the web site is used instead (if present). The ICO image format is universally understood by all modern browsers. All except Internet Explorer also can use JPEG, PNG, and GIF image file formats, for the link thumbnail. A few like FireFox can even make use of animated GIF's or SVG image file formats. However as these latter formats can not typically hold multiple images at different resolutions and color counts, it is probably better to stick with the ICO file format for the "`favion.ico`" image. * * * 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 the programs own special thumbnail format (ignoring the filename suffix in that directory). 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 all the thumbnails quickly using XV, then magick the XV thumbnails of the JPEG images, into GIF images for further processing... xv -vsmap & # generate thumbs with the "Update" button rm .xvpics/\*.gif # delete XV thumbs of existing "gif" thumbnails magick 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](http://www.ict.griffith.edu.au/anthony/info/graphics/xv_mods.hints) , which allows you to get XV to use a larger thumbnail size. I myself use 120x90 pixel thumbnails. * * * Further Processing -- Adding Fluff ---------------------------------- The above is only the beginning of what you can do 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, it adds unnecessary extras 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](../annotating/#labeling) . Just remember to use the "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `" or "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" rather than a "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" in those examples.For example... magick thumbnail.gif \\ -background Lavender -fill navy -font Candice -pointsize 24 \\ label:Hatching -gravity South -append \\ labeled.gif [![[IM Output]](labeled.gif)](labeled.gif) With the use of [Compound Fonts](../fonts/) you can overlay some very fancy labels onto the image itself. Here for example I used a [Denser Soft Outline Font](../fonts/#denser_soft_outline) technique to annotate the thumbnail, darkening the area around the text to ensure it always remains readable. magick -define jpeg:size=400x400 hatching\_orig.jpg -resize '120x200>' \\ \\( +clone -sample 1x1\\! -alpha transparent -sample 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 annotated.gif [![[IM Output]](annotated.gif)](annotated.gif) Note how I do not use the pre-generated "`thumbnail.gif`" image, or use the [Thumbnail Resize Operator](../resize/#thumbnail) to strip the profiles and comments from the image. I then used "`[+clone](https://imagemagick.org/script/command-line-options.php?#clone) `", "`[+sample](https://imagemagick.org/script/command-line-options.php?#sample) `", and "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) `", to generate a larger transparent working canvas, which also contains a copy of the original image's meta-data. This lets me use the images 'comment' string with the annotate "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operator, to supply the text to overlay on the image. Only at the end after I have composed the text overlay do I clean up and "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" that information. ### Raised Button The "`[-raise](https://imagemagick.org/script/command-line-options.php?#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. magick thumbnail.gif -raise 8 raised\_button.gif [![[IM Output]](raised_button.gif)](raised_button.gif) The same operator has a 'plus' form that can be used to make a sunken highlighting effect. magick thumbnail.gif +raise 8 sunken\_button.gif [![[IM Output]](sunken_button.gif)](sunken_button.gif) ### Bubble Button With some trickiness the "`[-raise](https://imagemagick.org/script/command-line-options.php?#raise) `" operator can be used to produce a smooth 'bubble-like' raised button. magick thumbnail.gif -fill gray50 -colorize 100% \\ -raise 8 -normalize -blur 0x8 bubble\_overlay.png magick thumbnail.gif bubble\_overlay.png \\ -compose hardlight -composite bubble\_button.png [![[IM Output]](thumbnail.gif)](thumbnail.gif) ![==>](../img_www/right.gif) [![[IM Output]](bubble_overlay.png)](bubble_overlay.png) ![==>](../img_www/right.gif) [![[IM Output]](bubble_button.png)](bubble_button.png) See [Light Composition Methods](../compose/#light) for more information about this type of technique. For more effects like this see [Self Framing (Internal)](#self_frame_inside) below, and to take it to the next level see [Lighting Effect Mask](#lighting_mask) below. ### Adding Borders The humble simple "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operator can be used to generate some a complex framework around an images. magick thumbnail.gif \\ -bordercolor black -border 3 -bordercolor white -border 2 \\ \\( -background black -fill white -pointsize 24 \\ label:Hatching -trim +repage \\ -bordercolor black -border 10 \\ \\) -gravity South -append \\ -bordercolor black -border 10 -gravity South -chop 0x10 \\ border\_framework.gif [![[IM Output]](border_framework.gif)](border_framework.gif) ### Simple Frame In a similar way the "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" operator makes it easy to add a frame around the image magick thumbnail.gif -mattecolor peru -frame 9x9+3+3 framed.gif [![[IM Output]](framed.gif)](framed.gif) 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](../crop/#frame) . ### Montage Framing 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 an user specified string.Here is a simple use of "`magick montage`" to generate a framed thumbnail. magick montage -define jpeg: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](../formats/#jpg_non-im) for more details.[![[IM Output]](montage_simple.gif)](montage_simple.gif) Even with just "`magick montage`" you can get really fancy with your thumbnail generation. magick montage -define jpeg: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]](montage_fancy.gif)](montage_fancy.gif) See the "[Montage, Arrays of Images](../montage/) " for more details. You may be especially interesting in the [Montage HTML Thumbnail Image Maps](../montage/#html) 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. ### Soft and Blurred Edges The [Vignette Operator](../transform/#vignette) provides a simple means to add a blurry edge around an image. magick thumbnail.gif -alpha set \\ -background none -vignette 0x4 vignette.png [![[IM Output]](vignette.png)](vignette.png) Of course as this thumbnail uses semi-transparent color so it needs to be saved in the PNG format. The [Morphology Distance](../morphology/#distance) method provides a true transparent 'Feathering' of an image's edges. magick thumbnail.gif -alpha set -virtual-pixel transparent -channel A \\ -morphology Distance Euclidean:1,10\\! +channel feathered.png [![[IM Output]](feathered.png)](feathered.png) The maximum distance of the transparent area is controled by the special `10\!`' distance scaling flag. This was only added in IM v6.6.1-6. This has the added advantage of also working for shaped images, though a more complex initialization is needed to correctly preserve and anti-aliased pixels in the distance formula. See [Feathering Shapes using Distance](../morphology/#distance_feather) for more details. The feathering here is a pure linear gradient, and can be further adjusted using [Sigmoidal Non-linearity Contrast Operator](../color_mods/#sigmoidal) to give it a smoother more tapered look in a number of different ways. You can also [Feather Images using Blur](../blur/#feathering) , using the same method of adding a transparent [Virtual Pixels](../misc/#virtual-pixel) before bluring just the alpha channel. This generates a more softer feathering to the image, as well as noticeably rounded the corners of the image. magick thumbnail.gif -alpha set -virtual-pixel transparent \\ -channel A -blur 0x8 -level 50%,100% +channel soft\_edge.png [![[IM Output]](soft_edge.png)](soft_edge.png) The extra "`[-level](https://imagemagick.org/script/command-line-options.php?#level) `" operation (adjusting only the transparency channel) ensures the edge becomes fully transparent, rather than only half transparent. However it does fall sharply toward zero at the actual edge, due to the sigmoidal-like curve that blur generates. It also has an additive effect in the corners, causing them to become rounded, while with a shaped image with a sharp concavity, it can cause fully-transparent pixels to become semi-transparent. As such for shapes you may need to mask the result against the original image (using [Dst-In Composition](../compose/#dstin) ). For rectangular thumbnails however the result is satisfactory.You can see another example of using this type of feathering in [Layered Thumbnails](../layers/#layer_thumbnails) . If instead of doing a level adjustment on the blurred feather, you can [Threshold](../quantize/#threshold) the blurred alpha channel at '`50%`', so as to add psuedo-rounded corners to the above thumbnail image. magick thumbnail.gif -alpha set -virtual-pixel transparent -channel A \\ -blur 0x8 -threshold 50% +channel rounded\_corner\_blur.gif [![[IM Output]](rounded_corner_blur.gif)](rounded_corner_blur.gif) 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. Second the result is not a smooth anti-aliased curve, but shows 'jaggies' caused by the aliasing effect of [Threshold Operation](../quantize/#threshold) . This image can however be save to a GIF file format. See [GIF Boolean Transparency](../formats/#boolean_trans) for details. Also note that the "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" operation can become very slow when you work with a large argument for generating a larger rounded corner. As such this method of rounding corners on a large scale is not recommended at all. For a more unusual blurred edge effect, you can use a [Radial Blur](../blur/#radial-blur) on just the alpha channel. magick thumbnail.gif -alpha set -virtual-pixel transparent \\ -channel A -radial-blur 0x45 +channel radial\_blur\_edge.png [![[IM Output]](radial_blur_edge.png)](radial_blur_edge.png) This works better for perfectly square images. As the amount of angled blur becomes larger, you will eventually generate a circular like Vignette edge. magick thumbnail.gif -alpha set -virtual-pixel transparent \\ -channel A -radial-blur 0x100 +channel radial\_blur\_vignette.png [![[IM Output]](radial_blur_vignette.png)](radial_blur_vignette.png) The two step-like artifacts that can be seen is caused by the two image size dimensions. No 'step' will be seen for a square image. Adding a little extra normal blur to the last example can also improve the step problem. ### Rounded and Shaped Corners While thresholding a [Soft Blurred Edge](#soft_edges) (see above) will generate a rounded corner suitable for the Boolean transparency of GIF, it does not generate a smooth 'anti-aliased' corner. The proper way to generate an image with rounded corners, or of any other shape is to actually cut out each corner using a mask of the shape wanted. The following method from Leif Åstrand that multiplys a full image mask to generate the appropriate result. magick thumbnail.gif \\ \\( +clone -alpha extract \\ -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 \\ \\) -alpha off -compose CopyOpacity -composite rounded\_corners.png [![[IM Output]](rounded_corners.png)](rounded_corners.png) Basically extracts the white transparency 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 total amount of processing needed. That is more individual processing steps, but overall less processing of the actual pixels. For example, here is the same thing but cutting a simple drawn triangular shape from each corner. This will work with much larger images. magick thumbnail.gif -alpha set -compose DstOut \\ \\( -size 20x15 xc:none -draw "polygon 0,0 0,14 19,0" \\ -write mpr:triangle +delete \\) \\ \\( mpr:triangle \\) -gravity northwest -composite \\ \\( mpr:triangle -flip \\) -gravity southwest -composite \\ \\( mpr:triangle -flop \\) -gravity northeast -composite \\ \\( mpr:triangle -rotate 180 \\) -gravity southeast -composite \\ corner\_cutoff.png [![[IM Output]](corner_cutoff.png)](corner_cutoff.png) If you don't want transparency, but some other color, you can still do the above and then [Remove Transparency](../masking/#remove) . This can be important for JPEG images. However an even simpler solution (in terms of complexity and memory usage) has been found in a [IM forum discussion](https://magick.imagemagick.org/viewtopic.php?t=17626) . This overlays colored corners ('`Red`' in this case) rather than making them transparent. magick thumbnail.gif \\ \\( +clone -crop 16x16+0+0 -fill white -colorize 100% \\ -draw 'fill black circle 15,15 15,0' \\ -background Red -alpha shape \\ \\( +clone -flip \\) \\( +clone -flop \\) \\( +clone -flip \\) \\ \\) -flatten rounded\_corners\_red.png [![[IM Output]](rounded_corners_red.png)](rounded_corners_red.png) Unfortunately this method can not be used to simply 'erase' the image corners to transparency, due to an interaction with a 'background canvas' of the [Flatten Operation](../layers/#flatten) , a future layering operator may solve this. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The last example will fail for versions of IM before v6.6.6-5 due to both the "`[-flip](https://imagemagick.org/script/command-line-options.php?#flip) `" and the "`[-flop](https://imagemagick.org/script/command-line-options.php?#flop) `" operators not handling the virtual canvas offset correctly._ | Using a [Polar Cycle Trick](../distorts/#polar_tricks) we can generate a perfect anti-aliased circle mask for any sized thumbnail. Of course we will only use the distorted image as a mask for the original image, so as to get the best result. magick thumbnail.gif -alpha set \\ \\( +clone -distort DePolar 0 \\ -virtual-pixel HorizontalTile -background None -distort Polar 0 \\) \\ -compose Dst\_In -composite -trim +repage circle\_masked.png [![[IM Output]](circle_masked.png)](circle_masked.png) We will take this style of image processing further in [Border with Rounded Corners](#rounded_border) below. There we not only cutting out corners, but also overlay appropriate framing images. ### Torn Paper Edge Leif Åstrand , contributed the following IM code to generate an edge that looks like it was torn from a fibrous paper (like newspaper)... magick thumbnail.gif \ \( +clone -alpha extract -virtual-pixel black \ -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \ -alpha off -compose Copy_Opacity -composite torn_paper.png [![[IM Output]](torn_paper.png)](torn_paper.png) One improvement may be to make it look like you ripped it from a newspaper corner. magick thumbnail.gif -bordercolor linen -border 8x8 \ -background Linen -gravity SouthEast -splice 10x10+0+0 \ \( +clone -alpha extract -virtual-pixel black \ -spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \ -alpha off -compose Copy_Opacity -composite \ -gravity SouthEast -chop 10x10 torn_paper_corner.png [![[IM Output]](torn_paper_corner.png)](torn_paper_corner.png) 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](https://imagemagick.org/script/command-line-options.php?#shadow) `" operator makes the [Generation of Shadows](../blur/#shadow) of any shaped image easy. For example, here an I add a semi-transparent colored shadow, to the thumbnail. magick thumbnail.gif -alpha set \\ \\( +clone -background navy -shadow 60x0+4+4 \\) +swap \\ -background none -mosaic shadow\_hard.gif [![[IM Output]](shadow_hard.gif)](shadow_hard.gif) But you can just as easily create soft fuzzy shadows, too. magick -page +4+4 thumbnail.gif -alpha set \\ \\( +clone -background navy -shadow 60x4+4+4 \\) +swap \\ -background none -mosaic shadow\_soft.png [![[IM Output]](shadow_soft.png)](shadow_soft.png) 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](https://imagemagick.org/script/command-line-options.php?#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. Warning, while the above works for individual thumbnails, it will generally fail when you want to layer multiple thumbnails over the top of each other. The reason is that shadows do not accumulate together, in the same way that normal images do. To see how to handle shadows from multiple layered images see [Layers of Shadows](../layers/#layer_shadow) . ### Adding Some Thickness Adding a thickness to an image or a shape look a bit like adding 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. magick thumbnail.gif -alpha set \\ \\( +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]](thickness.gif)](thickness.gif) 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. ### 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. magick 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]](poloroid.png)](poloroid.png) A more complex version of the above was added to IM v6.3.1-6 as a "`[-polaroid](https://imagemagick.org/script/command-line-options.php?#polaroid) `" transformation operator. For example... magick thumbnail.gif -bordercolor snow -background black +polaroid \ poloroid_operator.png [![[IM Output]](poloroid_operator.png)](poloroid_operator.png) 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](https://imagemagick.org/script/command-line-options.php?#caption) `", set your own shadow color, specify your own rotation (or none at all). magick -caption '%c' hatching\_orig.jpg -thumbnail '120x120>' \\ -font Ravie -gravity center -bordercolor Lavender \\ -background navy -polaroid -0 poloroid\_caption.png [![[IM Output]](poloroid_caption.png)](poloroid_caption.png) For more information on using this operator see [Complex Polaroid Transformation](../transform/#polaroid) . 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. magick thumbnail.gif \ -bordercolor white -border 6 \ -bordercolor grey60 -border 1 \ -bordercolor none -background none \ \( -clone 0 -rotate `magick null: -format '%[fx:rand()*30-15]' info:` \) \ \( -clone 0 -rotate `magick null: -format '%[fx:rand()*30-15]' info:` \) \ \( -clone 0 -rotate `magick null: -format '%[fx:rand()*30-15]' info:` \) \ \( -clone 0 -rotate `magick null: -format '%[fx:rand()*30-15]' info:` \) \ -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]](poloroid_stack.png)](poloroid_stack.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The " `` `magick ...` `` " embedded command in the above example generates a random floating point number from -15 to +15. For more infomation on using IM as a mathematical calculator see [FX Expressions](../transform/#fx_escapes)
. An alturnative is to assign random numbers to shell variables and substitute them into the above command instead._ | 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. magick 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]](poloroid.gif)](poloroid.gif) For details about this technique (and more) see [GIF images on a solid color background](../formats/#bgnd) . The above 'stacked polaroid' technique graciously provided by Ally of [Ally's Trip](http://www.allystrip.com/) and Stefan Nagtegaal for [Muziekvereniging Sempre Crescendo](http://sempre-crescendo.nl/) , both of which use Polaroid-like thumbnails extensively on their web sites. In the [IM User Forum](https://magick.imagemagick.org/viewtopic.php?t=7530) , the user _[grazzman](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=7473) _ went a little further by overlaying images onto a rotating canvas to create a photo spread. magick -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]](poloroid_spread.gif)](poloroid_spread.gif) 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. * The framing has been hardcoded into the above, and depends on the size of the thumbnail image. In a real application the framing may be moved to the thumbnail generation stage rather than in the above photo spread. * As "`[-rotate](https://imagemagick.org/script/command-line-options.php?#rotate) `" also expands the size of the canvas the position in which images are added is changing, unless you place them using an offset from "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) center`" position. * And finally, a constantly rotating the background frame is not a good idea in terms of quality. Rotating an already rotated image, adds more pixel level distortions to the result than doing one rotate for each separate image before being overlaid. A similar randomized stacking of photos over a larger area was developed for [Stas Bekman's Photography](http://stason.org/photos/gallery/) , 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](../layers/#layer_examples) , as well as in [Overlapping Photos](../photos/#overlap) . * * * 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. ### Self Framing (External) **Self Framing** is a technique that can be used to frame an image, using the image itself to generate the framing colors and patterns. That is, to say the added frame is not fixed, but varies so as to roughly match the image being framed. You can do this in two ways. Extend the original image so as to create, an _External Frame_, or use part of the actual image itself to create an _Internal 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. magick 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]](self_bordered.gif)](self_bordered.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Instead of using [Level Adjustments](../color_mods/#level_plus)
to brighten (or darken) the framing image, an alturnative way of making the border a lighter or darker color is to [Color Tint](../color_mods/#colorize)
the frame using something like...
"`-fill white -colorize 30%`"_ | Another way of color tinting the image to generate the frame, you can simply get IM to overlay a semi-transparent [Frame](../crop/#frame) on top of the enlarged image. However this requires you to know the size of the thumbnail so as to exactly resize it exactly the right amount to accommodate the generated frame. magick 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]](self_framed.gif)](self_framed.gif) A variation of the above uses the special [viewport](../distorts/#distort_viewport) control and the default [Virtual Pixel, Edge](../misc/#edge) setting to extend the edge of a blurred image to generate the extenal frame. magick thumbnail.gif \\( +clone \\ -set option:distort:viewport 150x120-15-15 \\ -virtual-pixel Edge -distort SRT 0 +repage \\ -blur 0x3 +level 20%,100% \\) \\ \\( -clone 0 -bordercolor white -border 1 \\) \\ -delete 0 -gravity center -compose over -composite \\ self\_blurred\_edge.gif [![[IM Output]](self_blurred_edge.gif)](self_blurred_edge.gif) Just a word of warning. A small edge defect (such as a tree or leaf) can produce some undesirable results in a frame that was generated using only the edge of the image. The viewport does need to know the size of the original image to enlarge and offset that viewport the appropriate amount. However you can use [FX Escape Expressions](../transform/#fx_escapes) to calculate the viewport size (see examples below). An alternative is to use a blurred [Virtual Pixel, Dither](../misc/#dither) in the above example. This will spread the colors further and be not quite so 'edgy'. But if you add blurs before and after the expansion you use the dither to produce a cloth-like effect. magick thumbnail.gif \\( +clone -blur 0x3 \\ -set option:distort:viewport '%\[fx:w+30\]x%\[fx:h+30\]-15-15' \\ -virtual-pixel Dither -distort SRT 0 +repage \\ -blur 0x0.8 +level 20%,100% \\) \\ \\( -clone 0 -bordercolor white -border 1 \\) \\ -delete 0 -gravity center -compose over -composite \\ self\_blurred\_dither.gif [![[IM Output]](self_blurred_dither.gif)](self_blurred_dither.gif) The first blur modulates the average color, while the second adjusts how 'pixelated' or smooth the dither pattern is. Here is another example, this time using [Virtual Pixel, Mirror](../misc/#mirror) , with a [Soft Edge](#soft_edges) (blackened) which turned out to work very well for this specific image. magick thumbnail.gif \\( +clone \\ -set option:distort:viewport '%\[fx:w+30\]x%\[fx:h+30\]-15-15' \\ -virtual-pixel Mirror -distort SRT 0 +repage \\ -alpha set -virtual-pixel transparent \\ -channel A -blur 0x8 +channel \\ -background Black -flatten \\) \\ +swap -gravity center -compose over -composite \\ self\_mirror.gif [![[IM Output]](self_mirror.gif)](self_mirror.gif) In all the above 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 and matches each thumbnail image that is framed. Fred Weinhaus has created a script "`[imageborder](http://www.fmwconcepts.com/imagemagick/imageborder/) `" to make self framing images easier, with borders being generated from blurred magnifications of the original image, or some form of [Virtual Pixel](../misc/#virtual-pixel) setting defining the contents. ### Self Framing (Internal) Rather than enlarging the image to add the new border, we can magick parts of the image itself into a border. We have already seen some techniques of adding a frame, inside the image itself. The [Raised Button](#button) and [Bubble Button](#bubble) techniques do this, using the "`[-raise](https://imagemagick.org/script/command-line-options.php?#raise) `" operator. Here we generate a lighter blurred version of the original image which is then overlaid using a mask also generated from the original image. A white edge is then added to separate that lighter blured version from the center un-modified part of the image. magick 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]](self_blurred_border.gif)](self_blurred_border.gif) You can also use the [Frame Operator](../crop/#frame) to achieve something a little different to the previously seen [Button](#button) effects. The trick is to first [Shave](../crop/#shave) the original image before applying. For example, here I make a copy of the original image, shave and frame it using transparent frame, before overlaying that over the original image. magick thumbnail.gif \\( +clone -shave 10x10 \\ -alpha set -mattecolor '#AAA6' -frame 10x10+3+4 \\ \\) -composite inside\_frame\_trans.gif [![[IM Output]](inside_frame_trans.gif)](inside_frame_trans.gif) The problem with this is that you will always 'lighten' or 'darken' (de-contrast) the flat parts of frame around the original image. To avoid this we can use the same technique as the [Bubble Button](#bubble) technqiue. We generate a frame on a perfect grey canvas, and modiy it so as to generate a [Lighting Effects Composition Mask](../compose/#light) , to adjust the colors of the original image. For example, here I use a '`[VividLight](../compose/#vividlight) `' composition with the framed mask image to better preserve primary colors. magick thumbnail.gif \\ \\( +clone -shave 10x10 -fill gray50 -colorize 100% \\ -mattecolor gray50 -frame 10x10+3+4 \\ \\) -compose VividLight -composite inside\_frame\_light.gif [![[IM Output]](inside_frame_light.gif)](inside_frame_light.gif) Like the [Bubble Button](#bubble) you can also blur the lighting mask before applying. Here I used more normal '`[HardLight](../compose/#hardlight) `' compose which does not enhance primary colors, with a blurred frame lighting mask. magick thumbnail.gif \\ \\( +clone -shave 10x10 -fill gray50 -colorize 100% \\ -mattecolor gray50 -frame 10x10+3+4 -blur 0x2 \\ \\) -compose HardLight -composite inside\_frame\_blur.gif [![[IM Output]](inside_frame_blur.gif)](inside_frame_blur.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Some [Light Composition Methods](../compose/#light)
may require you to [Swap the Images](../basics/#swap)
before you compose them to get the correct lighting effect._ | To take this type of effect even further, producing much more complex results see the advanced [Lighting Effect Mask](#lighting_mask) . ### 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. magick -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]](border_heart.png)](border_heart.png) For other ways of generating an edge on an existing shaped image see the [Edge Transform](../transform/#edge) .You can also optionally give the frame a little depth by using a [Shadow Effect](../blur/#shadow) . magick border\_heart.png \\( +clone -background black -shadow 60x3+3+3 \\) \\ -background none -compose DstOver -flatten border\_overlay.png [![[IM Output]](border_overlay.png)](border_overlay.png) Now that we have a simple overlay frame, we can underlay the image in the center, underneath the frame by using a '`[DstOver](../compose/dstover) `' composition. magick border\_overlay.png thumbnail.gif \\ -gravity center -compose DstOver -composite border\_overlaid.jpg [![[IM Output]](border_overlaid.jpg)](border_overlaid.jpg) Now you can generate a library of pre-prepared frames to use with your images, such as this [Autumn Leaves Image](../images/autumn_leaves.png) . magick thumbnail.gif autumn\_leaves.png +swap \\ -gravity center -compose DstOver -composite \\ border\_leaves.gif [![[IM Text]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Text]](../images/autumn_leaves.png)](../images/autumn_leaves.png) ![==>](../img_www/right.gif) [![[IM Text]](border_leaves.gif)](border_leaves.gif) Note that I swapped the order of the images and used '`[DstOver](../compose/#dstover) `' to place the second, main image 'under' the frame. That way it is the frame that determines the final size of the image, and not the original image. However doing this would also loose any meta-data the main image has (for the same reason). If you really want to preserve the thumbnails meta-data (such as labels and comments, such as a copyright message), then the best idea is to [Pad Out the Thumbnail](#pad) to the same size as the frame, than this use the default '`[Over](../compose/#over) `' composition to overlay the frame. That way the thumbnail is the 'destination' image and its image meta-data is preserved. ### Badge Overlay Example Here is another more complex pre-prepared overlay example this time using a correctly sized image (using extent as a crop method), from the IM Forum Discussion [Composite Overlay and Masking](https://magick.imagemagick.org/viewtopic.php?f=1&t=19116) . magick thumbnail.gif -gravity center -extent 90x90 \\ badge\_overlay.png -composite badge.png [![[IM Text]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Text]](../images/badge_overlay.png)](../images/badge_overlay.png) ![==>](../img_www/right.gif) [![[IM Text]](badge.png)](badge.png) Note that the image itself is not distorted, just lightened and darkened slightly, a circle cut out and shadow added, all in the one overlay image. If this was a real badge, or 'glass bubble' then the image should also be distorted a little too (perhaps using a [Barrel Distortion](../distorts/#barrel) ), but it works well without needing such distortion. For the next step in the 'badge' example, see [Badge using Mask and Paint](#badge_mask_paint) , which adds background transparency around the outside of the badge. ### Mask 'n' Paint 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, to transparency. For this you would typically use 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. The two images can be applied in two different ways. You can either 'mask' first to remove the unwanted parts from the image, then overlay the frame, _or_ you can overlay a frame, and then mask the unwanted parts of both the original image and overlaid colors to transparency. Which method you use is critical, and the images involved will be designed for a specific technique. You can not use images for one method in the wrong order or things will not work properly. For example lets create more complex shaped border but this time don't worry about setting the background. magick -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]](border_ellipse.png)](border_ellipse.png) 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, so as to preserve and set them correctly.To make it more interesting give this 'fuzzy' border a random bit of coloring. magick border_ellipse.png \ \( -size 120x100 plasma:Tomato-FireBrick -alpha set -blur 0x1 \) \ -compose SrcIn -composite border_ellipse_red.png [![[IM Output]](border_ellipse_red.png)](border_ellipse_red.png) 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. magick -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]](border_ellipse_mask.png)](border_ellipse_mask.png) The color of this 'mask' image is not important, just its shape, as it basically defined what parts will be classed as inside and what will be outside. The mask can be a gray-scale mask, or it can be a shape mask such as shown above. Though the later is typically more useful, and can even be a shape of the parts to erase, or the parts to be kept (as above). In this case the images are designed as a "_mask 'n' paint_" technique, meaning you should first erase the unwanted parts, then overlay the additional border colors (which also has a transparency mask involved). For example... magick thumbnail.gif -alpha set -gravity center -extent 120x100 \\ border\_ellipse\_mask.png -compose DstIn -composite \\ border\_ellipse\_red.png -compose Over -composite \\ border\_mask\_paint.png [![[IM Output]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](border_ellipse_mask.png)](border_ellipse_mask.png) ![ + ](../img_www/plus.gif) [![[IM Output]](border_ellipse_red.png)](border_ellipse_red.png) ![==>](../img_www/right.gif) [![[IM Output]](border_mask_paint.png)](border_mask_paint.png) Two [Duff-Porter Alpha Composition Operations](../compose/#duff-porter) are always is needed. One to make parts transparent, and another to overlay the additional colors to outline the border or frame. Two images are needed and as such be kept separate. Some formats like MIFF and GIF do allow you to save both images into the same file, for easier storage. Of course you can combine the two images to create a single simple overlay framing image, but only if you want to use a fixed non-transparency color for the outside parts of the result. For example pre-define the outside as a DodgerBlue color... magick border\_ellipse\_mask.png -alpha extract -negate \\ -background DodgerBlue -alpha shape \\ border\_ellipse\_red.png -compose Over -composite \\ border\_ellipse\_overlay.png [![[IM Output]](border_ellipse_overlay.png)](border_ellipse_overlay.png) But in that case you could simply underlay a solid color or some other background image under the previously generated double masked image... magick border_double_masked.png \ \( -size 120x100 plasma:Green-Green -blur 0x1 \) \ +swap -compose Over -composite border_background.png [![[IM Output]](border_background.png)](border_background.png) The point is with two images, a 'mask' and 'overlay' image, you have a lot more freedom in how you add the border to the image. You could even define multiple 'mask' images, to define the different 'windows' of the 'overlaid' border image. You can also add optional highlights and shadows, rather than hard coding them into a single overlay framing image. Now for an important caveat. The edges of the masking image **must not** coincide with the edges of the overlay image. If they match up, you will not get the correct handling of colors along the coinciding edges, or generate other weird 'halo' effects. As such you need to make sure the mask edges fall somewhere within the fully-opaque region of the overlay image. Caution and fore-thought with the two masking operations is needed. ### Border with Rounded Corners As you saw above the [Mask 'n' Paint Technique](#mask_paint) 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](https://imagemagick.org/script/command-line-options.php?#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 coordinates at which to locate the rectangle is for the exact 'center' of the stroke-width used to define the rectangle (it can be a floating point value). Also it is given in terms of 'pixel coordinates' (see [Pixel vs Image coordinates](../distorts/#control_coordinates) ), which means that a value of 1,1 refers to the second pixel form the top and left edges, but more importantly it refers to the 'center' of the pixel which is in reality 1.5 units from the real top and left edges. Now we will use a stoke width (SW) of 3, that makes the image 3 pixels larger on all sides. It then means the rectangle will be positioned `SW/2 - 0.5` or 1.0 pixels from the top left, and `ImageSize + SW*1.5 - 0.5` or Image size + 4 pixels at the bottom right. Here we use IM itself to do these calculations, generating the exact draw command that are need using fancy [FX escapes](../transform/#fx_escapes) . This is saved as a [Magick Vector Graphics File](../draw/#mvg_file) that can be directly used by draw in later commands. magick thumbnail.gif \ -format 'roundrectangle 1,1 %[fx:w+4],%[fx:h+4] 15,15'\ info: > rounded_corner.mvg [![[IM Text]](rounded_corner.mvg.gif)](rounded_corner.mvg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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](../canvas/#transparent) using the original image (which is first enlarged by the stroke-width), to get the size right. magick thumbnail.gif -border 3 -alpha transparent \\ -background none -fill white -stroke none -strokewidth 0 \\ -draw "@rounded\_corner.mvg" rounded\_corner\_mask.png magick thumbnail.gif -border 3 -alpha transparent \\ -background none -fill none -stroke black -strokewidth 3 \\ -draw "@rounded\_corner.mvg" rounded\_corner\_overlay.png [![[IM Text]](rounded_corner_mask.png)](rounded_corner_mask.png) [![[IM Text]](rounded_corner_overlay.png)](rounded_corner_overlay.png) And there we have the overlay border image, and transparency mask image, we need for the double masking technique. Note that the masks are for an image that is stroke width larger than the original image, and that the erasing shape mask (in white) does not cover the whole of the enlarged area, as there is a 1 pixel gap all around it.So lets apply it using the [Double Masking](#double) technique... magick thumbnail.gif -alpha set -bordercolor none -border 3 \\ rounded\_corner\_mask.png -compose DstIn -composite \\ rounded\_corner\_overlay.png -compose Over -composite \\ rounded\_border.png [![[IM Output]](rounded_border.png)](rounded_border.png) 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. magick thumbnail.gif \\ -format 'roundrectangle 1,1 %\[fx:w+4\],%\[fx:h+4\] 15,15' \\ -write info:tmp.mvg \\ -alpha set -bordercolor none -border 3 \\ \\( +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]](rounded_border_in_one.png)](rounded_border_in_one.png) 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 below in [Fancy Corner Overlays](#fancy) . In many ways this is an extension of the above method, but using separate masking for each corner of the image, so as to keep the working images small in size. ### Badge using Mask 'n' Paint Here is a much more complex "mask 'n' paint" example, that was developed from the image used previously in the [Badge Overlay](#badge_overlay) example above. The generation of the two images was 'fudged', and was discussed IM forums [Composite Overlay and Masking](https://magick.imagemagick.org/viewtopic.php?f=1&t=19116) . Idealy the two images would have been developed together. magick thumbnail.gif -alpha set -gravity center -extent 90x90 \\ badge\_mask.png -compose DstIn -composite \\ badge\_shading.png -compose Over -composite \\ badge\_trans\_bg.png [![[IM Text]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Text]](../images/badge_mask.png)](../images/badge_mask.png) ![ + ](../img_www/plus.gif) [![[IM Text]](../images/badge_shading.png)](../images/badge_shading.png) ![==>](../img_www/right.gif) [![[IM Text]](badge_trans_bg.png)](badge_trans_bg.png) Note that above I said that the you should avoid trying to align transparency edges and the mask edges. In the above example I did just that, and the edges of the resulting image will not be quite correct. However as the coloring is really only a subtile shading rather that a strong edge, it seems to work okay in this example. Caution however should be exercised. For the next step in the 'badge' examples, see [Badge using Paint and Mask](#badge_paint_mask) , which reverses the order of the two composition operations, requiring a different set of images. ### Paint 'n' Mask Technique Rather than '_Mask then Paint_' you can use a different set of images and overlay the additional colors first, before masking out the background. That is, you can perform a '_Paint then Mask_'. That is, you would take your image, and overlay the border which sets not only all of the final border colors, but also masks and colors some or all the parts outside parts the original image. You then use a separate 'outside' or 'clipping' mask to remove all the unwanted parts of the resulting image. Also note that both 'overlay' and 'masking' image defines the inside edge separately to the outside edge of the border. As a result one image does not completely define the whole border in a single image, which can make it a little harder to use. However it can be simpler to implement. For example... magick -size 120x90 xc:none -fill black -stroke black -strokewidth 0 \\ -draw 'ellipse 45,45 55,37 0,360' \\ -channel RGBA -negate -blur 0x3 +channel \\ \\( granite: -auto-level -blur 0,0.7 \\) \\ -compose ATop -composite border\_paint.png magick -size 120x90 xc:none -fill black -stroke black -strokewidth 5 \\ -draw 'ellipse 59,45 56,40 0,360' border\_mask.png magick thumbnail.gif -alpha set \\ border\_paint.png -compose Over -composite \\ border\_mask.png -compose DstIn -composite \\ border\_paint\_mask.png [![[IM Output]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Output]](border_paint.png)](border_paint.png) ![ + ](../img_www/plus.gif) [![[IM Output]](border_mask.png)](border_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](border_paint_mask.png)](border_paint_mask.png) Note how some parts of the overlaid colors are removed. This is the key feature of the _Paint 'n' Mask_ technique, allowing you to use a simpler overlay, which is then adjusted by the mask. This method of image masking is what is used in the next [Page Curl Corners](#pagecurl) example set, and again later in [Fancy Corner Borders](#fancy) below. ### Page Curl Corners [Fred Weinhaus](http://www.fmwconcepts.com/fmw/fmw.html) created a special shell script called [PageCurl](http://www.fmwconcepts.com/imagemagick/pagecurl/index.php) which will, add a simple page curl to an existing image, using some very complex mathematics (in shell). For example... pagecurl thumbnail.gif pagecurl.png [![[IM Output]](pagecurl.png)](pagecurl.png) Internally it is actually using the [Paint 'n' Mask](#paint_mask) technique. That is, first overlays a slightly too large 'curl overlay', then erases (masks) the rest of the image, including a small amount of the overlay, that will become the transparent corner. However if you want to apply a page curl to a lot of images, using the full script (above) is a rather slow technique. It does after all do a huge amount of mathematical processing (using IM itself as a floating point calculator), to actually calculate and generate the appropriate overlay and masking images. To apply a pagecurl to a lot of images it is better to use the script once so as to generate the overlay and transparency mask image once only. So lets extract those two images for a smaller 64x64 pixel images (using a special '`-i "pagecurl"` option added to the script for this purpose). magick -size 64x64 xc: miff:- | pagecurl -e 0.3 -i "pagecurl" - null: [![[IM Output]](pagecurl_overlay.png)](pagecurl_overlay.png) [![[IM Output]](pagecurl_mask.png)](pagecurl_mask.png) The above command creates two image files: "`pagecurl_overlay.png`" and "`pagecurl_mask.png`" shown. The input image itself does not matter as it is the masking images that we want. The 'page curled' result is just junked using the special "`[null:](../files/#null) `" image file format. magick thumbnail.gif -alpha set -gravity SouthEast \ -define compose:outside-overlay=false \ pagecurl_overlay.png -composite \ pagecurl_mask.png -compose DstIn -composite \ pagecurl_thumbnail.png [![[IM Output]](pagecurl_thumbnail.png)](pagecurl_thumbnail.png) Of course these images are not the same size as our thumbnail or probably any image you are wanting to apply it to, but that does not matter, as we can use a couple of extra options to ensure they work as expected. Specifically, the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting ensures that the two overlay images are positioned in the lower right corner. And the special [Define Setting](../basics/#define) '`compose:outside-overlay=false`' will prevent the mask image from erasing the parts of the image not covered by the smaller image. See [Outside-Overlay Setting](../compose/#outside-overlay) for a full description. If you like to apply this to a lot of images you can use the "`magick mogrify`", using a special technique involving using "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to do the [Mogrify Alpha Composition](../basics/#mogrify_compose) . However this method of composition does not understand the special define setting, so it will only work with images, overlays, and masks that are all the same size. pagecurl -e 0.5 -i /tmp/pagecurl {_one image_} null: magick mogrify {_magick mogrify -format and -path options_} -alpha set \\ -draw 'image Over 0,0 0,0 "/tmp/pagecurl\_overlay.png"' \\ -draw 'image DstIn 0,0 0,0 "/tmp/pagecurl\_mask.png"' \\ {_all images to be pagecurled_}... ### Fancy Corner Overlay Here we look a bit deeper into used this 'double masking' technique to modify an image in different ways in different areas, rather than applying a single large mask or frame to the whole image. In this case we will only double mask the corners. The rest of the border (to match) is added separatally. [![[IM Output]](../images/fancy_orig.gif)](../images/fancy_orig.gif) The corner images I will use was generated from the original source (shown right) which I found in the [DIY Frames Section](http://www.ict.griffith.edu.au/anthony/icons/prog/frames/Icons.html) of [Anthony's Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) . 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]](../images/fancy_sub.gif)](../images/fancy_sub.gif) [![[IM Output]](../images/fancy_add.gif)](../images/fancy_add.gif) A color overlay and masking image was generated, from that initial image, so that we could use a [Paint 'n' Mask](#paint_mask) technique, for overlaying the corner onto the image. Notice that these images, did not actually use any semi-transparent pixels, or even any shading of colors. As such this fancy border can be used to produce clean looking 'GIF' thumbnails for web pages. 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 extra border colors. After that the two corner masks, must be composted onto each of the corners of the expanded image. magick thumbnail.gif -alpha set -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]](fancy_border.gif)](fancy_border.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that to preserve the transparent border that is being added, you must set "`[-compose](https://imagemagick.org/script/command-line-options.php?#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'. See the [Border Operator](../crop/#border)
for details._ | The beauty of only using corner masks is that any size image can be framed using this technique, as long as it is large enough for the corner masks being added. That is, you are not limited by the size of the framing images you have available. Of course each of the four corner images and the borders is the same all the way around the image, just rotated. That is, the shadow or thickness effect is all 'inward'. To fix this you would need to generate a different corner peice for each and every corner, and the addition of the extra edges around the original image would need to be asymetrical. Basically it becomes much more complex, so as to produce true shadowing effects. A better solution may be to remove the shadow effect from the corner piece, apply it as before, but then add shadow effects globally. Caution is needed. ### Badge using Paint 'n' Mask The same badge image processing seen previously in [Badge Overlay](#badge_overlay) and [Badge Mask 'n' Paint](#badge_mask_paint) , can also be performed by painting then masking. Here we first paint all the colors an shades onto the then mask out the final transparency of the image. magick thumbnail.gif -alpha set -gravity center -extent 90x90 \\ badge\_paint.png -composite badge\_shape.png -compose DstIn -composite \\ badge\_paint\_mask.png [![[IM Text]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Text]](badge_paint.png)](badge_paint.png) ![ + ](../img_www/plus.gif) [![[IM Text]](badge_shape.png)](badge_shape.png) ![==>](../img_www/right.gif) [![[IM Text]](badge_paint_mask.png)](badge_paint_mask.png) If this seems awkward for this specific image, you are right, it is. The reason that that we not only need to shade and highlight the original image, but we also need to fill out any areas that will contain shadow effects with black. Specifically any parts that will become fully transparent (and only pixels that really are fully transparent) will need to be painted with black. On the other hand semi-transparent pixels with shadow effects will have both a partial shade effect and a partial transparency mask. In other words shadows make an otherwise simple paint and mask technique awkward in the division of painting and masking effects. This is why a paint and mask technique is typically not used when dealing with semi-transparent additions to an image, such as when adding shadows or a flare stars. If the image did not contain any transparency-effects, than the paint process does not look so horrible, and can in many case be simplier than other techniques, as you can 'cut off' the painted overalys with the mask when finished. The [Page Curl](#pagecurl) example was such a case, as we use the mask to trim the page curl overlay to make a seemless whole.Also note the gap between the hard black region and the shading effects in the paint image. This gap reflects warning I have mentioned before about ensuring that you do not overlap the results of any internal masking with the edges of any paint/overlay external mask. It is only in this specific case that this required gap becomes so obvious. For the next step in the 'badge' examples, see [Badge using Lighting Effects](#badge_lighting) , which merges the two masking images into a single mask/shading image. Lighting Mask Technique ----------------------- ### Glass Bubble Button The next level of complexity in thumbnail processing is the application of very complex lighting effects. The trickiness here is not so much the application of a lighting effect to an image, but the generation of the appropriate shading effect. For example using a [Aqua Effect](../advanced/#aqua_effects) you can give an thumbnail a very complex shading effect that makes it look like it has been enclosed by a 'bubble' of glass. Also this works better with a thumbnail that has [Rounded Corners](#rounded) . For lets generate a rounded corners mask for our thumbnail image, using a pure gray color. magick thumbnail.gif -alpha off -fill white -colorize 100% \ -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 \ -background Gray50 -alpha Shape thumbnail_mask.png [![[IM Output]](thumbnail_mask.png)](thumbnail_mask.png) Now that we have a pure gray 'shape mask' we want to use, I can apply the [Aqua Effect](../advanced/#aqua_effects) effect to generate a lighting overlay, for this shape. magick thumbnail_mask.png -bordercolor None -border 1x1 \ -alpha Extract -blur 0x10 -shade 130x30 -alpha On \ -background gray50 -alpha background -auto-level \ -function polynomial 3.5,-5.05,2.05,0.3 \ \( +clone -alpha extract -blur 0x2 \) \ -channel RGB -compose multiply -composite \ +channel +compose -chop 1x1 \ thumbnail_lighting.png [![[IM Output]](thumbnail_lighting.png)](thumbnail_lighting.png) With a final light/shade overlay image such as the above we can easily apply it to any thumbnail image of the right size. magick thumbnail.gif -alpha Set thumbnail_lighting.png \ \( -clone 0,1 -alpha Opaque -compose Hardlight -composite \) \ -delete 0 -compose In -composite \ glass_bubble.png [![[IM Output]](glass_bubble.png)](glass_bubble.png) Not only does this add the appropriate shading effects to any thumbnail of this size, but the same lighting image masks the thumbnail into the proper shape. It is important to note that only the color channels are used to apply the lighting effect, the alpha channel is not used in this process. Similarly when masking only the alpha channel is used, not the color channels. Without this seperation of channels for different effects, you will not get the correct result. For a discussion on extracting a lighting effect from images see the IM user forum topic [Extracting light layer from two images](https://magick.imagemagick.org/viewtopic.php?f=1&t=19337) . This can be taken much further however in that we can also directly add shadow effects to this lighting mask. The added color however must be pure black, and you need to ensure the lighting effect composition chosen will make an image perfectly black is the lighting mask is black. However this is actually how shadow effects are normally added to an image, as such you can just add shadows to the "lighting effect mask" directly, and all will be well! The same thing is true for adding lighting 'flares', but only using white pixels for the flare overlay. In essence a "lighting effect image" can again actually merge the two [Mask 'n' Paint](#mask_paint) images back into a single image. As you will see in the next example. ### Badge using Lighting Effects Using the images from [Badge using Mask 'n' Paint](#badge_mask_paint) technique, I applied them to a pure gray canvas image, so as to quickly generate a "masked lighting effect" image, Actually I could also have used the other style of masking ([Badge using Paint 'n' Mask](#badge_paint_mask) ) just as easily. I then apply the single masking image to the thumbnail reproducing the desired result. # merge "mask 'n' paint" images with a gray image, # to create a "lighting mask" magick -size 90x90 xc:gray50 -alpha set \\ badge\_mask.png -compose DstIn -composite \\ badge\_shading.png -compose Over -composite \\ badge\_lighting.png # Apply the single "lighting mask" magick thumbnail.gif -alpha set -gravity center -extent 90x90 \\ badge\_lighting.png \\ \\( -clone 0,1 -alpha Opaque -compose Hardlight -composite \\) \\ -delete 0 -compose In -composite \\ badge\_final.png [![[IM Text]](thumbnail.gif)](thumbnail.gif) ![ + ](../img_www/plus.gif) [![[IM Text]](badge_lighting.png)](badge_lighting.png) ![==>](../img_www/right.gif) [![[IM Text]](badge_final.png)](badge_final.png) Actually I rather like this form of masking as the mask image itself looks almost identical to the image you are after, just the colors are missing. That is, after all how a lighting mask is created, just apply the effects to a perfect gray image, and you get a "lighting mask" image. Just remember that with this particular technique, the semi-transparent shadow must be pure black for it to work properly. You can not use a gray colored for any pixel that does not contain at least part of the original image. All transparent and semi-transparent areas must be pure white or black in color, with the appropriate level of alpha transparency. **Why does only one image work?** Previously we needed two images! The answer is that the masking image is limited only to only adding either pure black or white shades of color. By doing this the shading (lighting) effect, and its mask, is essentially merged into the color component of the "_Lighting Effect Mask_". As a result of this the alpha channel becomes free to hold the previously separate transparency mask for the final image. The limitation of this however is that you can only add white and black shades to the image. You can not add for example a gray color to the image being masked. Note however that it is posible to add some tints of primary and secondary colors of some color space, but only in a limited way, and I have never seen it used. In summery you can not add specific colors or fancy borders to the image, only shades and shadows, highlights and flares, or simple black or white text. However you should not attempt to mix or overlap added white and black effects, as the resulting gray anti-aliasing pixels between the two produces a shaded color from the underlying image, and not the expected gray color. That is, the drawback with this technique! ### Masking images with distortions... What is more incredible is that as as the shading colors is just a gray-scale image, you can compress the lighting effects to just one color channel and the alpha channel mask. This can then be used to free two color image channels for other image processing effects! That is, you can store other things into the single 'masking image'. Specifically you can add distortion effects into the same mask image! For more information on this see [Unified Distortion Image](../mapping/#distortion_unified) which does exactly this! A sort of ultimate masking image. * * * Framing using Edge Images ------------------------- [![[IM Image]](../images/oak_frame_sample.jpg)](../images/oak_frame_sample.jpg) One common 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 an image. For example, here is 'thin black with gold trim' frame that was modified from images provided by Michael Slate . [![[IM Image]](../images/blackthin_top.gif)](../images/blackthin_top.gif) [![[IM Image]](../images/blackthin_btm.gif)](../images/blackthin_btm.gif) 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. A similar set of framing pieces are this 'thin ornate gold' tileable border images. [![[IM Image]](../images/goldthin_top.png)](../images/goldthin_top.png) [![[IM Image]](../images/goldthin_btm.png)](../images/goldthin_btm.png) As these images has some fine detail you cannot just simply stretch the image to the desired length. Nor can you just [Rectangular Rotate](../warping/#rect_rotate) these pieces to produce the other edge pieces, as doing so will get the shading of the fine detail wrong. A [Diagonal Transpose](../warping/#transpose) 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]](../images/bamboo.gif)](../images/bamboo.gif) 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. The bigger problem with this frame is that if you just tile it simply, the macro detail becomes very regular, and as such you may need to randomise the tile offset, or even randomise the lengths of pieces being appended togther so as to give it a more natural look. More on this later. 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 pieces that will cover the length of the image dimensions. There are only two basic ways 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 internal detail, and may become a distraction to the look of the final image. 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, please be careful that the tiles do match up properly, and to a pixel boundary so as to ensure you have an uniform color and proper cycling of the detail in your framing images. It you don't you can get an artificial looking joint between the tiles, the become obvious because of the repeation of the tiles. In the real world picture framers also have the same problem in joining pieces together to make longer pieces. Basically it is very easy to get two different shades of wood, or very different grain pattern, that when 'dove-tailed' together, makes the joint very obvious. So really 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 get some interesting random tiling effects, that may need some randomized lengthing and shortening of the peices to remove. I will not go into this however, and will leave it as an 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 generate the longer edge lengths needed. ### Over-simplistic Append We can just lengthen the simple 'bamboo' frame above, by tiling it to the right length, then [append](../layers/#append) the images together. The tiling is done simply by the special [Tiled Canvas](../canvas/#tile) image generator "`[tile:](../canvas/#tile) `" to tile an image that is being read in. magick 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]](frame_append.gif)](frame_append.gif) 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](../canvas/#tile-offset) for each edge of the image. magick 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]](frame_tile_offset.gif)](frame_tile_offset.gif) 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. magick thumbnail.gif -alpha set -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]](frame_overlaid.gif)](frame_overlaid.gif) Note the measurements and positioning for this type of framing is not simple, and could use some randomization such as I hardcoded into the above example. Also you can improve the look further by rounding of the ends of the lengths of frame, with some additional and appropriate shading. 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](#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](../crop/#frame) .The solution then was simple. Read in the image, and "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" it, to create a template which of the areas to be framed. magick thumbnail.gif -alpha set -bordercolor none \\ -compose Dst\_Out -frame 15x15+15 frame\_template.gif [![[IM Output]](frame_template.gif)](frame_template.gif) 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. It does not generate 'anti-aliaing' pixels of varing colors in the corners. Note that to make things easier the width of those areas (15 pixels) is width of the framing pieces we will add to the image. if the vertical edges were a different thickness to the horizontal edges, this technique would not work very well. In fact few methods would would well in such a situation. This image is the framing template and by tiling each of our framing pieces into the four differently colored areas using [Color Fill Primitives](../draw/#color) , we will get our 45 degree corner joints, very simply and easily.For example... magick frame\_template.gif \\ -tile blackthin\_top.gif -draw 'color 1,0 floodfill' \\ frame\_top\_filled.gif [![[IM Output]](frame_top_filled.gif)](frame_top_filled.gif) You can repeat this process for the other three edges. Using transposes to ensure that the highlights and shaodws of the internal detail remain correct. magick 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]](frame_filled.gif)](frame_filled.gif) From an IM forum discussion [45 degree frame joints](https://magick.imagemagick.org/viewtopic.php?f=1&t=21867) a simplier solution, involving pre-rotating the bottom edge was found. Here is the full example using the [In Memory Register](../files/#mpr) to save intermediate images. magick thumbnail.gif -write mpr:image +delete \\ goldthin\_top.png -write mpr:edge\_top +delete \\ goldthin\_btm.png -rotate 180 -write mpr:edge\_btm +delete \\ \\ mpr:image -alpha set -bordercolor none \\ -compose Dst -frame 25x25+25 -compose over \\ \\ -tile mpr:edge\_btm \\ -transverse -draw 'color 1,0 floodfill' \\ -transpose -draw 'color 1,0 floodfill' \\ -tile mpr:edge\_top \\ -transverse -draw 'color 1,0 floodfill' \\ -transpose -draw 'color 1,0 floodfill' \\ \\ mpr:image -gravity center -composite frame\_gold.png [![[IM Output]](frame_gold.png)](frame_gold.png) As you can see we still have a problem, it looks very artifical in the top left and bottom right corner, due to a diagonal mirror effect that results from the tiling. To fix this we need to add a randomised "`[-tile-offset](https://imagemagick.org/script/command-line-options.php?#tile-offset) `", so as to remove this mirror effect. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _[Tile Offset](../canvas/#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._ | **Scripted Version****This needs to be re-written using the last example as template**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](../warping/#rect_rotates) and some randomized [Image Rolls](../warping/#roll) 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](../canvas/#tile_memory) technique and the frame template (generated) is used to mask those images, as we did above. image=thumbnail.gif image_w=`magick $image -format %w info:` image_h=`magick $image -format %h info:` top=goldthin_top.png btm=goldthin_btm.png width=`magick $top -format %h info:` length=`magick $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.... magick -page +$width+$width $image +page -alpha set \ \( +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]](framed_script.png)](framed_script.png) 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 use of [In-Memory Tile Images](../canvas/#tile_memory) so we can pre-process the framing images, all in the one command. This makes it more complex but also more versatile. The above code has been built into a shell script, which you can download ("`[frame_edges.tar.gz](../scripts/frame_edges.tar.gz) `" from the [IM Example Scripts](../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. #### Future example Using tiling edges with matching corner peices. The edge images will need to match up to pre-prepared corner pieces, but also tile neatly across the fixed length of the image. That means that the whole tiled edge may need some stretching or compression so as to align the edge tiles with its corner pieces. To work properly teh edge tiles must repeat at least 3 or 4 times across the smallest image edge. An example of this type of tiled edge/corner is the implementation of a border of 'leaves' or 'fleur' effects. * * * --- # Comparing -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Image Comparing =================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_left.gif)Methods of Comparing Images](#methods) -- what is different? * [Compare Program](#compare) * [Difference Images](#difference) * [Flicker Compare](#flicker) * [Comparing Animations](#animation) [![](../img_www/granitesm_left.gif) Comparison Statistics](#statistics) -- how different? [![](../img_www/granitesm_left.gif) Sub-Image Matching and Locating](#sub-image) Finding smaller images in larger. [![](../img_www/granitesm_right.gif) Finding Duplicate Images](#doubles) -- finding two images that are the same [![](../img_www/granitesm_right.gif) Sorting Images by Type](#type_general) -- image classifications for comparing * [Gray-scale Images](#type_greyscale) * [Linear Color](#type_linear) * [Pure Black and White](#type_bw) * [Color Images](#type_spot_color) * [Midtone Colored](#type_midtone) * [Text vs Line Drawing](#type_lines) * [Real Life vs Cartoon](#type_reallife) [![](../img_www/granitesm_right.gif) Handling Specific Image Types](#type_specific) [![](../img_www/granitesm_right.gif) Image Metrics](#metrics) -- finger-printing images for comparision [![](../img_www/granitesm_right.gif) Web Cameras](#camera) -- Finding what has changed in fixed cameras The ability to compare two or more images, or finding duplicate images in a large collection, is a very tricky matter. In these examples we look at comparing images to determine how they similar they are, and where they differ. This may involve classifying or grouping images into various types for better handling. Discovering some [metric](http://en.wikipedia.org/wiki/Metric_%28mathematics%29) to simplify and group similar images. And [clustering](http://en.wikipedia.org/wiki/Data_clustering) similar images together based on such metrics. However such comparisons, and or studies while difficult can be rewarding, with the ability to find image duplicates, copies, and even removal of 'spam' or other text or notices from images. * * * Methods of Comparing Images --------------------------- ### Compare Program The "`magick compare`" program is provided to give you an easy way to compare two similar images, to determine just how 'different' the images are. For example, here I have two frames of an animated 'bag', which I then gave to "`magick compare`' to highlight the areas where it changed. magick compare bag\_frame1.gif bag\_frame2.gif magick compare.gif [![[IM Output]](../images/bag_frame1.gif)](../images/bag_frame1.gif) [![[IM Output]](../images/bag_frame2.gif)](../images/bag_frame2.gif) ![==>](../img_www/right.gif) [![[IM Output]](compare.gif)](compare.gif) As you can see you get a white and red image, which has a 'shadow' of the second image in it. It clearly shows that three areas that changed between the two images. Rather than saving the 'compare' image, you can of course view it directly, which I find more convenient, by output to the special "`[x:](../files/#x) `" output format, or using the "`[display](../basics/#display) `" program. For example.. magick compare bag\_frame1.gif bag\_frame2.gif x: magick compare bag\_frame1.gif bag\_frame2.gif miff:- | display As of IM v6.4 you can change the color of the differences from red to some other more interesting color... magick compare bag\_frame1.gif bag\_frame2.gif \\ -highlight-color SeaGreen magick compare\_color.gif [![[IM Output]](compare_color.gif)](compare_color.gif) As of IM v6.4.2-8 you can specify the other color as well. magick compare bag\_frame1.gif bag\_frame2.gif \\ -highlight-color SeaGreen -lowlight-color PaleGreen \\ magick compare\_colors.gif [![[IM Output]](compare_colors.gif)](compare_colors.gif) If you don't want that 'shadow' of the second image, from IM v6.4.2-8 you can add a "`-compose src`" to the options to remove it. magick compare bag\_frame1.gif bag\_frame2.gif \\ -compose Src compare\_src.gif [![[IM Output]](compare_src.gif)](compare_src.gif) By using all three extra settings we can generate a gray-scale mask of the changed pixels... magick compare bag\_frame1.gif bag\_frame2.gif \\ -compose Src -highlight-color White -lowlight-color Black \\ magick compare\_mask.gif [![[IM Output]](compare_mask.gif)](compare_mask.gif) Note however that this mask is of ANY difference, even the smallest difference. For example you can see all the minor differences that saving an image to the [Lossy JPEG Format](../formats/#jpg) produces... magick bag\_frame1.gif bag\_frame1.jpg magick compare bag\_frame1.gif bag\_frame1.jpg magick compare\_lossy\_jpeg.gif [![[IM Output]](../images/bag_frame1.gif)](../images/bag_frame1.gif) [![[IM Output]](bag_frame1.jpg)](bag_frame1.jpg) ![==>](../img_www/right.gif) [![[IM Output]](compare_lossy_jpeg.gif)](compare_lossy_jpeg.gif) As you can see even though you can't really see any difference between GIF and the JPEG versions of the image, "`magick compare`" reports a lot of differences. By using a small [Fuzz Factor](../color_basics/#fuzz) you can ask IM to ignore these minor differences between the two images. magick compare -metric AE -fuzz 5% \ bag_frame1.gif bag_frame1.jpg magick compare_fuzz.gif [![[IM Text]](compare_fuzz.txt.gif)](compare_fuzz.txt) [![[IM Output]](compare_fuzz.gif)](compare_fuzz.gif) Which shows that most of the actual differences are only minor. The special "`[-metric](https://imagemagick.org/script/command-line-options.php?#metric) `" setting of '`AE`' (short for "Absolute Error" count), will report (to standard error), a count of the actual number of pixels that were masked, at the current fuzz factor. ### Difference Images To get a better idea of exactly how different the images are, you are probably better of getting a more exact '`[difference](../compose/#difference) `' composition image.... magick composite bag\_frame1.gif bag\_frame1.jpg \\ -compose difference difference\_jpeg.gif [![[IM Output]](difference_jpeg.gif)](difference_jpeg.gif) As you can see while "`magick compare`" showed that JPEG created a lot of differences between the images, a '`[difference](../compose/#difference) `' composition was quite dark, indicating that all the differences were relatively minor. If the resulting image looks too black to see the differences, you may like to [Normalize](../color_mods/#normalize) the image (using the more mathematically correct "`[-auto-level](https://imagemagick.org/script/command-line-options.php?#auto-level) `", so as to enhance the results. magick difference\_jpeg.gif -auto-level difference\_norm.gif [![[IM Output]](difference_norm.gif)](difference_norm.gif) This still shows that most of the differences are still very minor, with the largest difference occurring along the sharp edges of the image, which the JPEG image file format does not handle very well. On the other hand getting a difference image between the two original frames of the animation shows a very marked differences between the two images, even without any enhancement. magick composite bag\_frame1.gif bag\_frame2.gif \\ -compose difference difference\_frames.gif [![[IM Output]](difference_frames.gif)](difference_frames.gif) Note that as the '`[difference](../compose/#difference) `' compose method is associative, the order of the two images in the above examples does not matter, although unlike "`magick compare`", you can compare different sized images, with the destination image determining the final size of the difference image. The different method is even more useful when used with the "`magick`" program, as you can process the resulting image further before saving or displaying the results. For example you can threshold and merge each of the color channels to to generate a mask of any pixel that changed color between the two images. magick bag\_frame1.gif bag\_frame2.gif -compose difference -composite \\ -threhold 0 -separate -evaluate-sequence Add \\ difference\_mask.gif [![[IM Output]](difference_mask.gif)](difference_mask.gif) This is basically what the "`magick compare`" program does, but with more controls as to the color and output style. However as you can see it tends to find even the smallest minor change between two images. If the images are from a lossy image file format, such as JPEG, or a GIF image that required color reduction and dithering (color quantization), then that would probably match everything in the image. As such it it typically not very useful. For better results you can try to figure out just how different the pixel colors are. For example we can gray-scale the result, so as to get a better comparison image, than a colorful one. magick bag\_frame1.gif bag\_frame2.gif -compose difference -composite \\ -colorspace Gray difference\_gray.gif [![[IM Output]](difference_gray.gif)](difference_gray.gif) Now unlike "`magick compare`", the difference image shows a mixture of both images combined in the final result. For example look at the weird 'talisman' seems to appear in the forehead of the cat. This was originally the handle of the bag from the first image. This merger can make it confusing as to exactly what differences you are seeing, and you see a megere of both the additions and removals from the image. Because of this confusion of details, the "`magick compare`" is usually the better way for us humans to view, while the 'difference' image is the better method for further processing the image. However grayscaling a difference image will simply average (actually a weighted average) the RGB distances together. As a result a single bit color difference could be lost though [Quantum Rounding Effects](../basics/#quantum_effects) . If even the smallest difference between images is important, a better method is to add the separate color channels of the difference image, to ensure you capture ALL the differences, including the most minor difference. magick bag\_frame1.gif bag\_frame2.gif -compose difference -composite \\ -separate -evaluate-sequence add difference\_add.gif [![[IM Output]](difference_add.gif)](difference_add.gif) The difference values produced in the above is known as a 'manhattan distance' metric. That is, the distance between the two colors of each image when you are restricted to orthogonal (or axial) movement. Be warned however that large differences may become clipped (or burned) as it can exceed the pixel data 'Quantium Range', or integer limits, unless using a HDRI version of IM. To take this further you can get the color vector distance, by using some squares and square roots to implement a Pythagorean or Euclidean distance. magick bag\_frame1.gif bag\_frame2.gif -compose difference -composite \\ -evaluate Pow 2 -separate -evaluate-sequence Add -evaluate Pow 0.5 \\ difference\_vector.gif [![[IM Output]](difference_vector.gif)](difference_vector.gif) This is in fact similar what a 'fuzz' factor actually measures as part of its thresholding (when no transparency is involved). However 'fuzz' also divides the squared values by 3, before adding, to ensure the results do not exceed the image color range limits. Doing this means you would only get a pure 'white' pixel in the result for difference between opposite primary and secondary colors, such between a blue and yellow pixel. So lets do that scaling too... magick bag\_frame1.gif bag\_frame2.gif -compose difference -composite \\ -evaluate Pow 2 -evaluate divide 3 -separate \\ -evaluate-sequence Add -evaluate Pow 0.5 \\ difference\_vector\_scaled.gif [![[IM Output]](difference_vector_scaled.gif)](difference_vector_scaled.gif) This is actually very similar to what you would get for a "`-colorspace Gray`' difference image (as above), but it is much more accuriate representation of color difference. You could leave of the second '`Pow 0.5`' modification in which case you will get a Squared difference Image. There are other color distance metrics, which you can read about on the [Color Difference, Wikipedia](http://en.wikipedia.org/wiki/Color_difference) page. Most of these involve generating vector differences (see last) but using a different colorspace, such as LAB or LUV. This would however be more important in comparing real world color differences (EG: human vision difference measures). Also see [Background Removal](../masking/#bg_remove) , where difference images like the above are used to perform background removal. You may also like to look at this external page on [Change Detection](http://ecocam.evsc.virginia.edu/change_detection_description/change_detection_description.htm) as a practical example of its use. ### Flicker Compare An alternative to the "`magick compare`" program to see differences between images is to do a flicker comparison between the similar images at a reasonably fast rate. magick -delay 50 bag\_frame1.gif bag\_frame2.gif -loop 0 flicker\_cmp.gif [![[IM Output]](flicker_cmp.gif)](flicker_cmp.gif) To make this easier I wrote a script to display an animation of two given images called "`**[flicker_cmp](../scripts/flicker_cmp) **`" which flips between the two images, just like the above example. It also adds a label at the bottom of the displayed image so as to detail which image you are seeing at any particular moment. ### Comparing Animations You can also compare the differences in two coalesced animations using a special 'film strip' technique. See a similar 'append' technique in [Side by Side Appending](../anim_mods/#append) . Basically we append all the animation frames together to form one large, and long image. The two images are then compared and a new animation is created by splitting up the animation into separate frames again. For example... magick \\( anim1.gif -coalesce -append \\) \\ \\( anim2.gif -coalesce -append \\) miff:- | \\ magick compare - miff:- |\\ magick - -crop 160x120 +repage anim\_compare.gif The result is an animation of the 'compare' images, producing a 'dimmed' version of the second animation, overlaid with a highlight showing the parts which are different. Note that for this to work the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" size much match the original size of the animation. Also the animation will lose any variable time delays that it may have had, using a constant time delay based on the first frame of the original animation. Another image comparison technique useful for animations is used to locate all the areas in which an animation changes, so as to divide the animation's unconnected parts. This way you can separate a large animations into a number of smaller animations. See [Splitting up an Animation](../anim_mods/#split) . * * * Comparison Statistics Just how different are two images? ---------------------------------------------------------- **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Statistics from difference image... The following outputs verbose information and extracts just the section containing the channel statistics of the image.... magick image1 image2 -compose Difference -composite \\ -colorspace gray -verbose info: |\\ sed -n '/statistics:/,/^ \[^ \]/ p' The numbers in parenthesis (if present) are normalized values between zero and one, so that it is independent of the Q level of your IM. If you don't have these numbers, you should think of upgrading your IM. To get the average (mean) grey level as a percentage you can use this command... magick image1 image2 -compose Difference -composite \\ -colorspace gray -format '%\[fx:mean\*100\]' info: For non-percentage you can use the even simplier.. magick image1 image2 -compose Difference -composite \\ -colorspace gray -format '%\[mean\]' info: Compare Program Statistics... You can get an actual average difference value using the -metric magick compare -metric MAE image1 image2 null: 2>&1 Adding -verbose will provide more specific information about each separate channel. magick compare -verbose -metric MAE rose.jpg reconstruct.jpg null: 2>&1 Image: rose.jpg Channel distortion: MAE red: 2282.91 (0.034835) green: 1853.99 (0.0282901) blue: 2008.67 (0.0306503) all: 1536.39 (0.0234439) Their are a number of different metrics to chose from. With the same set of test images (mostly the same) Number of pixels AE ...... Absolute Error count of the number of different pixels (0=equal) This value can be thresholded using a -fuzz setting to only count pixels that have a larger then the threshold. As of IM v6.4.3 the -metric AE count is -fuzz effected. so you can discount 'minor' differences from this count. magick -metric AE -fuzz 10% image1.png image2.png null: Which pixels are different can be seen using the output image (ignored in the above command). This is the ONLY metric which is 'fuzz' effected. Maximum Error (of any one pixel) PAE ..... Peak Absolute Error (within a channel, for 3D color space) PSNR .... Peak Signal to noise ratio (used in image compression papers) The ratio of mean square difference to the maximum mean square that can exist between any two images, expressed as a decibel value. The higher the PSNR the closer the closer the images are, with a maximum difference occurring at 1. A PSNR of 20 means differences are 1/100 of maximum. Average Error (over all pixels) MAE ..... Mean absolute error (average channel error distance) MSE ..... Mean squared error (averaged squared error distance) RMSE .... (sq)root mean squared error -- IE: sqrt(MSE) Specialized metrics MEPP .... Normalized Mean Error AND Normalized Maximum Error These should directly related to the '-fuzz' factor, for images without transparency. With transparency, makes this difficult the mask should effect the number of pixels compared, and thus the 'mean' but this is currently not done. FUZZ fuzz factor difference taking transparency into account NCC normalized cross correlation (1 = similar) I produced the following results on my test images... \_metric\_|\_\_low\_Q\_jpeg\_\_|\_\_black\_vs\_white\_\_ PSNR | 29.6504 | 0 PAE | 63479 | 65535 MAE | 137.478 | 65535 MSE | 4.65489e+06 | 4.29484e+09 RMSE | 2157.52 | 65535 The first column of numbers is a compare of images with low-quality JPEG differences, where the test image was read in and saved with a very low -quality setting. The second "black vs white", is a compare of a solid black image verses a solid white image. If the 'average color' of the image is ignored by the comparision then the resulting value will be very small. This seems only to be the case with the PSNR metric, as all others produced a maximum difference value. The e+06 is scientific notation, on how many places to shift the decimal point. EG: 4.65489e+06 --> 4,654,890.0 Thus is equal to about 4 million, and is the square of 2157.52 WARNING: numbers are dependant on the IM Quality (Q) levels set at compile time. The higher the quality the larger the numbers. Only PSNR should be unaffected by this. For this reason IM also gives you a 'normalized' result that is uneffected by the compile time quality setting, though may still have minor 'quantum' or 'interger rounding' effects. I have NOT figured out if there are any of the existing "-define" options usable the "compare" function. NOTE for opaque colors AE -fuzz and RMSE distances are equivelent. HOWEVER, when transparent colors are involved AE fuzz factor testing will treat two different fully-transparent colors as being the same while RMSE will treate them as being different! For example... To AE fully-transparent white and fully-transparent black are the same. magick compare -metric AE xc:#0000 xc:#FFF0 null: 0 But to RMSE they are VERY different magick compare -metric RMSE xc:#0000 xc:#FFF0 null: 56755 (0.866025) Dissimilarity-threshold If you get a 'too different' error, you can disable that using... -dissimilarity-threshold 1.0 But what is this threshold? For more info, see my very old raw text notes... [Image Comparing, Tower of Computational Sorcery](http://www.ict.griffith.edu.au/anthony/info/graphics/image_comparing) * * * Matching Sub-Images and Shapes ------------------------------ **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Using "compare -subimage-search" option... magick compare -subimage-search large\_image.png sub-image.png results-%d.png This produces two images results-0.png which displays the matching location results-1.png which is a map of possible top-left corner locations showing how well the sub-image matches at that location. Note the second image is smaller, as it is only top-left corner locations. As such its size is large\_image - small\_image + 1 The search however is based on a difference of color vectors, so produces a very accurate color comparison. The search basically does a compare of the small image at EVERY possible location in the larger image. As such it is is slow! **very very slow.**. The best idea is to compare a very very SMALL sub-image to find possible locations, than use that to then do a difference compare at each possible location for a more accurate match. Have a look at the script https://imagemagick.org/Usage/scripts/overlap and associated discussion [Overlapped Images](https://magick.imagemagick.org/viewtopic.php?f=1&t=22526&p=95286) Which looks at locating 'high entropy' sub-images of one image to search for posible matches in a second image so the overlap offset between the two images can be discovered, and the images merged into a larger image. Another discussion uses sub-image searches to find tiling patterns in larger images, with the goal of generating tilable images [Stitching image over a canvas](https://magick.imagemagick.org/viewtopic.php?f=1&t=22860) Example using RMSE and the new -grayscale function to merge the separate color difference channel results into a final image magick large\_image.png small\_image.png miff:- | magick compare -metric RMSE -subimage-search - miff:- | magick - -delete 0 -grayscale MS show: Similarity Threshold As many time people are only interested in the first match that matches. As soon at this 'good' match is found, there is no need to continue searching for another match. The -similarity-metric defines what you would regard as a good match. A "-similarity-threshold 0.0" will abort on the very first 'perfect' match found, while "-similarity-threshold 1.0" (the default) will never match and will search every posible point. A value between will set a color only 'fuzz' factor on what you would find an acceptable match. Note that if the sub-image search is aborted, the second 'map' image will only contain a partial result, only showing the results up until the comapre aborted its search). Some Basic Sub-Image Search Examples.... Grab a screen shot of a terminal window ("screen.png"), and crop out an image of a single letter or word ("letter.png"). Just report first match.... for speed, immeditally abort after finding that first match. Don't bother outputing the incomplete image results. magick compare -subimage-search -metric AE -similarity-threshold 1.0 \\ screen.png letter.png null: 2>&1 NOTE speed will be highly dependant on where in the image that first match is found. Find all occurances of exactly that image, as an image (white dots on matches, black elsewhere) magick compare -subimage-search -metric AE \\ screen.png letter.png miff:- 2>/dev/null | magick - -delete 0 show: Extract a list of the coordinates of all matching letters (white dots) (as an enumerated pixel list, ignoring anything black) magick compare -subimage-search -metric AE \\ screen.png letter.png miff:- 2>/dev/null | magick - -delete 0 txt:- | grep -v '#000000' Just the coordinate list magick compare -subimage-search -metric AE \\ screen.png letter.png miff:- 2>/dev/null | magick - -delete 0 txt:- | sed -n '/#FFFFFF/s/:.\*//p' NON-ImageMagick sub-image search solutions... "visgrep" from the "xautomation" package. This is much simpler sub-image search program, that only outputs a list of coordinates for the matches (or even multiple sub-image matches). Because it is so much simpler (for near exact matching) and not trying to generate 'result images' for further study, it is also a LOT FASTER. For example... visgrep screen.png letter.png Timed results using "compare" to get just the first match 0.21 seconds using "compare" to get a 'results image' 1.56 seconds ditto, but extracting the coordinate list 1.76 seconds using "visgrep" to get all matching coordinates 0.09 seconds Other Methods of sub-image searching.... HitAndMiss Morphology This is essentually a binary match, where you define what pixels much be 'background' and what must be forground. However it also allows you to define areas where you don't care if the result is a foregorund or background. Basically a binary pattern search method. Correlate (a Convolve variant) This is similar to Hit and Miss but using greyscale values. Positive values for forground and negative values for background, and zero for don't care. It is however limited to grayscale images. See [Correlation and Shape Searching](../convolve/#correlate_search) . Both of these are basically just as slow as the previous sub-image compare, but less accurate with regards to colors. However it's ability to specify specify a shape (don't care areas) to the sub-image makes then useful as a search method. However you need to magick the sub-image into a 'kernel', or array of floating point values, rather than as an actual image. FFT Convolve (NCC) Fast Fourier Transforms is a slow operator, but usually many orders of magnitude faster than the previous two methods use. The reason is that a convolution in the frequency domain is just a direct pixel by pixel multiplication. The 'Convolve' method, can be converted into a 'Correlate', simply by rotating the sub-image being searched for by 180 degrees. See [Correlate](../convolve/#correlate) . Basically by converting images into the 'frequency' domain, you can do a sub-image search, very very quickly, compared to the previous, especially with larger sub-images that can be the same size as the original image! This I believe has been added as a NCC compare metric. Peak Finding and extracting (for near partial matches)... Once you have compared the image you will typically have a 'probably map' of some kind which defines how 'perfect' the match was. What you want to do now is to find the best match, or perhaps multiple matches in the image. That is, you want to locate the major 'peaks' in the resulting map, and extract actual locations. \* Using a Laplacian Convolution Kernel To get results you need to find the 'peaks' in the image, not necessarily the brightest points either. You can get this by convolving the image so as to subtract the average of the surrounding pixels from the central pixel. As we only want positive results, a bias removes the negative results. magick mandril3\_ncc1.png \\ -bias -100% -convolve Laplacian:0 result.png Thresholding and using it as a mask, and we can extract just those pixels. magick mandril3\_ncc1.png \\ \\( +clone -bias -100% -convolve Laplacian:0 -threshold 50% \\) \\ -compose multiply -composite \\ txt:- | grep -v black The problem is you can get a cluster of points at a peak, rather than a definitive pixel, especially for two peak pixel surrounded by very low values. \* Using a Peaks Hit and Miss Morphology Kernel magick mandril3\_ncc1.png \\ -morphology HMT Peaks:1.5 result.png The problem is that this may produce no result if you get two peak pixels with exactly the same value (no gap between foreground and background) However there are other 'peak' kernels that will still locate such a peak cluster. \* Dilate and compare Dilate (expand maximum values) the image 3 times then compare it to the original image. Any peak within the area of dilated kernel size (7 pixel square) will remain the same value. Set all pixels that show a difference to pixels to zero. Method by HugoRune (IM discussion topic 14491) \* Looped match and remove. Basically find the highest pixel value, note it. Then mask all pixels in an area around that peak, and repeat until some limit (number points or threshold) is reached. See a shell script implementation of this in Fred Weinhaus's script "`[maxima](http://www.fmwconcepts.com/imagemagick/maxima/) `" This does not look at finding the center of large 'cluster' of near equal valued pixels, though this would be very rare in real images. \* Sub-pixel locating If the peak is not an exact pixel, but could conceivably be a sub-pixel location (between pixels) then some form of pattern match (gaussian curve fit) in the area of the peak may let you locate the peak to a sub-pixel coordinate. This may be more important in image registration for parorama stitching, especially when you are not using a large number points to get a best-fit average of the perspective overlay. \* Finding a tile pattern in an image When you have all the points, a search for a repeating pattern (similar vector distances between multiple peaks) should point out some form of tiling structure. Improving the Sub-Image Matching... The major problem with Correlate, (or the fast FFT correlate, which is the same thing) is that it has absolutely no understanding of color. Correlation (or convolve) is purely a mathematical technique that is used against a set of values. With images that means it is only applied against the individual channels of an image, and NOT with vector color distances. While compare actually does real comparing of color vectors. This will find shapes better than correlate but is much much slower. As such to make proper use of correlate you should magick your images (before hand for speed, or afterward against results) to try and highlight the color differences in the image as a greyscale 'correaltion' image. ASIDE: Use -channel to limit operations to one greyscale channel will improve speed. In IMv7 greyscaling will reduce images to one channel so will gain speed improvements automatically. For example instead of intensity, you may get a better foreground / background differentiation, by extracting the Hue of an image. Though you may need to color rotate the hue's if there is a lot of red in the sub-image being searched for. See the examples of HSL and HSB, channel separation, to see this problem. https://imagemagick.org/Usage/color\_basics/#separate Another greyscaling method that should work very well is to do edge detection on the two images. This will highlight the boundaries and shape, which is typically much more important than any smooth gradient or color changes in the image. For examples of Edge detection methods see https://imagemagick.org/Usage/convolve/#edgedet You may like to also look at directional or compass type edge detection. Basically Anything that will enhance the shape for your specific case is a good idea. Just apply it to BOTH images before correlating them. Scale and Rotation Invariant Matching... \* position independence... \* matching rotated sub-image (angle independent) \* matching resized sub-images (size independent) \* Both size and angle independence -------------- Other more specific image matching.. Matching Lines... Hough Algorithm Matching Circles... Hough Algorithm Variant Matching Faces A combination of the above. * * * Finding Duplicate Images ------------------------ #### Identical files Are the files binary identical that is they are exactly the same file and probably just exact copies of each other. No ImageMagick required. Don't discount this. You can compare lots of files very very quickly in this way. The best method I've found is by using MD5 check sums. md5sum \* | sort | awk {'print $2 " " $1'} | uniq -Df 1 And that will list the md5's of images that are identical. Using this technique I created scripts that can generate and compare md5sum lists of files returning the files that are md5 identical. Note however that any change to an image file other than a direct copy, will be classed by this as being different, even if the image data itself is the same. It only takes a date change or other minor meta-data difference in the file to make the image different. #### IM Image Signatures You can have IM generate a 'signature' for each image... magick identify -quiet -format "%#" images... The generates a hash string much like MD5 and SHA256 do. However unlike the latter, it uses the actual image data to generate the signiture, not the images metadata. Thus, if you have two copies of the same picture but with different creation/modification timestamps, you should get same signature for both files, whereas MD5 and SHA256 will produce two signatures even though the image itself is the same. WARNING: reading and writing a JPEG image will generate different image data and thus a different signature. This is simply due to the lossy compression JPEG image format uses. #### Direct Comparison You can directly compare two images (using the "`magick compare`" program) if they are the same size, to see how well they match. (See above) This is very slow, and in my experience not very useful when used against a full sized image, because it is so slow. However it is probably the best way to get an idea of just how similar two images are. #### Image Classification In my attempts to compare images I have found that Color, Cartoon-like, and Sketches all compare very differently to each other. Line drawings and gray-scale images especially tends to have smaller differences that color images, with just about every comparison method. Basically as the colors are all in a line any color metric tends to place such images 3 times closer together (1 dimentional colorspace verses a 3 dimentional colorspace) Basically this means that separating your images into at least these two groups can be a very important first step in any serious attempt at finding duplicate or very similar images. Other major classifications or image types can also make comparing images easier, just by reducing the number of images your are comparing against. See Image classification below. #### Thumbnail Compares You have a program create (in memory) lots of small thumbnails (say 64x64 pixels) of images to compare looking for duplicates, which you proceed to do by direct comparison. It is typically the first thing that people (myself included) attempt to do, and in fact this is the technique most image comparing programs (such as photo handling software) does. In fact this works well and does find images that exactly match. Also with a little blur, and loosing of the difference threshold, it can even find images that have had been been slightly cropped, and resized However attempting to store in memory 10,000 such thumbnails will often cause a normal computer to start thrashing, becoming very slow. Alternatively storing all those thumbnails (unless the program does this for user viewing reasons) uses a lot of disk space. One method of improving the disk thrashing problem, is to only have a smaller number of images in memory. That is, by comparing images in groups, rather than one image to all other images. A natural grouping is by directory, and comparing each directory of images with other directories of images. In fact this is rather good, as images tend to be grouped together, and this group of images will often match a similar group. Outputting matching images by directory pairs, is thus a bonus. Also how acceptably similar two images are depends on their image type. Comparing two line drawings needs to have very small 'threshold' to discount images that different, while comparing images with large areas of color often needs a much larger threshold to catch similar images that were cropped. Real world images have a bigger problem in that a texture can produce a very serious additive difference between images that has a very slight offset. Because of this you may need to simply such images, into general areas of color, either by using median filters, blurring, color reduction, or color segmentation. After such a process a real world image, generally can be compares in a similar way to cartoons. #### Image Metrics Create a small metric for each image is a linear ordered (O) operation. While comparing all images with all other images is a squared ordered (O^2) operation. A metric is not ment to actually find matching images, but group similar (likely matching) images in such a way that you can do a more intensive comparison on smaller groups. As such any metric comparison should be lenient, and accept images that have a low probably (but still a probably) of a match. But it should not so lenient as to include too many miss-matches. Also you may like to consider multiple metrics, as some metrics may match up images that another metric may 'just miss' as they fall in different neighbouring regions (threshold miss-match). In the next section ([Metrics](#metrics) ) is a number of different IM generated metrics I have experimented with, or theorized about, including: average color, predominant color, foreground background, edge colors, matrix of colors, etc.Günter Bachelier, has also reported the possibilities of using more exotic metrics for image comparison, such as: Fourier descriptors, fractal dimensions, convex areas, major/minor axis length and angles, roundness, convexity, curl, solidity, shape variances, direction, Euler numbers, boundary descriptors, curvature, bending energy, total absolute curvature, areas, geometric centrum, center of mass, compactness, eccentricity, moments about center, etc, etc. My current effort is in generating and using a simple 3x3 matrix of color averages to represent the image (See [Color Matrix Metric](#metric_color_matrix) below). As these are generated (or requested) the metric is cached (with other file info) into special files in each directory. This way I only need to re-generate a particular metric when and if no cached metric is available, or the image changed. #### Similarity or Distance The metrics of two images (or the actual images) can be compared using a number of different methods, generally producing a single distance measure or 'similarity metric' that can be used to cluster 'similar' images together. * Direct Threshold, or Maximum Difference, (Chebyshev Distance) Just compare images by the largest difference in any one metric. The threshold will produce a hyper-cube of similar images in the multi-dimensional metric space. Of course the image difference is only based on one metric and not over all metrics. * Average Difference (Mean Distance, Averaged Manhattan Distance) Sum all the differences and optionally divided by the number of metrics. This is also known as the Manhattan Distance between two metrics, as is is equivalent to the distance you need to cover to travel in a city grid. All metrics contribute equally, resulting in things appearing 'closer' than you expect. In space a threshold of this metric will produce a diamond like shape. * Euclidean (Pythagorean) Difference Or the direct vector distance between the metrics in metric space. The value tends to be larger when more metrics are involved. However, one metric producing a big difference, tends to contribute more than the other metrics. A threshold produces a spherical volume in metric space. * Mathematical Error/Data Fit or (Moment of Inertia???) Sum all squares of all differences, then get the square root This is more typically used to calculate how close a mathematically curve fits a specific set of data, but can be used to compare image metrics too. This is seems to provide the best non-vector distance measure. * Vector Angle Find the angle between the two lines from the center of the vector space created by the images metric. This should remove any effect of contrast or image enhancements that may have been applied to the two images. _Yet to be tested_ * Vector Distance For images that are line drawing or greyscale images, where all the individual color vectors in a metric are in the same direction, the relative distances of the metrics from the average color of the image is probably more important. Normalizing the distances relative to the largest distance may reduce the effect of contrast. That is, this is a line drawing image, comparison method. _Yet to be tested_ * Cluster Analysis All the metrics are plotted and grouped into similar clusters within the multi-dimensional space. A good clustering package may even be able to discover and discount metrics that produce no clustering. _Yet to be tested_ At the moment I am finding that the "Mathematical Error" technique seems to work well for both gray-scale and color metrics, using a simple 3x3 averaged "[Color Matrix Metric](#metric_color_matrix) " (see below). #### Human Verification After the computer has finished with its attempts to find matching images, it is then up to the user to actually verify that the images match. Presenting matches to the user can also be a difficult task, as they will probably want the ability to... * See the images side-by-side * Flick very very quickly between two images, at their original size, and optionally a common 'scaled' size. * Flick between, or overlay, differently scaled and translated images. to try to match up the images. * See other images in the same directory (source) or prehaps the same cluster (other near matches) as the matching image, so as to deal with a whole group rather than each image individually. * Rename, Move, Replace, Delete, Copy the Images between the two (or more) directories, to sort out the images, and reject others. * and so on... . Currently I group matches into sets and use a combination of programs to handle them under the users control. These programs include IM's "`magick display`" and "`magick montage`", as well as image viewers "`XV`" and "`GQview`". However I am open to other suggestions of programs that can open two or more directories simultaneously, and display collections or image groups from multiple directories. Remote or control by other programs or scripts can be vital, as it allows the image groups to be setup and presented in the best way for the user to look at and handle. No program has yet met my needs. For example "`gqview`" has collections, and a single directory view, but does not allow multiple directory views, or remote / command line control of the presentation. However the collections do not show what directory each image is from, or flip the single directory view to some other directory. It also has no remote program control. On the other hand the very old "`xv`" does allow multiple directory views (its using multiple 'visual schnauzer' windows), and a collection list in its control window, but only one image can be viewed at a time, and only one directory can be opened and positioned from its command line. Of course it also has no remote control. These are the best human verification programs I have found, which I use a script to setup and launch for each image group, matching pairs, or all group matched images. But none are very satisfactory. A light table and associated software seems to me to be the better method of sorting out images, but for that you need larger touch sensitive screeens, and there in lies great expense. #### Cross-type Image Comparison One of the harder things I would like to do is find images that were created from another image. For example, I would like to match up a line drawing that someone else has colored in, or painted, to produce cartoon or even ultra realistic images. A background may also have been added. These things are very difficult and my experiments with edge detection techniques have so far been inconclusive. Finding the right metric in this is the key, as humans can make the 'similarity' connection much better, but you still have to find possible matches to present to the user. #### Summary of Finding Duplicate Images In summary, my current procedure of finding and handling duplicate images is a pipeline of programs to find and sort out 'similar' images. Generate/Cache Image Types and Metrics -> Compare metrics and cluster images. -> compare images in cluster for matches -> group into sets of matching images (by source directory) -> human verification As you can see I am looking a highly staged approach. Mail me your ideas!!! * * * Sorting Images by Type ---------------------- Determining what type of image is important as most methods of comparing images only work for a specific type of image. It is no good comparing an image of text against an artists sketch, for example. Nor is it useful to use a color image comparison method on image which is almost pure white (sketch). Usually the first thing to do when comparing images is to determine what type of image, or 'colorspace' the image uses. Basic classifications of images can include... * Black and white line drawing or text image (almost all one color) * Images consisting of two basic colors - equally (pattern images?). * Gray-scale artists drawings (lots of shades) * Linear Color images (colors form a gradient but not from black and white) * Cartoon like color image with large areas of solid colors. * A real life image with areas of shaded colors * Image contains some annotated text or logo overlay. (a single spike of color) After you have basic categories you can also attempt to sort images, using various image metrics, such as... * Average color of the whole image * predominant color in image * Foreground/Background color of image. What is worse, is that JPEG, or resized images are often also color distorted, making such classifications much more difficult as colors will not be quite as they should be. Greys will not be pure greys, and lines may not sharp and clear. An ongoing long term discussion on sorting images by type is on the IM Users Forum... [How to check image color or black and white](https://magick.imagemagick.org/viewtopic.php?f=1&t=19580) . ### Gray-scale Images The simplest way to check if an image is greyscale is to look at the color saturation levels of the image. That is, easilly done by converting the image into a 'Hue' image colorspace and getting the average and maximum values of the color (typically green) channel. For example.. magick rose: granite: -colorspace HCL \ -format '%M avg=%[fx:mean.g] peak=%[fx:maxima.g]\n' info: [![[IM Text]](greyscale_test.txt.gif)](greyscale_test.txt) The numbers are normalized to a 0 to 1 range. As you can see the "rose" is very colorful (30% average), with a strong peak (approaching 1) The "granite" image however has a very low saturation (2% or so) and low peak value. Though it is not pure greyscale it is very close to it. A low average and high peak will indicate small patches of strong color. Thresholding the same channel can generate a mask of the colorful areas of the image. PROBLEM: The above does not find images that are linear in color. That is images which only contain colors that form a linear color gradient, such as a yellowed (sepiatone) photos, or blue prints. These are essentially colorful greyscale images. See next image type. ### Is Image Linear Color Another technique is to do a direct 'best fit' of a 3 dimensional line to all the colors (or a simplified Color Matrix of metrics) in the image. The error of the fit (generally average of the squares of the errors) gives you a very good indication about how well the image fits to that line. The fitting of a line to the 3 dimensional image generally involves some vector mathematics. The result will not only tell you if the image uses a near 'linear' set of colors, but works for ANY scale of colors, not just light to dark, but also off-grey lines on yellow paper. The result can also be used to magick the image into a simpler 'grey scale' image, (or just magick a set of color metrics to grey-scale metrics) for simpler comparisons, and better match finding. My trial test program does not even use the full image to do this determination, but works using a simple [Color Matrix Metric](#metric_cmatrix) below of 9 colors (27 values) to represent the image). However be warned that this test generally does not differentiate an unshaded line drawings very well. Such images are almost entirely a single background color (typically white) and as such my not show any form of linear gradient of colors. They should be separated out first using a different test (see next, it is actually much easier). Mail me if interested, and let me know what you have tried. ### Pure Black and White images To see if an image is near pure black and white image, with little in the way any color or even greys (due to anti-aliasing), we can make a novel use of the "`[-solarize](https://imagemagick.org/script/command-line-options.php?#solarize) `" option (See the IM example on [Solarize](../color_mods/#solarize) ). Applying this operation on any image results in any bright colors becoming dark color (being negated). As such any near white colors will become near black colors. From such an image a simple statistical analysis of the image will determine if the image is purely (or almost purely) black and white. magick wmark\_dragon.jpg -solarize 50% -colorspace Gray wmark\_bw\_test.png magick identify -verbose -alpha off wmark\_bw\_test.png | \\ sed -n '/Histogram/q; /Colormap/q; /statistics:/,$ p' > wmark\_stats.txt [![[IM Output]](wmark_dragon.jpg)](wmark_dragon.jpg) ![==>](../img_www/right.gif) [![[IM Output]](wmark_bw_test.png)](wmark_bw_test.png) ![==>](../img_www/right.gif)[![[IM Text]](wmark_stats.txt.gif)](wmark_stats.txt) If you look at the statistics above you will see that the color 'mean' is very close to pure black ('`0`'), while the 'standard deviation' is also very small, but larger than the 'mean'. Thus this image must be mostly pure black and white, with very few colors or mid-tone greys. For general gray-scale and color images, the 'mean' will be much larger, and generally the 'standard deviation' smaller than the mean. When that happens it means the solarized image has very little near pure black in it. That is, very few pure black or white colors are present. Lets repeat this test using the built in granite image. magick granite: granite.jpg magick granite.jpg -solarize 50% -colorspace Gray granite\_bw\_test.png magick identify -verbose -alpha off granite\_bw\_test.png | \\ sed -n '/Histogram/q; /Colormap/q; /statistics:/,$ p' > granite\_stats.txt [![[IM Output]](granite.jpg)](granite.jpg) ![==>](../img_www/right.gif) [![[IM Output]](granite_bw_test.png)](granite_bw_test.png) ![==>](../img_www/right.gif)[![[IM Text]](granite_stats.txt.gif)](granite_stats.txt) Note how the 'mean' is now much larger, toward the middle of the color range, with a 'standard deviation' that is much smaller than the size of the 'mean'. As of IM v6.4.8-3 you will also see two other statistic values that can be helpful in determining the type of image. Both '[Kurtosis](http://en.wikipedia.org/wiki/Kurtosis) ' and '[Skewness](http://en.wikipedia.org/wiki/Skewness) ', are is relatively large (and positive) in the first Black and White image also reflects the fact that very few grays are involved when compared to a Gray image. However 'mean' vs 'standard divination' is still probably the better indicator for comparison purposes. Note that this comparison does not differentiate between 'black on white', or 'white on black' but once you know it is not really a gray-scale image a simple check of the images normal mean will tell you what the background color really is. ### Spot Colored Images These images fail the greyscale test above, but are still, black and white but with a small area or patch of color in it. Small patches of color could easily be swamped by the overall average of a large image, can could be mis-typed as being greyscale. We are not interested in an images with just say a single pixel of color, which is likely to be a bit error, or a speckling of such pixels across the image. But say an image with a color arrow or a small colored object. In other words a concentrated spot of color. In a discussion on the IM Forum [False positive for greyscale images using the "saturation test"](https://magick.imagemagick.org/viewtopic.php?f=1&t=29781) It was thought to break up images into smaller sections, and then look for a high saturation in any one of those areas. This lead to the following method. * magick image into a colorspace with a Saturation or Chroma channel * Resize Image smaller by a 1:50 (2%) ratio (EG a 'spot size' for color) * Threshold on the get the maximum saturation/chroma value Individual or very small spots will be removed, but a larger color spot will have at least one colorful pixel in the resized image. ### Midtone Colored Images [![[IM Output]](../images/midtone_image.jpg)](../images/midtone_image.jpg) Images which are sepia-toned, or with midtone grays colored to some highlight color (for example the image to the right) can prove to be much more difficult to distinguish. Generating such images is easy, as shown in [Midtone Color Tinting](../color_mods/#tint) , though are not very common. The colors still form a gradient (line) of colors in the color space, but that gradient falls along a curved path, typically a parabola of some kind, in a plane. But distinguishing such images can be very difficult. One technique is to get a standard deviation of any hues, that does not have an extremely small saturation. All hues in a midtoned color image should be very similar even if there are not many of them. This technique was presented in the specific post in [How to check image color or back and white](https://magick.imagemagick.org/viewtopic.php?f=1&t=19580&p=135373) . Just a reminder that the Hue is a cyclic value, and wraps around the the color 'red'. To test properly you may have to do it twice, with the hues shifted by 180 degrees. Also Hue has no real meaning for any color with a very low saturation (grey), so any such color should be ignored in testing the standard deviation of hues. ### Text vs Line Drawing If you have an image that is almost purely a single color (typically white) then you can try to see if the image contents could be classified as either text, or a line drawing. Text will have lots of small disconnected objects, generally grouped into horizontal lines. On the other hand, line drawings should have everything mostly connected together as a whole, and involving many different angles. Note that cartoon-like color images could also be turned into a line drawing for simpler image comparing, so a line drawing comparison method would be a useful thing to have. Anyone? To find out more about the text, a number of techniques has been discussed in the IM forums, [Check if image contains text](https://magick.imagemagick.org/viewtopic.php?f=1&t=21263) . ### Real Life vs Cartoon Like Basically cartoons have very specific blocks of color with sharp bordered regions, often made sharper by using a separating black line. They also usually have a minimal gradient or shading effects. Real life images however have lots of soft edging effects, color gradients, and textures, and use lots of different colors. This is of course not always true. A real life image could have a very cartoon like quality about it, especially a very high contrast is used, and some modern cartoons are so life-like that it can be difficult to classify them as cartoons. Generally the major difference between a real life image and a cartoon is textures and gradients. As such to determine what type of image it is requires you to compare the image, to the same image with the fine scale texture removed. A large difference means the image is more 'realistic' and 'real world' like, rather than than 'cartoonish' or 'flat'. Also remember a line drawing, artist sketch, and text can also be very cartoon like in style, but have such a fine texture and detail to it that the above could think of the image as real world. As such line drawings and sketches should be separated out before hand. Jim Van Zandt offers this solution... * write out the color of every pixel * sort by color * write out the pixel count for every color * sort by pixel count * Work your way through the list until you have accounted for half the pixels in the image. * If #pixels >>> #colors then it's cartoon like. The initial section can be classed as histogram. See the "`[histogram:](../files/#histogram) `" examples. _If you have created some sort of image classification scheme.. Even if only roughly, please let us know your results, so others (including myself) can benefit._ * * * Handling Specific Image Types ----------------------------- Here are notes and information on more specific image determination techniques. ### Bad Scan or Printouts In the real world, things never work quit as perfectly as you would like. Scanners have broken sensors and printer drums have scratches. Both of these problems generally result in scans and printouts containing long vertical lines. Determining if an image has these vertical lines is however fairly easy. The idea is to average the pixels of all the rows in an image together. Any 'fault' will appear as a sharp blip in the final pixel row the number of which you can count using a 'threshold histogram' of the pixel row. FUTURE -- image example needed for testing magick bad\_printout.png -crop 0x1+0+0 -evaluate-sequence mean \\ -threshold 50% -format %c histogram:info:- faster method but needs image height (assumed to be 1024) magick bad\_printout.png -scale 1024x1 \\ -threshold 50% -format %c histogram:info:- When you have determined and removed such 'bad lines' from a fax, printout, or scan, you can then continue with your other tests without needing to worry about this sort of real world fault. ### Blank Fax First you will need to "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) `" off any headers and footers that a fax may have added to a page. You can then either to a 'threshold histogram' (see previous) to see how many individual black pixels there are. FUTURE -- image example needed for testing magick blank\_fax.png -threshold 50% -format %c histogram:info:- Or you can do a [Noisy Trim](../crop/#trim_blur) to see if the image actually contains any more solid area or objects worthy of your attention. FUTURE -- image example needed for testing ### Spammed Images A spammed image will generally show a predominant pure color spike in the images color histogram. A check on the color in the image will usually show it to be in one of the corners of the image. However this will not work with cartoon like images. ### EMail Spam Images These are images designed to get past the various spam filters. Basically the text of the ad is hidden in an image using various colors and extra 'dirt' and other noise added to make it harder to detect. And while these are difficult to distinguish from say a logo of a company email header, they are usually also much larger than the typical email logo. One discovery technique is to use a large median filter on the image. EMail spam text will generally disappear, while a logo or image will still remain very colorful. * * * Image Metrics, quickly finding images to compare ------------------------------------------------ A metric represents a type of 'finger print' to represent an image, in a very small amount of memory. Similar images should result in a similar metric. Note however that a metric is not designed to actually find matching images, but to try to discount images that are definitely not a match. That is, a good metric will let you disregard most images from further comparisons, thus reduce the amount of time needed to search all the images. ### Average Color of an image You can use -scale to get an average color of an image, however I also suggest you remove the outside borders of the image to reduce the effect of any 'fluff' that may have been added around the image. magick image.png -gravity center -crop 70x70%+0+0 \\ -scale 1x1\\! -depth 8 txt:- Alternatively to get 'weighted centroid' color, based on color clustering, rather than an average, you can use -colors magick rose: -colors 1 -crop 1x1+0+0 -depth 8 -format '%\[pixel:s\]' info:- rgb(146,89,80) This will generally match images that have been resized, lightly cropped, rotated, or translated. But it will also match a lot of images that are not closely related. The biggest problem is that this metric will generally disregard images that have been brightened, dimmed or changed the overall hue of the image. Also while it is a great metric for color and real-world images, it is completely useless for images that are greyscale. All such images generally get lumped together without any further clustering within the type. This in turn shows why some initial classification of image types can be vital to good image sorting and matching. ### Predominant Color of an image The predominant color of an image is a little different, instead of the average which merges the background colors with the foreground, you want to find the most common foreground color, and perhaps a percentage of how much of the image consists of that predominant color. As such you cannot just take a histogram of an image, as the image may use a lot of individual shades of color rather than a specific color. This can be done using the low level quantization function -segment, then taking a histogram. This has an advantage over direct use of -colors as it does not attempt to merge distant (color-wise) clusters of colors, though the results may be harder to determine. FUTURE example After which a histogram will given you the amount of each of the predominant colors. However, usually the predominant color of a cartoon or line drawing is the background color of the image. So it is only really useful for real-life images. On the other hand, you may be able to use to discover if an image has a true background, by comparing this to the images average border color. Please note that a pictures predominant color is more likely to be more strongly influenced by the background color of the image, rather than the object of interest. That is, usually in or near the center of the image. ### Border Colors By repeatedly cropping off each of the four edges (2 to 3 pixels at most) of an image, and calculating the borders average color, you can determine if an image is framed, and to how deep. Whether there is a definite background to the image. Or if there is some type of sky/land or close-up/distant color separation to the overall image. By comparing the averaged side colors to the average central color of the image you can discover if the image is uniform without a central theme or subject, such as a photo of an empty landscape.[](metric_histogram) ### Histogram - General Color Matching For a metric concerning the types of colors to be found in an image, a histogram of one sort or another is used. This is done by creating an array of 'color bins' and incrementing the count of each 'bin' as the colors are found. Now I can't see you storing a large histogram for every image! So you will either only store the most predominant colors in the histogram or you would use a much smaller number of bin's (with more pixels in each bin). An ordinary histogram of 'color bins' does not really work very well. The reason is that each color will always fall into one bin. That is, each pixel is added to each bin on an all or nothing bases without any regard to how near that color is an edge of a bin. This in turn does not make for a good metric. One solution is to create a histogram that has overlapping bins. That is every color (except maybe black or white) will fall into two color bins. Then later when you compare images a near color will match at least one of those bins. Another alternative is to create the histogram by having each color contribute to each 'bin' according to how close it is to the center of the bin. That is a color on the edge of one bin will actually share itself across two bins. This will generate a sort of fuzzy, or interpolated histogram, but one that would more accurately represent an image, especially when only a very small number of color 'bins' are used. Also histograms are traditionally either just the gray scale component of an image or three separate RGB component. But this is not a very good representation. You could try instead Hue, Saturation and Luminance Histograms to better represent the image. Alternatively why limit yourself to a 1 dimensional histogram. How about mapping the colors to a set a set of real colors across the whole color space! That is, rather than binning just the 'red' value, why not count it in a 3-dimensional color bin (is what ever colorspace works best). That would generate a histogram that would truly represent the colors found within an image. Such a 3-d histogram metric could be a simple array of say 8x8x8 or 2048 bins. That is, a 2Kbyte metric. A color search would then locate the correct number of near by bins, and get an interpolated count of the nearby bins. Which would represent the number of colors 'close' to that color within the image! ### Foreground/background Color Separation Using -colors you can attempt to separate the image into foreground and background parts, by reducing the image to just two colors. Using a -median filter first will remove the effect of minor details, and line edges and noise that may be in the image. Of course that is not very good for mostly white sketch-like images. magick rose: -median 5 +dither -colors 2 \\ -depth 8 -format %c histogram:info:- This shows a red and a grey color as the predominant colors in the image. A trim/crop into the center of the image should then determine what is foreground and what is background. magick rose: -median 5 +dither -colors 2 \\ -trim +repage -gravity center -crop 50% \\ -depth 8 -format %c histogram:info:- Which shows the red 'rose' color is the predominant foreground color. Note that a landscape image may separate differently in that you get a lower ground color and an upper sky color. As such a rough look at how the colors were separated could be very useful for image type determination. Also a picture with some text 'spam' will often show a blob of color in one corner that is far more prominent that the rest of the image. If found redo with 3 colors, then erase that area with the most common 'background' color found before doing your final test. This technique is probably a good way of separating images into classes like 'skin tone' 'greenery' 'landscape' etc. ### Average Color Matrix A three by three matrix color scheme ("`-scale 3x3\!`") is a reasonable color classification scheme. It will separate, and group similar images together very well. For example sketches (all near white), gray-scale, landscapes, seascapes, rooms, faces, etc, will all be separated into basic and similar groups (in theory). This is also a reasonable metric to use for indexing images for generating [Photo Mosaics](http://libcaca.zoy.org/study/part7.html) . The output of the NetPBM image format is particularly suited to generating such a metric, as it can output just the pixel values as text numbers. Remember this would produce a 27 dimensional result, (3x3 colors of 3 value), so a multi-dimensional clustering algorithm may be needed. _Do you know of a good 3d clustering program/algorithm?_ For example, here is the 3 x 3 RGB colors (at depth 8) for the IM logo. magick logo: -scale 3x3\\! -compress none -depth 8 ppm:- |\\ sed '/^#/d' | tail -n +4 251 241 240 245 234 231 229 233 236 254 254 254 192 196 204 231 231 231 255 255 255 211 221 231 188 196 210 The above can be improved by using 16 bit values, and possibly cropping 10% of the borders to remove logo and framing junk that may have been added... magick logo: -gravity center -crop 80% -scale 3x3\\! \\ -compress none -depth 16 ppm:- | sed '/^#/d' | tail -n +4 63999 59442 58776 62326 58785 58178 51740 54203 54965 65277 65262 65166 45674 47023 49782 56375 55648 55601 65535 65535 65535 52406 55842 58941 44635 48423 52881 Of course like the previous average color metric, this will also have problems matching up images that have been color modified, such as hue, or brightness changes. (See next section) Also this metric can separate line drawings within its grouping, though only in a very general way. Such drawing will still be grouped more by the color of the background 'paper' rather than by content, and generally need a smaller 'threshold' of similarity, than color images.[](metric_cdiff_matrix) ### Color Difference Matrix The biggest problem with using the colors directly as a metric, is that you tie the image to a particular general color. This means any image that has been brightened or darkened, or its hue was changed, will not be grouped together. One solution to this is to somehow subtract the predominant or average color of the image from the metric, and using a matrix of colors makes this possible. Here for example I subtract the middle or center average color from all the surrounding colors in the matrix. magick logo: -gravity center -crop 80% -scale 3x3\\! -fx '.5+u-p{1,1}' \\ -compress none -depth 16 ppm:- | sed '/^#/d' | tail -n +4 51093 45187 41761 49419 44529 41163 38834 39947 37950 52371 51007 48152 32767 32767 32767 43469 41393 38587 52629 51279 48521 39500 41587 41926 31729 34168 35867 Note that I add .5 to the difference as you cannot save a negative color value in an image. Also the use of the slow "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator is acceptable as it only 9 pixels are processed. Note that the center pixel ("32767 32767 32767" at the start of the second line in the above) will not change much (any change is only due to slight rounding errors), and could be removed, from the result, reducing the metric to 24 dimensions (values). Alternatively, you can subtract the average color of the image from all 9 color values. magick logo: -scale 3x3\\! \\( +clone -scale 1x1 \\) -fx '.5+u-v.p{0,0}' \\ -compress none ppm:- | sed '/^#/d' | tail -n +4 38604 35917 34642 37011 33949 32441 32839 33841 33649 39447 39259 38369 23358 24377 25436 33538 33174 32426 39612 39434 38605 28225 30576 32319 22271 24381 27021 This also could be done by the metric comparator, rather than the metric generator. The metric still separates and clusters color images very well, placing similar images very closely together, regardless of any general color or brightness changes. It is still sensitive to contrast changes though. This metric modification could in fact be done during the comparison process so a raw [Color Matrix Metric](#metric_color_matrix) can still be used as a standard image metric to be collected, cached and compared. This is what I myself am now doing for large scale image comparisons. Unlike a straight color average, you can use this metric to differentiate between different line drawing images. However as line drawing use a linear color scale (all the colors fall in a line in the metric space, the differences between images is roughly 1/3 that of color images. As such a very different threshold is needed when comparing line drawings. Is thus still better to separate line drawings and grayscale images from color images. In other words this is one of the best metrics I have yet found for color images. Just be sure to determine what images are line drawings first and compare them separately using a much lower threshold. Lucky for us the metric itself can be used to do the separation of images into [greyscale](#type_grayscale) , or [linear color image](#type_linear) . Suggestions welcome.[](metric_diff_neigh) ### Difference Of Neighbours The above generates a 3x3 matrix, with the center pixel subtracted, and all the values offset to a perfect gray. However a better method is that instead of trying to save the color of the individual cells, to instead generate the differences between each cell and its neighbours (8 neighbours). That is, instead of saving the color of the top left corner, save the difference between that corner and the top-middle, center, and left-middle. Of course even with a small 3x3 array, you will end up with a signiture containing 12 differences, though you don't need to encode the full difference just a general difference level. such as equal, or large/small positive/negative difference values This is much more likely to find images that match even between images which contain wildly different colors, as the actual color play no part in the signature at all. The '[libpuzzle](http://libpuzzle.pureftpd.org/project/libpuzzle) ' image comparison library does exactly that though it uses a 9x9 matrix, with just the center pixels of each cell being averaged together. It also limits itself to grayscale versions of the image. The technique is completely defined in a postscript paper, [Image Signature for Any Kind of Image](http://www.cs.cmu.edu/~hcwong/Pdfs/icip02.ps) . The paper also goes into methods of storing that signature in a database and how to actuall perform a lookup to find of images with similar (not nessarially the same) signatures. It is the first paper I have discovered that actually goes into detail on how to do this. :-)[](metric_perceptual_hash) ### Perceptual Hash Reduce the image to an 8x8 and calulate an average intensity. Each bit of the 64-bit hash is then 1 if the pixel is above the average or 0 if its less than average. To compare the similarity between two images you simply compare the bitwise hashes, bit by bit, and returning a hamming distance. The closer the hamming distance, the more similar the images are. Anything above 21 / 64 is considered not similar. The [pHash](www.phash.org) eems to use YCbCr encoding. Some talk about working directly with the DCT from JPEG and the most promising works with the magnitude / phase and maps it to a log polar coordinate system. * * * Matching images better ---------------------- Miscellaneous notes and techniques I have either not tried or did not work very well for comparing larger images for more exact image matching.[](segmentation) ### Segmentation Color As you can see many of the above metrics use a blur/median filter followed by then color reduction techniques are basic attempts to simplify images to better allow them to be classified. However the [Color Quantization Operator](../quantize/#colors) is not really designed for this purpose. It's job is to reduce colors so as to highlight the important details of the image. For image comparison however we don't really want to highlight these features, but highlight areas of comparative interest. This is the job of a related color technique known segmentation... ASIDE: from Leptonica: Image segmentation is the division of the image into regions that have different properties. This operator blocks out areas of similar colors removing the detail from those areas. Then, when you compare the two images, you are comparing areas rather than low level details in the images. IM implements a segmentation algorithm, "`[-segment](https://imagemagick.org/script/command-line-options.php?#segment) `", for its implementation details see [SegmentImage()](https://imagemagick.org/www/api/segment.html) . Example: magick logo: -median 10 -segment 1x1 \\ +dither -scale 100x100\\! segment\_image.gif One problem is that -segment is VERY slow, and it only seems to work for larger images. Small images (like a rose: or a 100x100 scaled logo:) seems to result in just a single color being produced. This may be a bug. Of course you can still scale the image after segmenting it, as we did above. that way you can store a larger number of images in memory to compare with each other. Also the resulting segmentation does not seem to work very well, when compared to the image segmentation algorithm that Leptonica provides. See [Leptonica: Color Segmentation](http://www.leptonica.com/color-segmentation.html) . However an alternative to the IM segmentation, is to miss-use the color quantization function to find areas of similar color. Example: magick logo: -scale 100x100\\! -median 3 \\ -quantize YIQ +dither -colors 3 segment\_image.gif The disadvantage is that -color limits the number of color areas that may be present in an image, where segment tries to preserve similar areas, regardless of how many areas are really present in the image (or at least that is what it should do).[](edge_compare) ### Colorless Edge Comparison Image color is notoriously unreliable, particularly for cartoon like images. Different users could quite easily recolor such images, add different colors backgrounds, or even take a sketch and color it in. One way to match up such images is to some basic color reduction, as per method above, but then rather than comparing images based on the resulting color you perform an edge detection, and further processing so that only the outlines of the most important color changes are used for the metrics and comparison of the images. For example... magick logo: -scale 100x100\\! -median 3 \\ -quantize YIQ +dither -colors 3 -edge 1 \\ -colorspace gray -blur 0x1 outline\_image.gif An alternative may be to use the -lat (Local Area threshold) for edge detection, which may give you some better control... magick logo: -scale 100x100\\! -median 3 \\ -quantize YIQ +dither -colors 3 \\ -lat 3x3-5% -negate \\ -colorspace gray -blur 0x1 outline\_image.gif Of course for comparing you would use a line drawing comparison method. ??? how would you compare line drawings in a workable way ??? Multiply images together and see if resulting image added or reduced the intensity of the lines. Mis-Matching lines will become black. * * * Web Cameras What has changed in fixed cameras ----------------------------------------------- **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Walter Perry reports... The project I am working involves processing groups of 20 images sent from a surveillance camera in response to the camera sensing motion.  These cameras are at remote locations and once they detect motion the images are sent to a local server.  Once at the local server, I want to be able to "filter" out those images that do not contain what caused the event. I use PerlMagick to compare the first image in the series (which will always not contain anything other than the normal background) with the rest of the images.  I am getting an "average" difference for all the images and then if the individual difference is greater than the average difference I keep the image as it has something in it. This approach works great no matter day or night or what the lighting conditions.  I originally was trying to use just a percentage difference above the first image, but that was not too reliable and really depended on the lighting conditions.  Based on this comparison, I will then determine which images have "content" and those images which are empty of any motion. Once I obtain the only those images that contain "motion". * * * --- # Animation Modifications -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Animation Modifications =========================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Simple Modifications of Animations](#mods) * [Annotating](#annotating) - add a copyright notice over ALL frames * [Drawing](#draw) - modify a coalesced animation * [Frame By Frame](#frame_mod) - modify animations one frame at a time * [Cropping\_Smaller](#crop) - limit the area of the animation * [Crop the Canvas Too](#crop_viewport) - viewport cropping an animation * [Bounds Trimming](#trim) - automatic canvas size reduction * [Repositioning Frames](#repage_relative) - moving sub-frames around * [Reversing Animations](#reverse) - making animations run backward * [Patrol Cycles](#patrol) - cycle back and forth between two ends * [Color Morphing](#morph) - animated change between two images * [Resize Morphing](#morph_resize) - animated change in size * [Wipe](#wipe) - creating a wipe from one image to another * [Animated Distorts](#distort) - animated distortion of images * [Append a Label](#label) - add a label to an animation * [Remove Transparency (Flatten)](#remove_trans) - add colored background [![](../img_www/granitesm_right.gif) Animation Alpha Composition](#compose) * [Draw Images](#compose_draw) - overlay an image onto animation * [Layer Composition](#composite) - alpha composition for image lists * [Single Image Composition](#composite_single) - compose layer with single image * [Static Background](#background) - compose over a larger background [![](../img_www/granitesm_right.gif) All that Glitters...](#glitter) * [Glitter Animations](#glitter) - Animate a masked area of an animation * [Glitter Tiles](#glitter_tiles) - 'hole in the image' underlaying * [Sparkles](#sparkle) - overlaying transparent glitter * [Flares and Stars](#flares) - Seeding Flares and Stars onto images [![](../img_www/granitesm_right.gif) Resizing Animations](#resize) * [Problems Resizing Animations](#resize_problems) _(under construction)_ * [Resizing Animation Techniques](#resize_methods) _(under construction)_ * [Resize With Flatten](#resize_flatten) - A general solution * [Color Table Blowout](#resize_colors) * [Animation as Padded Thumbnails](#resize_thumbnail) [![](../img_www/granitesm_right.gif)Merging Multiple Animations](#merging) * [Serial or Time-wise Append](#serial) * [Side by Side Appending (time synced)](#append) * [Appending Animated Fonts](#append_fonts) * [Splitting up an Animation](#split) * [Merging Time Disjoint Animations](#merge) _(under construction)_ This page contains practical examples of working with GIF animations. It is highly recommended that you read and understand the [Basics of Animations](../anim_basics/) and at least the overall handling of [Optimizing GIF Animations](../anim_opt/) , before trying to understand these examples. * * * Simple Modifications of Animations ---------------------------------- ### First an Important point DO NOT save the intermediate, animations which you are not finished processing, directly to GIF, especially images that you have yet to perform any sort of [Semi-Transparency Handling](../anim_opt/#semitrans_opt) or [Color Optimization](../anim_opt/#color_opt) . If you made the big mistake of saving to GIF you would have just made the resulting animation worse, as IM would have now performed an automatic [Color Quantization](../quantize/#colors) , to reduce the number of colors present to fit the images into the limited GIF format. Not only that but it did each frame completely separately to every other frame, producing different color selections and dither patterns. That is, turn makes any further processing, particularly any [Frame Optimization](../anim_opt/#frame_opt) just that much harder. This is especially important for resized GIF animations, or ones you have added a multi-color overlay or underlay, as this can add a lot of extra colors. You can use the IM internal format MIFF, as a temporary file format if you want to work on an animation in steps or use individual PNG format images for each of the frames being edited. Just do not do the final save to GIF unless you are now sure you will not have color problems. I repeat... **Do not use GIF as an intermediate file format, use MIFF, or PNG images.** ### Annotating \- add a copyright notice over ALL frames As of IM version 6.2.6, you can "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" an animation, in similar way to that detailed in [Annotating on top of Images](../annotating/#anno_on) , simply by doing so. For example, here we annotate the [previous dispose animation](../anim_basics/#previous) created in [Animation Basics](../anim_basics/) . magick canvas\_prev.gif -gravity center \\ -fill black -annotate +1+1 "Copyright" \\ -fill white -annotate +0+0 "Copyright" \\ annotate.gif gif\_anim\_montage annotate.gif annotate\_frames.gif [![[IM Output]](annotate.gif)](annotate.gif) [![[IM Output]](annotate_frames.gif)](annotate_frames.gif) The reason this works, is that "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" will position text relative to the virtual canvas of an image, and not relative to the actual image data. As such the position of the text on each frame is correct for an animated image. Before version 6.2.6 however "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `", like many other image operators, positioned information, and overlays, relative to the actual image, and ignored any page or virtual canvas offset a sub-frame may have. One word of warning, drawing on an animation like this, without first [Coalescing](../anim_basics/#coalesce) the animation, can cause some unusual effects, due to an animations existing optimization scheme (see next set of examples). As such (and as you will see) removing any existing frame and transparency optimizations by [Coalescing](../anim_basics/#coalesce) it first is recommended. ### Drawing \- modify a coalesced animation Now while "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" places text relative to the virtual canvas of each frame, many other images operations do not. This includes all "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operations, which only draw things relative to the actual image, and completely ignore any offset it may have on a larger canvas. For example, here we draw a fancy green circle near the top left corner of the [previous dispose animation](../anim_basics/#previous) . magick canvas\_prev.gif -fill LimeGreen -stroke SeaGreen \\ -draw 'circle 35,35 20,30' draw\_circle\_fail.gif gif\_anim\_montage draw\_circle\_fail.gif draw\_circle\_fail\_frames.gif [![[IM Output]](draw_circle_fail.gif)](draw_circle_fail.gif) [![[IM Output]](draw_circle_fail_frames.gif)](draw_circle_fail_frames.gif) Well as you can see "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" drew the circle relative to the 'actual image', rather than the larger virtual (page) canvas the image is part of. The result is, as is typical in this sort of situation... a mess. The simple solution to this is to first [Coalesce](../anim_basics/#coalesce) the animation, before drawing, then re-optimise the GIF animation afterwards. See [Optimizing Animations](../anim_opt/) for details. magick canvas\_prev.gif -coalesce \\ -fill LimeGreen -stroke SeaGreen -draw 'circle 35,35 20,30' \\ -layers Optimize draw\_circle.gif gif\_anim\_montage draw\_circle.gif draw\_circle\_frames.gif [![[IM Output]](draw_circle.gif)](draw_circle.gif) [![[IM Output]](draw_circle_frames.gif)](draw_circle_frames.gif) Note how the IM animation optimizer actually decided to just not overwrite the part that was drawn on. This is actually more optimal than if it had drawn on the actual sub-frame images themselves. This method will let you overlay any sort of annotation, copyright notice, or watermark you like. Of course you may need to use the special [Layers Composition](#composite) technique to actually overlay an image onto every frame in an animation. If you get really good you can even do so far as doing [Animation Merging](#merging) to overlay an animated copyright notice on your animation. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _While this 'coalesce-optimize' technique will work with most operations involving animations, especially with IM's optimizer, there are some operations that do such drastic changes to images, such as major color changes, and shadings, and with semi-transparency, that the resulting animation failing to optimize very well.

For example just about any "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" operation is likely to produce an animation that will optimize very badly afterward due major color changes. See [Resizing Animations](#resize)
below for solutions to this.

_ | ### Frame by Frame \- modifying one frame at a time By using the IM [Image List or Sequence Operators](../basics/#image_seq) you can modify each frame of the animation separately. The trick is to extract each frame in parenthesis, modify it, then replace the original image with the modified version. For example, here we add text as a copyright watermark into the animation, as an animation itself, making it even harder to remove. So as not to completely destroy the animation, I also used semi-transparent colors. magick canvas\_prev.gif -coalesce -gravity center \\ -font Ravie -pointsize 24 -fill '#FFF8' -stroke '#0008' \\ \\( -clone 0 -annotate 0 'This' \\) -swap 0 +delete \\ \\( -clone 1 -annotate 0 'This' \\) -swap 1 +delete \\ \\( -clone 2 -annotate 0 'image' \\) -swap 2 +delete \\ \\( -clone 3 -annotate 0 'is' \\) -swap 3 +delete \\ \\( -clone 4 -annotate 0 'Copy\\nright' \\) -swap 4 +delete \\ -layers OptimizeFrame frame\_mod.gif gif\_anim\_montage frame\_mod.gif frame\_mod\_frames.gif [![[IM Output]](frame_mod.gif)](frame_mod.gif) [![[IM Output]](frame_mod_frames.gif)](frame_mod_frames.gif) Note the use of [Parenthesis](../basics/#parenthesis) , to limit the effect of the "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" operation to just a simple 'clone' of one frame of the animation. The modified image is then returned to its proper position in the image sequence using the [Swap](../basics#swap) and [Delete](../basics#delete) operators. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The single number usage in the "`[-swap](https://imagemagick.org/script/command-line-options.php?#swap) `" operator was added in IM v6.3.4-3. before this you would need to specify "`-swap 3`" as "`-swap -1,3`", for it to work properly._ | This technique of modifying individual frames will probably be one of the most important techniques in manipulating image animations you will encounter. You will also notice that I actually added the same text to both the first and second image. The first image in the above animation is a [Zero Delay Intermediate Frame](../anim_basics/#zero) , which is used to define the background for the rest of this animation. That is, it flashes by so fast, it is not usually visible to the users, nor is it meant to be visible. Thus the first two actual frames in the above animation should be regarded as a single visible frame, rather than two separate frames.. The frame with a non-zero time delay is the last frame of a 'display' frame sequence. Similarly for other fast running animations, you may need to modify a number of frames to make your change visible for any appreciable length of time. This is not a problem for a static annotation that was drawn over all the frames (see previous [Annotating](#annotating) example above). This brings us to an important point about GIF animations. **Study an animation before attempting to modifying it. It can make a BIG difference to the final result.** ### Cropping \- limit the area of animation IM has endeavored to make the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" image operation work correctly relative to an images virtual canvas rather than to the actual image (IM version 6.1.1 onward). This in turn allows you to do things previously not directly possible. For example crop the images of a GIF animation and still have it work as expected for all animations. magick canvas_prev.gif -crop 50x50+3+30 cropped.gif gif_anim_montage cropped.gif cropped_frames.gif [![[IM Output]](cropped_frames.gif)](cropped_frames.gif) [![[IM Output]](cropped.gif)](cropped.gif) As you can see the crop worked, just like it would for a [cropping a single image](../crop/) , preserving the appropriate offset and page size, so the image data is still positioned correctly, even though the area involved has been reduced. As you can see this did not change the overall virtual canvas size! | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Do **not** use "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" to remove the crop offsets from a frame optimized GIF animation. Doing do will also remove the needed frame offsets that the position the sub-frames on the virtual canvas, and which later frames may rely on to animate correctly._ | The above "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operation did however produce a warning message... [![[IM Text]](cropped_error.txt.gif)](cropped_error.txt) As the crop of one of the frames in the animation missed the sub-frame overlay image used for that frame. that is one frame did not update the area that was cropped from teh animation. As a result that frame now does not contain any real image! To compensate, IM not only produces a warning message, but generates a special '[Missed Image](../crop/#crop_missed) ' as a placeholder in the animation to keep everything in order, and preserve any 'delay' or 'disposal' methods attached to that frame. You can leave that placeholder, or fix it as you like. In this case the '[Missed Image](../crop/#crop_missed) ' is needed for the animation to run as expected. However if multiple consecutive missed images are generated, you can probably merge them together into a single missed image using the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`[RemoveDups](../anim_opt/#removedups) `'. Caution and study of the animation is however still recommended. (See [Splitting up an Animation](#split) below, for a more detailed example of this. ### Crop the Canvas Too \- viewport crop of the animation Just as a normal crop, preserved the virtual canvas of the original images, so did a crop of an animation. This is probably not the intent in this case. Because of this, in IM version 6.2.4-5, a special flag '`!`' was added to the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument. This flag will cause crop to not only crop the individual image frames, but also adjust the page or canvas information about the image to that same area. This is known as a 'viewport crop', as the result will be as if you are looking at the image though a 'window' or 'viewport' of the size and position of the crop argument. Not only is the size of the virtual canvas set to the size of the crop area, but the offset of each frame in the animation is adjusted to keep things correct. (See [Viewport Crop with Canvas/Page Adjustments](../crop/#crop_viewport) ). For example lets repeat the previous crop, but also crop the canvas information using the '`!`' flag... magick canvas\_prev.gif -quiet -crop 50x50+3+30\\! crop\_viewport.gif gif\_anim\_montage crop\_viewport.gif crop\_viewport\_frames.gif [![[IM Output]](crop_viewport_frames.gif)](crop_viewport_frames.gif) [![[IM Output]](crop_viewport.gif)](crop_viewport.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The '`!`' character has special significance to some UNIX shells, like "`csh`", and must be escaped with a backslash, even when placed inside quotes. IM will ignore backslashes, in geometry arguments so it does not hurt to always backslash it._ | As you can see the result is more like what you probably really wanted to achieve when cropping an animated image. Note that I included a "`[-quiet](https://imagemagick.org/script/command-line-options.php?#quiet) `" setting to ask IM not to give the warning message about the [Missed Image](../crop/#crop_missed) , that we generated in the previous crop attempt. This is recommended whenever cropping animations, as the warning does not really apply. Note that a [Viewport Crop](../crop/#crop_viewport) will also allow you to increase the canvas area or even re-position everything within the canvas. However it is dangerous as any images which fall partially or completely outside the crop area will be cut down to only show the part of the image that appears within that area. Just one final word of warning. When using a 'viewport crop' the frame images are moved in the negative direction to the offset given for the 'viewport'. This can appear illogical, unless you remember that the offset in the crop operator is the position of the viewport, and not a direct re-position of the images themselves. ### Bounds Trimming \- automatic canvas size correction As with the previous operations trimming an animation can be tricky. If the animation consists of a simple [Cleared Frame Animation](../anim_basics/#cleared) , then you can trim an animation simply by working out the maximum bounds of all the individual frames within the animation. As of IM v6.3.4-8 you can do this very easily using a '`TrimBounds`' layer method. magick anim\_bgnd.gif -layers TrimBounds anim\_trim\_bounds.gif [![[IM Output]](../anim_basics/anim_bgnd.gif)](../anim_basics/anim_bgnd.gif) ![==>](../img_www/right.gif) [![[IM Output]](anim_trim_bounds.gif)](anim_trim_bounds.gif) For users before this version of IM you can still do the same thing, but only in a two step process (which also performs other unwanted processing). To do this you would use a [Layers Merge](../layers/#merge) to merge all the frames of an animation down to a single layer, and then have IM report the size and offset of that layer... magick anim_bgnd.gif -layers merge -format '%wx%h%X%Y' info: [![[IM Text]](anim_trim_bounds.txt.gif)](anim_trim_bounds.txt) Now that you know the bounds of all the frames, you can just [Viewport Crop](#crop_viewport) the whole animation to this size. magick anim\_bgnd.gif -crop 89x77+5+10! anim\_trim\_crop.gif [![[IM Output]](../anim_basics/anim_bgnd.gif)](../anim_basics/anim_bgnd.gif) ![==>](../img_www/right.gif) [![[IM Output]](anim_trim_crop.gif)](anim_trim_crop.gif) If you also want to trim a static background from an animation then your best bet is to delete the first frame from a [Frame Optimized](../anim_opt/#frame_opt) animation, before using the [Layers Merge](../layers/#merge) step. You can then use the returned bounds for the [Viewport Crop](#crop_viewport) on the original animation. ### Repositioning Frames A similar and related operation is the 'relative repage' operator. This will add the given offset to all the individual sub-frame layers of the animation, allowing you to adjust their positions relative to the whole canvas. To make a "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operation relative, you also add a '`!`' flag to its argument. For example, here we displace the second an later frames of an animation 30 pixels down and right, returning the first 'background' frame in its normal '`+0+0` position. magick canvas\_prev.gif -repage 0x0+30+30\\! \\ \\( -clone 0 -repage +0+0 \\) -swap 0,-1 +delete \\ repage\_offset.gif `magick identify repage_offset.gif` [![[IM Output]](repage_offset.gif)](repage_offset.gif) [![[IM Text]](repage_offset.txt.gif)](repage_offset.txt) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The above animation will fail (show only the first two frames) for Windows Internet Explorer version 8. This happens any time a frame attempts to draw an image beyond the bounds of the animation canvas._ | Notice that none of the images have been 'cropped' or cut down. Only their positions have been changed, relative to the original background image, even if the image was moved 'off canvas'.If you like, you may also like to expand the canvas to match these new bounds, either by adjusting the canvas size directly... magick repage\_offset.gif -repage 130x130 repage\_canvas.gif [![[IM Output]](repage_canvas.gif)](repage_canvas.gif) By using the [Bounds Trim Layers Method](#trim) you can automatically expand the animations bounds just enough to include the images which were now being placed 'out-of-bounds'... magick repage\_offset.gif -layers TrimBounds repage\_bounds.gif [![[IM Output]](repage_bounds.gif)](repage_bounds.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Using "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" to move images left or up, especially with a small canvas, is likely to fail for GIF animations. This format basically cannot use a negative image offset.

For that you may be better off also applying a 'viewport crop', or using the 'trim bounds' to shift all the offsets into a larger positive canvas. Either method will guarantee a positive offset to all the image frames.

The PNG and MNG formats can handle negative offsets, but many web browsers and other programs may not understand such offsets, producing weird effects. One version of the "`Firefox`" web browser for example produces extremely large images, when attempting to display a PNG with a negative offset._ | ### Reversing Animations \- making animations run backward, or cycle As of IM v6.3.3, the "`[-reverse](https://imagemagick.org/script/command-line-options.php?#reverse) `" image sequence operator was added (see [Reverse Operator](../basics/#reverse) for more details). This allows you very simply reverse the order of a coalesced animation sequence. For example, here I make a 'hand draw k' animation become undrawn! magick script\_k.gif -coalesce -reverse \\ -quiet -layers OptimizePlus -loop 0 reversed.gif [![[IM Output]](reversed.gif)](reversed.gif) I had to re-add the "`[-loop](https://imagemagick.org/script/command-line-options.php?#loop) `" option to the above as this needs to be attached to the first image, which is now the last image! The result could also use some timing adjustments, but as you can see it now 'undraws' the letter! Be sure to "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" the image sequence before reversing it, as any [Frame Optimizations](../anim_opt/#frame_opt) present are dependant on the image order. Better to remove those optimizations first. ### Patrol Cycles \- cycle back and forth between two ends A similar technique is to add a reversed order of frames to the end of the animation, so the resulting animation cycles between the first and last frames of the original animation. It's a bit like a guard walking a patrol between two points, and is called a 'Patrol Cycle'. Here I use the image [Duplicate Operator](../basics/#duplicate) (added to IM v6.6.8-7) to generate the extra frames (reversed). magick script\_k.gif -coalesce -duplicate 1,-2-1 \\ -quiet -layers OptimizePlus -loop 0 patrol\_cycle.gif [![[IM Output]](patrol_cycle.gif)](patrol_cycle.gif) Notice that I didn't just copy all the images of the animation, but skipped copying the very first and last image of the original sequence. If I had copied all the images, the first and last images would appear for twice the expected period of time, and make the animation file larger than is needed. Even so, you should again watch out for [Zero Delay Intermediate Frames](../anim_basics/#zero) at the start and end of the animation, as these can result in unexpected problems. Basically do not do this without studying the animation first, or you are asking for trouble. Also to allow better optimization of the result, you may even need to add some extra [Zero Delay Intermediate Frames](../anim_basics/#zero) , between the forward and reverse cycles, to improve optimization. These extra frames were probably not provided in the original animation optimization as the whole animation normally resets when it loops. See [Splitting Frame Updates](../anim_opt/#splitting) for more details of how these extra frames help optimize and improve the animation. Here is an older method using the [Clone Operator](../basics/#clone) to generate duplicate frames. magick script\_k.gif -coalesce \\( -clone -2-1 \\) \\ -quiet -layers OptimizePlus -loop 0 patrol\_cycle\_2.gif [![[IM Output]](patrol_cycle_2.gif)](patrol_cycle_2.gif) ### Color Morphing \- animated change between two images The "`[-morph](https://imagemagick.org/script/command-line-options.php?#morph) `" operator is an especially interesting operator. It will take a list of images, and insert extra frames between them, so as to do a soft color change from one image to the next. This operator is not however a true 'morph' as it only modifies the pixels color creating a sequence of [Blended Images](../compose/#blend) . A true movie like 'morph' also involves image [Distortion](../distorts) to transform the outline of the object in the image to the objects in the other image. For example, here I create a [Patrol Cycle](#patrol) using a color morph to generate the extra frames between the rose image and its flipped form. magick -delay 20 rose: \\( +clone -flip \\) -morph 5 \\ -duplicate 1,-2-1 rose\_flip.gif [![[IM Output]](rose_flip.gif)](rose_flip.gif) This is not particularly good as all the images have the same delay. The result is that the animation never seems to 'rest' or pause between the two end points of the cycle. A better solution would be to have a pause on the original and its 'flipped' form. That however requires you adjust the delays of the original images to be different to the morphing images. magick rose: \\( +clone -flip \\) -morph 5 -set delay 10 \\ \\( -clone 0 -set delay 240 \\) -swap 0 +delete \\ \\( +clone -set delay 240 \\) +swap +delete \\ -duplicate 1,-2-1 rose\_flip\_pause.gif [![[IM Output]](rose_flip_pause.gif)](rose_flip_pause.gif) As you can see the timing delays can become very important for generating a good animations, allowing the animation to 'rest' at just the right points. As of IM v6.6.9 you can set the delay using a [FX Percent Escapes](../transform/#fx_escapes) calculating based on the index of the image. Here the FX expression says use a delay of 10 if the image ingex is not the first (t=0) or the last (t=n-1), otherwise use larger value. magick rose: \\( +clone -flip \\) -morph 5 \\ -set delay '%\[fx:(t>0&&t0&&t0&&t and [FX Percent Escapes](../transform/#fx_escapes)
involving image indexes, such as '`%p`', '`%n`', '`%[fx:t]`' and '`%[fx:n]`' were broken. Typically they would only return unhelpful values of either '`0`' or '`1`', and not the actual index and number of images in the current image sequence._ | ### Append a Label \- add a label to whole animation As always there are a number of ways to actually append a label to an image. For example, for animations that has an initial background canvas, or one that only overlays new color to previous frames, then you can just append the label to the first frame of the image. The other frames will not remove it.Here we just add some extra space with "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `", and "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" some text in it. magick canvas\_prev.gif \\ \\( -clone 0 -coalesce -gravity South -background white \\ -splice 0x18 -annotate 0 'Label First' \\) \\ -swap -1,0 +delete label\_first.gif [![[IM Output]](label_first.gif)](label_first.gif) However this only works for some animations, It would not work for a common [Cleared Frame Animation](../anim_basics/#cleared) which clears or replaces all the pixels after each frame has been displayed. For a more general method that works for all animations, we need to first "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" the animation to the un-optimized [Coalesced Animation](#coalesced) . Then we can add the label to each and every coalesced frame of the animation, before re-optimizing it. magick canvas\_prev.gif -coalesce \\ -gravity South -background white -splice 0x18 \\ -annotate 0 'A Better Label' \\ -layers Optimize labeled\_anim.gif [![[IM Output]](labeled_anim.gif)](labeled_anim.gif) Rather than using "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" to draw text into the added extra space, you can use a composition method (see next sections) to compose an image into the added space. That way you can prepare a much fancier label to add to the animation. Of course doing this can cause some animations not to optimize very well afterward, especially [Cleared Frame Animations](../anim_basics/#cleared) , but that is the price you pay for adding labels. One solution for that type of animation is to prepend a 'initial background canvas' that contains the label, as shon in the section explainging [Cleared Frame Animations](../anim_basics/#cleared) . Also note that adding a label to an animation can result in many extra colors being added. This could overflow the GIF color limits, as such you may have to be prepared to color optimize your animation as well. A very difficult task that is best to avoid if possible (see [Color Optimization](../anim_opt/#color_opt) ). This can be a problem for any general modification to any animation. ### Remove Transparency \- add a solid color background A large number of animations you find on the web have a transparent background. These are very useful as you can place them on web pages without needing to worry about any background pattern that may be present. However when processing animations, especially when applying other image operators such as "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" and "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `", such an animation has problems. The general solution is [Remove Transparency](../masking/#remove) from the image, generally by somehow overlaying them onto a specific color, such as the specific color that us used as the background to a web page. [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) For example, here I have a simple transparent overlay animation of a letter 'K' being drawn as if by an invisible hand. As this GIF animation is drawn with transparency, and only overlays images onto the previous frames (adding pixels, never removing them), a simple way of setting a background color (or image) is to add it to just the first frame of the animation. All the other frames contain a transparent color for the background, so will not effect the result. Here we use the [Flatten Operator](../layers/#flatten) to overlay the first frame of the animation onto a '`LimeGreen`' background color. We can use "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" for this as we are only applying it to a single image, and NOT the whole animation. magick script\_k.gif \\( -clone 0 -background LimeGreen -flatten \\) \\ -swap 0,-1 +delete script\_k\_flatten\_0.gif [![[IM Output]](script_k_flatten_0.gif)](script_k_flatten_0.gif) It is also important to not that the original first frame was only a single pixel in size. The [Flatten Operator](../layers/#flatten) not only colored the background, but also expanded that frame to its full size. that is it 'filled out' the frame as well. Note however that as only the first frame of the animation has been colored. This method is preferred, as any optimization (such as the heavy optimization that this animation contains) is preserved. Coloring the first frame will not work for all GIF animations. It only works for simple [Overlay Animations](../anim_basics/#overlay) . For a general method of removing the transparency from an animation, you need to first "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" the animation, and then actually [Remove Transparency](../masking/#remove) from all the frames, using the [Alpha Remove Operator](../masking/#alpha_remove) . This time lets do this using a '`Tomato`' background color. magick script\_k.gif -coalesce -background Tomato -alpha remove \\ -layers Optimize script\_k\_alpha\_rm.gif [![[IM Output]](script_k_alpha_rm.gif)](script_k_alpha_rm.gif) Of course the resulting optimization may not be the as optimal as the original, but the animation no longer has any transparency in it. As an additional side-effect, any '`[Background](../anim_basics/#background) `' dispose settings in the animation will have been converted to either '`[None](../anim_basics/#none) `' or '`[Previous](../anim_basics/#previous) `', by the [Frame Optimization](../anim_opt/#frame_opt) process, as transparency is no longer an issue. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _[Alpha Remove](../masking/#alpha_remove)
was added to IM v6.7.5. If your IM version is older you will need to use an alternative method such as using a side effect of the [Border Operator](../crop/#border)
. See [Remove Transparency](../masking/#remove)
for details of this and other methods._ | A more complex background handling such as underlaying a background image or pattern, requires a much more complex handling of animations, than the simple modifications we have looked at so far. This is what we will look at next. * * * Multi-Image Alpha Composition ----------------------------- The next level of animation handling requires you to be able to compose single static images either over, or under an existing animation. That is, general [Alpha Composition](../compose/#compose) . This gets even trickier when two separate sets of images are being merged. Before IM v6.3.3-7 multi-list composition was only possible using specially designed API scripts, or shell scripts that saved and merged individual frames of the animation. Neither was very nice techniques, but that was all that was possible. That is, now changed. ### Draw Images \- draw an image onto a list of images The "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator has the ability to compose a _source_ image on top of a list of images. It is also the only multi-image alpha composition method that you could use in the "`[mogrify](../basics/#mogrify) `" command, or against multiple images, before IM v6.3.3-7. The reason this Alpha Composition technique was so important was because it allowed you to specify an image as a separate argument to the current image list. That is, within the quoted [Magick Vector Graphic](../draw/#mvg) language of "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `". Because of its historical importance, I will show its use in detail, especially for users which still have older versions of IM.For example, here I overlay rose image over the whole animation. magick canvas\_prev.gif -coalesce \\ -gravity NorthEast -draw 'image over 5,5 0,0 "rose:"' \\ -layers Optimize draw\_over.gif [![[IM Output]](draw_over.gif)](draw_over.gif) This allows you to [Compose](../compose/#compose) an external _source_ image over every image in the current image sequence. This is good enough for most purposes. For example by using the '`[Dst_Over](../compose/#dstover) `' composition method you could also place an image 'under' the animation as a static background. For example, here we 'underlay' a "`netscape:`" built-in image, though it could have been any external image file... magick script\_k.gif -coalesce \\ -draw 'image DstOver 0,0 0,0 "netscape:"' \\ -layers Optimize script\_k\_netscape.gif [![[IM Output]](script_k_netscape.gif)](script_k_netscape.gif) Note that the size of the animation has not changed, as it is the _destination_ images define the final size of the alpha composition. If you did want to create a larger canvas, you had to adjust the size and offsets of the animation appropriately to accomidate the background. For example using a [Relative Repage](#repage_relative) of the animation before coalescing. magick script\_k.gif -repage 100x100+20+20\\! -coalesce \\ -draw 'image DstOver 0,0 0,0 "granite:"' \\ -layers Optimize script\_k\_granite.gif [![[IM Output]](script_k_granite.gif)](script_k_granite.gif) Also if you wanted to use an image that had already been read-in, created, or modified, then you need to use a "[MPR: Memory Program Register](../files/#mpr) to provide you with a 'read source' for that image. magick -size 53x54 xc:SkyBlue -fill DodgerBlue \\ -draw 'circle 26,27 24,8' -write mpr:bgnd +delete \\ \\ script\_k.gif -coalesce \\ -draw 'image DstOver 0,0 0,0 "mpr:bgnd"' \\ -layers Optimize script\_k\_mpr\_bg.gif [![[IM Output]](script_k_mpr_bg.gif)](script_k_mpr_bg.gif) That is, about the limit of Draw Alpha Composition methods. No overlaying the animation images 'over' a _destination_ image of unknown size, and no way to merge two separate multi-image sequences together. That was until... ### Layers Composition \- alpha composition for image lists With IM v6.3.3-7 the "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) `" method, '`**Composite**`' was added allowing you compose two completely separate sets of images together. (For a short summary see [Layering Images, Layer Composite](../layers/#layer_composite) )To do this on the command line, a special '`[null:](../files/#null) `' marker image is needed to define where the first _destination_ list of images ends and the overlaid _source_ image list begins. But that is the only real complication of this method. So lets try it out by creating a set of shadows from set of images, then overlaying the original image over those shadow images... magick script\_k.gif -coalesce coalesced\_k.gif magick coalesced\_k.gif -background black -shadow 100x3+2+5 \\ -background SkyBlue -alpha remove shadows\_k.gif magick shadows\_k.gif null: coalesced\_k.gif \\ -layers Composite compose\_shadow.gif gif\_anim\_montage compose\_shadow.gif compose\_shadow\_frames.gif [![[IM Output]](coalesced_k.gif)](coalesced_k.gif) [![[IM Output]](shadows_k.gif)](shadows_k.gif) [![[IM Output]](compose_shadow.gif)](compose_shadow.gif) [![[IM Output]](compose_shadow_frames.gif)](compose_shadow_frames.gif) The above example is very important, so I will explain it in detail. First we generate a [Coalesced](../anim_basics/#coalesce) version of our animation so as to remove any [Optimizations](../anim_opt/) that may be present to make the animation ready for some serious processing, without any GIF optimizations interfering with the processing. Next we created an animated shadow image from our coalesced animation, and [Remove Transparency](#remove_trans) , as GIF cannot handle semi-transparent shadows. This is the animation that want to add 'under' our original animation. It has the same number of frames, and even the same timings as the original animation. This correspondence is important, so don't forget it. Now we read in the two animation or layer sequences, but we add a special '`[null:](../files/#null) `' image separator between them, so that ImageMagick knows when one sequence ends and the next sequence begins. This image separator is automatically removed by the next all important "`-layer composite`" operation. Other API's should be able to use separate 'Wands' of images, rather than a single sequence with a special separator. The layers composition is then performed just as if these two animations or image sequences were just a simple single image, rather than a sequence of multiple images. Each pair of images, one destination, and one source, are composited together, to generating a merged (composited) sequence on images. The final result is that we have added shadows to our original animation sequence, which is ready for GIF optimizations, or just direct use. Now you can do all the above steps in a single command. However you can't just use "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `" to create a copy of the original sequence, since we don't really know (or want to know) how many images are in the sequence. Instead you can use a "[MPR: Memory Program Register](../files/#mpr) to save a whole list of images. It's sort of like taking a snapshot of the whole image sequence currently in memory, and then reading it in again later. The result is a command like this, though I used a different colored background. magick script\_k.gif -coalesce -write mpr:images \\ -background black -shadow 100x3+2+5 \\ -bordercolor Wheat -border 0 \\ null: mpr:images -layers Composite \\ magick composite\_shadow.gif [![[IM Output]](composite_shadow.gif)](composite_shadow.gif) This version actually works better as we did not loose the offset information that the [Shadow Operator](../blur/#shadow) generates (GIF's cannot save a negative offset, so resets it to zero). We could fix that in the above by using a MIFF file format for the intermediate images rather than GIF, or, as you will see in the next example, by using a "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geomtry) `" composition offset. Basically these examples shows that the [Layers Composite Operator](#composite) actually understands the individual Virtual Canvas Offset ("`[-page](https://imagemagick.org/script/command-line-options.php?#page) `") settings and will handle them, just like a [Layers Flatten](../layers/#flatten) or better still [Layers Merge](../layers/#merge) operators would handle them. But the [Layers Composite Operator](#composite) also understands the use of a Composite Geometry ("`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `") offset (zero by default), to control the overall placement of the whole overlay image sequence. It even understands the effects of "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" on that global offset. For example.. let's overlay our original 'K' animation 'South' of the generated shadow animation... magick shadows\_k.gif null: coalesced\_k.gif \\ -geometry +0-10 -gravity South -layers Composite \\ magick composite\_south.gif [![[IM Output]](composite_south.gif)](composite_south.gif) The above also shows that just like normal two image [Alpha Composition](../compose/#compose) , it is the destination image sequence that controls the final output image size, and any composition overlay will be clipped to the destination canvas image. As such you should ensure all the destination images is large enough to contain your final results. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The resize capability of "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" is not strictly part of the composite operation, it only resizes the last image of the current image sequence. As such it will not do what you expect if used with multi-image [Layers Composition](../#composite)
. See [Resize Geometry](../resize/#geometry)
for details._ | Basically Layers Composition is very much like normal composition. Quite simple really. _Did I say simple?_ **Layers Composition details...**...As you saw above the command line version of "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) Composite`" uses the first '`[null:](../files/#null) `' image found in the current image list as a marker to separate the two lists. The two image lists are separated and the '`null:`' junked before the two lists are [Alpha Composited](../compose/#compose) together, two images at a time. Only an image generated from the special '`[null:](../files/#null) `' image source can be used for the marker, and if not found an error will be reported. You currently cannot read this '`[null:](../files/#null) `' marker image from a pipeline (at least not at this point), only generate it when needed. Layer composition is also rather more complex than a simple, two image [Alpha Composition](../compose/#compose) , as the images virtual canvas of the image list also accounted for. Normally alpha composition ignores any virtual canvas size and offset for positioning purposes, using only the images actual size. This special layers method uses the virtual canvas information, for geometry positioning, so as to align the two image sequences. To this end any virtual canvas offset a sub-frame has is also added to the normal "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" adjusted, "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" composition offset, to work out the position of the image overlay. Only the virtual "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" canvas size of the first image of each list is used to work out the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" adjustment to the "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" composition offset. The canvas size of later images is ignored, with only the individual virtual "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" offset being added to the calculated "`[-geometry](https://imagemagick.org/script/command-line-options.php?#geometry) `" offset. In other words "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) Composite`" is designed for alpha composition of 'layers' or 'animations', and the special requirements of such image lists. **Caveats**...You do however still need to be careful with image lists you are overlaying. If for example if the _destination_ list images are not large enough, or positioned incorrectly to contain the overlaid _source_ image, the overlaid image will be clipped, or miss the destination image completely. For this reason it is a good idea to [Coalesce](../anim_basics/#coalesce) the _destination_ images to the full canvas size, before overlaying smaller _source_ images. For example see [Side-by-Size Animation Append](#append) examples below where canvas size needed to be expanded to provide space for the appended images. Also if the _source_ image list is an GIF animation, then you may need to be sure that the sub-frames are clean of things like: [Compression Optimizations](../anim_opt/#compress_opt) , and fancy [Frame Optimizations](../anim_opt/#frame_opt) ; or you may have problems. On the other hand a [Cleared Frame Animation](../anim_basics/#cleared) or [Coalesced Animation](../anim_basics/#coalesced) can be directly '`[Composite](#composite) `' without any problems. Just remember that [Layers Composition](#composite) does not understand any existing [GIF Disposal Methods](../anim_basics/#dispose) that may be present in the images, though it preserves the _destination_ GIF animation meta-data, such as: [Dispose Method](../anim_basics/#dispose) , [Frame Delay](../anim_basics/#delay) , and [Iteration Loop Limits](../anim_basics/#loop) . The one exception to this is given in a special case below. ### Single Image Composition \- compose images with a single image Normally two lists of images of equal length are composed together, one image pair at a time until either of the image lists runs out. Neither list of images will be repeated. The composition will just stop. You are left with just the original _destination_ image list with the added compositions. The '`[null:](../files/#null) `' separator image, and all the _source_ images are deleted from the current image list. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _An API interface to this layers method, should allow you produce two separate image lists, and it will be left up to you to delete both input image lists that was used to generate the resulting list of images. The '`[null:](../files/#null) `' separator should not be needed._ | However if one of the lists only contains a single image, that image will be composed against all the images in the other list. It does not matter if that single image is a _source_ image or a _destination_ image. The method will do the composition against the other image list, and preserve the GIF meta-data of the _image list_, rather than the single image, even if that image is the _destination_ image. This 'compose against a single image' is a special case for [Layers Composition](#composite) , and is very useful for adding a background to an animation (see next), or inserting a static object into an animation. ### Static Background \- compose over a larger background For example using this special [Single Image Layer Composition](#composite_single) method we can compose an animation over a a static background... magick -size 100x100 plasma:fractal null: \\( script\_k.gif -coalesce \\) \\ -gravity Center -layers Composite \\ -layers Optimize magick composite\_background.gif [![[IM Output]](composite_background.gif)](composite_background.gif) As the background image is the _destination_, it defines the final size of the animation, but all the meta-data (delays, labels, comments, etc) will come from the source image list. Normally that information comes from the destination image list. This is only time the source image provides the meta-data information during an image composition. Also note that as [Layers Composition](#composite) understands "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", the image is properly centered, without you needing to do the calculations yourself. However if the source frames contained offsets, these will also be added to the gravity defined position, so that the relative position of all the sub-frames remains correct. Note that as the animation "`[script_k.gif](../images/script_k.gif) `" is actually a type of [Overlay Animation](../anim_basics/#overlay) their are alturnative methods of adding a static background to the animation. See the section above on [Remove Transparency](../anim_basics/#remove_transparency) for an example (onto a solid color, but can be any image). The same is true for the even simpler [Cleared Frame Animation](../anim_basics/#cleared) . In that case you don't even need to [Coalesce](../anim_basics/#coalesce) the animation first, but can directly compose it onto a background image. However you may need to "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" the '`dispose`' method being used afterward or better still [Optimize](../anim_opt/#optimize) the [Fully Coalesced Animation](../anim_basics/#coalesced) . However any other type of optimized animation, will require that "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" operation, and full composition with all the animation frames. As such it is probably better to to use the above method, just to be sure all GIF animations are handled correctly. * * * All that Glitters... -------------------- ### Glitter Animations The above [Layers Composition](#composite) methods makes it a lot easier to generate simple animations, such as glitter. First we need some glitter that is large enough to cover the image being processed. Here I will generate a three image glitter animation from some [Random Specks Images](../canvas/#random_specks) . First this is a raw black and white glitter on pure transparency, generating 3 frames of glitter by separating the three color channels into black and white [Channel Images](../color_basics/#channels) . It is basically a raw starting point for generating any other type of glitter. The '`30%`' threshold controls how many 'dots' there are per frame. magick -size 100x100 xc: +noise Random -separate \\ null: \\( xc: +noise Random -separate -threshold 30% -negate \\) \\ -compose CopyOpacity -layers composite \\ -set dispose background -set delay 20 -loop 0 glitter\_overlay.gif [![[IM Output]](glitter_overlay.gif)](glitter_overlay.gif) From this 'raw' glitter you can overlay it using a '`[Screen](../compose/#screen) `' alpha composition to only brighten some color, to generate a glitter of a specific color. I use the [Border Flatten Method](#flatten) (above). Just a plain color... magick glitter\_overlay.gif \\ -compose Screen -bordercolor GoldenRod -border 0x0 glitter\_gold.gif [![[IM Output]](glitter_gold.gif)](glitter_gold.gif) Using the [Layer Composition](#composite) , you can also use a single image, or even multiple images to provide a variable colored background. For example, here I generate three [Fractal Plasma](../canvas/#plasma_fractal) images, to provide a slightly randomised coloring to the glitter pattern. magick glitter\_overlay.gif null: -size 100x100 \\ plasma:red-firebrick plasma:red-firebrick plasma:red-firebrick \\ -compose Screen -layers composite glitter\_plasma.gif [![[IM Output]](glitter_plasma.gif)](glitter_plasma.gif) Of course there are lots of other glitter styles and movement patterns. You can find and download many such glitter tiles from the WWW. To apply a glitter like this to an image, there are a number of different methods. Typically you mask the glitter to a specific shape and or background. For this can either use a transparent shape (composited using [DstIn](../compose/#dstin) ) magick -size 100x100 -fill white -background none -font Candice \\ -gravity center -pointsize 90 label:A glitter\_mask\_trans.gif magick glitter\_plasma.gif null: glitter\_mask\_trans.gif -alpha set \\ -compose DstIn -layers composite glitter\_masked\_trans.gif [![[IM Output]](glitter_mask_trans.gif)](glitter_mask_trans.gif) ![==>](../img_www/right.gif) [![[IM Output]](glitter_masked_trans.gif)](glitter_masked_trans.gif) Or a black and white mask image (composited using [CopyOpacity](../compose/#copyopacity) ) magick -size 100x100 -fill white -background black -font Candice \\ -gravity center -pointsize 90 label:A glitter\_mask.gif magick glitter\_plasma.gif null: glitter\_mask.gif -alpha off \\ -compose CopyOpacity -layers composite glitter\_masked.gif [![[IM Output]](glitter_mask.gif)](glitter_mask.gif) ![==>](../img_www/right.gif) [![[IM Output]](glitter_masked.gif)](glitter_masked.gif) Ok we have an area that has been masked, you can complete the image, generally by overlaying the masked glitter on the original image. However in our case I'll underlay a background, and overlay an border. magick glitter\_masked.gif -size 100x100 \\ null: gradient:gold1-gold4 -compose DstOver -layers composite \\ null: \\( -fill none -background none -stroke white -strokewidth 2 \\ -font Candice -gravity center -pointsize 90 label:A \\) \\ -compose over -layers composite glittered\_letter.gif [![[IM Output]](glittered_letter.gif)](glittered_letter.gif) This last example also cleaned up any GIF transparency problems by the removal of all transparency from the final image and the overlay of a smooth border around the glittered region. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _While I may have used GIF format images in the above to allow me to magick display individual steps of the process, in practice you would either combine all the steps into a single command, or use a better intermediate image file format such as MIFF. That is, done to avoid the inherent problems of the GIF format, until we have finished._ | ### Glitter Tiles \- 'hole in the image' underlays As mentioned there are a lot of pre-prepared animated glitter tile images available on the WWW (do a search for "glitter tiles"). One source is a [IM Studio](https://imagemagick.org/MagickStudio/scripts/MagickStudio.cgi) user, _[scri8e](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=143) _ and his web site [Moons Stars](http://www.scri8e.com/stars) . Be warned however that I find most glitter tiles to be rather horrible looking, or too fast.[![](../images/glitter_blue.gif)](../images/glitter_blue.gif) For this example I found and modified a blue glitter tile with some small star patterns in it. I thought it would be useful for giving the IM wizard a glittering clothing, making him look really magical. Probably the easiest ways to glitter an existing image is to cut holes in the image rather than trying to mask out the glitter pattern. This however only works for images that do not contain transparency to start with. Alternatively, you could remove the transparency from an image, and when finished, re-add the original transparency. So lets take the IM Examples logo, and use [Color Replacement](../color_basics/#replace) to cut out all the blue parts of the image. Sort of giving our wizard a cloak of invisibility ;-) magick logo.gif -alpha set -fuzz 33% -transparent blue logo\_holed.gif [![[IM Output]](../images/logo.gif)](../images/logo.gif) ![==>](../img_www/right.gif) [![[IM Output]](logo_holed.gif)](logo_holed.gif) Note the use of the [Fuzz Factor](../color_basics/#fuzz) to adjust just how much of the blue color should be removed. Be warned however that this is not a nice way to cut out an area of an image as it produces [Aliased Edges](../antialiasing/#floodfill) . But no simple feathered cut-out feature is currently available as yet. Okay we have an image with a hole (or lots of holes). The next step is to underlay glitter tile image. The problem is the above tile is too small, it will not cover the whole image!The following uses a tricky technique to tile the multi-image glitter tile. However you still need to give a size that is larger than the original image to ensure that you can cover it completely. magick glitter\_blue.gif -virtual-pixel tile \\ -set option:distort:viewport 180x180 -distort SRT 0 \\ glitter\_blue\_tiled.gif [![[IM Output]](glitter_blue_tiled.gif)](glitter_blue_tiled.gif) Now lets dress our wizard in his new cloths, by placing the above tiled glitter under the 'holey' image. magick logo\_holed.gif null: glitter\_blue\_tiled.gif \\ -compose DstOver -layers composite \\ -loop 0 -layers Optimize logo\_glittered.gif [![[IM Output]](logo_glittered.gif)](logo_glittered.gif) You can of course do all these steps all in the one command. Here I limit the hole generation to just the wizards cloak, which has two separate specific parts. magick logo.gif -alpha set -fuzz 10% -fill none \\ -draw 'matte 120,150 floodfill matte 150,120 floodfill' \\ null: \\( glitter\_blue.gif -virtual-pixel tile \\ -set option:distort:viewport 300x300 -distort SRT 0 \\) \\ -compose DstOver -layers composite \\ -loop 0 -layers Optimize logo\_glitter\_cloak.gif [![[IM Output]](logo_glitter_cloak.gif)](logo_glitter_cloak.gif) The holes in the above were created using [Matte Fill Draw primitives](../draw/#matte) to select an actual point and color from the image for the color replacement. This means I don't need to use such a high [Fuzz Factor](../color_basics/#fuzz) as I did originally, as my comparison color came from the specific areas selected. Also I used a larger tiling 'viewport' so as to ensure I completely cover the image being tiled, without needing to know its exact dimensions. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The use of the [General Distortion Operator](../distorts/#distort)
and its special "`viewport`' option (added to IM 6.3.6-0), also gives you the opportunity to modify the distortion pattern in other special ways. Such as give it a 'perspective' look or rotate the pattern into a non-rectangular angles. Doing this can enhance the tiling so it does not have such an uniform look about it.

For some example see [Affine Tiling](../distorts/#affine_tile)
._ | ### Sparkles \- overlay mostly transparent glitter The major problem with the two previous glitter animation techniques is that it is an all or nothing type of replacement. You cannot use the original shading or background of the image. Also the glitter is completely restricted to the area that was masked. It can not extend beyond the bounds of the area involved. As such some small areas, such as the wizards 'hat' in the previous example, does not handle glitter very well. Sparkles are different, in that the animation added is mostly transparent. as a consequence the original image, can still show through. Such animations are usually added to an image one of two ways. Either the animation overlay itself is transparent, or it is of the form of black background with white 'sparks' where the image should be brightened. **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Here is an example of a mostly transparent 'sparkles' overlay. _Example Here_ As you can see you can have colorful sparkle overlays when this form is used. The major problem with this is that a GIF animation was used to save it, (which is typically the case), so the overlay is heavily aliased. That is, it can not contain any semi-transparent pixels to smooth out the look of the overlaid image. If it did, you would have get horrible black halos around the 'sparkles' in the final result. Lets mask out and overlay this onto the wizard. _Example Here_ The other form of sparkles is white sparkles on a black background (a gray-scale image). These are masked and overlaid so as to brighten the image to add the sparkle. For example... _Example Here_ One of the best things about sparkles is you can generate a sequence of frames where sparkles slowly appear and then disappear. This can get quite complex, but is no very hard to do. _Example Here_ ### Adding Flares and Stars Animations Where glitter consists of single points of brightness, and sparkles can overlay some areas of an image, flares are usually added individually. A 'flare' is basically a point that flashes to cover a large area for just a moment. A 'star' is similar except the coverage is more in the form of 'rays' of brightness. These usually are 'seeded' from specific points, but the result often extends, at least momentarily well beyond the seeding area. For example a flare that is mask limited to a specific area looks very very stupid and unnatural. The more difficult aspects of flares is locating good 'seed' points and timing of multiple flares appropriately. **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Final example I want to create... A 'sparkle' the travels up the wizards wand, then flares, and dissolves into a number of small sparkle flares over an area. Then the sequence repeats. * * * Resizing Animations ------------------- ### Problems with Resizing Animations The biggest problem with resizing GIF animations is that the "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" operator is designed specifically to make the resulting images as close to ideal (after the resize) as possible. It does this by merging and generating lots of additional colors in the image to make it look better. The resulting images are far from ideal for saving to the limited GIF file format. With GIF's limited color table, this results in heavy [Color Reductions](../quantize/#intro) in the resized images. For a single GIF image that is not so bad, but for a GIF animations, the default [Error Correction Dithering](../quantize/#dither_error) of the reduced color set produces problems, in 'dither noise' between frames, and in turn a bad frame optimization for final file size. It is even worse when transparent colors are also being used, which is a common practice for typical GIF animations used for web pages. Transparency is also commonly used for [Compression Optimization](../anim_opt/#compress_opt) techniques, for animations that would otherwise not need it. What happens is that "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" produces semi-transparent pixels in the overlay images. Then when the images are saved back to a GIF file format, these pixels are then converted to either fully-transparent or fully-opaque, both producing major color distortions in the resulting animation. If any form of optimization is used... frame, transparency or LZW... then the transparency effects will basically result in a **disastrously resized GIF animation**. That is, the facts, Jack! So you will need to live with it. Even if you avoid using "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `", by using "`[-sample](https://imagemagick.org/script/command-line-options.php?#sample) `", you will still have major problems unless you "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `" the animation first. ### Resizing Animation Techniques As shown above, there are are serious problems in resizing GIF animations, none of which are easily resolved. The solution also generally depends on just what type of image was resized in the first place, be it cartoon like, or a real-world video image. Here are the methods I know about, or have been contributed... ### Avoid resizing If it is at all possible, DO NOT RESIZE. You can for example [Canvas or Viewport Crop](#crop_viewport) your animation to just trim it down to fit in the space you need it for. Or you can generate the GIF animation at the right size in the first place. Neither technique is typically the best option, but if you can, consider it, as it will save you a lot of problems and hair pulling. ### Direct resizing As mentioned about directly using "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" will have problems, either with number of colors for each frame, or with semi-transparent colors. For example this goes really bad... magick script\_k.gif -resize 20x20 script\_k\_direct.gif [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) ![==>](../img_www/right.gif) [![[IM Output]](script_k_direct.gif)](script_k_direct.gif) Now that did not work very well, and that is because the original image has some heavy frame optimizations. Each 'frame' of the animation is not the same size, and the "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" will resize each and every frame image completely separately from the other images. That is, the above resized the actual frame images, and not the virtual canvas of the animation to the size given. Actually I am surprised the resulting animation wasn't more 'crazy' than just the blank area shown. That brings us to the first point about resizing animations. First ensure that all the frames are fully defined, and ALL optimization has been removed. In other words [Coalesce](../anim_basics/#coalesce) the animation before attempting to resize it. For example... magick script\_k.gif -coalesce -resize 20x20 script\_k\_direct2.gif [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) ![==>](../img_www/right.gif) [![[IM Output]](script_k_direct2.gif)](script_k_direct2.gif) The next problem is one of transparency colors. If you look at the result above you will see that the edges of the smaller animation are horribly aliased ('staircased'). That is, because GIF cannot save the semi-transparent colors the "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" operator generated. The colors within the animated object will also have had the colors merged together to produce new colors, but that is usually not nearly so bad as the edge aliases. ### Resize with Flatten, A General Solution. The best idea when generating a GIF thumbnail is to avoid the problems of transparency entirely. That is, [Flatten the Animation](#flatten) , either before or after resizing the animation. That way you do not loose the 'anti-aliasing' of edges in resized images. In fact I have found most good GIF animation websites do exactly that when generating their GIF animation thumbnails. Of course the thumbnail will then be limited to use on a specific colored background, usually 'white', but sometimes 'black', or 'silver' (web page grey) though that last is less common these days. For example, here I create a smaller thumbnail on a background color appropriate for this web page. magick script\_k.gif -coalesce \\ -bordercolor LightSteelBlue -border 0 \\ -resize 20x20 -layers Optimize script\_k\_thumbnail.gif [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) ![==>](../img_www/right.gif) [![[IM Output]](script_k_thumbnail.gif)](script_k_thumbnail.gif) This is the recommended solution for general GIF thumbnail handling. Any other method requires either human control, or a very sophisticated GIF thumbnail handling logic. ### Color Table Blowout The biggest problem (as I mentioned at the start of this section) is that huge number extra colors are generated in the image, especially near lines, and the edges of adjoining color areas. You also get resize-halo of semi-transparent colors around the edges of images. This in turn enlarges the size color table needed for a simple minimal colored animation, which in turn means a larger file size when a resize simple animation is saved. Worse still each and every frame in the resizes animation, probably generates a different set of colors, further enlarging the file size for your 'thumbnailed' animation. There is also the problem that after [Color Quantization](../quantize/#colors) , you may no longer have the same specific colors as the original animation (see [Quantization does NOT Preserve Colors](../quantize/#quantize_not_exact) ). That is, instead of having a simple area of pure white, you may now have an off white area. ### Resize using Sample To avoid generating extra colors when resizing the simplest way is to "`[-sample](https://imagemagick.org/script/command-line-options.php?#sample) `", the animation, rather than resizing it. This will preserve the current colors in the animation and allow you to easily re-optimize the animation at the new size. magick script\_k.gif -coalesce -sample 20x20 script\_k\_sample.gif [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) ![==>](../img_www/right.gif) [![[IM Output]](script_k_sample.gif)](script_k_sample.gif) However while this works, you are basically removing rows and columns of pixels from the image, loosing image data and hence quality in the process. With cartoon-like images, that often leaves 'dotty' borders, and missing or distorted details. If your resize is more than 50% of the animations original size, as is the case above, the result is often quite horrible, especially when texture or a other color pattern is used in the animation. It is not surprising then that many GIF animation libraries are filled with such horrible sample-resized animations that they have copied from all over the net. I often wish they would clean out this sort of crap, but that means a reducing the number of GIFs on offer, and that in turn reduces the marketing statistics of the number of GIFs available, which the advertising department does not like. As a consequence, crappy GIF animations are common. ### Resize using Liquid Resize A similar method to using the [Sample](#resize_sample) method above is to use [Liquid Rescale](../resize/#liquid-rescale) , which is also known as [Seam Carving](../resize/#liquid-rescale) . This also removes or added whole pixels from the images involved, but tries to do so in a way that preserves as much of the image complexity as possible. Look at the above links to see how you can use it to generate nicer resized images. Unfortunately at this time there is no way to use this on a general animated image, as it does not have an understanding of an images complexity, and we cannot currently extract the rescaling method to apply it to each frame of an animation in a consistent way. Hopefully this will change at some point in the future. ### Resize and Restore Colors Sampling an animation just results in removing rows and columns of pixels, and the possible removal of thin lines and other important details. But merging pixels together using "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `", produces far too many new colors for the GIF format. So the obvious solution is to do the "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" but then use the original animations colors to restore the resized animations colors, by using a colormap. FUTURE: example with original color table restored This has the added advantage of not generating local color tables. Results however may be better with dither turned off, so as to avoid any 'dither noise'. This is especially true for cartoon like images that has large smoothly colored areas. FUTURE: non dithered color table restored example ### Full Color Optimize If a horrible sampled thumbnail is not to your liking, then you are faced with the prospect of going through a full [Color Optimization](../anim_opt/#color_opt) of the resized GIF Animation. To sort out just what 'new' colors you want the animation to keep. However this is often not so bad, for most animations, but it can be a major effort for more complex animations like when converting a [Video to GIF Animation](../video/#gif) . That is, if you dealing with a cartoon like animation, you will now have heavily anti-aliased lines and edges. For animations that involve a transparent background, you will also have to properly deal with semi-transparent pixels around the edge of your animation, also caused by the anti-aliasing features of resize. See the section on [GIF Boolean Transparency](../formats/#boolean_trans) for the many methods you can use to handling this. ### Large Resize Reductions When you plan to resize a large animation to a much smaller animation, you face the problem of important parts of the animation disappearing. This is actually a problem for static images as well as animations. See [Resizing Line Drawings](../resize/#thin_lines) for any known solutions for this. Any further suggestions, ideas, or techniques are most welcome. * * * Merging Multiple Animations --------------------------- I said it before, but it becomes especially important when merging animations... **Know as much as you can about the animation you are working with!** The "`[gif2anim](../scripts/gif2anim) `" script is ideal for this purpose. Its sister script "`[anim2gif](../scripts/anim2gif) `", is also commonly used here to re-create an animation using its original settings. (See basic usage of the script in [Animation List Information](../anim_basics/#list_info) .) Without knowledge of how an animation works it is next to impossible to merge them in various ways. Programs can be developed (the ultimate goal of these examples) to do this. But, such programs are often very complex and can produce unexpected results. Because of this you should still follow these examples, as they will give you a major insight into how animations should be handled and merged. ### Serial or Time-wise Append Appending two GIF animations together so that one sequence follows another time-wise is simple with IM. You basically just list them on the command line and they will follow each other. But it may not be quite as easy as it looks. For example, after some searching of the web, I found (well stole and heavily modified for this example) a couple of animations of some letters being drawn. Now I'd like to join these images so when one animation completes the next one starts, as if someone is writing the word '`OK`'. Here are the letters, the 'animation sequence' and the details of the internals of these two animations. gif2anim -n script\_o.gif gif2anim -n script\_k.gif  [![[IM Text]](script_o.anim.gif)](script_o.anim) [![[IM Text]](script_k.anim.gif)](script_k.anim) [![[IM Output]](../images/script_o.gif)](../images/script_o.gif) [![[IM Output]](../images/script_k.gif)](../images/script_k.gif) These sequences start with an empty canvas then just slowly add and modify pixels to this canvas. They never remove, clear or make transparent any pixels added by previous frames. For our purposes however it does not matter if they do or not as it will have little bearing on the results. Nor will the number of the frames in the animation have a bearing on this operation. What is important to know is the timings of the frame, as this could produce problems. In particular note the timed delay on the first, or in this case the final frame. This technique is very common, giving the viewer time to see the final result before the animation clears and re-starts. It is these delays and frames that will cause use problems when doing time-wise appends. Also notice that the '`k`' animation has a slight delay in the middle of the animation sequence. This delay represents the end of the first brush stroke in this animation and the second brush stroke. This delay will also need to be preserved, meaning we can't just change all the time sequences in the animation to a constant value. Something that is not shown in the above, is that the first frame of both animations is actually blank canvas. We will probably want to junk that canvas on the second animation as an useless waste of time, though it should be kept on the first animation as a starting delay. Now that we have examined the two animations, lets try to join them together so one follows the other in time. Time appending animations is actually a very simple operation, just append the two animated images on the command line. So lets just try that... magick script\_o.gif script\_k.gif script\_ok\_try1.gif [![[IM Output]](script_ok_try1.gif)](script_ok_try1.gif) Well the result was far from perfect. The letters get drawn in the right sequence, but on top of each other! Not only that but as the first '`o`' animation is thinner (40 pixels) than the second '`k`' animation (53 pixels), so the very last bit of the final '`k`' letter gets clipped by that smaller framing canvas size. The position of the second animation can be moved by using a [relative repage](#repage_relative) , as shown above. This method of re-positioning will preserve any existing offsets that may be present in that animation, just move them all as a single related group. In this case almost all the frames have and existing offset, as this is a highly optimised animation. To accommodate this shifted position and avoid 'clipping' the second animation we also need to enlarge the canvas size for the whole animation. Changing the the canvas size before reading the first animation or frame will enlarge the canvas area in which the animation runs, and prevent the 'K' from being clipped. magick -page 90x54 script\_o.gif \\ \\( script\_k.gif -repage +37+0\\! \\) script\_ok\_try2.gif [![[IM Output]](script_ok_try2.gif)](script_ok_try2.gif) The result is a vast improvement. Though now the delays between the drawing of the letters, is definitely noticeable. What we want is a much smaller delay for the last frame of the first '`O`' animation. Just large enough to look like the invisible artist is re-positioning the pen. To do this we make a copy of that last frame of the first animation, then change the delay of just that frame using the "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `" operator. We then re-add that frame back into the image sequence by deleting the original un-modified image. Also as we have now set a good delay between the drawing of the letters, the initial blank canvas (just representing an initial start delay) in the second animation is now redundant, so we can just delete that frame, without problems. If this frame actually contained part of the image, then we may need to adjust its delay, instead of removing. magick -page 90x54 script\_o.gif \\( +clone -set delay 20 \\) -delete -2 \\ \\( script\_k.gif -delete 0 -repage +37+0\\! \\) script\_ok.gif [![[IM Output]](script_ok.gif)](script_ok.gif) And our serial or time-wise appending of two animations is complete and all the little problems associated with these two particular animations are fixed. Notice that at no time did I try to globally change ALL of the individual frames, or their timing delays. That is, I preserved as much of the original animations as I could while achieving my goal. This is important as not all animations use a constant timing delay between frames and changing this can make an animation look very bad. ### Side by Side Appending (time synced) Suppose you want both animations to be appended side-by-side, but have both parts of the animation animating at the same time. This is not so easy, as you need to append (or composite together) each pair frames in the the two animations together, so the animation also works together.. The real problem to doing this is the IM command line only works with a single sequence of images. It does not have the luxury of an API where you can keep two separate image sequences, to loop through and append them together into a third. I can think of three basic techniques in which to do this appending. Before be start however you should first study the two animations, to check on the time sequences, and other details of the animation. The "`[gif2anim](../scripts/gif2anim) `" script is good for this, and the generated "`.anim`' file can be useful later. gif2anim -n bag\_left.gif gif2anim -n bag\_right.gif  [![[IM Text]](bag_left_orig.anim.gif)](bag_left_orig.anim)  [![[IM Text]](bag_right_orig.anim.gif)](bag_right_orig.anim) [![[left]](../images/bag_left.gif)](../images/bag_left.gif) [![[right]](../images/bag_right.gif)](../images/bag_right.gif) If you look at the information summaries you will see that the two animations have the exact same number of frames, and almost exactly the same time sequence. It is the similarity of the timing that is important here, and you can say the animations are already 'time synchronised'. However while the timings may be correct, the animations are frame optimized, rather than fully-coalesced. But the canvas area height are the same, making appending the two frames side-by-side practical. Actually this animation was badly 'split' (see [splitting animation](#split) in the next example set) so that the 'cat' animation was cut in two, and the original lost. Other modifications resulted in a very slight timing difference, which only made the division more obvious. This was a problem that was presented to me by _[gmabrys](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=8005) _ in a discussion on [IM Forums](https://magick.imagemagick.org/viewtopic.php?f=7&t=8068) , though the actual problem he gave was far, far, worse. ![[left]](../images/bag_right.gif)![[right]](../images/bag_left.gif) Now browsers usually animate each of the separate GIF images, without any synchronization. As such the two animations may become out-of-sync with each other, producing a 'cat' that appears to have been part of a chainsaw massacre. You may be able to see this effect to the right where I placed two animations side-by-side on the browser's page, especially if you are on a distant server via slow links. Now lets attempt to append them together into one, properly synchronized animated image. #### Appending separate files The simplest way is to just coalesce the two animations and separate them into separate image files, one frame per image. The separate images can then be append together (or otherwise modify the frames) as appropriate. When done the new frames can then be used to re-build the animation. This however requires you to save a lot of extra information about the animation that could very easily be lost during this processing. # Separate animations into coalesced frames (plus a ".anim" file) gif2anim -c bag_left.gif gif2anim -c bag_right.gif # Append the separated frames them together for i in `seq -f '%03g' 1 11`; do \ magick bag_left_$i.gif bag_right_$i.gif +append bag_append_$i.gif; \ done # Rebuild the animation (using one of the ".anim" files) anim2gif -c -b bag_append bag_left.anim # Cleanup rm -f bag_left.anim bag_right.anim rm -f bag_{left,right,append}_???.gif [![[IM Output]](bag_append_anim.gif)](bag_append_anim.gif) As you can see this is quite an involved process, generating many individual temporary images, and thus requiring quite a bit of clean up when finished. Of course if you are debugging the above, the individual temporary files make it easier to figure out what is going wrong with your processing. It also shows the power of the "`[gif2anim](../scripts/gif2anim) `" script and is inverse the "`[anim2gif](../scripts/anim2gif) `" script in separating, and saving the animation meta-data, and then later re-building GIF animations. Basically it lets you preserve the original timings of the animations, without needing to code them into your script directly. The final image also still needs to be re-optimized, though in this case you will get very little optimization as a lot of things are happening simultaneously throughout the animation between each and every frame #### Layered Composition A better technique is to overlay animations using a multi-image list [Layer Composition](#composite) . This involves just enlarging one set of images, and overlaying the other set to join them together. In fact this is what the normal "`[-append](https://imagemagick.org/script/command-line-options.php?#append) `" operator does internally, so it isn't that different. Here I just tell IM how big to make the canvas, and the fill it out using "`[-coalesce](https://imagemagick.org/script/command-line-options.php?#coalesce) `". I then overlay other coalesced animation with an appropriate offset. magick bag\_left.gif -repage 97x92 -coalesce \\ null: \\( bag\_right.gif -coalesce \\) \\ -geometry +50+0 -layers Composite bag\_append.gif [![[IM Output]](bag_append.gif)](bag_append.gif) Of course the above technique means I needed to know just how big the final animation will be, as well as the offset needed for the overlaid animation. But the process is fast, works very well, and a scripted command can pre-read the images to determine that information. To make a more universal animation appending method, we need to do some fancy image handling to automatically determine the final size and offset of the append. To do this without pre-reading the animation, requires some jumping though some hoops, but a single command general animation append is possible. First we need to append the first coalesced frame of each animation to create a canvas that is the right size and this is then cleared. The first animation is coalesced and overlaid into left half of this canvas, then the second animation is then coalesced and overlaid with a "`-gravity East`" to place it in the right-most half of the pre-prepared canvas, to avoid the need for an offset. magick bag\_left.gif'\[0\]' -coalesce \\( bag\_right.gif'\[0\]' -coalesce \\) \\ +append -channel A -evaluate set 0 +channel \\ bag\_left.gif -coalesce -delete 0 \\ null: \\( bag\_right.gif -coalesce \\) \\ -gravity East -layers Composite bag.gif [![[IM Output]](bag.gif)](bag.gif) And there you have a general technique to append two time synchronized animations together. ### Double Append, Appending - or Appending Animated Fonts Before finishing with appending animations, there is one other technique I would like to show you. This technique can append multiple animations at the same time, but at the cost of loosing all the timing information that was present. Often (but not always) those timings is not a big loss. Basically we append all the frames of each animation together vertically into a single image, and then append or overlay the whole animation as two simple images. This is sort of like taping the two film strips together side-by-side to produce a wider film strip. magick \\( bag\_left.gif -coalesce -append \\) \\ \\( bag\_right.gif -coalesce -append \\) \\ +append -crop x92 +repage \\ -set delay 30 bag\_dbl\_append.gif [![[IM Output]](bag_dbl_append.gif)](bag_dbl_append.gif) This did not require any temporary files, but as I mentioned at the start, all the original time delays have been lost. For this example I just set all the animation delays to a constant value, producing a reasonable, though different result. Also to re-build the animation we needed to know the frame height of the original animation, to correctly divide ([Tile Crop](../crop/#crop_tile) ) the widened 'film strip'. Though it is possible to recover those timings using the "`[gif2anim](../scripts/gif2anim) `" scripts, doing so sort of defeats the purpose of using this method, and you may as well just used the first animation append technique, by appending the individual frames as temporary files. As you are appending the animations as simple images, you can append together a whole series of animations all at the same time, (producing an even wider 'filmstrip') and that is what makes this technique such an useful one. For example you can use it with animated fonts that all use the same timings. Though I have found that while a lot of animated fonts have the same number of frames, they usually have slightly different timings for each letter so as to de-synchronize the animated letters (see [Splitting up an Animation](#split) for reasons why that is desirable). A neon sign on the other hand should have synchronized animation timings, so I'll use it as an example... magick \\( neon\_h.gif -coalesce -append \\) \\ \\( neon\_e.gif -coalesce -append \\) \\ \\( neon\_l.gif -coalesce -append \\) \\ \\( neon\_l.gif -coalesce -append \\) \\ \\( neon\_o.gif -coalesce -append \\) \\ +append -crop x60 +repage -set delay 100 neon\_hello.gif [![[IM Output]](../images/neon_h.gif)](../images/neon_h.gif) [![[IM Output]](../images/neon_e.gif)](../images/neon_e.gif) [![[IM Output]](../images/neon_l.gif)](../images/neon_l.gif) [![[IM Output]](../images/neon_l.gif)](../images/neon_l.gif) [![[IM Output]](../images/neon_o.gif)](../images/neon_o.gif) ![==>](../img_www/right.gif) [![[IM Output]](neon_hello.gif)](neon_hello.gif) You could also do something a little fancier, by adjusting timings and the number of loops in the resulting animation. magick neon\_h.gif'\[0\]' neon\_e.gif'\[0\]' neon\_l.gif'\[0\]' neon\_l.gif'\[0\]' \\ +append \\( +clone \\) -append \\ \\( neon\_o.gif -coalesce -append \\) +append \\ \\( +clone \\) -append \\( +clone \\) -append \\( +clone \\) -append \\ -crop x60 +repage -set delay 3 \\ \\( -clone 0 -set delay 300 \\) -swap 0,-1 +delete \\ \\( -clone 1 -set delay 10 \\) -swap 1,-1 +delete \\ \\( +clone -set delay 200 \\) +swap +delete \\ -quiet -layers OptimizeFrame neon\_hell.gif [![[IM Output]](neon_hell.gif)](neon_hell.gif) The first two lines makes the 'always lit' part of the sign (first frame of each of the previously animated letters). After this the last 'broken' letter is added and the whole animation is doubled up a couple of times to produce about 16 frames. The timings are set to complete the desired effect with the first and last frame being displayed for a long period, while the rest of the frames flash by past really fast ( "`-delay 10`" ). Actually this GIF animation optimizes a lot smaller than you would probably think for the number of frames involved. Basically the IM GIF optimizer found that it only needed to re-overlay the 'O' animation every second frame, and used a '[Previous](../anim_basics/#previous) ' disposal to just restore the previous lit 'O'. The animation is thus only about 50% larger than the basic flashing un-optimized 'hello' image. Check it out yourself. _Can you improve the neon animation? Make it more realistic? It is a shame GIF animations don't have sound._ ### Splitting up an Animation Now that we have the animation rejoined together, lets attempt to split it up correctly for use on a web servers, so that the individual parts can animate separately, without interfering with each other. This is actually reasonably hard, and I will not attempt to completely automate the process. There are however tools on the WWW that can do this. First of all we need to study the animation to find what parts of the animation changes over the whole period. For that we need to find the differences from one frame to the next, add them all together into a map showing the areas that are being animated, verses though that remain completely static. This is tricky. Basically a [Multi-Image Alpha Composition](#composite) is used to find a '`[Difference](../compose/#difference) `' image between each frame of the animation. These greyscale difference images, are added together, then the channels are separated and also added together. A final threshold then makes any non-zero change between any frame of the animation, pure white. The result is a black image with white anywhere the image changed, highlighting the areas of change. magick bag.gif -coalesce -set delay 0 \\ -bordercolor red -border 0 -alpha off null: \\ -duplicate 1,1--2 -compose difference -layers composite \\ +delete -compose plus -background black -flatten \\ -separate -flatten -threshold 0 bag\_areas.gif [![[IM Output]](bag.gif)](bag.gif) ![==>](../img_www/right.gif) [![[IM Output]](bag_areas.gif)](bag_areas.gif) Now we can see that this animation could be divided into at least three areas: a 'cat' area at the top, a small 'bear' to the left, and a flapping 'wing' to the right. All with simple orthogonal (vertical or horizontal) cuts.So lets just do this, with some simple [Viewport Crops of the Animation](#crop_viewport) . magick bag.gif -coalesce -crop 97x39+0+0\\! bag\_cat.gif magick bag.gif -coalesce -crop 50x54+0+39\\! bag\_bear.gif magick bag.gif -coalesce -crop 47x54+50+39\\! bag\_wing.gif | | | | --- | --- | | [![[IM Output]](bag_cat.gif)](bag_cat.gif) | | | [![[IM Output]](bag_bear.gif)](bag_bear.gif) | [![[IM Output]](bag_wing.gif)](bag_wing.gif) | These three images can be displayed by the browser together and not have the 'Texas Chainsaw Massacre' look about it, as at no point does a sub-animation cross the boundaries of another. Now technically, you can make a couple more cuts so as to separate the areas that are not animated from the animated areas, splitting this animation into about six or more areas, though you will not gain much from optimization doing this. All it would really do is complicate your web page, and create more files for the user to download. Now unlike the larger animation, these smaller areas will animate quite independently from each other. We can even also change the timings of these simple sub-animations without adversely affecting the result so as to completely de-synchronize them from the other sub-animations. The result is a nicer less repetitive animated image (see below). If you study the 'bouncing bear' and the 'flapping wing', you will find they form a simple two frame cycle that simply repeats a number of times, to match the timing of the waving cat. We can thus junk the extra repeats to simplify these animations. Also the first two frames of the 'cat' are also exactly the same. However unlike the 'bear' and 'wing' you can't just remove one of them, as each frame contains time delays to allow the 'bear' and 'wing' to animate without the cat being present. To correctly remove these duplicate frames, you need to use the "`[-layer](https://imagemagick.org/script/command-line-options.php?#layers) `" method '`[RemoveDups](../anim_opt/#removeDups) `' to locate and merge the timings of such duplicate frames in a coalesced animation. And here are the final optimizations, of all three separated animations with the timing changes to improve the overall de-synchronization of the sub-animations. I have also displayed all three animations side-by-side on the page, just as they should be displayed. magick bag\_cat.gif -layers RemoveDups \\ -quiet -layers Optimize bag\_cat\_opt.gif magick bag\_bear.gif -delete 2--1 -set delay 47 \\ -layers Optimize bag\_bear\_opt.gif magick bag\_wing.gif -delete 2--1 -set delay 33 \\ -layers Optimize bag\_wing\_opt.gif   | | | | --- | --- | | [![[IM Output]](bag_cat_opt.gif)](bag_cat_opt.gif) | | | [![[IM Output]](bag_bear_opt.gif)](bag_bear_opt.gif) | [![[IM Output]](bag_wing_opt.gif)](bag_wing_opt.gif) |  As a final summary: The two original (badly split) images totalled [![[IM Text]](bag_orig_size.txt.gif)](bag_orig_size.txt) bytes, which is about the same as the appended version. After correctly splitting the animation, which allows good optimization of the sub-animations, we get a total of [![[IM Text]](bag_opt_size.txt.gif)](bag_opt_size.txt) bytes over three image. Quite a good saving. ### Distant Change Frame Splitting **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Example of splitting up frame updates of 'two changing objects that are far apart', without involving transparency (fixed background), but preserving the timing syncronization between the parts. Then repeat with a transparency background, (needing 'OptimizePlus' to generate the 'cleared' pixels. See [Splitting Frame Actions](../anim_opt/#splitting) for the general example. ### Merging Time Disjoint Animations Before any two animations can be merged together to run synchronously, you need to make all animations use the same number of frames, and use the same set of time delays. How difficult the merger is really depends on how disjoint the timings of the animation is. If the time delays are basically constant, you can simply ignore them and fix the timings latter. An example where time could be ignored in merging a 2 frame animation with a 6 frame animation was given in a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=12573) . Also if the total cycle time is very different, you may need to adjust things so that one animation loops 2 or 3 times so as to fill the cycle time of the other animation. Basically timing is what matters. Probably something like...* \+ Figure out and adjust animations to a common total loop cycle time * \+ Coalesce both animations to remove any frame optimizations. * \* Convert frame time delays into, time-since-start of animation. * \* Double up frames as appropriate to time-synchronize. * \* Convert time-since-start back into frame time delays. * \+ Overlay the coalesced time-synchronized frames as desired. * \+ Optimally merge and remove any 'zero delay' frames. * \+ Re-optimize the new animation. The '\*' parts could be turned into a single new "`[-layer](https://imagemagick.org/script/command-line-options.php?#layers) `" method to time synchronize the two animations with similar total cycle time durations. **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Example, time disjoint, but same cycle time... For example suppose you have two animations of three frame with time delays of 10 10 10 5 5 20 Both animations are 30 time units long already so that is not a problem. Now magick the above to the time index when each frame should appear... and show the overall time line at which frames appear... 0 10 20 |\_\_ NOTE that both animations 0 5 10 | end or loop at 30 From this you can see that you need to insert some extra frames to make them match. The first frame of the first animation needs to be repeated at time index 5 0->5 10 20 0 5 10 And the last frame of the second animation also needs to be duplicated at time index 20 0->5 10 20 0 5 10->20 The arrow '->' in the above means the same frame is just repeated (duplicated) into the next time index. They are actually the same image. Now that the timings of the frames in both animations are the same, you can simply merge (composite) the frames together, to get final animation that is 4 frames long. The four frame will thus have time delays of 5 5 10 10 which still add up to 30 time units (overall time per loop cycle) Current state of development.... While IM can help gather time delay information (try the '-t' option for "gif2anim") and build the animation. IM can't perform the time synchronization needed for two separate coalesced animations. This may become a special built-in option. That is, you will need figure out and double up appropriate coalesced animation frames so as to change two time-disjoint animations into two time-synchronized animations. Once you have the animations time synchronized, you can then simply use the new "-layers Composite" method, to overlay or merge the two time-synchronized animations together very easily. All the above however assumes the total loop time of the two animations are at least roughly equal, or not a major concern. **Simplified Solution** A simplified limited solution has been [Discussed on IM Forums](https://magick.imagemagick.org/viewtopic.php?p=50325) , for use with fast changing animations (similes). The solution takes each animation and expand it so that the animation has a fixed frame rate. That is, all frames are duplicated so that each frame is shown for a conatant 6 centi-seconds each. As such one frame with a 22cs delay may be replaced by 4 x 6cs frames (24cs total). After this the animations are further modified so that short animations are looped multiple times so that the two animations are finally of equal length. That is, the two animations are made the same overall length in terms of both time, and number of frames. Once both animations has the same frame-rate and the same length, [Layer Composition](#composite) can be used to merge/overlay the two animations, in the right position. The result can then be optimized using [Remove Duplicate Frames](../anim_opt/#removedups) to remove any extra unwanted frames (with appropriate timing adjustments and other [Optimizations](../anim_opt/#intro) applied before saving. This method of having all your component animations in a fixed frame length form is especially well suited to animation libraries. ----- Other example to create.... \* Overlay two moving equal time animations into a single animation (dancing butterflies, circling atoms, or birds?) This should be a straight layers composition. \* Overlaying a moving animation on a fix background. (displace animation linearly with time) \* Overlay two animations with different numbers of frames but constant time delays (see [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=12573) ). \* Oveylay two time disjoint animations (as outlined above) \* Overlay a simple animated figure, on an animated background. (full animation merge) * * * --- # Advanced Techniques -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Advanced Techniques ======================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) | | | | | | --- | --- | --- | --- | | | [![](../img_www/granitesm_right.gif) 3D Bullets from Shapes](#3d-bullets) | | Using a script to generate huge numbers of images
Color tinting and shaping a 3-D gray-scale shade image | | [![](../img_www/granitesm_right.gif) Making Logos 3D](#3d-logos) | Using transparent overlays to tint the basic shaped image | | [![](../img_www/granitesm_right.gif) Reflections](#reflections) | Adding Surface Reflections of many types. | | [![](../img_www/granitesm_right.gif) Jigsaw Pieces](#jigsaw) | Cutting out and enhancing an odd shaped piece from a photo | | [![](../img_www/granitesm_right.gif) "Gel" Effects](#gel_effects) | Adjusting the size, brightness, and sharpness of the highlight
Lighting and Darkening using 'Screen' and 'Multiply' compose | | [![](../img_www/granitesm_right.gif) "Aqua" Effects](#aqua_effects) | Using 'curves' to adjust the highlights. | | [![](../img_www/granitesm_right.gif) Tilable Stars and Comets](#stars) | Randomized Points.
"My God! It's full of stars! -- 2001, A Space Odyssey" | | [![](../img_www/granitesm_right.gif) Radial Flares](#radial_flares) | Generating random rays and rings around a central point. | This page provides very large examples where we use multiple techniques to produce some compound image manipulation effects, beyond the basic image operations of IM. The major techniques are summarized in the index above. While many techniques are provided on other pages, such as creating font templates, fancy labeling images, and using masks, these pages show how you can combine those techniques together to produce a more complex effect. * * * 3-D Bullets from Shapes -- A Scripted Approach ---------------------------------------------- There are a lot of 'bullet' images available on the web for your web listings. But you can generate your own 3d objects, and allowing you to make your whole web site conform to a particular style that ties it all together. One of the best ways to do that is to create a 'generate' script that lets you automatically generate a whole range of buttons and shapes of a particular style, but using any color you require. This is one such, very simple script. Here we use the "`[-shade](https://imagemagick.org/script/command-line-options.php?#shade) `" option to generate 3d looking objects from a plain shaped transparency. The shape has only straight on/off transparency, which is carefully preserved, allowing it to be used as transparent GIF images for general use on web pages. The resulting grayscale 'shaded' image is then coloured using the "`[-tint](https://imagemagick.org/script/command-line-options.php?#tint) `" operator, to set the mid-tone greys of the image, while leaving the more extreme black and white shadings alone. After that the original shape of the image provided is re-added to the colored result. As a bonus if the input image had only a Boolean transparency the result also has a Boolean transparency appropriate for a GIF format image. magick {input_image} -alpha set \ \( +clone -channel A -separate +channel \ -bordercolor black -border 5 -blur 0x2 -shade 120x30 \ -normalize -blur 0x1 -fill {color} -tint 100 \) \ -gravity center -compose Atop -composite \ {output_image} Note that the input image is only read in once by the above script. This allows you to also use the script in a pipeline of commands using '`-`' as the input and output filenames (with perhaps an IM image format setting). This can be important when writing your own IM scripts. The above command was written into a very simple shell script called "[`create_bullet`](create_bullet) ", and the following commands were executed, to generate a whole range of symbol images in many different colors. magick +antialias -size 15x15 xc:none -draw 'circle 7,7 3,3' ball.gif create\_bullet ball.gif grey ball\_grey.gif create\_bullet ball.gif red ball\_red.gif create\_bullet ball.gif green ball\_green.gif create\_bullet ball.gif blue ball\_blue.gif create\_bullet ball.gif yellow ball\_yellow.gif create\_bullet ball.gif maroon ball\_maroon.gif create\_bullet ball.gif cyan ball\_cyan.gif magick -size 12x12 xc:black square.gif create\_bullet square.gif grey square\_grey.gif create\_bullet square.gif red square\_red.gif create\_bullet square.gif green square\_green.gif create\_bullet square.gif blue square\_blue.gif create\_bullet square.gif yellow square\_yellow.gif create\_bullet square.gif maroon square\_maroon.gif create\_bullet square.gif cyan square\_cyan.gif # retrieve asterix symbol from # [Anthony's Web Images, Symbols](http://www.cit.griffith.edu.au/images/Symbols/Images.html) create\_bullet asterix.gif grey asterix\_grey.gif create\_bullet asterix.gif red asterix\_red.gif create\_bullet asterix.gif green asterix\_green.gif create\_bullet asterix.gif blue asterix\_blue.gif create\_bullet asterix.gif yellow asterix\_yellow.gif create\_bullet asterix.gif maroon asterix\_maroon.gif create\_bullet asterix.gif cyan asterix\_cyan.gif # Use a heart symbol from "WebDings" font (22 point => 16x16 pixel image) magick -font WebDings -pointsize 22 -background none \\ label:Y -trim +repage heart.png create\_bullet heart.png grey heart\_grey.png create\_bullet heart.png red heart\_red.png create\_bullet heart.png green heart\_green.png create\_bullet heart.png blue heart\_blue.png create\_bullet heart.png yellow heart\_yellow.png create\_bullet heart.png maroon heart\_maroon.png create\_bullet heart.png cyan heart\_cyan.png | [![[IM Output]](ball.gif)](ball.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](ball_grey.gif)](ball_grey.gif) | [![[IM Output]](ball_red.gif)](ball_red.gif) | [![[IM Output]](ball_green.gif)](ball_green.gif) | [![[IM Output]](ball_blue.gif)](ball_blue.gif) | [![[IM Output]](ball_yellow.gif)](ball_yellow.gif) | [![[IM Output]](ball_maroon.gif)](ball_maroon.gif) | [![[IM Output]](ball_cyan.gif)](ball_cyan.gif) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [![[IM Output]](square.gif)](square.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](square_grey.gif)](square_grey.gif) | [![[IM Output]](square_red.gif)](square_red.gif) | [![[IM Output]](square_green.gif)](square_green.gif) | [![[IM Output]](square_blue.gif)](square_blue.gif) | [![[IM Output]](square_yellow.gif)](square_yellow.gif) | [![[IM Output]](square_maroon.gif)](square_maroon.gif) | [![[IM Output]](square_cyan.gif)](square_cyan.gif) | | [![[IM Output]](asterix.gif)](asterix.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](asterix_grey.gif)](asterix_grey.gif) | [![[IM Output]](asterix_red.gif)](asterix_red.gif) | [![[IM Output]](asterix_green.gif)](asterix_green.gif) | [![[IM Output]](asterix_blue.gif)](asterix_blue.gif) | [![[IM Output]](asterix_yellow.gif)](asterix_yellow.gif) | [![[IM Output]](asterix_maroon.gif)](asterix_maroon.gif) | [![[IM Output]](asterix_cyan.gif)](asterix_cyan.gif) | | [![[IM Output]](heart.png)](heart.png) | ![==>](../img_www/right.gif) | [![[IM Output]](heart_grey.png)](heart_grey.png) | [![[IM Output]](heart_red.png)](heart_red.png) | [![[IM Output]](heart_green.png)](heart_green.png) | [![[IM Output]](heart_blue.png)](heart_blue.png) | [![[IM Output]](heart_yellow.png)](heart_yellow.png) | [![[IM Output]](heart_maroon.png)](heart_maroon.png) | [![[IM Output]](heart_cyan.png)](heart_cyan.png) | Only the shape or transparency of the source image is used in generating the bullets, as such any shape can be used. Pick your own shape that is unique to your website. Also note that GIF or PNG can be used, with or without transparency defining the shape. The command makes no distinction. If you do use a larger image than that shown here, you may also like to increase the amount of blurring that is applied before the shade operation. Otherwise you may find only the areas close to the edge of the images will be rounded. Also it may be better to blur multiple times rather than use a big blur value (to increase the speed of the blurring). Of course if you make some improvements or have other ideas, please let me know, so we can share them with others. * * * Making Logos 3-D ---------------- In this example we have a flat colored logo, with a difficult shape, which we what to image process to give it a distinct 3-D look. To do this we use the logo to generate highlights and shadows, and magick them into transparencies to overlay on the original image. It uses a lot different techniques from all of the example pages to achieve this effect, step by step. This example makes heavy use of images generated by the [Shade Operator](../transform/#shade) . and various [Alpha Compositing](../compose/) methods. I suggest you become familiar with these image operators before proceeding, or look them up when you wish to understand better what is going on. * * * Before we can start however we will need a simple logo to apply our technique to, and its mask.... Lets first create a shape for the color background of logo example... magick -size 170x100 xc:black \\ -fill white -draw 'circle 50,50 13,50' \\ -draw 'circle 120,50 157,50' \\ -draw 'rectangle 50,13 120,87' \\ -fill black -draw 'circle 50,50 25,50' \\ -draw 'circle 120,50 145,50' \\ -draw 'rectangle 50,25 120,75' \\ -fill white -draw 'circle 60,50 40,50' \\ -draw 'circle 110,50 130,50' \\ -draw 'rectangle 60,30 110,70' \\ -gaussian 1x1 -alpha off logo\_mask.png [![[IM Output]](logo_mask.png)](logo_mask.png) Now we use our mask to cut out the solid color of our logo, and add some text to generate a plain, solid color logo. magick logo\_mask.png -background red -alpha shape \\ -font Candice -pointsize 36 -fill white -stroke black \\ -gravity Center -annotate 0 "Ant" \\ logo.png [![[IM Output]](logo.png)](logo.png) * * * Now lets give it a 3D-look, by using [Overlay Highlighting](../transform/#shade_overlay) techniques. magick logo.png -alpha extract -blur 0x6 -shade 110x30 -normalize \\ logo.png -compose Overlay -composite \\ logo.png -alpha on -compose Dst\_In -composite \\ logo\_3D.png [![[IM Output]](logo_3D.png)](logo_3D.png) Adding shadows is also easier thanks to the new [Shadow Generation](../blur/#shadow) operator provided by IM. magick logo\_3D.png \\( +clone -background navy -shadow 80x4+6+6 \\) +swap \\ -background none -layers merge +repage logo\_3D\_shadowed.png [![[IM Output]](logo_3D_shadowed.png)](logo_3D_shadowed.png) Just for fun lets finish by overlay our logo on a 'rough paper' like background. A huge number of other background canvases can also be created, see [Background Examples](../backgrounds/) for a collection of such examples. magick logo\_3D\_shadowed.png \\ \\( +clone +repage -alpha off -fx 'rand()' -shade 120x30 \\ -fill grey70 -colorize 60 \\ -fill lavender -tint 100 \\) \\ +swap -composite logo\_3D\_bg.jpg [![[IM Output]](logo_3D_bg.jpg)](logo_3D_bg.jpg) * * * Reflections ----------- Reflections are relatively easy to do, but often it does not seem like it. You have to deal with aspects such as surface color and texture, and also with how any such effect increases with the distance between the surface reflection and the object that is being reflected by that surface. Basically what should be a relatively simple matter, very quickly becomes quite a complex one. [![[IM Output]](../images/pokemon.gif)](../images/pokemon.gif) So lets start with the reflection of a relatively simple image, in this case an image of a Pokemon character, Azumarill (See right). Substitute your own image if you like. Now doing a reflection of a perfect mirror you would simply copy and flip the source object, and add some background behind it to make it to give it some context. For example... magick pokemon.gif \\( +clone -flip \\) -append \\ -size 100x100 xc:black +swap \\ -gravity North -geometry +0+5 -composite reflect\_perfect.png [![[IM Output]](reflect_perfect.png)](reflect_perfect.png) #### Surface Color - General Attenuation The thing to note in the above is that the reflection being perfect, does not really look like a reflection in a black surface. It's more like a 'mirror tile' of the original image, which is also true. Even a normal bathroom mirror does not reflect all the light hitting it, and it is about the best mirror you can get. So the first rule of reflections is... **Reflections are never ever perfect.** All reflections are never a 100% reflection, and as such are colored by the surface (or the surrounding environment). It is an imperfect world, and reflections enhance and demonstrate these imperfections very well. So let use try this again, but this time lets color the reflection by the color of the reflecting surface. You can do this in two ways. The simplest method is to simply [Colorize](../color_mods/#colorize) the reflection the same color as the surface. The amount of coloring depends on how good the surface is at reflecting, for colored surfaces, that is usually pretty bad, so a large amount of color needs to be added, "`65%`" is quite good for a black surface. magick pokemon.gif \\ \\( +clone -flip -fill black -colorize 65% \\) -append \\ -size 100x100 xc:black +swap \\ -gravity North -geometry +0+5 -composite reflect\_colored.png [![[IM Output]](reflect_colored.png)](reflect_colored.png) Much better... Now it actually looks like a reflection! The other way to make a reflection weaker is to make the reflected image semi-transparent, or translucent. For example multiply the images alpha value, to make only about 35% of the source object visible. magick pokemon.gif -alpha on \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\) -append \\ -size 100x100 xc:black +swap \\ -gravity North -geometry +0+5 -composite reflect\_alpha.png [![[IM Output]](reflect_alpha.png)](reflect_alpha.png) This is actually preferred, as it means the color of the surface can be any color or even some type of color texture or pattern. For example, lets generate a horizontal wooden floor, using an infinite tiling technique from [Viewing Distant Horizons](../distorts/#horizon) . magick tile\_wood.gif -set option:distort:viewport 100x100 \\ -virtual-pixel tile -distort Perspective \\ '0,0 -20,65 96,0 60,40 96,96 120,55 0,96 50,99' \\ wooden\_floor.png [![[IM Output]](wooden_floor.png)](wooden_floor.png) And now overlay our image with its semi-transparent reflection onto this wooden floor. magick pokemon.gif -alpha on \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\) -append \\ wooden\_floor.png +swap \\ -gravity North -geometry +0+5 -composite reflect\_wood.png [![[IM Output]](reflect_wood.png)](reflect_wood.png) Without the reflected object the wooden surface looks rather dull and lifeless, but with some object reflected in it, the floor suddenly has a very highly polished look to it! #### Distorted Source Okay. Lets try something a little more fancy, and give the image a bit of some 3D [Perspective](../distorts/#perspective) depth to it. magick pokemon.gif -alpha on -virtual-pixel transparent \\ +distort Perspective '0,0 0,0 0,64 0,64 64,0 54,10 64,64 54,54' \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\) -append \\ +filter -size 100x100 xc:black +swap \\ -gravity North -geometry +0+5 -composite reflect\_distort\_bad.png [![[IM Output]](reflect_distort_bad.png)](reflect_distort_bad.png) Which is obviously wrong. It looks like the image is distorted, but remains flat on to the original user. Why because... **Object that is in contact the surface will also contact their reflection.** It seems pretty obvious but I have seen people get this wrong. Of course if the object is floating about the surface then they will not make contact. One way to fix this would be to distort the source image and the reflection of that image separately, before [Layer Merge](../layers/#merge) the results together. magick pokemon.gif -alpha on -virtual-pixel transparent \\ \\( -clone 0 \\ +distort Perspective '0,0,0,0 0,64,0,64 64,0,54,10 64,64,54,54' \\) \\ \\( -clone 0 -channel A -evaluate multiply .35 +channel \\ +distort Perspective '0,0,0,128 0,64,0,64 64,0,54,98 64,64,54,54' \\ \\) -delete 0 +swap -background none -layers merge \\ +filter -size 100x100 xc:black +swap \\ -gravity North -geometry +0+5 -composite reflect\_distort\_sep.png [![[IM Output]](reflect_distort_sep.png)](reflect_distort_sep.png) As you can see by the very different set of distortion parameters, distorting a reflection can get very difficult. It is even more difficult as a simple change to the first distortion requires a calculated change to the second distortion for the reflected image. There are two more rules that will tell you how the coordinates of the reflected distortion should be calculated. **Reflections in a horizontal surface are always directly downward.** That is, a reflection is always toward the user, which as an user is directly in front of an image, will mean that any reflection in a horizontal surface will be downward, directly toward the user. This is a law of physics, and that is one thing you do not want to break, if you want your images to be at least semi-realistic. And finally one other rule that you should remember. **Vertical surfaces, reflected in horizontal surfaces have reflections that the same height as the reflected object** It does not matter how 'distant' the object appears to be in an image, the height of its reflection in the final image should be the same height as the object being reflected! It is not obvious, and very easy to get wrong. These three rules mean, that the X value of the reflected coordinate remains the same, by the Y value is flipped downward around the 'surface contact point' by the same amount it is above that point. As such with some care you can calculate the distortion coordinates for the reflection, based on the coordinates of the distorted source image. Now these rules also provide us with a method that can simplify reflections for distorted images. Just append the reflection to the source image first, then distort the source image as if it has no reflection attached, letting its reflection distort along with the main image... magick pokemon.gif -alpha on -virtual-pixel transparent \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\) -append \\ +distort Perspective '0,0,0,0 0,64,0,64 64,0,54,10 64,64,54,54' \\ -gravity North -crop 100x100+0-5\\! \\ -background black -compose Over -flatten reflect\_distort.png [![[IM Output]](reflect_distort.png)](reflect_distort.png) As you can see this works a lot easier, and you only have one set of distortions to deal with for the object, making changes a lot simpler too. It also allows you to use distortions that would be otherwise be impossible to repeat to create a separate reflection. For example, generating a 3D arc from the image... magick pokemon.gif -alpha on -virtual-pixel transparent \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\) -append \\ +distort Barrel '0,0,0,1 0,0,-.35,1.5 32,32' \\ -gravity North -crop 100x100+0-5\\! \\ -background black -compose Over -flatten reflect\_3Darc.png [![[IM Output]](reflect_3Darc.png)](reflect_3Darc.png) One final point before we proceed to the next section... Shadows will generally obey the same rules as reflections, except for the last two rules. They may not fall directly downward, but point away from the light source (parallel for distant light sources). Also they will not be a same distance from the 'surface contact point', but they will have the same ratio of distances, just not 1:1 ratio as you get for reflections. #### Gradient Attenuation So far we have dealt with a perfectly smooth reflective surface, but most surfaces are not polished to a mirror shine. A seemingly smooth surface is actually not smooth at smaller scales and this in turn effects the light that is reflected off such a surface. That effect also grows stronger with the distance the reflected light has to travel between the object and the point of reflection. As such... **Reflections get weaker and more distorted, the further it is from the source image.** The simplest way to create a distance effect is to make the reflection weaker the further it is from the surface. For this is is usually acceptable to make the reflection a little brighter close to the image. magick pokemon.gif -alpha on \\ \\( +clone -flip \\ -size 64x28 gradient:gray40-black \\ -alpha off -compose CopyOpacity -composite \\ \\) -append \\ -gravity North -crop 100x100+0-5\\! \\ -background black -compose Over -flatten reflect\_attenuated.png [![[IM Output]](reflect_attenuated.png)](reflect_attenuated.png) This works reasonably well, and is so easy to generate that it is a rather common method of generating reflections. The technique works as a good percentage of the light being reflected is not a perfect reflection, but more of the global environment. The more distant you are from the original image, less of the original image is reflected. #### Blurred Attenuation The component that makes up the real reflection of the source object, does not simply get weaker with distance. In reality reflections get more blurry, fuzzy and distorted with distance, as the reflecting surface is generally not very smooth. This is not a macro distortion, but distortions at very small microscopic levels. The same effect that produces specular lighting reflections. That is, close in to the source of the reflection they can be reasonably sharp, but the further you get from the source the more blurred the image becomes. Before IM version 6.5.5-0, this was something that was very difficult to achieve (it was possible, but not without a lot of trickiness). However now you can use [Variable Blur Map](../mapping/#blur) to blur a reflection based on its distance from the source image quite easily. However for this to work, it is a good idea to add a transparent border around the object into which to blur. In these examples, I extended the final image so you can see the whole reflection, so you can appreciate its effect. magick pokemon.gif -alpha on \\ -background None -gravity South -extent 100x100 \\ \\( +clone -flip -channel A -evaluate multiply .35 +channel \\ -size 100x100 gradient:gray5-white \\ -compose Blur -set option:compose:args 10 -composite -compose Over \\ \\) -append -trim +repage \\ -gravity North -crop 100x140+0-5\\! \\ -background black -compose Over -flatten reflect\_blurred.png [![[IM Output]](reflect_blurred.png)](reflect_blurred.png) The reflection blur can be enhanced further by using a vertically stretched blur ellipse. For example using elliptical blur arguments of '`10x30`' rather than a simple circluar blur of '`20`'. If you then combine the "Blurred Attenuation" with a "Gradient Attenuation" you will start to get a very realistic reflection of a typical, not-so-polished, but smooth surface reflection. magick pokemon.gif -alpha on \\ -background None -gravity South -extent 100x100 \\ \\( +clone -flip \\ \\( -size 100x64 gradient:'rgba(0,0,0,0.6)-none' \\ -size 100x36 xc:none -append \\ \\) -compose Dst\_In -composite \\ \\( -size 100x100 gradient:gray5-white \\ \\) -compose Blur -set option:compose:args 4x8 -composite \\ \\) -append -trim +repage \\ -gravity North -crop 100x140+0-5\\! \\ -background black -compose Over -flatten reflect\_blur\_atten.png [![[IM Output]](reflect_blur_atten.png)](reflect_blur_atten.png) You would be hard pressed to get a better reflection image for flat surfaces than this. Future: To add examples of... Surface Texture effects frosted - or non smooth surfaces (small scale randomised distortions) rippled - water reflections (very little blur or attenuation, just stronger macro distortion) * * * Jigsaw Pieces ------------- One of the most interesting things I have been asked to help with was to cut out and enhance an odd shaped 'jigsaw' piece from a larger picture. Actually Theo van Hoesel, also known as "[Mr Jigsaw](http://virtual-jigsaw-puzzle.blogspot.com/) ", wanted to generate a lot of separate pieces, at lots of different rotations. The following was developed from our discussion for just one piece, but with the right set of templates, any pattern of pieces can be generated. | | | | | --- | --- | --- | | To the right is a thumbnail linked to a 800x600 image of a photo of the Holocaust Memorial, Berlin, Germany. I took this photo during on my European trip in April 2006. It looks like a great image to make a really hard jigsaw puzzle from. And below it is a template image of the jigsaw piece I will be extracting from the above image. It was part of a set of such images. The full set of jigsaw pieces contains 192 such masks, in a 16 by 12 array, including edges and corners. This specific jigsaw piece is a **100x100 pixel mask**, and designed to be used at a **+365+96 offset** on an **800x600 pixel image**. These figures are only important if you have a large set of different pieces that will fit together. If you don't plan to do this then of course you can use any offset you like. | | [![[photo]](../img_photos/holocaust_tn.gif)](../img_photos/holocaust_md.jpg) | | [![[IM Output]](../images/jigsaw_tmpl.png)](../images/jigsaw_tmpl.png) | I myself have collected a number of such jigsaw sets, which can let me make a jigsaw of any image. And this is what Theo van Hoesel, is actually doing on his [website](http://virtual-jigsaw-puzzle.blogspot.com/) . If you are making an actual jigsaw puzzle then the offset information is very important, as it identifies the location and placement of that piece from the original image. As such I will try to preserve this information. Note that offsets for masks could in some cases be negative, due to the extra padding around the shape, so you may need to test and adjust image commands to handle this situation. The extra padding itself will allow you to easily rotate, add thickness and shadow effects to the final image, without needing to change the size or offset of the cutout jigsaw piece.First however lets magick this template into an outline. magick jigsaw\_tmpl.png -edge .5 -blur 0x.5 jigsaw\_edge.png [![[IM Output]](jigsaw_edge.png)](jigsaw_edge.png) I can then overlay this onto the image to get a rough idea as to what is going to be cutout to form the jigsaw piece. magick holocaust\_md.jpg \\ \\( jigsaw\_edge.png -negate \\) -geometry +365+96 \\ -compose multiply -composite \\ -crop 100x100+365+96 +repage jigsaw\_outline.png [![[IM Output]](jigsaw_outline.png)](jigsaw_outline.png) Normally this is not done when generating a jigsaw, but is useful to do when the position of the piece is not important (as it isn't part of a larger puzzle). If so you can adjust the offset to select better content for that jigsaw piece. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Due to the way "`[-edge](https://imagemagick.org/script/command-line-options.php?#edge) `" works the jigsaw outline generated above is inside the masked (white) area masking image. This can be important if you like to make use of this outline later._ | Okay we have a jigsaw shape, and an offset for the piece to cut out. so lets cut it out and rotate it too. magick holocaust\_md.jpg \\ -crop 100x100+365+96\\! -background none -flatten +repage \\ \\( jigsaw\_tmpl.png -alpha off \\) -compose CopyOpacity -composite \\ -rotate -20 -gravity center -crop 100x100+0+0 +repage \\ jigsaw\_cutout.png [![[IM Output]](jigsaw_cutout.png)](jigsaw_cutout.png) Note that we cropped the source image to the area covered by out template shape. We will not need the area outside the mask, and removing it early will speed up the image processing. Also note the special use of a [viewport crop](../crop/#viewport) , followed by "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `". This method of cropping will ensure that we will be guaranteed a 100x100 pixel image from which to 'cutout' the template, even when using masks of edge or corner pieces, and also handle a negative offset for pieces on or near the top, or left, edges of the image. The rotate is also performed at this point as most enhancements will add effects based on a specific direction. The result of that rotate is also center cropped as this operator, normally expands the resulting image size, depending on the rotation angle used, and we don't want it to do that. The first enhancement is to give the pieces a slightly beveled, or rounded, highlight around the edges. This is as per [Shade Highlight Overlays](../transform/#shade_overlay) , which allows fine control (4 separate factors) of way the highlight is produced. magick jigsaw\_cutout.png \\ \\( +clone -channel A -separate +channel -negate \\ -background black -virtual-pixel background \\ -blur 0x2 -shade 120x21.78 -contrast-stretch 0% \\ +sigmoidal-contrast 7x50% -fill grey50 -colorize 10% \\ +clone +swap -compose overlay -composite \\) \\ -compose In -composite jigsaw\_bevel.png [![[IM Output]](jigsaw_bevel.png)](jigsaw_bevel.png) In a real jigsaw this bevel is a result of machine press cutting the jigsaw pieces. It also gives the pieces a slight dent, so if the pieces are fitted back together you can still see the impression of the cuts. Now lets add some thickness to the piece. This is the best and quickest way I have found, though I don't consired it a very good technique. If you can find something better, then please let me know. magick jigsaw\_bevel.png \\ \\( +clone -fill DarkSlateGrey -colorize 100% -repage +0+1 \\) \\ \\( +clone -repage +1+2 \\) \\( +clone -repage +1+3 \\) \\ \\( +clone -repage +2+4 \\) \\( +clone -repage +2+5 \\) \\ -background none -compose DstOver -flatten \\ jigsaw\_thickness.png [![[IM Output]](jigsaw_thickness.png)](jigsaw_thickness.png) And finally how about some shadow. magick jigsaw\_thickness.png \\ \\( +clone -background Black -shadow 50x3+4+4 \\) \\ -background none -compose DstOver -flatten \\ jigsaw\_shadow.png [![[IM Output]](jigsaw_shadow.png)](jigsaw_shadow.png) All the above commands can be easily saved into a single shell script, and I have done this for my own use. The script "**`[jigsaw](../scripts/jigsaw) `**" will take three image parameters: source photo, template, and destination, as well as numerous options to enable the various enhancements shown above. It does not need to use a jigsaw shape either. Any mask template could be used to cut out parts of images, with appropriate added effects. The biggest difference between the above, and my script version, is that by default, the script keeps the final image as small as possible, while keeping track of offset of the cutout image. By preserving this offset position you can to use a simple "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" or "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" to overlay multiple pieces back together to produce interesting effects (see last example below). Here is just a few examples of using this script, in a number of ways. jigsaw -o +365+96 -m null: jigsaw\_tmpl.png jigsaw\_mask.png magick -size 800x600 xc:gray miff:- |\\ jigsaw -r 30 -l -h -s miff:- jigsaw\_mask.png jigsaw\_grey.png jigsaw -r -60 -h -t 4 -s holocaust\_md.jpg jigsaw\_mask.png jigsaw\_piece.png magick jigsaw\_cnr.png -resize 50% -flip -flop -repage 120x90 \\ -background black -flatten -flip -flop jigsaw\_cnr\_tmpl.png jigsaw -t 3 -s -r 15 -d +15+7 \\ holocaust\_tn.gif jigsaw\_cnr\_tmpl.png holocaust\_piece\_tn.png magick jigsaw\_cnr\_tmpl.png -negate png:- |\\ jigsaw -t 3 -s holocaust\_tn.gif png:- holocaust\_puzzle\_tn.png magick holocaust\_puzzle\_tn.png holocaust\_piece\_tn.png \\ -background none -mosaic holocaust\_jigsaw\_tn.png [![[IM Output]](jigsaw_mask.png)](jigsaw_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](jigsaw_grey.png)](jigsaw_grey.png) [![[IM Output]](jigsaw_piece.png)](jigsaw_piece.png) [![[IM Output]](../images/jigsaw_cnr.png)](../images/jigsaw_cnr.png) ![==>](../img_www/right.gif) [![[IM Output]](jigsaw_cnr_tmpl.png)](jigsaw_cnr_tmpl.png) ![==>](../img_www/right.gif) [![[IM Output]](holocaust_piece_tn.png)](holocaust_piece_tn.png) [![[IM Output]](holocaust_puzzle_tn.png)](holocaust_puzzle_tn.png) ![==>](../img_www/right.gif) [![[IM Output]](holocaust_jigsaw_tn.png)](holocaust_jigsaw_tn.png) The last image is the beginning of a possible jigsaw thumbnail style... It takes a corner jigsaw piece, and with some scaling and expansion converts the mask, into a full sized image template mask. This is then used to not only cut out the corner piece from an existing thumbnail, but also is negated to produce the rest of the image as well. Overlaying these two images then produces quite a fancy looking jigsaw thumbnail. Note the use of a '`-d +15+7`' in the options to the piece creation. This displaces the 'page offset' of the generated PNG image by a small amount relative to its original position in the image, producing the result shown, simply and easily. See the script itself for the other options available. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As page offsets generated can be negative, and could contain an optional soft shadow effect, it is recommended that only PNG images be used for extracted pieces. GIF images cannot handle negative page offsets, or shadow effects, nor does it produce a smooth looking anti-aliased edges when transparency is involved.

Generally you should avoid GIF (and JPEG) images for all but your final image. For more information see [Common Image Formats](../formats/)
examples page._ | You are not limited to jigsaw puzzle templates, but any shaped mask can be used with any image. Let me know what you come up with. I am not quite finished with the development of the "`[jigsaw](../scripts/jigsaw) `" script, as I would like some better controls for the highlighting, thickness and shadow effects, and possibly a 'negate mask' option. It is however basically a complete working program you are free to use. Give me a link back if you use it for a web page :-) For those with some PerlMagick API skill, try taking the above script and converting it to PerlMagick for speed, then submitting it to me so that everyone else can also use it, and know just how good you are at using IM. Further suggestions and ideas are always welcome. If you are just wanting to cut out all the pieces from an image using a collection of masks (with or without virtual pixel offsets), then the following command will let you do ALL of them very quickly. magick mask\_\*.png -set filename:mask %t -alpha shape \\ null: image.jpg -compose In -layers composite \\ pieces\_%\[filename:mask\].png Each other resulting "`pieces_mask_*.png`" images, contains not only the appropriate image from the original image at the correct offset, but also preserves that offset in the final image. It does this using the [Multi-Layer Composition](../anim_mods/#composite) to merge all the images to the left of the special "`null:`" marker image, with the single image on the right. As an added bonus it will incorporate the filename of the mask that was used into the piece image filename (including its final image file format), making identifying what piece is what much easier. (See [Filename Percent Escapes](../files/#save_escapes) for details. Note that the masks do not have to completely cover the whole original image, but should not leave spaces or gaps between pieces. Of course for a proper jigsaw all the masks should [Align](../masking/#aligning) properly, so as to produce a seamless whole, such as shown in the [Dst\_Out Composition examples](../compose/#dstout) . * * * "Gel" Effects ------------- The 3-D shadings used above is only the start of what you can do with highlight and shaded effects. By doing various histogram adjustments to the output of "[\-shade](https://imagemagick.org/script/command-line-options.php?#shade) " an enormous range of possibilities is available. One such effect you can reproduce is known as a 'Gel' effect, such as often see in "`Photoshop` how-to web sites (Google for "Gel Effects Tutorial"). First lets create the shape we need. This could be a pre-prepared image or extracted from a 'Dings' font, like we did with the 3D bullet shaped "heart" above. In this case lets use a simple oval shape for a button... magick -size 100x60 xc:none \\ -fill red -draw 'circle 25,30 10,30' \\ -draw 'circle 75,30 90,30' \\ -draw 'rectangle 25,15 75,45' \\ gel\_shape.png [![[IM Output]](gel_shape.png)](gel_shape.png) Now lets add the sharp 'Gel' highlight to the colored shape, using a highly modified blurred shade operation... magick gel\_shape.png \\ \\( +clone -alpha extract -blur 0x12 -shade 110x0 -normalize \\ -sigmoidal-contrast 16,60% -evaluate multiply .5 \\ -roll +5+10 +clone -compose Screen -composite \\) \\ -compose In -composite gel\_highlight.png [![[IM Output]](gel_highlight.png)](gel_highlight.png) We applied "[\-shade](https://imagemagick.org/script/command-line-options.php?#shade) " to a copy of the transparency (matte) channel after blurring it to round it off. Ths shade used a light source without any 'height' or 'azimith' angle to it, which basically means wer get a grey colored highlight of just one side of the blurred shape, and black for everything else. This highlighting greyscale was then adjusted (sharpened) using the "[\-sigmoidal-contrast](https://imagemagick.org/script/command-line-options.php?#sigmoidal-contrast) " operator to reduce the size the highlighted area (the '`60%`' threshold level) and sharpen its edges (using a very high '`16`' exponential factor). With such a high exponential value, the operator is almost acting like a 'fuzzy' "[\-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) " operator, to produce a flat region of color basied on the shape of the original image. For more information on this smooth contrast/threshold function see [Sigmoidal Non-linearity Contrast](../color_mods/#sigmoidal) . And finally the level of the highlight was adjusted using a "[\-evaluate](https://imagemagick.org/script/command-line-options.php?#evaluate) " to multiply all the colors by the desired highlight level, then a "[\-roll](https://imagemagick.org/script/command-line-options.php?#roll) " is used to shift its position into the shaped area. Now, as the highlight is grey on black (black to remain unchanged), a '`[Screen](../compose/#screen) `' alpha composition is used to lighten the non-black areas by the given grey level. Now all that is left is to darken the borders a little... magick gel\_highlight.png \\ \\( +clone -alpha extract -blur 0x2 -shade 0x90 -normalize \\ -blur 0x2 +level 60,100% -alpha On \\) \\ -compose Multiply -composite gel\_border.png [![[IM Output]](gel_border.png)](gel_border.png) Note that this time I used a vertically lit "[\-shade](https://imagemagick.org/script/command-line-options.php?#shade) " for edge darkening, which makes the areas I want to preserve unchanged, a white color. As such after adjusting the greyscale using a [Reversed Level Adjustment](../color_mods/#level_plus) , and restoring the transparency saved by the [Alpha Extract Method](../basics/#alpha_extract) , I was then able to use a '`[Multiply](../compose/#multiply) `' alpha composition to darken the effected borders. Lets finish of the oval 'Gel' button with some text and shadow effects... magick gel\_border.png \\ -font Candice -pointsize 24 -fill white -stroke black \\ -gravity Center -annotate 0 "Gel" -trim -repage 0x0+4+4 \\ \\( +clone -background navy -shadow 80x4+4+4 \\) +swap \\ -background none -flatten gel\_button.png [![[IM Output]](gel_button.png)](gel_button.png) * * * "Aqua" or "Bubble" Effects -------------------------- You can also adjust a full 3-D "[\-shade](https://imagemagick.org/script/command-line-options.php?#shade) " (with a 30 degree lighting) tint to produce a "Aqua" water effect. For this however we need to do a histogram adjustment in a way that is similar to what you do with GUI graphical programs like "`Gimp`" and "`Photoshop`". I will first do this slowly step by set so you can see the steps I am following. First lets create an image to use, in this case a curvy letter A. magick -background none -fill DodgerBlue \\ -font Candice -pointsize 72 label:A -trim +repage \\ -bordercolor None -border 1x1 \\ aqua\_shape.png [![[IM Output]](aqua_shape.png)](aqua_shape.png) Note that I added a one pixel transparent border around the image. This makes the next processing steps just that little bit easier. Now we need to generate [Rounded Shade](../transform/#shade_blur) of this shaped image. magick aqua\_shape.png \\ -alpha Extract -blur 0x8 -shade 130x30 -alpha On \\ -background gray50 -alpha background -auto-level \\ aqua\_shade.png [![[IM Output]](aqua_shade.png)](aqua_shade.png) The funny line that deals with [Alpha Background](../basics/#alpha_background) is to reset the hidden color of the transparent areas to a mid-tone grey, so that it does not have an effect on the color normalization. This can be very important. Now we magick that shade into a 'lighting effect' that looks vaguely like the way light is distorted by a bubble of water or glass. magick aqua\_shade.png \\ -function polynomial 3.5,-5.05,2.05,0.3 \\ aqua\_lighting.png [![[IM Output]](aqua_lighting.png)](aqua_lighting.png) The [Polynomial Function](../transform/#function_polynomial) which is used for a [Curves Adjustment](../color_mods/#curves) of the image. It is this function that gives the overall effect, and can be difficult to determine. To do I passed the control points needed for this 'curve' to the IM support shell script called "`[**im_fx_curves**](../scripts/im_fx_curves) `". This then returns the the 'coefficents' for the polynomial equantion needed for the 'curve that fits these control points. im\_fx\_curves -c -p 0,30 100,80 50,50 80,50 > aqua\_coeffs.txt [![[Gnuplot]](aqua_plot.gif)](aqua_plot.jpg) ![==>](../img_www/right.gif)[![[Coeffs]](aqua_coeffs.txt.gif)](aqua_coeffs.txt) The final adjustment of this lighting effect is make the edges of the lighting effect darker. magick aqua\_lighting.png \\ \\( +clone -alpha extract -blur 0x2 \\) \\ -channel RGB -compose multiply -composite \\ aqua\_light+edge.png [![[IM Output]](aqua_light+edge.png)](aqua_light+edge.png) And the shading overlay is complete. All that is left is to apply this to the original image, using [HardLight Composition](../compose/#hardlight) . magick aqua\_shape.png aqua\_light+edge.png \\ -compose Hardlight -composite aqua\_result.png [![[IM Output]](aqua_result.png)](aqua_result.png) Notice that the final overall color of the resulting image is actually the original color of the original shape. In fact you coluld even apply this to a multi-colored image, without any problems at all. So lets repeat all the steps above, including the creation of the initial shape image, all in one command. magick -background none -fill DodgerBlue \\ -font Candice -pointsize 96 label:'Aqua Text' -trim +repage \\ \\ \\( +clone -bordercolor None -border 1x1 \\ -alpha Extract -blur 0x8 -shade 130x30 -alpha On \\ -background gray50 -alpha background -auto-level \\ -function polynomial 3.5,-5.05,2.05,0.3 \\ \\( +clone -alpha extract -blur 0x2 \\) \\ -channel RGB -compose multiply -composite \\ +channel +compose -chop 1x1 \\ \\) \\ -compose Hardlight -composite aqua\_text.png [![[IM Output]](aqua_text.png)](aqua_text.png) If you study the above you will see that all the steps previously outlined is applied to generate the lighting image which is then composited onto the original image. * * * Tilable Stars and Comets ------------------------ I wanted to make a tile of random star fields (with the stars of variable intensities) for various purposes. This was the result of my slowly improving attempts at this. A [random noise](../canvas/#random) image is used to thin itself out generate a speckle pattern. magick -size 100x100 xc: +noise Random -channel R -threshold 5% \ -negate -channel RG -separate +channel \ -compose multiply -composite speckles.gif [![[IM Output]](speckles.gif)](speckles.gif) This pattern is the basis for glitter animation effects, but also the start point for other effects. For example to make stars we need to modify its random 'speckle' pattern a bit more, so as to make things more realistic. magick -size 100x100 xc: +noise Random -channel R -threshold 1% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel tile -blur 0x.4 -contrast-stretch .8% \ stars.gif [![[IM Output]](stars.gif)](stars.gif) Note that I multiply not only the speckle mask ('`R`' channel) but the star intensity image ('`G` channel) twice as well. This produces a squared fall-off in the pixel intensities so that more darker stars are present than bright ones, just as it is in the real night sky. After this we enlarge the size of the stars based on their intensity by [Blurring](../blur/#blur) . This produces an effect similar to the stars burning onto an astronomers photographic plate, making it even more realistic. The larger the blur value the larger the effect. A final "`[-contrast-stretch](https://imagemagick.org/script/command-line-options.php?#contrast-stretch) `" brings the results back to visibility. By using two [random noise](../canvas/#random) images, (one for the mask, the other for the star color), we can generate randomly colored stars, instead of simple greyscale ones. magick -size 100x100 xc: +noise Random -channel R -threshold 1% \ -negate -channel RG -separate +channel \ \( xc: +noise Random \) -compose multiply -flatten \ -virtual-pixel tile -blur 0x.4 -contrast-stretch .8% \ stars_colored.gif [![[IM Output]](stars_colored.gif)](stars_colored.gif) This however may need more work, as we need to square the intensity of the colors directly instead of just simply multiplying them against a linear distribution. It does however work, and provides a starting point for further development. Note the color does not have to be random but could easily come from some other image for the stars. For example the star color itself could be sourced from the image that will be used as the final background. Now that I have a star-scape generator, I can simply use "`[-motion-blur](https://imagemagick.org/script/command-line-options.php?#motion-blur) `" to create a field of falling stars! magick -size 100x100 xc: +noise Random -channel R -threshold .4% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel tile -blur 0x.4 -motion-blur 0x20+45 -normalize \ star_fall.gif [![[IM Output]](star_fall.gif)](star_fall.gif) Of course we want less stars and less of a 'fall-off' in star intensities. By [Polar Distorting](../distorts/#polar) the image we can make the comets flying or spiraling into a point! magick -size 250x100 xc: +noise Random -channel R -threshold .4% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel Tile -background Black \ -blur 0x.6 -motion-blur 0x15-90 -normalize \ +distort Polar 0 +repage star_inward.gif magick -size 250x100 xc: +noise Random -channel R -threshold .4% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel Tile -background Black \ -blur 0x.6 -motion-blur 0x15-60 -normalize \ +distort Polar 0 +repage star_spiral.gif [![[IM Output]](star_inward.gif)](star_inward.gif) [![[IM Output]](star_spiral.gif)](star_spiral.gif) Here we motion blur the stars in six directions (in pairs) then merge them together to create a field of 'star bursts', such as you get in a glass lens. magick -size 100x100 xc: +noise Random -channel R -threshold .2% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel tile -blur 0x.3 \ \( -clone 0 -motion-blur 0x10+15 -motion-blur 0x10+195 \) \ \( -clone 0 -motion-blur 0x10+75 -motion-blur 0x10+255 \) \ \( -clone 0 -motion-blur 0x10-45 -motion-blur 0x10+135 \) \ -compose screen -background black -flatten -normalize \ star_field.gif [![[IM Output]](star_field.gif)](star_field.gif) Note how the darker stars only generate a small dot and very little in the way of a 'star burst', while the bigger bright stars generate a very large 'star burst'. Now if I can find a way to add a 'sinc()' type blurring so as to produce a flare 'ring' around the brightest stars as well, we will have a great star field generator. Add some plasma background and we can even generate fake astronomical photos of nebula and gas clouds. By combining the above with a [plasma glitter animation](../anim_mods/#glitter) you can make set of stars that look like christmas decorations. magick -size 100x100 xc: +noise Random -separate \ null: \ \( xc: +noise Random -separate -threshold 50% -negate \) \ -compose CopyOpacity -layers composite \ null: \ plasma:red-firebrick plasma:red-firebrick plasma:red-firebrick \ -compose Screen -layers composite \ null: \ \( xc: +noise Random -channel R -threshold .08% \ -negate -channel RG -separate +channel \ \( +clone \) -compose multiply -flatten \ -virtual-pixel tile -blur 0x.4 \ \( -clone 0 -motion-blur 0x15+90 -motion-blur 0x15-90 \) \ \( -clone 0 -motion-blur 0x15+30 -motion-blur 0x15-150 \) \ \( -clone 0 -motion-blur 0x15-30 -motion-blur 0x15+150 \) \ -compose screen -background black -flatten -normalize \) \ -compose multiply -layers composite \ -set delay 30 -loop 0 -layers Optimize stars_xmas.gif [![[IM Output]](stars_xmas.gif)](stars_xmas.gif) The above technique is only the start of what can be achieved. Using some simple animations techniques, glitters and random flares can be created which can be added to images. One simple example of this was provided in [GIF animation examples](../anim_basics/#gif_anim) , using a simple shell script "**`[star_field](../scripts/star_field) `**" to generate the stars bursts. What can you to with this star generator? **Challenge:** * Generate glitter rather than stars. The initial speckle field should be limited by a mask (say by multiplying). Both glitter and stars can then be overlaid onto an image using 'screen' composition. * Use a masked 'speckle field' to generate star bursts for overlaying. By masking the seeds rather than the complete star burst, means that 'rays' of the bursts can leave the masked area to overlay other parts of the image. That is, rays are not just 'cutoff'. * Create an animation of a random star bursts. This may require you to magick animate a single field of star bursts (perhaps with the rays rotating). * By generating a few star burst animations, you can merge them together to form a series of overlapping star bursts from different locations. * Find a single 'seed' point on the brightest part of the image by histogram stretching a thresholding. Then picking single pixels until one hits the masked area. * Creating stars on the edge a flat shaded shape. If you manage any of the above challenge or use the star generator for some other purpose, please let me and the rest of the IM community know. * * * Radial Flares ------------- Experiments in generating radial flares. Note that the width of the initial image before polar distorting, basically sets the number of rays that will be produced. magick -size 100x1 xc: +noise Random -channel G -separate +channel \ -scale 100x100\! +write flare_1a.png \ \( -size 100x100 gradient:'gray(100%)' -sigmoidal-contrast 10x50% \) \ -colorspace sRGB -compose hardlight -composite +write flare_1b.png \ -virtual-pixel HorizontalTileEdge -distort Polar -1 \ flare_1_final.png [![[IM Output]](flare_1a.png)](flare_1a.png) ![==>](../img_www/right.gif) [![[IM Output]](flare_1b.png)](flare_1b.png) ![==>](../img_www/right.gif) [![[IM Output]](flare_1_final.png)](flare_1_final.png) Note how I use "`[+write](https://imagemagick.org/script/command-line-options.php?#write) `" to save intermediate images for display. this is a debugging technique which is detailed in [Complex Image Processing and Debugging](../basics/#complex) . Here is another example using multiple overlays to achieve a different looking flare. Note the technique used to generating intermediate debugging and example images showing the steps involved. magick -size 100x1 xc: +noise Random -channel G -separate +channel \ -size 100x99 xc:black -append -motion-blur 0x35-90 \ \( -size 100x50 gradient:'gray(0)' \ -evaluate cos .5 -sigmoidal-contrast 3,100% \ -size 100x50 xc:'gray(0)' -append \) \ \( -size 1x50 xc:'gray(0)' \ -size 1x1 xc:'gray(50%)' \ -size 1x49 xc:'gray(0)' \ -append -blur 0x2 -scale 100x100\! \) \ \ -scene 10 +write flare_2%x.png \ \ -background 'gray(0)' -compose screen -flatten +write flare_2f.png \ \ -virtual-pixel HorizontalTileEdge -distort Polar -1 \ -colorspace sRGB flare_2_final.png [![[IM Output]](flare_2a.png)](flare_2a.png) [![[IM Output]](flare_2b.png)](flare_2b.png) [![[IM Output]](flare_2c.png)](flare_2c.png) ![==>](../img_www/right.gif) [![[IM Output]](flare_2f.png)](flare_2f.png) ![==>](../img_www/right.gif) [![[IM Output]](flare_2_final.png)](flare_2_final.png) The major problem with using polar distort for generating flare images is that the rays become wider with the radius, where really we want them to either remain a roughly constant width as they get dimmer, or at least thinner. _Ideas and pointers welcome_Color tinting can also be important in this type of image. For example, here I [Tint Mid-Tone Colors](../color_mods/#tint) Blue. magick flare\_2\_final.png -fill SkyBlue -tint 100% flare\_2\_color.png [![[IM Output]](flare_2_color.png)](flare_2_color.png) The percentage used for the "`[-tint](https://imagemagick.org/script/command-line-options.php?#tint) `" operation can also be used to adjust the intensity of the rays and flare ring, though it will not change the white core of the image very much. These examples were taken further in the IM Forum discussion [Using Radial Flare for a Mask](https://magick.imagemagick.org/viewtopic.php?t=16004) . * * * --- # Video Handling -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Video Handling ================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Video to GIF, Optimization Summary](#gif) [![](../img_www/granitesm_right.gif) De-interlace a Video Frame](#deinterlace) ImageMagick is not particularly suited to the handling of Digital Video handling, but it is commonly used for this purpose, especially in the Linux environment. Here I explore techniques and examples that are specific to handling of real life (and raytraced) video sequences. * * * Video to GIF, Optimization Summary ---------------------------------- A software developer who uses IM to create Movie GIFs, [Benoit Rouleau](http://software.benetonfilms.com/) , in discussion with me, gave me an AVI video of a [plane flying over](../images/plane.avi) , to help us mutually explore IM video conversion techniques. However while the AVI itself is quite small, the uncompressed video is a massive [![[IM Text]](plane_avi_size.txt.gif)](plane_avi_size.txt) bytes in size, and involves [![[IM Text]](plane_avi_ncolors.txt.gif)](plane_avi_ncolors.txt) colors, over [![[IM Text]](plane_avi_frames.txt.gif)](plane_avi_frames.txt) frames.IM however has no real trouble converting this video into a GIF animation. However be warned that you will probably get some unsupported 'AVI chunk' errors, which can be ignored by using a "`[-quiet](https://imagemagick.org/script/command-line-options.php?#quiet) `" [control setting](../basics/#controls) . magick -quiet -delay 1 plane.avi plane.gif [![[IM Output]](plane.gif)](plane.gif) This used ImageMagick's the default [Color Quantization and Dithering](../quantize/) methods, to produce a very reasonable conversion of the video. Very few color problems exist, because the video uses very few colors to start with. This is not always the case, especially as GIF has 256 colors per frame limit. However the animation file is [![[IM Text]](plane_size.txt.gif)](plane_size.txt) bytes in size, which while only 1/5th the size, due to color reduction and GIF pixel data compression, it is still rather large. Also if you study the resulting animation further you will find that of the [![[IM Text]](plane_avi_frames.txt.gif)](plane_avi_frames.txt) frames in the image, [![[IM Text]](plane_ctables.txt.gif)](plane_ctables.txt) frames had their own own separate [local color table](../anim_opt/#colortables) added. That is, each and every frame in the GIF animation required there own color index table. That is, while each frame has less that 256 colors (due to the GIF format limitations), the whole animation is using a total of [![[IM Text]](plane_ncolors.txt.gif)](plane_ncolors.txt) colors. Unfortunately the GIF format does not compress color tables, so all those extra color tables could be using up to:   256 colors \* 3 byte per color \* 106 frames;   or 81,408 bytes of file space. Not a lot for a 1Gbyte video but still an appreciable amount of space, especially as we optimize the video further. Added to this is that the animation will not GIF frame optimize very well. Not only because the background is moving (due to the camera panning upward), but also because IM used a [Error Correction Dither](../quantize/#dither_error) (Hilbert Curve Dither), which produces a pseudo-random pattern of colors that is different from frame to frame. A later example will make this 'dither noise' much more visible. #### Common Global Color Table Here I [Generate a Single Global Color Table](../anim_opt/#colortables) for all the frames of the video. magick -quiet -delay 1 plane.avi +remap plane\_cgc.gif This naturally results in [![[IM Text]](plane_cgc_ctables.txt.gif)](plane_cgc_ctables.txt) local color tables, and a file size of [![[IM Text]](plane_cgc_size.txt.gif)](plane_cgc_size.txt) bytes.[![[IM Output]](plane_cgc.gif)](plane_cgc.gif) As you can see the resulting animation has no extra local colortables. Instead IM generated a single global color table of [![[IM Text]](plane_cgc_ncolors.txt.gif)](plane_cgc_ncolors.txt) of the 'best' colors based on all the frames in the animation. Unfortunately this also resulted in the pixel data not compressing as well as it did before, as a stronger dither was required. The result is a slightly worse looking animation, that is roughly the same size as the previous. For this specific video of limited colors, I could even reduce the number of colors used even further say to only 64 colors without too many problems, producing an even smaller animation file size. This however is very dependent on the video sequence used, and may not look very good. Your own video may have a better result or worse result, especially when dealing with a video that uses a lot more colors and possibly multiple scenes. #### Universal Global Color Table The better way to generate a 'smaller' GIF animation is to just supply a general universal range of colors rather than generate the 'best' global color table for an animation. Use one that should work well regardless of what colors are present in the original video. Another reason for doing this is that you can make you video longer without serious detrimental effects on the color selection, or resorting local color tables for each frame. Each frame is dithered to the same color map, completely independently of what other frames are in the animation.Here I use a ['332' color map](../quantize/#332_colormap) which is usually regarded as being a very good standard colormap when no transparency is needed. I have often seen this colormap (or a 219 color ['web-safe' colormap](../quantize/#netscape) ) used often in various video formats. magick -quiet -delay 1 plane.avi -remap colormap\_332.png plane\_ugc.gif [![[IM Output]](plane_ugc.gif)](plane_ugc.gif) This animation has [![[IM Text]](plane_ugc_ctables.txt.gif)](plane_ugc_ctables.txt) local color tables, and as a result the animation is smaller or [![[IM Text]](plane_ugc_size.txt.gif)](plane_ugc_size.txt) bytes in size. The problem however is that you will often see an obvious and annoying 'noise' in areas of constant color. This noise was also present in ALL the previous video animations. It is only now visible due to the use of a more universal, and thus more widely spread out color mapping. The noise is actually caused by the dithering of the reduced color set when regenerating the image. However, this produces a pseudo-random pattern of colors that changes from frame to frame, resulting in the appearance of background noise in the image. See [Problems with E-Dithers](../quantize/#dither_prob) for more detail as to why this happens.We could just turn off the color dithering to remove the 'dither noise'... magick -quiet -delay 1 plane.avi \\ +dither -remap colormap\_332.png plane\_ugc\_nd.gif Which has [![[IM Text]](plane_ugc_nd_ctables.txt.gif)](plane_ugc_nd_ctables.txt) local color tables, and is [![[IM Text]](plane_ugc_nd_size.txt.gif)](plane_ugc_nd_size.txt) bytes in size.[![[IM Output]](plane_ugc_nd.gif)](plane_ugc_nd.gif) The resulting animation is a very small 1/60th the size of the original animation, generally because of the large expanses of solid color producing extremely good pixel compression. But while it fixes the dither noise, and make for a very small file size, you get color banding instead, which is generally regarded as a very bad trade-off. #### Ordered Dithered Video The real solution is to use a different color dithering technique, which does not produce a different pattern from one frame to the next.For example, here I used a [Ordered Dither using Posterized Color Levels](../quantize/#od_posterize) to dither the same universal ['332' colormap](../quantize/#332_colormap) . magick -quiet -delay 1 plane.avi \\ -ordered-dither o8x8,8,8,4 +remap plane\_od.gif Which has [![[IM Text]](plane_od_ctables.txt.gif)](plane_od_ctables.txt) local color tables, and is [![[IM Text]](plane_od_size.txt.gif)](plane_od_size.txt) bytes in size.[![[IM Output]](plane_od.gif)](plane_od.gif) The above also used the "`[+remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator, to ensure that all the images use the exact same global color map (which the ordered dither already reduced to a maximum of 256 colors). As the number of colors is already optimal, the "`[+remap](https://imagemagick.org/script/command-line-options.php?#remap) `" operator does no dithering, or color reduction. The resulting dither pattern is not random, and does not change greatly from one frame to the next. Thus the 'dither noise' has been remove from the animation resulting in a fixed color pattern from from to frame. The pattern is also very repetitive allowing much better compression. And finally as the color map is fixed, it should work reasonably well regardless of what video is used. #### Higher Quality Ordered Dithered Video This specific video however only uses a small range of colors, mostly various shades of blue, so it doesn't actually use a lot of the colors provided by a general uniform colormap. In fact only [![[IM Text]](plane_od_ncolors.txt.gif)](plane_od_ncolors.txt) colors were used in the last video animation! This is extremely low, and as such also quite visible. But it also means that this particular animation can benefit from using a large number of 'color levels' in the ordered dither operation, so as improve the overall quality. First however we need to determine how many color levels the animation can handle before it reaches the 256 color limit imposed by both the GIF file format and the global colormap re-mapping. The tricky part however is that you must determine these BEFORE you save the animation to the limited GIF format. And here is the command I use... magick -quiet plane.avi -ordered-dither o8x8,23 -append -format %k info: [![[IM Text]](plane_od2_find.txt.gif)](plane_od2_find.txt) Basically I increased and decreased the number of color levels to use, until I had a figure that was just within the required 256 color limit.I can then apply the discovered 'color level' choice to the plane animation. magick -quiet -delay 1 plane.avi \\ -ordered-dither o8x8,23 +remap plane\_od2.gif Which has [![[IM Text]](plane_od2_ctables.txt.gif)](plane_od2_ctables.txt) local color tables, is [![[IM Text]](plane_od2_size.txt.gif)](plane_od2_size.txt) bytes in size, and [![[IM Text]](plane_od2_ncolors.txt.gif)](plane_od2_ncolors.txt) colors.[![[IM Output]](plane_od2.gif)](plane_od2.gif) As you can see a very high quality, ordered dithered video was generated, which is on a par with the 'best colormap' global color map version we generated earlier, but also 1/3 smaller in size, while the 'dither noise' is now much harder to see. Of course as the quality is so much higher, it does require a larger file size, as it doesn't compress as well as the low quality version. On the other hand you now actually have a good control over the quality vs file size trade-off in the form of the number of 'color levels' used. Just remember this technique is a _special case_, for an animation that does not use too many colors. And making the video longer by adding more frames will also add more colors, and thus require a reduction in the 'color level' quality control. This is about the best method of color optimization I have yet seen for general GIF animations. It removes 'dither noise', provides some quality control, and retains the ability to use other GIF animation optimization methods, such as [Frame Optimization](../anim_opt/#frame_opt) . #### Compression (Transparency) Optimization Because this video uses a panning camera, the background of the video changes from frame to frame. This means the GIF animation will not [Frame Optimize](../anim_opt/#frame_opt) very well.However we can still use a simple [Transparency Optimization](../anim_opt/#opt_trans) to further reduce the final size of the GIF animation. magick plane\_od2.gif -layers OptimizeTransparency +remap plane\_opt.gif The result is [![[IM Text]](plane_opt_size.txt.gif)](plane_opt_size.txt) bytes in size, and [![[IM Text]](plane_opt_ncolors.txt.gif)](plane_opt_ncolors.txt) colors.[![[IM Output]](plane_opt.gif)](plane_opt.gif) That is, one extra color, a transparent color index, was added to the image, and any pixel that does not change the currently displayed color was made transparent. This in turn generates large segments of transparent areas in the original animation, as well as repeats of similar pixel sequences, which generates an improved LZW compression in the final GIF image. Not bad, the animation is now half that of the direct conversion to GIF, and still a reasonably high quality. _If you like to add to the above, discuss the techniques to further improve them, please contact me, or the IM forum. I am more than happy to hear about your views, techniques and discussions, or look at a specific video/animation problem you may have._ One such discussion is [Finding the "right levels" for quantization with anim GIF](https://magick.imagemagick.org/viewtopic.php?f=1&t=20081&p=79602) . #### Giflossy Compression LZW Optimization A new tool, [GifLossy](https://kornel.ski/lossygif) which is a fork of the original [Gifsicle](http://www.lcdf.org/gifsicle/) program modifies the colors of each frame so as to allow LZW to compress the image much more.For example, here I applied it to the original GIF animation, asking it to reduce the colors to a single 256 color table. gifsicle -O3 --lossy=80 --colors 256 plane.gif -o plane\_giflossy.gif Which has an absolutely amazing size of [![[IM Text]](plane_giflossy_size.txt.gif)](plane_giflossy_size.txt) bytes. It isn't nearly as high a quality as what we achieved using ordered dither but it is less than 1/2 the size.[![[IM Output]](plane_giflossy.gif)](plane_giflossy.gif) Emboldened by that above result I decided to use [GifLossy](https://kornel.ski/lossygif) on the best ordered dither result we got, to see if it can make it even smaller. gifsicle -O3 --lossy=80 plane\_od2.gif -o plane\_od2\_giflossy.gif And we did get an even smaller size of [![[IM Text]](plane_od2_giflossy_size.txt.gif)](plane_od2_giflossy_size.txt) bytes. Unfortunately we basically lost the high quality ordered dither result we works so hard to achieve before. Which is disappointing.[![[IM Output]](plane_od2_giflossy.gif)](plane_od2_giflossy.gif) * * * De-Interlacing a Video Frame ---------------------------- Not all images are from digital cameras. It is very common to extract images from a digital video feed from a non-CCD video camera. These images are interlaced for direct display on a TV, resulting in every second line being a different frame of the image (interlacing). For two frames where things aren't moving, the interlacing is usually not very noticeable. Perhaps producing only a slight edge blurring of the image. But when a fast moving object is involved, the resulting interlaced image is very disconcerting, as two frames have been merged together.Wolfgang Hugemann (Germany), had this problem and sent me a snapshot of a [crash test](../img_photos/video_frame.png) , that Wolfgang took himself. But for demonstration I will use a smaller image cropped from this one. The techniques however will work on the full sized image. magick video\_frame.png -crop 100x100+200+470 +repage interlaced.png [![[IM Output]](interlaced.png)](interlaced.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Wolfgang Hugemann used a TIFF format for the original video frame, I converted this to PNG for use on IM Examples. Do NOT be tempted to use JPEG for these images, until you have finished processing as it will destroy the low level quality needed for this process._ | As you can see the interlacing shows two separate frames, as it comes from a interlaced PAL digital video sequence, (approx 50 half frames per second). Yes the car was moving very fast and the camera is using a high speed shutter, producing a very high quality video image. The resulting image is two interwoven half-frames with the car's side mirror moving quite a distance during the intervening 1/50 second time period between half frames.Here we just replace one of the interlaced half-frames (every second line) with white. This is the standard de-interlacing method, known as a 'BoB' filter. This was contributed by Wolfgang for IM Examples. magick interlaced.png -fx "floor(j/2)==j/2 ? u : 1" deinterlace\_1.png [![[IM Output]](deinterlace_1.png)](deinterlace_1.png) Now the [FX operator](../transform/#fx) is slow, so an alturnative is to create a 'striped image'. Such an image can be generated from the special "`pattern:Horizontal2`" built-in image.That image can then be overlaid with the original, using a '`[Screen](../compose/#screen) `' composition method to overlay white lines, or use '`[Multiply](../compose/#multiply) `' or overlay black lines. For example... magick -size 100x100 pattern:Horizontal2 \\ interlaced.png -compose Multiply -composite deinterlace\_2.png [![[IM Output]](deinterlace_2.png)](deinterlace_2.png) Negating the pattern can be used to select the other half of the interlaced image. Or if you change the '`Multiply`' to '`Screen`' you can extract frames with a white background.As an alternative I tried to fill in the missing frame lines by just duplicating the previous line. magick interlaced.png -fx "u.p{i,j-j%2}" deinterlace\_3.png [![[IM Output]](deinterlace_3.png)](deinterlace_3.png) You can also use a [Pixelization Technique](../transform/#pixelate) to shrink and expand an image so as to double up every second line. magick interlaced.png -sample 100%x50% \\ -sample 100%x200% deinterlace\_4.png [![[IM Output]](deinterlace_4.png)](deinterlace_4.png) And with a slight variation you can combine the lines on both sides to vertically smooth the half-frame image as part of the resize expansion. magick interlaced.png -sample 100%x50% \\ -resize 100%x200% deinterlace\_5.png [![[IM Output]](deinterlace_5.png)](deinterlace_5.png) The result is a particularly nice extraction of one frame of the interlaced video image.If you want to extract the other half-frame from the image you can adjust the '`sampling:offset` (as of IM v6.8.4-7) magick interlaced.png -define sample:offset=75 \\ -sample 100%x50% -resize 100%x200% deinterlace\_6.png [![[IM Output]](deinterlace_6.png)](deinterlace_6.png) Before this version of IM you would need to "`[-roll](https://imagemagick.org/script/command-line-options.php?#roll) `" the image by one pixel, to achieve the same result. * * * --- # Common Formats -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Common Image Formats ======================================================================== **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) A Brief Summary of Common Image File Formats](#summary) [![](../img_www/granitesm_right.gif) GIF Image File Format](#gif) * [GIF Limited Color Table](#gif_colors) * [GIF Transparency Color](#gif_trans) * [GIF Boolean Transparency](#boolean_trans) * [GIFs on a solid color background](#bgnd) * [GIFs on a background pattern](#bg_pattern) * [GIFs for non-specific backgrounds](#dither) (transparency dithering) * [Non-ImageMagick GIF Processing](#gif_non-im) * [GIF Offset Handling](#gif_offsets) * [Related GIF Output Formats - GIF87](#gif87) [![](../img_www/granitesm_right.gif) JPEG Image File Format](#jpg) * [JPEG compression](#jpg) * [JPEG transparency - NOT](#jpg_trans) * [JPEG Color Distortion](#jpg_color) * [Reading JPEG images](#jpg_read) * [Writing JPEG images](#jpg_write) * [Related JPEG Output Formats](#jpg_formats) (A quick summary) * [Non-ImageMagick JPEG Processing](#jpg_non-im) (A quick summary) * [Lossless JPEG Processing](#jpg_lossless) [![](../img_www/granitesm_right.gif) PNG Image File Format](#png) * [PNG compression](#png_quality) * [PNG better compression](#png_compress) * [PNG, Web Browsers and Transparency](#png_www) * [PNG and the Virtual Canvas](#png_offsets) * [PNG Resolution, Density and Units](#png_density) * [PNG Sub-Formats](#png_formats) * [Writing PNG Image Controls](#png_write) * [Non-ImageMagick PNG Processing](#png_non-im) [![](../img_www/granitesm_right.gif) Image Profiles](#profiles) * [Changing Colorspace of an Image](#color_profile) -- RGB <=> CMYK conversion * [IPTC Profiles](#profile_iptc) [![](../img_www/granitesm_right.gif) A Word about Vector Image Formats](#vector) [![](../img_www/granitesm_right.gif) Other Image File Formats](#other) [Postscript (PS),  Encapsulated PS (EPS),  PDF](#ps) , [PbmPlus/NetPBM (PBM, PGM, PPM, PNM, PAM)](#pbmplus) , [TIFF](#tiff) ,   [BMP](#bmp) ,   [ICO](#ico) ,   [RAW Digital Image (CRW,CR2,etc)](#crw) , [MPEG, M2V and AVI](#mpeg) ,   [MNG](#mng) ,   [Digital Picture Exchange (DPX)](#dpx) , [PSD](#psd) ,   [WMF](#wmf) ,   [MacroMedia Flash (SWF)](#swf) , [Webpage HTML Conversion](#html) ,   [PCL Printing Format](#pcl) , [Kodak PhotoCD Format (PCD)](#pcd) ,   [Raw RGB Data](#rgb) , Many of the image file formats have particularities which you need to keep in mind when using that format. This page deals with these special needs, and ways to improve results in those formats. * * * A Brief Summary of Common Image File Formats -------------------------------------------- For an introduction to reading and writing image formats see [Image File Formats](../files/) . While a list of all the ImageMagick file formats are given on the [IM Image Formats Page](https://imagemagick.org/script/formats.php) . Here is a very quick summary of the most common 'normal' image file formats, as well as their general advantages and disadvantages... [**GIF**](#gif) This format is extremely common, and has been around for so long that all image handling programs understand it. But only uses a limited number of colors (a 256 color table) and only saves using 8 bit quality. However its built-in run-length encoding allows it to save images with only a few colors very efficiently. While the format has transparency, it only understands Boolean (on/off) transparency and so consequently suffers from 'aliasing' or 'jaggies'. Plain text with thin lines suffers badly when saved as a transparent GIF image. The only solution to this problem is to tie the GIF image to a specific background of the web page in which it is used. The GIF format can save multiple images to form an animation sequence, and for this purpose also saves the image canvas size and offset (page) information. Note however that negative offsets are not supported, and attempts to do so resets that offset to zero. Its best used for small images of cartoons, line drawings, and small icons, all of which have limited colors, and will allow it to compress well. Its use however should be avoided when a newer format like PNG is available. [**JPEG**](#jpg) Does not handle transparency at all. The image is equivalent to using "`[-alpha off](https://imagemagick.org/script/command-line-options.php?#alpha) `" operation to remove the alpha channel, so any background transparency commonly becomes black depending on the image processing used to generate the image. This format is also 'lossy', producing edge effects on sharp lines and borders and thus should not be used for any intermediate image processing, or storage of image originals (unless they were already in this format). It is well suited to long term storage of real life photographs, but avoid it if you plan to further process the image, or the image contains large areas of solid colors. [**PNG**](#png) This format is intended to eventually replace older formats like GIF and TIFF. It is a modern format capable of handling 16 bit quality with four color channels allowing the full use of semi-transparent colors. It also includes a huge number of lossless image compression options. Its biggest disadvantage is that it is still relatively new, such that the Microsoft IE (v6) web browser does not automatically handle it correctly. However a fix is available for this problem. The format does not save canvas size information (where GIF does), but it does save the canvas offsets and even negative offsets (which GIF does not), though some web browsers have problems when a negative offset is used, so this is not recommended for a final image to be displayed in a browser. For saving intermediate 'layered' images, the ability to save negative offsets can be very important and is often much more important than its not saving canvas size information. **MNG** This is the multi-image format for PNG, and allows animations to movie quality levels and speed. _A simple example of using MNG is wanted, so if you have one mail me._ The MNG animation format appears to becomeing obsolete and has been abandoned by some web broswers such as FireFox. [**TIFF**](#tiff) This is the Image interchange format that was developed to transfer high quality images between programs before any serious image formats were available. Unfortunately, because of this beginning, the format has been modified with a haphazard array of features and compression styles and no programs understands them all. The format is now pretty well only use by "`[Photoshop](http://www.adobe.com/products/photoshop/) `" on windows platforms, and this is the only source that provides any sort of standard reference for the TIFF image format. TIFF files can handle multiple images, though few applications other than IM handle multiple image TIFFs. Generally, unless the internal format of the TIFF image is kept relatively basic, there is no guarantee that a TIFF file generated by one program will be usable by another program, including IM or even "`[Photoshop](http://www.adobe.com/products/photoshop/) `" itself. As such I do not recommend this format period! I suggest you use some other format than TIFF (or JPEG), especially for long term storing of images. The few notes I have on this format and its problems are provided below in the [Miscellaneous Formats, TIFF](#tiff) section. These usage notes were found in the IM mailing lists and forums, as I myself don't use or need to use TIFF. **Video Formats** Other movie quality animation formats generally based on using lossy compression to reduce the size (and quality) of the movie. Both formats are in a constant state of flux, improvements and security limiting features, making any form of processing difficult. At last count there was more than 200 video format 'codecs' that are in general use for one purpose or another. Because of this IM does not directly handle this format, instead it relies on other software packages, to handling the processing of the individual frames into and out of the animations. These 'delegate' programs include "`mpeg2decode`", "`mpeg2encode`", and "`mplayer`". See [MPEG, M2V, and AVI](#mpeg) below). | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Some system (like ubuntu) disable the use specific image file formats using a security policy. Type `magick -list policy` to see what policies and where they are set from are present on your system._ | * * * GIF Image File Format --------------------- The GIF format is a very widely known image file format, as it has been around for a very very very long time (from the late 1980's). It is often picked for images which are to be displayed on web pages that involve transparency or image animation. It is also about the only format absolutely universally understood by all web browsers. Unfortunately it is not a very good format for anything but line drawings, figures, diagrams, and cartoons. That is, because it is limited to a maximum of 256 colors, one of which is usually flagged as being transparent. Flagging one specific color in the image as transparent has some drawbacks. If the color to use as transparent is badly chosen, it can result in other parts of the image being transparent when that was not intended. Care must be taken to ensure that does not happen. Further more, the transparency ability is 'Boolean', which basically means it is either fully on, or fully off. Semi-transparent colors are just not possible, and if present need to be made either transparent or opaque. That means the format can not provide any form of anti-aliasing of edges of an image, usually resulting in a bad case of the 'jaggies'. (See [Anti-Aliasing](../antialiasing/) ) Because the "GIF" image formats color limitations causes so many problems, especially from a high quality image processing package like ImageMagick, I would like to say up front... **Avoid GIF format, if at all possible. If you must use it, do so only as the final step.** Finally for a long time the compression algorithm used by GIF was patented. Consequently it was not available for use by many image processing programs, such as ImageMagick. Thus very old IM programs will output GIF format images un-compressed, and thus using more disk space than it should. You can fix this using a GIF batch compression program such as "`**[Gifsicle](http://www.lcdf.org/gifsicle/) **`" or "`**[InterGIF](http://utter.chaos.org.uk/~pdh/software/intergif.htm) **`". However as the patent expired completely in mid-2004, the current release of IM has the GIF image compression re-enabled again. The image compression is also rather simple, and works best on images with large areas of solid, unchanging colors. Or on simple repeated patterns of the same set of colors, such as you get using [Ordered Dithering](../quantize/#ordered-dither) (not the default dither in IM). Finally GIF images can save multiple images in the one file. And this is used to generate [GIF Animations](../anim_basics/) as understood by pretty well all web browsers, since the technique was first introduction by the very old "Netscape" browser. **In Summary** The GIF image file format with its limited color table, Boolean transparency, and simplistic compression (if enabled), makes it ideal for small images, such as thumbnails, and especially "cartoon-like" icons, logos, and symbols images with large areas of solid colors. Its animation abilities also make it an ideal method of generating flashy attention grabbing logos and advertisements you see all over the World Wide Web. For anything else its limitations make it a poor image file format and you may be better moving to JPEG, PNG, or a video image format for your needs. GIF Limited Color Table ----------------------- FUTURE: color reduction examples -- reference basic color dithering Ensuring that a specific color is present in the final GIF image Map color tables to color reduce. See [Color Quantization](../quantize/#colors) . See [Advanced 3-D Bullet Scripting](../advanced/#3d-bullets) for an example of generating multiple images over a range of colors. This technique can also be used to auto-magick your image into multiple images for many different backgrounds colors and patterns. GIF Transparency Color ---------------------- For example, here we use identify to extract the transparent color, and the color table a particular GIF image file used to represent transparency. The perl script extracts just the specific fields of interest (which can be multi-line). magick identify -verbose hand_point.gif |\ perl -0777 -ne 's/^ //gm; \ print $& while /^(Colors|Alpha|Colormap):.*?(?=^\S)/gms' [![[IM Output]](../images/hand_point.gif)](../images/hand_point.gif) [![[IM Output]](hand_point.txt.gif)](hand_point.txt) As you can see, a transparent grey color ('`#CCCCCC00`') was used for this image and this color has its own separate entry in the color table. You can also see that even though this image only uses 5 colors (one transparent), the color table used is for 8 colors. that is because the GIF file format can only use a color table that is a power of 2 in size. That is the color table is always 2, 4, 8, 16, 32, 64, 128 or 256 color entries in size. As such the last 3 color table entries are not used. Actually they are just not refered to. In some cases these unused entries may not be the last three entries in the color table, and could actually contain any color value. You can also actually have duplicate color values, though IM typically removes any such duplicate color entries if it processes the image in some way. As of IM version 6.2.9-2 (and in some older versions), IM will preserve the color table, and more specifically the transparent color value, whenever it reads, processes and writes a GIF image. magick hand_point.gif -fill white -opaque wheat hand_white.gif magick identify -verbose hand_white.gif |\ perl -0777 -ne 's/^ //gm; \ print $& while /^(Colors|Alpha|Colormap):.*?(?=^\S)/gms' [![[IM Output]](hand_white.gif)](hand_white.gif) [![[IM Output]](hand_white.txt.gif)](hand_white.txt) As you can see even though the image was modified (all '`wheat`' color pixels were replaced with a '`white`' color) the transparent color used was preserved However if the final image has no transparency, the transparency color entry ('`Alpha:`') in the color table is completely removed. magick hand_point.gif -background white -flatten hand_flatten.gif magick identify -verbose hand_flatten.gif |\ perl -0777 -ne 's/^ //gm; \ print $& while /^(Colors|Alpha|Colormap):.*?(?=^\S)/gms' [![[IM Output]](hand_flatten.gif)](hand_flatten.gif) [![[IM Output]](hand_flatten.txt.gif)](hand_flatten.txt) If you like to change the transparent color that the GIF file format is using, you can use the "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#transparent-color) `" output setting (added IM v6.2.9-2). For example... magick hand_point.gif -transparent-color wheat hand_wheat.gif magick identify -verbose hand_wheat.gif |\ perl -0777 -ne 's/^ //gm; \ print $& while /^(Colors|Alpha|Colormap):.*?(?=^\S)/gms' [![[IM Output]](hand_wheat.gif)](hand_wheat.gif) [![[IM Output]](hand_wheat.txt.gif)](hand_wheat.txt) As you can see even though the result is not visibly different from the original, the transparent color was changed to a fully-transparent version of the '`wheat`' color. If you look closely you will also see that the image now has two '`wheat`' or '`#F5DEB3`' colors in its color table. That is, one transparent wheat and one opaque wheat. As of IM version 6.2.9-2, this presents no problem. Though only one transparent color can be defined by the GIF image file format. Why would you do that? Because some very old web browsers and graphic programs do not understand GIF transparency. So this option lets you set what color the transparent areas should be in that situation. Typical choices for the transparent color are '`white`' for modern browsers, OR more typically '`grey75`' ('`#BFBFBF`'), which was the original "`mosaic`" web browser page color. Other popular transparent color choices are '`grey`' ('`#BEBEBE`'), and '`silver`' ('`#C0C0C0`') which is what the 'hand' image above used. This shows just how popular that specific area of the gray-scale color range is for the transparent color. _FUTURE: add link to color selection._ | | | | --- | --- | | ![](../img_www/warning.gif) ![](../img_www/space.gif) | _Before IM v6.2.9-2, and the creation of the "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#transparent-color) `" output setting, IM would typically save the transparency of an image as the special color '`none`' (fully-transparent black), which is not particularly nice when transparency fails._ | Note that setting "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#transparent-color) `" does NOT add any transparency to a GIF image, nor does it magick the specified color to become transparent. All the option does is specify what color should placed in the color table for the color index that is used representing the transparent colors in a GIF image. If you want to change a specific (exact) color to become transparent, then use the "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `" [Color Replacement Operator](../color_basics/#replace) . GIF Boolean Transparency ------------------------ Because the GIF format does NOT understand semi-transparent colors, and as ImageMagick by default generates semi-transparent color as part of its normal [Anti-Aliasing Methods](../antialiasing/) , when you save a image to this format it will often come out horrible looking. For example, here I draw a simple black circle on a transparent background. Also I will generate an enlarged view of the edge of the images, to make it clear what is happening. First I will output using the PNG format... magick -size 60x60 xc:none -fill white -stroke black \\ -draw 'circle 30,30 5,20' circle.png magick circle.png -crop 10x10+40+3 +repage -scale 600% circle\_mag.png [![[IM Output]](circle.png)](circle.png) [![[IM Output]](circle_mag.png)](circle_mag.png) As you can see the edge of the circle on the left drawn (in PNG format) as a very clean looking (though slightly fuzzy) edge to the image. You can see the semi-transparent pixels in its enlargement. Now lets output the same image using the "GIF" image format... magick -size 60x60 xc:none -fill white -stroke black \\ -draw 'circle 30,30 5,20' circle.gif magick circle.gif -crop 10x10+40+3 +repage -scale 600% circle\_mag.gif [![[IM Output]](circle.gif)](circle.gif) [![[IM Output]](circle_mag.gif)](circle_mag.gif) The result is that the circle has a very sharp stair case effects along the outside edge of the circle, while the inside remains properly anti-aliased. Basically while PNG format can save semi-transparency pixel information, GIF cannot. The GIF image format can only save a single pure transparent color. In other words... **GIF format has an on/off or Boolean transparency** If you look more closely at the resulting GIF, you will find that the semi-transparent pixels could have either become fully-transparent or full-opaque. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _What ImageMagick actually does with semi-transparent pixels depends on just what version of IM you are using. It was for a long time not properly defined and what a version did, often depended on the last 'bug fix' that was applied due to bug reports from users.

As of v6.2.9-6 ImageMagick should by default threshold the image at a 50% level for both GIF and XPM image formats. This has become the accepted standard as used by image handlers, while still allowing you to set your own methods of dealing with the transparency problems of the GIF file format._ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Because of the GIF limitations, IM performs the following set of operations before saving to the GIF file format..._

_-channel A -threshold 50%
if (fully-)transparent pixels are present it then...
-quantize transparent -colors 255
otherwise if no transparent pixels present...
-colors 256_

_The -colors quantization process automatically does nothing if less that that many colors are present in the image. Nor will it do anything if the image has a valid colormap (as assigned by "`+/-map`").

It also does not attempt to use a common color map for multi-image GIF files. As such if the colors are very different from one frame to the next, a local color table may be added to each individual image saved into the GIF file format.

Also the settings used in the above are not permanent just temporary for the image being saved. That is, if you used "`-write image.gif`" the settings used during the process do not effect later operations._ | You may like to do the thresholding yourself, and this is recommended if you are not certain of what version of IM (especially older versions) you are using. magick -size 60x60 xc:none -fill white -stroke black \\ -draw 'circle 30,30 5,20' \\ -channel A -threshold 50% circle\_threshold.gif magick circle\_threshold.gif -crop 10x10+40+3 +repage \\ -scale 600% circle\_threshold\_mag.gif [![[IM Output]](circle_threshold.gif)](circle_threshold.gif) [![[IM Output]](circle_threshold_mag.gif)](circle_threshold_mag.gif) The above example performs the same "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) 50%`" on the alpha channel that IM now does automatically, that is if a pixel is more than 50% transparent, it will be made fully-transparent (using the color given by the "`[-transparent-color](https://imagemagick.org/script/command-line-options.php?#transparent-color) `" setting if defined. However you now have control of the threshold level as you like. Thresholding the alpha channel at 50% works well for most types of images. Especially those with a simple edge, but the technique breaks down rather badly, when you need to deal with large areas of semi-transparent pixels. This is what the most of the following examples for GIF handling will look at. For example suppose we want to save an image with a large [fuzzy semi-transparent shadow](../fonts/#fuzzy_shadow) such as this image (in PNG format)... magick -size 70x60 xc:none -font Candice -pointsize 50 \\ -fill black -annotate +10+45 'A' -channel RGBA -blur 0x5 \\ -fill white -stroke black -draw "text 5,40 'A'" a.png [![[IM Output]](a.png)](a.png) If you just magick this letter directly to GIF format or even use a "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" operation to control the Boolean transparency, you will be sorely disappointed. magick a.png a.gif magick a.png -channel A -threshold 75% a\_threshold.gif [![[IM Output]](a.gif)](a.gif) [![[IM Output]](a_threshold.gif)](a_threshold.gif) The first image is a normal save to GIF format, which as you can see thresholded the semi-transparent pixels at '`50%`', the second image was thresholded at '`75%`' allowing more semi-transparent pixels to become fully-opaque (or visible). If you just want to remove all the semi-transparent pixels (EG the shadow) you could try something like a "`-threshold 15%`", to remove just about all semi-transparent pixels. magick a.png -channel A -threshold 15% a\_no\_shadow.gif [![[IM Output]](a_no_shadow.gif)](a_no_shadow.gif) Most other solutions to the GIF Boolean transparency problem is to inextricably tie the image to the background color of the web page on which it lives. Methods for doing this are complex and tricky, and this is what we will now look at. ### GIFs on a solid color background What we would really like to to somehow preserve the shading of the semi-transparent and anti-aliased pixels, and still display it nicely on the WWW. To do this we have to be a little tricky. The typical solution is to match the image to the background on which you are going to display the image on. This is simple to do, just overlay the image onto a background of the appropriate color, before you save it to the GIF format. This removes the need for any form of transparency and the whole thing becomes a non-issue. Of course the limited number of colors is still an issue, but often not a big problem. magick a.png -background LightSteelBlue -flatten a\_overlay.gif [![[IM Output]](a_overlay.gif)](a_overlay.gif) See just about perfect! Of course for this method to work correctly you need to know what exactly the background color the image will be used on. Also after we are finished the image will not be much good on any other background. A big sacrifice to make. ### GIFs on a background pattern But what if you are using some pattern for a background, instead of a simple solid color? You could try positioning the overlay onto a copy of the background pattern so that the pattern in the resulting image matches the pattern of the web page. However that would require a lot of trial and error to get the background in the image to match up with the web page. Also you could only guarantee it to work for a particular browser, and then only that specific version of the browser. Not a good idea for a web page, so don't even bother to try. I certainly won't. Instead of trying to do a perfect match-up with the background pattern, lets just overlay it onto a color that at least matches the background we intend to use. For example lets overlay our image onto a 'typical' bubble like background pattern. But first we need to know the average color of this background. A simple way to find this color is to just [scale](../resize/#scale) the image down to a single pixel, then read the resulting color. magick bg.gif -scale 1x1\! -depth 8 txt:- [![[IM Text]](bg_color_avg.txt.gif)](bg_color_avg.txt) See [IM Pixel Enumeration Text Format](../files/#txt) for more information on the special "`txt:`" output format used. Now lets set the background transparency of the image using "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `". magick a.png -background '#BABBD7' -flatten a\_bg.gif [![[IM Output]](a_bg.gif)](a_bg.gif) I have setup the web page to overlay our image on that background, even though that background is NOT part of the image itself. Though the background color used matched the general color of the background pattern, it still has a very obvious rectangle of solid color, devoid of the the background pattern, around it. One practical solution is to declare the color we overlay, as the "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `" color in the GIF output. By doing this we remove the 'squareness' of the image. Also adding a small [fuzz factor](../color_basics/#fuzz) improves the result and adjusts the amount of space the transparent color uses, in the same way threshold did above. magick a.png -background '#B9BBD6' -flatten \\ -fuzz 5% -transparent '#B9BBD6' a\_bg\_trans.gif [![[IM Output]](a_bg_trans.gif)](a_bg_trans.gif) This is typically good enough to handle transparency in most GIF images, though it does tie the image to a specific background color. In essence we are using the transparency to set a basic outline shape to the image, rather than a true transparency. By using a color for the overlay and GIF transparency so that it matches the background pattern means it is no longer clear exactly where the image stops, and the background pattern starts. Be cautious however with the "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" setting, as too much and you can end up with more than just the outside of your image becoming transparent! magick a.png -background '#B9BBD6' -flatten \\ -fuzz 25% -transparent '#B9BBD6' a\_bg\_overfuzz.gif [![[IM Output]](a_bg_overfuzz.gif)](a_bg_overfuzz.gif) It will also fail if you used a color close to the background colour within the image itself. As such this technique is _not recommended_ for general images, but only in specific cases. To solve this problem we use a '`[-alpha floodfill](../draw/#alpha) `' to set the areas we want transparent. magick a.png -background '#B9BBD6' -flatten \\ -fuzz 25% -draw 'fill none alpha 0,0 floodfill' a\_bg\_none.gif  [![[IM Output]](a_bg_none.gif)](a_bg_none.gif) Now as long as the borders of our image do not 'leak' we can use similar colors inside the image as our background, and not have them turn transparent on us, due to 'over fuzzing'. Of course if our image has 'holes' in it, then those holes will also have to be taken care of too. In which case the previous 'fuzzed transparency' may work better. Did say handling a GIF transparency color is easy! NOT! An alternative technique especially for images with a sharp anti-aliased edge is to simply add a minimum outline of the background color. See [Outline or Halo Transparency](../masking/#outline) . **Remove the Background Color**... Trying an remove a specific background color from an existing GIF image is not easy. It is especially difficult if the overlaid image also contains the background color, as you then don't really know what is background and what isn't. The best solution is to get a copy of the same GIF overlay on two different and well known background colors. With two such images, you can recover the original overlay and all its semi-transparent pixels perfectly. See [Background Removal using Two Backgrounds](../masking/#two_background) . If you don't have two such images, then you can not perfectly recover the images semi-transparency, but there are techniques that can do a reasonable though imperfect job. For this see the other sections of [Background Removal](../masking/#bg_remove) . ### GIFs for non-specific backgrounds (or Dithering the Transparency) FUTURE: This will move into a more generalise (non-GIF specific), alpha dithering section. The biggest problem with the above is that it would only work if you happened to know exactly what color the background, or background pattern your image will be used on. If you don't know all is not lost. As you saw above, threshold does not work well for an image with a very large area of transparency, such as a fuzzy shadow. But another technique known as dithering can, and does NOT require knowledge of the background it will be used on. Basically dithering limits the transparency to on/off values, creating an effect of semi-transparency over a larger area using a pattern if pixels. In other words it fakes semi-transparency. This method was exampled in what is now known as the "[Opossum Examples](http://pmt.sourceforge.net/opossum/) ". Unfortunately these examples did not actually give the commands that were used to generate the example. For completeness I will attempt to demo them again here. The "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator converts all colors in an image into a pure black and white "Floyd-Steinberg error correction dither". However as it converts a grey scale image into just pure back and white colors we will need to extract an alpha channel mask from the image, dither that, and return it back into the image. magick a.png \\( +clone -fx a -alpha off -monochrome \\) \\ -compose CopyOpacity -composite a\_dither.gif [![[IM Output]](a_dither.gif)](a_dither.gif) In a similar way, there are a couple of other dither operators which can be limited to just the alpha channel using the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting (unlike "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `"). magick a.png -channel A -ordered-dither o2x2 a\_ordered\_2x2.gif magick a.png -channel A -ordered-dither o3x3 a\_ordered\_3x3.gif magick a.png -channel A -ordered-dither o4x4 a\_ordered\_4x4.gif magick a.png -channel A -ordered-dither checks a\_halftone\_2.gif magick a.png -channel A -ordered-dither h4x4a a\_halftone\_4.gif magick a.png -channel A -ordered-dither h6x6a a\_halftone\_6.gif magick a.png -channel A -ordered-dither h8x8a a\_halftone\_8.gif magick a.png -channel A -random-threshold 5x95% a\_random\_5x95.gif magick a.png -channel A -random-threshold 5x70% a\_random\_5x60.gif magick a.png -channel A -random-threshold 50x95% a\_random\_50x95.gif magick a.png -channel A -random-threshold 45x55% a\_random\_45x55.gif magick a.png -channel A -random-threshold 50x50% a\_random\_50x50.gif [![[IM Output]](a_ordered_2x2.gif)](a_ordered_2x2.gif) [![[IM Output]](a_ordered_3x3.gif)](a_ordered_3x3.gif) [![[IM Output]](a_ordered_4x4.gif)](a_ordered_4x4.gif) [![[IM Output]](a_halftone_2.gif)](a_halftone_2.gif) [![[IM Output]](a_halftone_4.gif)](a_halftone_4.gif) [![[IM Output]](a_halftone_6.gif)](a_halftone_6.gif) [![[IM Output]](a_halftone_8.gif)](a_halftone_8.gif) [![[IM Output]](a_random_5x95.gif)](a_random_5x95.gif) [![[IM Output]](a_random_5x60.gif)](a_random_5x60.gif) [![[IM Output]](a_random_50x95.gif)](a_random_50x95.gif) [![[IM Output]](a_random_45x55.gif)](a_random_45x55.gif) [![[IM Output]](a_random_50x50.gif)](a_random_50x50.gif) As you can see "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" produces a pattern of transparent and opaque colors to represent the overall transparency. This however produces a very noticeable regular pattern. However if you use a shadow color that is similar too but darker than the normal background then you can make this pattern almost completely invisible. The '`checks`' pattern (first image on second line) is of particular interest as it is a very simple 3 level pattern that is very clean, and neat. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The "`[-ordered-dither](https://imagemagick.org/script/command-line-options.php?#ordered-dither) `" was extended in IM v6.2.8-6 with 'half-tone' dither patterns. The operator was then completely revised for IM v6.3.0 with named dither patterns (use "`[-list](https://imagemagick.org/script/command-line-options.php?#list) threshold`" to see the full list). You can even generate your own dithering pattern to generate other special effects. See [Ordered Dithering Examples](../quantize/#ordered-dither)
and the [Ordered Dither Upgrade notes](../bugs/ordered-dither/)
for more details.

Before this redevelopment, arguments could only consist of the geometry strings '`2x2`', '`3x3`' and '`4x4`' (which will still work). However, anything else was then treated as being a "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" argument, usually with disastrous results. Caution is required when using this option on very old versions of IM._ | The "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" on the other hand produces a highly variable randomized dither that is different each time it is run. The purely random nature of the this dither algorithm however tends to produce large 'clumps' of pixels, rather than the smoother, algorithmic placed dithering generated by the "Floyd-Steinberg" "`[-monochrome](https://imagemagick.org/script/command-line-options.php?#monochrome) `" operator. The big advantage of "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" however is the limit controls it provides. By making the parameters very restrictive (for example as '50x50%') you would magick `[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" into a simple "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" operator. By being only a little less restrictive you can randomize just the very edge of the threshold limit, (for example using '45x55%'). | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" argument '`PxQ`', where `P` is the min threshold and `Q` is the max (the '%' symbol is required). So "5x95%" says anything below is 5% of `MaxRGB` is set to 0, anything above 95% is set to `MaxRGB` otherwise we choose a random value between 5% and 95% of MaxRGB, as the threshold level to use for that pixel. an argument of "5x95%" value is probably the best value to use in most situations._ | You can improve the final look by using a darker mid-tone color (like a dark grey) instead of black for the shadow color. By doing this the color will tend to blur into the background more making the dither less pronounced that what is shown above. If you do know approximately what the background color is, you can even use a darker color of that shade to make the shadow bend in better without restricting yourself to the specific background shade. Sort of mix the two methods a little to improve the overall result. Basically The more work you put into what you want to do, the better the result will be. FUTURE: dither example with a dither color matching the light blue background of this web page. ### Non-ImageMagick GIF Processing | | | | --- | --- | | [giftrans](http://www.ict.griffith.edu.au/anthony/software/#giftrans) | Lists all the attributes and color table of GIF image. It can also set a specific color index as the transparent color without modifying the images color table ordering, or merging color indexes holding the same color (not a recommended situation). The IM "`magick identify`" command I have found to do a better job of listing image attributes, including the 'loop repeat limit' in the "Mosaic Application Extension" used in image animations. See also the "`gif2anim`" script (below), which previously used this program to extract the GIF image meta-data needed to re-create the GIF from the individual 'frames' extracted. It now only uses "`magick identify`", to extract this meta-data. | | [GIFsicle](http://www.lcdf.org/gifsicle/) | This is a general-purpose image optimizer program, whose original purpose was to re-add compression to GIF images at a time when that algorithm was still under copyright. The program can also be used to add comments, create GIF animations and also optimise such animations in the same way that the IM "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `" operator does, though with further transparency optimizations such as [LZW Compression Optimization](../anim_opt/#opt_lzw)
. | | [InterGIF](http://utter.chaos.org.uk/~pdh/software/intergif.htm) | A similar program to GIFsicle, designed for processing animated GIFs. However it only provides [Transparency Compression Optimization](../anim_opt/#opt_trans)
. Other features however may be useful however. _Mail me your views._ | | [gif2anim](../scripts/gif2anim) | A shell script which takes a GIF animation file, and extracts all the individual frame images, as well as a "`.anim`" file containing all the IM "`magick` settings needed to rebuild the animation from the extracted frame images. | | [anim2gif](../scripts/anim2gif) | The reverse of the above script, which takes a "`.anim`" file containing all the IM "`magick` settings and rebuilding a GIF animation image. This script is very useful for studying, editing, adjusting and merging GIF animation files. For basic usage see [Animation List Information](../anim_basics/#list_info)
. Also see [Appending Animations (time synced)](../anim_mods/#append)
for a practical example of its use. | ### GIF Image Offset handling While the GIF format saves images with offsets as part of its image animation handling, it will not save a negative offset. Any attempt to save a negative offset to a GIF image will result in the offset being reset to zero. This can be a real pain when designing GIF image animations. If Internet Explorer web browser is given an GIF image whose 'page offset' places the image somewhere outside the 'page canvas size', it will ignore the page size and offset and display it as if it has no such offset. The ancient Mozilla web browser on the other hand will just display the image canvas, and apply the offsets to the image. This can result in an empty canvas being display with no image data present, which while correct, can be unexpected. Both will display the image using the page canvas size, with the appropriate page offset if the image is wholly contained on that page canvas. ### Related GIF Output formats GIF87: Output the image in the older GIF 87a format. If the "Mozilla" web browser sees this older format it will completely ignore the page geometry of the image, and will not use a larger 'page' frame, or use image offsets with the image. IM version 6.0.4 and earlier would normally produce a GIF89a format. But if the image was a GIF animation, and was split up into separate images using +adjoin, Im would use the GIF87a, resulting in inconsistent results when displayed in web browsers. IM after v6.0.4 will always produce a GIF 89a image format file, unless the user specifically asks for the older "`GIF87:`" output format. * * * JPEG Image File Format ---------------------- This format is about as common as the [GIF format](#gif) above. But where GIF is designed with small simple "cartoon-like" images in mind, JPEG is designed for large real life images with lots of different colors, and shades of colors, such as photographs. A key feature of the JPEG file format is its compression, which reduces image size while keeping the image acceptable to the human eye. This is a very complex process and beyond the scope of this discussion. For more information about this process and its effects see [Jpeg Compression Introduction](http://www.photo.net/learn/jpeg/) . And a great nitty-gritty explaination in the You Tube Video [JPEG DCT, Discrete Cosine Transform (JPEG Pt2)- Computerphile](https://www.youtube.com/watch?v=Q2aEzeMDHMA) Unfortunately, to compress images well, the algorithm intentionally _loses_ information. What is saved is **NOT** the same image as what is in memory; the color of a particular pixel or area of an image will generally will NOT be exactly the same color that was saved. This is particularly true near the edges of objects within the image. So as a quick word of warning... **IM is a general raster image processor, for modifying images. It will not do lossless JPEG modifications.** If you are interesting in lossless handling, see [Non-IM JPEG Handling](#jpg_non-im) . This lossy behaviour becomes even more noticable if a JPEG image is changed so that the amount of change to the top or left boundary is not a multiple of 8. When this happens the JPEG compression 'blocks' or 'cells' will be completely different, and that can produce a large increase in the final image save size. That is, operations such as chop, trim, shave, border, frame, extent, etc.. (See [Cutting and Bordering Operations](../crop/) that can shift the image data by a pixel offset that is not a 8. See the IM Forum discussion [Cropping an image result in an unexpected increased file](https://magick.imagemagick.org/viewtopic.php?f=1&t=20415&p=81480) for more details. Normally this _lossy_ nature of JPEG data is not very noticeable. However it can become noticeable when you either load and save a JPEG image multiple times or use a very low quality with a diagram showing sharp color changes. However as long as you don't load or re-use JPEG images over and over (preserve and apply operations from the original source), it is still a good file format even image types it is not particularly good at handling. As an example of this lossy JPEG nature, here I generate a simple image of two gradients appended together. While the gradients provide a smooth color change that JPEG handles very well, the sharp color change between the two gradients are not handled well. magick -size 5x10 gradient: gradient:blue-navy +append jpg\_lossy.gif magick jpg\_lossy.gif jpg\_lossy.jpg [![[IM Output]](jpg_lossy_mag.gif)](jpg_lossy.gif) ![==>](../img_www/right.gif) [![[IM Output]](jpg_lossy_tn.gif)](jpg_lossy.jpg) The first image is a magnified view of the undistorted GIF format version of the image (click the image to see or downlaod the un-magnified view). It only contains 20 colors, so in this case the GIF format can handle the image perfectly and actually generate a very small file size (see table below). On the other hand the JPEG version of the image shows clear color distortions that the JPEG compression added to the saved image, to allow it to compress it better. The distortions are greatest in the blue color channel, which is not surprising as blue is not resolved well by the human eye. That is, the human eye tends to 'spread out' blue colors naturally, so the JPEG algorithm takes advantage of this (by internally using a YCbCr colorspace). In fact without the magnification used above, you would be hard pressed to see the effect. Lets have a look at the effect of quality on the image. magick jpg\_lossy.gif -quality 100% jpg\_lossy\_100.jpg magick jpg\_lossy.gif -quality 80% jpg\_lossy\_80.jpg magick jpg\_lossy.gif -quality 50% jpg\_lossy\_50.jpg magick jpg\_lossy.gif -quality 20% jpg\_lossy\_20.jpg magick jpg\_lossy.gif -quality 5% jpg\_lossy\_5.jpg [![[IM Output]](jpg_lossy_mag.gif)](jpg_lossy.gif) ![==>](../img_www/right.gif) [![[IM Output]](jpg_lossy_100_tn.gif)](jpg_lossy_100.jpg) [![[IM Output]](jpg_lossy_80_tn.gif)](jpg_lossy_80.jpg) [![[IM Output]](jpg_lossy_50_tn.gif)](jpg_lossy_50.jpg) [![[IM Output]](jpg_lossy_20_tn.gif)](jpg_lossy_20.jpg) [![[IM Output]](jpg_lossy_5_tn.gif)](jpg_lossy_5.jpg) If you look closely at first image result in the above, which we saved the test image at '`100%`' or maximum quality, there is still some slight color distortion. It is very hard to see, but it is present. On the other hand using a progressively lower "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" setting for the JPEG image makes this color distortion even larger and more noticable. Not only that it sets up a sort of 'shadowing' of the edges producing 'waves' of color changes spreading out from the sharp edges. An effect commonly known as [Ringing Artefacts](../filter/#ringing) . However the reason for using compression is that the size of the resulting image is very dramatically smaller, at least initially. Here is a file list of the results and their size in bytes. [![[IM Text]](jpg_ls_lossy.txt.gif)](jpg_ls_lossy.txt) Note that the GIF image in this case is very small, as large 'blocks' of color compresses extremely well in GIF. As the JPEG quality gets lower, the size of the image also gets smaller. The default quality setting, when no JPEG quality is set, either by the user, or from the source image format file, is about 92%, which is a very high quality. However using a lower quality setting than '`50%`', image sizes do not get much smaller in terms of file size savings, only a much more progressively degraded image. It is a process of diminishing returns. In summary... **JPEG losses information, degrading images when saved. Use some other format for intermediate images during processing. Only use JPEG format, for the final image, not for further processing.** JPEG is also not good for artificial images with sharp color changes, such as line drawings, diagrams, or cartoon-like icons, text, and symbols. Such images with a low number of colors are better saved using a palette image format, such as GIF, or PNG8. A new JPEG image format, Jpeg2000, is becoming available which does allow lossless JPEG compression. However this requires the 'JasPer' library to also be installed. To use this special format, you also need to use a "`-compress jpeg2000`" option or save to a JP2 file format, so IM will call the right library. ### JPEG transparency - NOT Other than compression, the other major problem that JPEG users faces is that **JPEG does not save transparency** Thus while you can overlay images onto a background color or pattern and save to JPEG, you cannot give a JPEG image a free-form border or with see-through holes. As JPEG was designed to save real world images, and not parts of images, as such transparency was not an issue it was concerned about, when the format was created. Consequently the designers never worried about including an alpha channel, or other transparency information in the file format. For example let take the PNG with transparency we used above and magick it directly to JPEG. magick a.png a.jpg [![[IM Output]](a.png)](a.png) ![==>](../img_www/right.gif) [![[IM Output]](a.jpg)](a.jpg) As you can see all transparent parts just became black. But depending on the image source (especially GIF images) the transparent areas could have just as easily become some other random, or other inappropriate color. If this could be a problem the best idea is to have IM [Remove Alpha Transparency](../masking/#remove) , before saving the image to the JPEG image file format. ### JPEG Color Distortion (testing) As mentioned above, the compression algorithm JPEG used is lossy. That image will be modified to allow it to compress better, reducing file space, hopefully. Exactly how much color distortion occurs depends on the quality settings use. For example let us look at how many colors are in the IM built-in "`netscape:`" image... magick identify -format "Colors: %k" netscape: [![[IM Text]](jpg_colors_none.txt.gif)](jpg_colors_none.txt) As you can see this image by default has 216 colors in a large rectangular array. This type of image is NOT a very good image for saving to JPEG format, which makes it ideal for our purposes. So lets look at the number of colors a JPEG image save of this image produces... magick netscape: JPG:- |\ magick identify -format "Colors: %k\nFile Size: %b" - [![[IM Text]](jpg_colors_def.txt.gif)](jpg_colors_def.txt) That is, by default, the saved JPEG file has almost 9 times as many colors! Though the result would still look like the original image, the edges of the rectangular area will have had colors added to nearby. Saving at the highest quality setting will _not_ save the image without any color distortion... magick netscape: -quality 100 JPG:- |\ magick identify -format "Colors: %k\nFile Size: %b" - [![[IM Text]](jpg_colors_100.txt.gif)](jpg_colors_100.txt) As you can see a very high quality setting will only add a few extra colors but the image will still have a slight (minimal) color distorted. You can also see that the filesize is larger, as very little compression can be achieved. Now let us try "Lossless"... magick netscape: -quality 100 -compress Lossless JPG:- |\ magick identify -format "Colors: %k\nFile Size: %b" - [![[IM Text]](jpg_colors_lless.txt.gif)](jpg_colors_lless.txt) Still a color distortion! Obviously my JPEG library is NOT patched for lossless encoding. However remember only another patched library can read such a lossless JPG image. Alternatively I recommend compiling your IM to use the JasPer library and the newer JP2 image file format. magick netscape: JP2:- |\ magick identify -format "Colors: %k\nFile Size: %b" - [![[IM Text]](jp2_colors_lless.txt.gif)](jp2_colors_lless.txt) As you can see the Jpeg2000 format switched to other non-lossy methods of image compression, but does not color distort the image, by default. It also performs some very high compression methods on the image. However using a lower quality with the new JP2 format will again introduce the color distortions, so as to generate a smaller image, just like the normal JPEG image file format... magick netscape: -quality 50% JP2:- |\ magick identify -format "Colors: %k\nFile Size: %b" - [![[IM Text]](jp2_colors_50.txt.gif)](jp2_colors_50.txt) For more information of using the JPEG2000 coder, see [JPEG2000 encoding parameter documentation](https://imagemagick.org/script/jp2.php) . ### Reading JPEG Control Options > [\-define](https://imagemagick.org/script/command-line-options.php?#define) > jpeg:size={width}x{height} > > This setting is a hint to the JPEG image library to read just enough of the input (JPEG) image file to create an image that is at least the given size (width × height) or larger. If the input image is huge, this can greatly reduce the amount of memory IM needs for the image read, since IM will then be handling a smaller image. This, in turn, can dramatically increase the speed of the complete operation. Remember this is only a hint as the size of the image wanted, you are not guaranteed to get this size, just something close-to but larger than that size. Typically you will get something that is between this size and one twice that big, while preserving the images aspect ratio. Usually after reading a JPEG image with a size hint, the image is then immediately resized to its final 'exact' size. Typically using "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `" to strip any image profiles, as well. For example... > > magick -define jpeg:size=64x64 jpeg\_large.jpg jpeg\_size\_hint.jpg > magick -define jpeg:size=128x128 jpeg\_large.jpg \\ > -thumbnail 64x64 jpeg\_thumbnail.jpg > > | | | > | --- | --- | > | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.5.6-0 this coder setting was extracted from the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting. This caused problems when users used "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" for image creation but then had JPEG reading produce unexpected results. As such this was changed to be a special coder setting instead.

On older versions you may need to reset the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting using "`[+size](https://imagemagick.org/script/command-line-options.php?#size) ` before reading JPEG images, or IM may not real a JPEG image in full.

_ | > > Note that this modifier causes the JPEG library to skip the reading of whole columns and rows of pixels. As such it will produce effects much like the [Sampling Resize Operator](../resize/#sample) > , including its strong [Aliasing Artefacts](../filter/#aliasing) > . Because of this is it recommended that you specify at least double the final 'resize' of the image, to avoid this problem, just as shown in the above example. > > | | | > | --- | --- | > | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that the [Thumbnail Resize Operator](../resize/#thumbnail)
also uses the same sampling technique for extrememly large-scale resizing operations to quickly reduce the size of the image before using a normal resize operation, though to 5 times rather than double the final image size. The difference in size is a matter of final image quality._ | > > [+profile](https://imagemagick.org/script/command-line-options.php?#profile) > '\*' > > [\-strip](https://imagemagick.org/script/command-line-options.php?#strip) > > JPEG images as saved by digital cameras, scanning software and other image processing software like "photoshop" will often add large profiles of "_program comments_" to JPEG images. Either of these options will remove those profiles from an image, after that image read in. The "`[+profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operator will remove all color profiles from an image, while "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" will remove all profiles and meta-data that the image may have. Also note that "`[-thumbnail](https://imagemagick.org/script/command-line-options.php?#thumbnail) `" is a "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `" option that will also so a "`[-strip](https://imagemagick.org/script/command-line-options.php?#strip) `" at the same time. See also [Creating Thumbnails](../thumbnails/) > . > > [\-type](https://imagemagick.org/script/command-line-options.php?#type) > TrueColorMatte > > As JPEG does not save any form of transparency, when it is read in it will always be fully-opaque, and have not 'alpha' hannel in memory. This setting will force any JPEG image read in after the option to have a fully-opaque 'alpha' channel to be added to the image in memory. The better way to do this however is to use a "`[-alpha set](https://imagemagick.org/script/command-line-options.php?#alpha) `" or "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) set`", after reading the image, as it will have less impact on the reading and writing of other image formats. See [Image Type when Reading and Writing](../basics/#type) > and [Alpha Set](../masking/#alpha_set) > for more information. ### Writing JPEG Control Options By default the "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" and "`[-sampling-factor](https://imagemagick.org/script/command-line-options.php?#sampling-factor) `" that was found when reading the JPEG image is used when writing back to a JPEG image. This however may not produce the same file size on the disk, and you will still always have a further loss of image quality due to reading and re-saving an JPEG image. The JPEG quantization tables are not however preserved. > [\-quality](https://imagemagick.org/script/command-line-options.php?#quality) > {percent} > > Probably the more important option when saving JPEG images, as this controls just how much the image is compressed when save it to disk. The value is not a size percentage, just a quality value. The lower the value the smaller the image and the more image information is lost, producing more artifacts, and degrading the image. > > FUTURE: VERY low quality example of a photo > > NOTE: a quality setting of '`100%`' is not guaranteed to save an image without any loss of quality, just a minimal amount of loss. (See the next option) NOTE: You cannot determine a quality to get a specific file size, except through trial-and-error. Start with a "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" of 75% and check the resulting file size. If it is too large, reduce the quality by 10%; if too small, increase. After you have a lower and upper bound on quality, do a binary search to find a quality that best matches your desired file size. A total of five or six trials should be sufficient. > > [\-define](https://imagemagick.org/script/command-line-options.php?#define) > jpeg:extent={size} > > As of IM v6.5.8-2 you can specify a maximum output filesize for the JPEG image. The size is specified with a suffix. For example "`400kb`". It works by generating many versions of the JPEG image, doing a binary search, of the output quality "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" setting, until it gets as close as possible to the file size given without exceeding it. It does this by writing the image repeatably into a temporary file and once it has the appropriate quality size, it then outputs the final image to the given output filename, once. The output will thus still work fine when outputting the final image to a pipeline, or direct to network, and not just to a real file. However do not expect this process to be very fast due to I/O requirements. Perhaps 4 to 8 times slower. Mail me your results if you actually do a timing comparison. > > [\-compress](https://imagemagick.org/script/command-line-options.php?#compress) > LossLess > > While a "`[-quality](https://imagemagick.org/script/command-line-options.php?#quality) `" setting of '`100%`' can still produce slightly different colors (it is still 'lossy'), the "`-compress LossLess`" option will ask the JPEG library to save the image without any loss of data. As such re-reading the image will restore should be exactly as it was saved. WARNING: This will only work if your JPEG library has been patched for 'LossLess JPEG' encoding, but the use of the JP2 file format has replaced this so this option rarely has any real effect anymore. Also you _MUST_ also set "`-quality 100%`" for this to work. While intuitively you would think that saving with '`LossLess`' will automatically mean using a 100% quality, this is not the case. This is the result of tacking on an unusual patch for the JPEG image writing, which is a lossy format by definition. Of course the file generated will probably much be larger than a normal JPEG image. Also you will end up with a lossless compressed JPEG which you won't be able to read anywhere except with a similarly 'patched' JPEG library. As such 'lossless JPEG' is _NOT recommended_ and some other format (like PNG or JP2) should be used instead. > > [\-interlace](https://imagemagick.org/script/command-line-options.php?#interlace) > Line > > Use a 'Progressive JPEG' style that allows you to see large jpeg images while it is still being loaded. Also see the non-IM solution for re-encoding an existing JPEG without further loss, below. > > [\-sampling-factor](https://imagemagick.org/script/command-line-options.php?#sampling-factor) > {_horizontal_}x{_vertical_} > > Adjust the sampling factor used by JPEG library for chroma down sampling. This can be set to '`2x1`' for creating MPEG-2 animation files. "2x2, 1x1, 1x1" is IM's standard sub-sampling method and corresponds to 4:2:0, see [Wikipedia, Chroma Sub-Sampling](http://en.wikipedia.org/wiki/Chroma_subsampling) > . However when "quality" is 90 or higher, the channels are not sub-sampled. Basically it will define whether the processing 'block' or 'cell' size is 8 pixels or 16 pixels. > > [\-density](https://imagemagick.org/script/command-line-options.php?#density) > {_Xdpi_}x{_Ydpi_} > > While density has no effect on the output pixel size of the the resulting image. The above setting however is stored in the JFIF header of the JPEG image file format. Unfortunately some programs like Photoshop will ignore this setting if a density is also present in a special photoshop specific profile ('`8BIM`') stored in the image. Density is really only important when an output device is being used, such as printers or monitors, allowing these devices to display the image scaled to real world sizes. For example ensuring the photo or page you scanned is printed at the right size. For more information about density see and [Image Density Meta-data](../basics/#density) > and [Resample Resizing](../resize/#resample) > . > > [\-type](https://imagemagick.org/script/command-line-options.php?#type) > TrueColor > > IM will automatically use a gray-scale internal format for images that only contain gray-scale values. This setting will override this behaviour and force IM to always produce a color JPEG image rather than gray-scale. See [Image Type when Reading and Writing](../basics/#type) > for more information. > > [\-define](https://imagemagick.org/script/command-line-options.php?#define) > jpeg:optimize-coding=false > > Turn off the calculation of optimal Huffman coding tables for this image. This is on by default. It does require an extra pass over the image, to do the calculations needed, but this is minimal. > > [\-define](https://imagemagick.org/script/command-line-options.php?#define) > jpeg:q-table={path} > > Defines a file containing custom JPEG quantization tables, in XML. An example table is typically installed in "`/etc/ImageMagick/quantization-table.xml`" but is built-in to ImageMagick and thus not normally used. A number of discussions about generating tables are to be found in the [Digital Image Processing Forum](https://magick.imagemagick.org/viewforum.php?f=22) > , with specific discussions (at time or writing) at [JPEG Quantization Tables](https://magick.imagemagick.org/viewtopic.php?t=20414) > , [Better JPEG quantization tables?](https://magick.imagemagick.org/viewtopic.php?t=20333) > , [Stupid PET Trick qtable of one](https://magick.imagemagick.org/viewtopic.php?t=20402) > , [JPEG luma quantization table](https://magick.imagemagick.org/viewtopic.php?t=20427) > . This option was added to IM v6.5.7-8. ### JPEG Quality vs File Size The final file size of a JPEG file for a given quality is indeterminate. The whole process of compression is so complex with small changes producing wildly different changes to the compression. Its a 'butterfly-effect'. Even the same source picture with the same quality, but with different versions of IM, JPEG library, or other image processing programs, you will get very wide differences in file size, and observed quality. You may as well treat the quality setting as simple 'guess' as to how much compression or visual quality should be applied to a specific image. In essence it is a practical impossibility to pre-determine the final file size for a given image and quality setting... Except by actually doing it. IM however can do 'test runs' to discover the best quality to use for a specific file size by using the special '`jpeg:extent`' define. See [JPEG Write Controls](#jpg_write) above. It is extremely slow, but faster than a similar DIY solution. Doing this is not recommended, and not just because it is slow. By your fixed file size method, a simple image might come out at quality 90%, but contain 50k of unnecessary data, where as a complicated image would have to drop to quality 30% and be exhibiting JPEG artifacts (or to put it less technically, it would look rubbish) due to a shortage of data for the detail present. The better idea is to find a single quality setting that produces an average file size of 100KB for a reasonable selection of your images. Even then images with not much detail in may come out at only 50k. While images with lots of intricate detail may come out at 150k, both will look acceptable. For a practical guide to the JPEG compression and quality, see [Optimization of JPEG compression settings](http://www.ampsoft.net/webdesign-l/jpeg-compression.html) . Also see [JPEG Compression, Quality and File Size](http://www.impulseadventure.com/photo/jpeg-compression.html) for a look at the JPEG internal details. **Photoshop Tip**: Photoshop will add about 4 Kbytes of extra information to JPEG images to hold previews and color management info (profile '`8BIM`'). If you do not want that information, use the 'Save for Web' function. This tip was found in a paper on JPEG compression by [Gernot Hoffmann](http://www.fho-emden.de/~hoffmann/howww41a.html) . ### Related JPEG Output Formats PJEG: Write a Progressive load JPEG Image. This is not often used in these days of fast network downloads, but was very common when dial-up modems were the norm. Basically write every N lines first, then a line between them, and so on, so you can see an image even after only down downloading a small percentage of the complete image. JPEG2000: The latest JPEG format with new additions. This format requires the 'JasPer jp2' library to be installed or you get a error.. "`no encode delegate for this image format`" This format uses wavelet compression to compress images instead of the standard JPEG DCT method. This gives you much better compression ratios for the same image quality. Thus reducing disk space even more. Unfortunately it hasn't been widely adopted yet, so you can't use it for external purposes, at least until web browsers and other image viewers and editors also start making use of the format. Any images saved with this format are only readable by users with this library, and it will probably be a long time before a good percentage of uses use this library. Particularly windows users as Microsoft will probably not include it unless enough people demand it. **Quicktime Tip**: Quicktime uses jp2 format but it must be output at "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) 8`". ### Non-ImageMagick JPEG Processing (A quick summary) | | | | --- | --- | | jpegtran | Standard tool that is installed with the JPEG library. This allows you to apply various transforms to JPEG format images without decoding and re-encoding the image data, thus avoiding the JPEG data to become degraded. (see below) | | [jpegtrans](http://www.jpegclub.org/) | A newer version of the previous "`jpegtran`" program, though many of the added features (such as lossless cropping) has now been built into the distributed library version (above). | | [jhead](http://www.sentex.net/~mwandel/jhead/) | A more user-friendly lossless JPEG handler, especially with regards to the EXIF digital camera profile. That the handling of comments, date adjustments, thumbnail extraction, deletion or replacement, profile stripping, etc. It also attempts to ensure that other profiles are not trashed, which is something that "`jpegtran`" tends to do. There are also other similar programs such as "`[ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/) `", and "`[Exifer](http://www.exifer.friedemann.info/) `". Many JPEG to web photo-album programs also does this. | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The JPEG lossless rotation (which all the above provide) will only work correctly for images that have a size that is divisible by 8 or 16. This is true with most (but not all) digital camera photos. If you try this with an image that is an odd size the right or bottom edge blocks (containing the partial size) will not be positioned correctly in the final image, as these block can only exist on the right or bottom edge.

For an example of this see this [specific discussion](https://magick.imagemagick.org/viewtopic.php?t=16784&p=62157)
_ | As you can see most of these programs are designed to process JPEG image meta-data without re-processing the JPEG compressed image. (see next) ### Lossless JPEG Processing As decoding and re-encoding a JPEG image results in a degrading of image quality (unless lossless compression is used) the JPEG image library provides a number of special programs that can manipulate the image, without loss of quality. These commands will also be generally a lot faster than IM equivalents, as they do not have to do as much processing of the image. When modifying comments in JPEG images You can use the lower level JPEG library programs "`rdjpgcom`", "`wrjpgcom`" and "`jpegtran`". However I recommend you use "`[jhead](http://www.sentex.net/~mwandel/jhead/) `" program, as it preserves any profile or other information that is also present in the image. The "`jpegtran`" allows you to go further and actually losslessly manipulate image data, including 90 degree rotation, cropping, and drop-in. It Even allows the creation of mixed quality JPEG images. For a demonstartion of this see [JPEGhack](http://wiki.thorx.net/wiki/JPEGhack) page by Nemo Thorx. (See the notes below) However these commands are _NOT_ recommended for general use, as they are limited to the block boundaries (8 or 16 bit) of the JPEG image. That is, to say That is, you can only crop, rotate, or drop-in at a JPEG compression cell level, not at the actual pixel level.**Comments**... If you are creating [Montage Thumbnail Web Index Pages](../montage/#html) of your JPEG photos, and like to use the comments you add to the JPEG files, using the above programs, use a "`-label '%c'`" to tell montage to use the 'comment' field, before reading filename on the "`magick montage`" command line. You can also use that comment in a [Complex Polaroid Transformation](../transform/#polaroid) , or a [Polaroid Montage](../montage/#polaroid) or some type of image [Annotation](../text/#annotate) . The "`[jhead](http://www.sentex.net/~mwandel/jhead/) `" program be used to add or modify comments in JPEG image files. However I found using the "edit comments" ("`-ce`") option to not a good way to do that as it adds an extra newline to the end of the comment. This extra newline stuffs up the use of commands ('`%c`' label formatting escape) in IM. The better way is to use "comment input" ("`-ci`") to feeding in a comment (without newlines at the end), or the "comment literal" ("`-cl`") options to be a much better way... jhead -cl 'Photo of some stuff, by Joe Citizen' image_of_stuff.jpg **Thumbnails**... Brian Jackson also reports that most digital cameras (such as his is a Cannon 1D) embed a thumbnail somewhere between 12kb-25kb in size (160x120 pixels), in the JPEG image they produce. IM can extract these thumbnails using... magick image.jpg thumbnail:thumb.jpg However the program "`[jhead](http://www.sentex.net/~mwandel/jhead/) `" can also extract these thumbnails too... mkdir thumbs jhead -st "thumbs/&i" \*jpg This is super fast compared to IM as it does not edit the image, just transfer existing data. However the quality of the thumbnail is not nearly as good, as thumbnails IM can generate from the real image, and they also may not be rotated right, and they definitely will not be the size you want. **Using ExifTool**... From Rob, If you want more detailed editing of the profiles stored in JPEG image files, than what "`[jhead](http://www.sentex.net/~mwandel/jhead/) `" provides, have a look at more EXIF-centric applications of the perl based, "`[ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/) `", an alternative compiled version "`[ExifTool](http://www.dalibor.cz/minolta/exiftool.htm) `", and a Windows GUI "`[Exifer](http://www.exifer.friedemann.info/) `", just to name a few. With the Image::ExifTool Perl module installed, this will strip out all JPEG metadata loslessly. I found the following to be equivalent to the command line method for stripping EXIF data. In case anyone is interested in the future: use Image::ExifTool; $exifTool = new Image::ExifTool; $exifTool->SetNewValue('\*'); # delete all... $exifTool->WriteInfo('original\_image.jpg','modified\_image.jpg'); $errorMessage = $exifTool->GetValue('Error'); print $errorMessage; # (if has value an error occurred) Took some figuring because it turns out you needed to assign the setting first using SetNewValue then load and save simultaneously using WriteInfo. **Mixed JPEG Quality Images, using JpegTrans**... Wolfgang Hugemann {Auto@Hugemann.de} wanted the edges of a JPEG image to not be compressed at all, as it stuffs up photo handling. See [this site](http://www.photopla.net/wwp0703/stripes.php) . The solution provided by Yuval Levy solution was to use "`jpegtran`" to insert a low quality JPG, into a high quality JPEG... The solution:* produce two versions of the same image with ImageMagick, one at the high quality 100 and the other at low quality 60 (for size reduction). * use jpegtran to crop the q60, shaving off 8 pixels on each side * use jpegtran to merge the q60 on top of the q100 * use jpegtran to merge to a stripe Nemo Thorx , read the above and tried to implement Mixed JPEG quality. He succeeded and demonstrates the results on his Wiki pages at [JPEGhack](http://wiki.thorx.net/wiki/JPEGhack) . Basically it is very posible to do lossless JPEG, processing such as 'cropping' and 'dropping' new sections of JPEG blocks into an existing image. * * * PNG Image File Format --------------------- This is one of the newest and most modern image formats, supporting 32 bit colors including alpha channel transparency, but can also be optimised to a GIF like 8 bit index color scheme (256 color limit). As such it makes an excellent intermediate format for image processing without loss of image information. ### PNG compression When used with PNG output, quality is regarded as **two decimal figures**. The first digit (tens) is the zlib compression level, 1-9. However if a setting of '`0`' is used you will get Huffman compression rather than 'zlib' compression, which is often better! Weird but true! The second digit is the PNG data encoding filtering (before it is comressed) type: 0 is none, 1 is "sub", 2 is "up", 3 is "average", 4 is "Paeth", and 5 is "adaptive". So for images with solid sequences of color a "none" filter (`-quality 00`) is typically better. For images of natural landscapes an "adaptive" filtering (`-quality 05`) is generally better. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The PNG coder has been undergoing lots of work, and better methods of controlling the exact encoding and compression settings is typically set using the [Define Operator](../basics/#define)
.

See [Writing PNG Image Controls](#png_write)
below for more details of the defines, or loot at the comments in the PNG coder file, "`coder/png.c` source code.

_ | If you have an ImageMagick image with binary (on/off) transparency, the PNG encoder will write it in an efficient manner, using the tRNS chunk instead of a full alpha channel. But if any opacity value other than 0 or MaxRGB is present, it'll write a PNG with an alpha channel. You can force this behavior by using the "`-type TruecolorMatte`" image reading setting, or you can save the image using the "`PNG32:`" format file. An external program "`[pngcrush](http://pmt.sourceforge.net/pngcrush/) `" or the newer version "`[OptiPNG](http://optipng.sourceforge.net/) `" will attempt to re-compress a specific PNG for the best possible compression available, and is recommended for images that you plan to place on a web site. Another program "`[pngnq](http://www.cybertherial.com/pngnq/pngnq.html) `" will color quantize it to a 256 color, 8bit PNG, though it is not known if this support semi-transparent colors in that format. ### Better PNG Compression One point about PNG images is that PNG image will preserve the color of fully-transparent pixels. That is, even though you can not see it transparency has color, and PNG preserves that data. This means that in many cases PNG can be made to compress better by replacing that 'invisible color' with a static solid color, rather than garbage color that may be left over from previous image processing. There are two major methods you can use for this, using [Alpha Background Operator](../masking/#alpha_background) to just handle fully-transparent pixels only, or using a [Fuzz Factor with Transparency](../color_basics/#fuzz_alpha) type operation to also map near-semi-transparent colors to fully-transparent-black. For example, here I take the fuzzy shadowed "`a.png`" image we generated above and replace all pixels that are within 20% of full transparency. magick a.png -fuzz 10% -transparent none a\_compress.png [![[IM Output]](a_compress.txt.gif)](a_compress.txt) [![[IM Output]](a.png)](a.png) [![[IM Output]](a_compress.png)](a_compress.png) As you can see you get a substantial improvement in image size (around 50%). But with a sharp cut-off for the shadow of the image. Another alternative is to just make the shadow effect smaller, by adjusting transparency channel [Levels](../color_mods/#level) . magick a.png -channel A -level 20,100%,0.85 +channel \\ -background black -alpha background a\_compress2.png [![[IM Output]](a_compress2.txt.gif)](a_compress2.txt) [![[IM Output]](a.png)](a.png) [![[IM Output]](a_compress2.png)](a_compress.png) You can also improve the compression algorithm results, and thus the final size of your PNG image by using a smaller number of colors. magick image.jpg -thumbnail 200x90 -colors 256 \\ -quality 90 -depth 8 thumbnail.png This however is only recommended for small thumbnail images that do not involve transparency, and only as a final step as it is a very 'lossy' technique. ### PNG, Web Browsers and Transparency The Microsoft Internet Explorer (IE version 6 and earlier) does not correctly display PNG when any sort of transparency is involved. Now while this is the most well known browser not to fully support PNG, it isn't the only one. The [PNG transparency test](http://trific.ath.cx/web/png/) and [Another PNG test](http://entropymine.com/jason/testbed/pngtrans/) pages will let you test your browser. They also list the browsers and versions that produce the results displayed. However as IE (at least at time of writing) is probably the most common browser, you can add to your web page a number of work-arounds to the problem. For information on this look at my WWW Laboratory Page [PNG with Transparency and IE](http://www.ict.griffith.edu.au/anthony/wwwlab/pngtest/) , where I test and demonstrate the the "PNG in IE" solution I am using. Other solutions are to magick the PNG to either JPEG (with the right colored background), or GIF formats. These methods are discussed thoroughly for [GIF Images on Backgrounds](#bgnd) . Another solution is to set the color of all fully-transparent colors in a image before saving it to PNG. PNG will save that fully-transparent color, but be warned that just about any other IM operation will reset fully-transparent back to fully-transparent black (as transparent color is not suppose to matter at that is the way image mathematics work).For example the standard [IM examples test image](../#PNG) uses full transparent black for any pixel that is fully-transparent. We can verify this by either turning off the alpha channel, or saving it a JPEG... magick test.png test.jpg [![[IM Text]](test.jpg)](test.jpg) Now lets save this so that all the fully transparent colors was replace with fully-transparent '`silver`' color (see the [Alpha Background](../masking/#alpha_background) operator)... magick test.png -background silver -alpha Background test\_silver.png [![[IM Text]](test_silver.png)](test_silver.png) Note that the image should still look correct if transparency (or the special JAVA script on the page) is working on your browser.But if we turn off the alpha channel (by saving to JPEG that does not allow alpha) we can see that the PNG image really does use a 'silver' color for the fully-transparent pixels. magick test\_silver.png test\_silver.jpg [![[IM Text]](test_silver.jpg)](test_silver.jpg) Note however that this does NOT modify semi-transparent pixels, and these will still have their normal (non-transparent) colors without mixing that color with either the page background, or the color used for fully-transparency. As semi-transparency is no longer involved, borders can look jagged (aliased), as well as 'halo' effects, along lighter colored edges. For example look at the edges of the black and white circles which show the 'jaggies' aliasing effects. However using a gray replacement color should make this not as bad as as the original 'black' color used for full transparency. The other advantage of setting the color of fully-transparent pixels, is an improvment in compression of data. Sometimes, the underlying colors in transparent areas used during processing were preserved. These in turn do not compress as well as a solid color. As such setting the fully-transparent color as we did above, can produce a good saving in the final file size. However this should be done as a final step as many IM image processing operations will replace any fully-transparent color that is present in an image back into fully-transparent black. See the [Alpha Background](../masking/#alpha_background) operator for a list of operators known to do this. My preference is for PNG display problems, is for Microsoft to fix IE, and it seems that IE version 7 will finally have a fully working PNG transparency handling, in all situations. ### PNG and the Virtual Canvas While normally PNG will NOT save virtual canvas size information, it does save virtual canvas offset information, and if present, IM will try to generate a 'canvas size' that is appropriate for that offset and image size. This can be important to remember for some image operators such as "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `", "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" and "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `", etc., which make use of the images canvas or page size as part of its operation or results. Of course you can use the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" setting and "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator, to set or remove the virtual canvas size and offset. (See [Page Image Attribute](../basics/#page) ). For example, the second IM "`magick`" sees the offset that is present in this PNG image, and defines a canvas that is large enough to ensure the image is visible within the virtual canvas bounds (Added to IM v6.1.7)... magick rose: -repage 0x0+40+30 png:- |\\ magick - -background LightBlue -flatten png\_offset\_flattened.jpg [![[IM Output]](png_offset_flattened.jpg)](png_offset_flattened.jpg) However, even though the PNG format will not normally save canvas size information, IM does add some virtual canvas size meta-data to PNG images. This data however will only be usable by IM commands, and is generally ignored by other PNG image format readers. For example the second "`magick`" command does see some virtual canvas size information... magick rose: -repage 100x100+10+10 png:- |\\ magick - -background LightBlue -flatten png\_size\_flattened.jpg [![[IM Output]](png_size_flattened.jpg)](png_size_flattened.jpg) If the PNG is processed by some non-IM program this canvas size meta-data will probably be lost. Remember canvas size information is not normally part of the PNG image file format. The other thing to note is that the 'offset' information can have a negative offset (unlike the GIF format), and IM will handle these appropriately, making the format good for storing intermediate [Layer Images](../layers/) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Some web browsers do not handle negative offsets very well, producing odd results (one version of firefox had this problem). Best to avoid a negative offset in images that may be used by other programs like web browsers._ | ### PNG Resolution, Density and Units After some testing it seems the PNG image file format does not support a "`[-units](https://imagemagick.org/script/command-line-options.php?#units) `" setting of '`PixelsPerInch`', only '`undefined`' and '`PixelsPerCentimeter`'. Because of this IM converts a given density/unit setting into the appropriate values for '`PixelsPerCentimeter`'. _More to come on this subject_. ### PNG Sub-Formats | | | | --- | --- | | PNG: | Default. Save image using economical format. | | PNG8: | The PNG equivalent to GIF, including Boolean transparency and a 256 color table. | | PNG24: | 8 bit RGB channels without an alpha channel. Special case can include boolean transparency (see below) | | PNG32: | Force a full RGBA image format with full semi-transparency. | | PNG48: | 16 bit RGB channels without alpha channel | | PNG64: | 16 bit RGBA image (including semi-transparency) | | PNG00: | Inherit PNG color and bit depth from input image. | For more information see [Image Type I/O Setting](../basics/#type) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _PNG8 was defined by PhotoShop, not the PNG group. And while it can handle multiple semi-transparent colors, as well as a fully-transparent color, IM assumes that it doesn't. This provides a way to force images to work properly with default be readable by Internet Explorer v6. The "`Photoshop CS`" program can read it._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The PNG48, PNG64 and PNG00 styles were added as of IM v6.8.2-0_ | You can force IM to create an image color index table (or palette) then IM will save that image using a "`PNG8:`" format... magick {input\_image} -type Palette indexed.png To force the use of an single 8 bit greyscale channel, but not a palette indexed image use... magick {input\_image} -type GrayScale -depth 8 gray.png You can (added IM v6.3.5-9) also output greyscale with a transparency channel. magick {input\_image} -type GrayscaleMatte gray\_with\_transparency.png And for a simple two color image... magick {input\_image} -type BiLevel bitmap.png A special case exists for PNG24 images. If the image only contains boolean transparency, and all thge transparent colors are the same and that color is only used for transpareny, then the PNG coder will specify that specific color as being transparent. For example... magick a.png -channel A -threshold 75% +channel \\ -background hotpink -alpha background png24:a\_png24\_alpha.png [![[IM Output]](a_png24_alpha.png)](a_png24_alpha.png) This image does not have a pallette, but does have some on/off alpha. The [\-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) of the alpha channel ensures only boolean (on/off) transparency is present, while the [Alpha Background](../masking/#alpha_background) option ensures all fully transparent pixels is a specific color. The above does NOT ensure there is no opaque pixel with that color, so the above can still fail. ### Writing PNG Image Controls To better control the writing of PNG images, Glenn Randers-Pehrson revised a number of coder "`[Define Global Setting](../basics/#define) `" controls, for IM v6.5.2. These include... [\-quality](https://imagemagick.org/script/command-line-options.php?#quality) '{level}{filter}' The basic compression level and filter when saving a PNG image. [\-define](https://imagemagick.org/script/command-line-options.php?#define) png:compression-strategy=_zs_ [\-define](https://imagemagick.org/script/command-line-options.php?#define) png:compression-level=_zl_ [\-define](https://imagemagick.org/script/command-line-options.php?#define) png:compression-filter=_fm_ Completely define the compression system to be used for the PNG image being written. The [\-quality](https://imagemagick.org/script/command-line-options.php?#quality) setting will normally set the _zl_ and _fm_ values, but not the _zs_ setting. [\-depth](https://imagemagick.org/script/command-line-options.php?#depth) {depth} The general depth of the image to be generated, typically set to 8 or 16 bit. [\-define](https://imagemagick.org/script/command-line-options.php?#define) png:bit-depth={depth} Precisely specify the depth of the resulting PNG image file format. This overrides the normal IM "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" control, but only for writing PNG images, and only when the change can be made without loss. In the case of color-mapped images, this is the depth of the color-map indices, not of the color samples. [\-define](https://imagemagick.org/script/command-line-options.php?#define) png:color-type={type} Precisely specify the type of the PNG file being written. Values can be either | | | | --- | --- | | '`0`' | for Greyscale, which allows for '`bit-depths`' of 2, 3, 4, 8 or 16. | | '`2`' | for RGB, which allows for '`bit-depths`' of 8 or 16. | | '`3`' | for Indexed, which allows for '`bit-depths`' of 1, 2, 4 or 8. | | '`4`' | for Gray-Matte | | '`6`' | for RGB-Matte | Note that "`-define png:color-type='2'`" is specifically useful to force the image data to be stored as RGB values rather than sRGB values. However a similar effect can be achieved using "`-set colorspace sRGB`" on a linear RGB image. Howvever, do not expact that programs will honor this linear colorspace when reading. This includes ImageMagick. [\-profile](https://imagemagick.org/script/command-line-options.php?#profile) PNG-chunk-{x}:{file} Add a raw PNG profile at location {x} from {file}. The first 4 bytes of {file} contains the chunk name, followed by a colon ':' character, and then the chunk data. The {x} can be 'b' to place profile before the PLTE, 'm' between the PLTE and IDAT, or a 'e' for after the IDAT. If you want to write multiple chunks of the same type, then add a short unique string after the {x} to prevent subsequent profiles from overwriting the preceding ones . For example.. -profile PNG-chunk-b01:file01 -profile PNG-chunk-b02:file02 [+set](https://imagemagick.org/script/command-line-options.php?#set) date:create [+set](https://imagemagick.org/script/command-line-options.php?#set) date:modify These are image 'properities' which are created by ImageMagick whenever it reads a file. They contain (respectively) the image files create time (actually permission/owner/move change time) and last file modification time. Unfortunatally PNG image file formats like to write such image data with the PNG image file format, and if this data is different, then the file generated will also be different, even if nothing else has changed. magick logo: logo.jpg magick logo.jpg logo1.png sleep 2; touch logo.jpg # change the JPG file timestamp magick logo.jpg logo2.png diff -s logo1.png logo2.png magick compare -metric RMSE logo1.png logo2.png null: The "`diff`' in the above will return the message "`Binary files logo1.png and logo2.png differ`" Even though the "`magick compare`" returned "`0 (0)`" which says the images have exactly the same image data. Note that as IM overwrites these properities with the times of the PNG file it just read, you can't see the actual values of these properities recorded in the PNG using "`magick identify`". The solution is to save PNG images without any 'time stamps'. magick logo: logo.jpg magick logo.jpg +set date:create +set date:modify logo1.png sleep 2; touch logo.jpg magick logo.jpg +set date:create +set date:modify logo2.png diff -s logo1.png logo2.png This time "`diff`" reported... "`Files logo1.png and logo2.png are identical`" ASIDE: you can also use other UNIX programs such as "`cmp`", "`md5sum`", or "`sha1sum`" to compare binary image files. The latter two programs is not guranteed, but they are practically impossible to fool, and are faster for comparing more than two files (using the checksum) Thanks to some additions by GlennRP, the PNG developer you can now also use "`-define png:exclude-chunk=date`" to tell the PNG coder not to write date-related text chunks. ### Non-ImageMagick PNG Processing There are quite a number of helper applications for PNG, that could be useful adjuncts for generating a final PNG image file. | | | | --- | --- | | pngtrans | PNG information stored with an image | | [pngcrush](http://pmt.sourceforge.net/pngcrush/) | Tries to find the best compression of a PNG by attempting to compress the image using all logical PNG compression available, before making a final choice, for each individual image. This of course can take some time on each image. | | [OptiPNG](http://optipng.sourceforge.net/) | A newer PNG compression optimizer. | | [pngquant](http://www.libpng.org/pub/png/apps/pngquant.html) | Lossy PNG optimizer, reducing a PNG image down to an 8 bit color palette with dithering. It will build indexed-color PNG's with alpha transparency colors conveyed in the tRNS chunk. | | [pngnq](http://www.cybertherial.com/pngnq/pngnq.html) | A newer lossy PNG quantizer, to generate 8 bit color table PNG images. Also forces the use of a color palette. | | [pngout](http://www.advsys.net/ken/utils.htm) | A Windows platform PNG optimizer (with optional GUI) that uses a ZIP compressor that is optimized for space rather than speed (also on the page linked above). | Most of these are to improve the final size of the image file, either using a lossy OR non-lossy techniques. * * * Image Profiles -------------- Handling profiles photo quality images is important, However from what I can tell this is a very magical art, and not simple matter. Not all formats use profiles, but most modern formats do. This includes JPEG, PNG, TIFF, and (as of IM v6.3.4-1) GIF. If fact the problem is exacerbated by the fact that many programs do not even understand or look for color profiles in images. [Alan Gibson, aka Snibgo](http://www.snibgo.org/contact.htm) , put together a summary of how various web browsers handle various Color Profiles, on his own [Snibgo, ImageMagick Profiles](http://www.snibgo.org/improf.htm) page. This is worth a look. To list what profiles are present in an image use... magick identify -verbose image.tif | grep 'Profile-.\*bytes' Common Profiles (and pointer to info I have on them) include... | | | | --- | --- | | EXIF | [Digital Camera Meta-Data](../photos/#exif) | | ICC | [Image Color Space Profile](#color_profile) | | ICM | [Microsoft Color Management (like ICC)](#color_profile) | | IPTC | [Image and Author Info](#profile_iptc) | | 8BIM | Photoshop Meta-data profile. Including data on: Clip Paths... _What else?_ | | XMP | Adobe's Extensible Metadata Platform (XMP) (See [adobe page](http://www.adobe.com/products/xmp/)
) | You can extract these common profiles using some special output formats that IM provides for this purpose. For example... magick -define jpeg:size=64x64 image.jpg iptc:profile.iptc magick -define jpeg:size=64x64 image.jpg xmp:profile.xmp The "`[-define](https://imagemagick.org/script/command-line-options.php?#define) `" option in the above is used as a 'hint' to the JPEG library to reduce the amount of actual image data it reads into memory and then save a lot of processing of the data you don't actually intend to use. You can also insert or re-insert an arbitrary profile as a 'blob' or binary string containing whatever information you like. -profile '_profile\_name_:_data\_file_' That is, the file "`data_file`" is added 'as is' to the image as the profile _profile\_name_. IM or any other application will ignore such profiles, unless it specifically knows about it. #### Color Profile Basics First a quick word... **[Color Management is for Wimps](http://tinyurl.com/yr9mkt) -- Don't Play with them Messing with profiles generally makes things worse** So if the colors look good... Leave it alone. An user _fhoech_ in the IM Forums, (who has since disappeared) has quite a number of times posted the following basic introduction in using color profiles to change the color space used by images... The RGB, sRGB and CMYK are not colorspaces, they are color systems (which IM controls using the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" operator). There is no single RGB or CMYK colorspace, but a literally infinite amount of different colorspaces are possible in each color system. You need ICC (or ICM) profiles which accurately characterize the colors in your images. Normally, the ICC profile that describes an image should be embedded in the image itself, otherwise, you have to use a 'best guess' attempt which is only a workaround: Open the image in an ICC-capable image editor and assign different ICC profiles (do not convert!) until you find one that looks OK with your image (your monitor must be calibrated so you actually get a good preview of the colors). Then, save the image with the profile embedded. As to why you need two profiles: The source profile describes the colors in your image as they are now. The destination profile describes the colors in the output image after conversion. Also, you should take great care when converting to a given destination profile: If, for example, you use a profile that describes offset printing on uncoated stock but intend to use the images for printing on coated paper, you will of course not get any good results. The output profile needs to be an accurate representation of your intended output condition. When converting from a subtractive into an additive color-space (or visa-versa) without using the correct profile (for both steps of conversion) you won't get 'correct' colors or brightness in most cases, although you may be lucky and hit the mark 'by accident'. You can download color profiles from [International Color Consortium](http://www.color.org/srgbprofiles.xalter) . ### Changing Colorspace via Profiles While you can just simple magick color spaces directly like this... magick cmyk_image.jpg -colorspace rgb rgb_image.jpg The best solution for converting CMYK to RGB JPEG is to use color profiles with the "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operator. _Raf Lenaerts_ pointed out the following rules in using the "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operator within ImageMagick... If there is no embedded profile then the first "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" is the input profile. A second "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" then defines the output profile. If there is an embedded profile then a single of "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operator will immediately define the output profile. In summary... * The "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" must be placed between the input and output file. This is actually standard [IM Command Line Processing Practice](../basics/#cmdline) . * Use "`[+profile](https://imagemagick.org/script/command-line-options.php?#profile) `" with '`icm`' to remove any icc-profile present. * The first "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" then given, is the input profile. * The second "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" given, is the output profile. As such to use profiles for ALL images, you will need three "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operations: remove, input, and output profile options. For Example, If the input image already has a color profile then only one is needed. magick rgb_image.jpg -profile USCoat.icm cmyk_image.jpg But if the image doesn't (or you know it is a RGB image, without an existing profile), you can use... magick rgb_image.jpg +profile icm \ -profile sRGB.icc -profile USCoat.icm cmyk_image.jpg This sets the resulting image to a CMYK USCoat.icm profile. Another CMYK profile is the SWOP.icm profile. For the reverse (image already has a profile) use... magick cmyk_image.jpg -profile sRGB.icc rgb_image.jpg **WARNING:**If the original image already contains a profile, for example a CMYK profile, then given two profile conversions is a bad idea. For example magick cmyk_image.jpg -profile "CMYK.icc" -profile "RGB.icc" \ output_image.jpg Will result in a CMYK -> CMYK -> RGB conversion. But as CMYK is not symmetric, the the extra conversion step can result in a disastrous color conversion. (See the IM Forum discussion [Question on ICC profile conversion behaviour](https://magick.imagemagick.org/viewtopic.php?t=12900) ) #### Color Profile Modification The images you want to magick should all have ICC profiles embedded. As such to magick your images with same a CMYK ICC profile... magick rgb_image.jpg -profile CMYK_PROFILE cmyk_image.jpg This will magick using perceptive intent, the default (see [Color Space Conversion](http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm) for an detailed explanation on rendering intents). Because the results via perceptive intent can differ greatly depending on the software that was used to create the ICC profiles, you can use "`[-black-point-compensation](https://imagemagick.org/script/command-line-options.php?#black-point-compensation) `" along with "`[-intent](https://imagemagick.org/script/command-line-options.php?#intent)  relative`" to get a result that is somewhat nearer to what one might expect. magick rgb_image.jpg -intent relative -black-point-compensation \ -profile CMYK_PROFILE cmyk_image.jpg | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Both "`[-black-point-compensation](https://imagemagick.org/script/command-line-options.php?#black-point-compensation) `" and "`[-intent](https://imagemagick.org/script/command-line-options.php?#intent) `" settings need to be specified before the "`[-profile](https://imagemagick.org/script/command-line-options.php?#profile) `" operation for it to be effective._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The "`[-black-point-compensation](https://imagemagick.org/script/command-line-options.php?#black-point-compensation) `" option was added to IM v6.2.7-0._ | You can download color profiles from [International Color Consortium](http://www.color.org/srgbprofiles.xalter) . #### EXIF InterColorProfile On top of the above Color Profile handling, many Digital Cameras, save color profile information in the EXIF profile attribute '`InterColorProfile`'. This attribute is meant to be "_assumed in the event of no colour profile being embedded_", according to the document, "[Colour Management and Adobe PhotoShop 7](http://www.computer-darkroom.com/ps7_colour/ps7_1.htm) ". ### IPTC Profiles The IPTC profile is used in images to store identification attributes of the image, such as caption, credit, author, keywords, etc. If you want to add an IPTC profile to an image, you need a single -profile: magick image.jpg -profile iptc iptc_image.jpg If an image contains a profile you can save it with this, so you can add that profile to other similar images: magick iptc_image.jpg iptcData.iptc Or you can extract a text version of the profile that you can edit magick iptc_image.jpg IPTCTEXT:iptcData.pro Here for example is a profile contributed by _[fcaserio](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=8641) _ in the [IM Forums](https://magick.imagemagick.org/viewtopic.php?t=8688) . [![[IM Text]](iptcData.pro.gif)](../images/iptcData.pro) You can add this profile to an image using magick image.jpg +profile 8BIM -profile 8BIMTEXT:iptcData.pro \ iptc_image.jpg That image can be converted into an EPS (Encapsulated Postscript) with a TIFF preview (EPT), that also contains the IPTC profile. (Thanks _Tee Tanne_). magick itpc_image.jpg EPT:image.eps ### XMP Profiles Extract a XMP profile from a TIF image... magick picture.tif metadata.xmp * * * A word about Vector Image formats --------------------------------- Their is more than one style of image storage in the world... | | | | --- | --- | | **Raster** | Images which are stored and processed using arrays of colored pixels. Raster image formats include GIF, PNG, JPEG, TIFF, and so on. Images can consist of multiple arrays (channels) representing different colors, and can have multiple images, layers, or frames (depending on usage) in the one image file format file. | | **Vector** | Images are defined in terms of lines, thicknesses, tiles, gradients, and larger compound objects. Formats include SVG, Postscript, PDF, FIG, DXF, WMF, and even TTF fonts. It allows images to be resized, and even greatly enlarged _without loss of quality_. Also while editing such formats, you can generally move whole objects around without destroying what is underneath (object layering). | | **Fractal** | Images are a special rare case, used to achieve extreme compression of complex images, such as old paintings. However the only usage I know about is in a very expensive commercial product. Outside that usage it is also used for complex mathematical objects such as Mandelbrot and Julia sets, and in generating randomized splashes of color in screen savers (IFS). It is very rarely seen. | Why is this important? Because IM is a 'raster image processor', and while it can read or write images stored in one of the vector formats it does so by converting the image to and from an internal raster image. Consequently if you are trying to magick an image from a vector format, to another vector format, IM will essentially rasterize this image at the currently defined [resolution or density](../basics/#density) which will hopefully (but unlikely) be suitable for the output device you intend to use it on. In other words, any output from IM will never be a true vector format. While it can magick its internal raster format into a vector format file, the result is only a superficial vector image wrapper around an image in raster format. And unless the raster image is defined properly (at the right resolution) for the output device, the result will not be particularly good. Unfortunately new uses to IM do not know anything about this. They see IM as a converter that can magick say PDF to Postscript, producing images with 'blocky' aliasing effects, 'washed out' colors, or blurry images that just do not look good at all, on the intended output device. Which brings use to what I am trying to say... **Avoid using ImageMagick for 'Vector Image' to 'Vector Image' conversions** EG: converting between formats like: PDF, PS, SVG In other words, use the right tool for the right job. And for this situation, ImageMagick is not the right tool. That is, not to say IM can't be used to do such a conversion. After all most printers and monitors actually rasterize the image themselves for the actual printing onto a sheet of paper. The difference is that the printer knows what resolution it needs for the hardware it is using. ImageMagick does not. For examples of converting vector images to rasters (and improving such conversions), see the example [Postscript/PDF pre-formatted Text and Graphics Input](../text/#postscript) , and for SVG and user generated vector images see [SVG Image Handling](../draw/#svg) . You may also find the information on [Font Size, Resolution and Pointsize](../text/#pointsize) useful, particularly with regard to the effect of "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" on drawn text fonts. #### Non-IM Alternatives If you really do need to do general conversion between vector formats, the program [UniConvertor, Sk1 Project](http://sk1project.org/modules.php?name=Products&product=uniconvertor) (usually available as a standard linux package) and the [VectorSection](http://scratchcomputing.com/projects/vectorsection/) can be used to magick vector-to-vector without actually rasterizing the images. For general conversion of Postscript to other vector formats, look at "`[pstoedit](http://www.pstoedit.net/pstoedit) `", which is typically available in your systems extra package repositories. Also look at "`[epstopdf](http://www.ctan.org/tex-archive/support/epstopdf/) `" which is part of the [Comprehensive TeX Network (CTAN)](http://www.ctan.org/) . TeX and LaTeX are UNIX documentation (book and scientific article) text processing system. It has lots of tools to do with Postscript and PDF formats. For SVG to PDF conversion, Wolfgang Hugemann suggests that the easiest vector to vector conversion was to display the SVG in a browser (Firefox) and the print it using a PDF printer driver. Though the "Uniconvertor" could be used too. * * * Other Image File Formats ------------------------ There are of course a huge number of other image file formats that IM can use and understand, however using many of these less 'common' formats are specialized for some specific purpose, and often require some tweaking or other options to get them to perform the way you want them to perform. I do not recommend these file formats, and generally I myself don't used them. However I do try to log various notes, techniques, and options that have been reported on the IM mail list, or [IM forum](https://magick.imagemagick.org/viewforum.php?f=1) , so others may also use the information gleaned.Many of the notes are in a raw, unprocessed form, and I am willing to accept further contributions, ore re-writes to the notes below. * * * ### Postscript (PS, EPS) and Adobe PDF For basic handling see [Postscript Text Handling](../text/#postscript) and the warning about [Vector Image formats](#vector) . The major problem with Postscript and its related formats (like PDF) is that it is a complex page formatting language. That is, the format is a program and not really an image format! That means IM is forced to rely on another external program (or delegate) to 'run' the program and return the generated image. #### Encapsulated Postscript (EPS) Encapsulated Postscript is actually exactly the same as normal postscript (a vector image format) except it is a single page image, and a "Bounding Box' entry is present to define the exact area the image covers. The format was designed to to allow other programs to move and scale the image when inserting the postscript it defines into other postscript documents. IM handles it in basically the same way as postscript. (See above). magick image.jpg -compress none eps2:image.eps Use "EPS2:" or "EPS3:" to create JPEG compressed EPS files: Note: Adding profiles to EPS images are on the 'to do' list but is currently not supported. #### Postscript/PDF Input As this format is a vector image format it is effected by settings such as "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `", and "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `". Examples of reading Postscript (which is the same for EPS and PDF format) are provided in [Postscript Formatted Text](../text/#postscript) , and you should read this first. However the reading of these formats is very complicated, as they are full computer languages designed specifically to generate a printed page on high quality laser printers. This is well beyond the scope of ImageMagick, and so it relies on a specialized delegate program known as "[ghostscript](http://www.ghostscript.com/) " to read, and convert Postscript and PDF pages to a raster image. **One point.** As IM uses Ghostscript to rasterize a postscript file at a specific resolution, any raster images that are in the postscript file will often be blurred, or distorted, unless the exact density for that raster image is known. This also assumes that the postscript program itself does not rotate or otherwise manipulate the raster image. In fact, multiple delegates are present and selected by IM depending on the situation. For example the '`ps:color`' (using the '`bmpsep8`' ghostscript device) verses '`ps:alpha`' (using '`pngalpha`') is selected depending on if "`-channel RGBA`" had been set or not. The '`ps:color`' delegate is used rather than '`ps:alpha`' by default because the '`pngalpha`' ghostscript device only supports an one page/one image and PDF's generally are multi-page. Use "`-channel RGBA`" before reading the image to select the '`pngalpha`' delegate method. If all you want is the number of pages, using ghostscript can be a lot faster. gs -q -sPDFname=document.pdf pdfpagecount.ps %%Pages: 96 **Windows and Ghostscript** is a little more complex, as it requires the use of the windows registery. ##### Special ImageMagick PDF Reading options Special options for PDF handling... `-units PixelsPerInch` Should be set when handling PDF documents (reading or creation of). I am not sure what this does but reports indicate it should be set for correct working. `-define pdf:use-cropbox=true` Use a 'cropbox rather than the default 'mediabox' as per Adobe generated PDF files. (Basically adds a "`-dUseCropBox`" to the ghostscript conversion from PDF images. NOTE: This works if your PDF only has one page, but if it is a multiple paged PDF, it won't crop correctly. `-define pdf:use-trimbox=true` Use a 'trimbox rather than the default 'mediabox' as per Adobe generated PDF files. ##### Modifying the Input Delegate Modifying the system delegate is dangerous and a mistake could render IM unable to read postscript/PDF files. You also may need administration privileges, as you cannot replace a system defined delegate with a personal delegate, due to security ('hacker') measures. See [Delegates and Coders for Image Formats](../files/#delegates) for more info on the delegate XML syntax and meaning, and creating personal input/output delegates. On the forum topic [Convert EPS to JPG Unreliable](https://magick.imagemagick.org/viewtopic.php?t=8546) , it was suggested that you edit your system "`delegates.xml`" and replace "`-sDEVICE=bmpsep8`" to "`-sDEVICE=bmp16`". Other users have found that changing this to "`-sDEVICE=pnmraw`", also works better. I have not tried this myself, so can provide no guarantees about this, or what versions of Ghostscript this applies to. If you have any further info, please let me know. If you have a CMYK postscript or PDF file then the page [Blog of John](http://john.ukmn.com/2007/06/19/imagemagick-cmyk-to-rgb/) details how you can modify the delegate entry (Add a "`-dUseCIEColor`" ghostscript option) so ghostscript convert handles this this of postscript. Another possibility is to create a personal "[Delegate](../files/#delegate) which would invoke pdftoppm. Say the tag is called "`pdfalt`" which invokes the program "`pdftoppm`" or even "`pdfimage`" from the "`xpdf`" package. Then your stream would look something like this: magick pdfalt:image.pdf image.png _Anyone like to give the delegate creation a go? Let us know!_You may also like to try using "`pstoedit`" which can convert a postscript file to other vector formats, or passes the postscript into the ImageMagick API, to magick it to bitmap. I have not experiment or tested this, and would like some feedback. ### PDF Raster Image Extraction The rendering of any PDF pages to a specific size or 'density' is at the heart of the vector graphics using by PDF. It works great for text, or line drawings. But this also means that any raster image (pixel array) within the PDF has to be resized. But resizing is a 'lossy' operation, resulting in some image degrading, unless you use the original density of that raster image, which can vary from image to image within the PDF! It is thus advantageous to be able to extract the raster images from a PDF without any 'density' reference. You can extract the raster images directly using "`pdfimages`" program, which is part of either the [poppler-utils](https://poppler.freedesktop.org/) or the "[xpdf-utils](http://www.foolabs.com/xpdf/) software packages. These software packages also contain many other tools that you can find useful for PDF processing. See [Poppler for Windows](http://blog.alivate.com.au/poppler-windows/) and [Xpdf Reader](http://www.xpdfreader.com) . You may also like to look at the "`mutool`" from the package "[MuPDF](http://mupdf.com) " by the same people that look after GhostScript. An online tool to extract text and images is [Sumnotes](https://www.sumnotes.net/) (commercial with limited free trial). At a lower level Wolfgang Hugemann says you can extract any image contained by a PDF (especially from PDF's generated by scanners). Basically by extracting any byte sequence between "stream" and "endstream", and saving as a separate file. ### PDF Text Extraction You can use the GhostScript program "`ps2ascii`" or "`pstotext`". Or as an alternative that does both text and images, have a look at "`pdftohtml`" has an XML output that Ross Presser reports is "_pretty good at reassembling paragraphs._". Also the "`pdftk`" program can 'uncompress' a PDF so it can be edited directly, and to 'repair' corrupt PDF's. #### Postscript/PDF Output Options The following settings are known to effect the output of Postscript, Encapsulated Postscript, and PDF image formats: "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `", "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `", "`[-compress](https://imagemagick.org/script/command-line-options.php?#compress) `", "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `", By default no compression is used on PDF image output, so PDF files can often be a lot bigger than necessary. The following table equated the IM compression modes with the resulting Postscript compression mode used. **PS/PDF Compression Meanings** | Compression | image '`/Filter [ ... ]`' setting | | --- | --- | | "`-compress none`" | '`/ASCII85Decode`' | | "`-compress zip`" | '`/FlateDecode`' | | "`-compress jpeg`" | '`/DCTDecode`' | | "`-compress lzw`" | '`/LZWDecode`' | | "`-alpha off -monochrome -compress fax`" | '`/CCITTFaxDecode`' | | "`+compress`"
"`-compress rle`"
    any thing else | '`/RunLengthDecode`' | Recommended compressions for PDF is Zip (Deflate Compression) or Group4 (Fax) compression. magick image.gif -alpha off -monochrome -compress Zip -quality 100 \ -units PixelsPerInch -density 600 image_deflate.pdf magick image.gif -alpha off -monochrome -compress Group4 -quality 100 \ -units PixelsPerInch -density 600 image_group4.pdf These two commands produce much smaller PDF files than a direct conversion, of a black an white page. However which is smaller depends on the image and is impossible to determine without trying and testing the resulting size. #### Postscript/PDF Output Alternatives Remember that PDF is a vector image (document) format, and IM is a raster image processor. This means that any PDF document IM creates will basically consist of a single raster image per page. The images output in the PDF document will be fixed at a specific resolution (or pixel density), which can cause pixel distortion issues when viewed or printed at some other resolution. Also for text documents, using a raster image is wasteful, as plain text with fonts and formatting meta-data will always be a lot smaller and render better than a scanned raster image of the text. Because of this, other PDF creation programs may be better suited to your needs. This will let you keep images as images, and text and text, allowing you position the text and images together in a nicer more logical way, as well as insert text, and overlay arrows or connecting lines, in a more logical fashion. For example I suggest you look at the support programs provided by the TeX and LaTeX system. See [Comprehensive TeX Network (CTAN)](http://www.ctan.org/) . Another tool set is [Multivalent Document Tools](http://multivalent.sourceforge.net/Tools/) . Of course such programs are harder to automate, however I have in the past use the simple FIG vector graphic file format (see [Xfig](http://www.xfig.org/) ) to generate Postscript and PDF documents with text and graphics placed in an automatic way. **Image to PDF convertors**... The tool [sam2p](http://code.google.com/p/sam2p/) which is specialized in converting images to PDF files. So does all the preprocessing with ImageMagick and then making the final conversation using "`sam2p`". It even brings a small script to adjust the result to an A4 paper. From [sam2p README](http://sam2p.googlecode.com/svn/trunk/README) : | | | | --- | --- | | Q58) | Can sam2p generate a PDF which is scaled proportionally (i.e. keeping the aspect ratio) to a specified page size, and centered on the page? | | A58) | No, but the Perl script sam2p\_pdf\_scale.pl bundled with sam2p can post-process the file created by sam2p. For example, to scale and center a PDF on an A4 paper, do:

![----8<----](../img_www/text_top.gif)
sam2p input.img output.pdf
sam2p\_pdf\_scale.pl 595 842 output.pdf
![----8<----](../img_www/text_bot.gif) | Unfortunately it doesn't work with default PDFs created by IM. -- Sebastian Krause, from the IM Users Mailing List **Multi-paged PDF Documents**... You can use perl to combine multiple PDF files, without resorting to an IM, and its rasterization problem... > ![----8<----](../img_www/text_top.gif) > #!/usr/bin/perl > # Script pdf-combiner.pl > use strict; > use warnings; > use PDF::Reuse; > > prFile('combo.pdf'); # Output. > for (qw/a b c d/) # Inputs. > { > prImage("result\_$\_.pdf"); > prPage(); > } > prEnd(); > ![----8<----](../img_www/text_bot.gif) You can also use a JAVA toolkit to merge IM generated images into a PDF producing a better PDF than a simpler one that IM will generate... > ![----8<----](../img_www/text_top.gif) > #!/bin/bash > > for x in ./\*.jpeg > do > echo $x to ${x}.pdf > magick $x -quality 75 ${x}.pdf > done > > echo Merging... > java tool.pdf.Merge \*.pdf > ![----8<----](../img_www/text_bot.gif) Another user on [IM Discussion Forums](https://magick.imagemagick.org/viewtopic.php?t=13126) also suggested using [PDFjam](http://www.warwick.ac.uk/go/pdfjam) to merge multiple PDF pages together. * * * ### PbmPlus / NetPBM Image File Format: PBM PGM PPM PNM PAM The PbmPlus or "[NetPBM](http://netpbm.sourceforge.net/) " image manipulation filters (unix command line). These image formats come in a variety of styles "`PBM`" (bitmap), "`PGM`" (grayscale), "`PPM`" (color), "`PFM`" (floating point, for HDRI), "`PAM`" (arbitrary format), and "`PNM`" (any NetPBM format). Each of these (except "`PAM`" and "`PFM`") can also be either in a 'raw' binary form (the default when writing by either IM or NetPBM) , or as plain ASCII text format, (set using "`[-compress](https://imagemagick.org/script/command-line-options.php?#compress) None`"). IM can of course read any of them. The format should be regarded as using "linear-RGB" colorspace only, and NOT using "sRGB" as most other image file formats. However a depth of 16 should be used when using "linear-RGB" so caution is recommended to avoid heavy round off errors with depth 8 images. The NetPBM formats typically saves one image per file. However IM, and many other NetPBM utilities will read and write files with multiple images simply concatinated together. As such when writing images it may be a good idea to set the appropriate "`[-/+adjoin](https://imagemagick.org/script/command-line-options.php?#adjoin) `" setting when writing files. (See [Writing Multiple Image Sequences](../files/#adjoin) for details). The PPM file format is actually especially important to ImageMagick as it is the communication format used during the conversion of Postscript and PDF images via the "[ghostscript](http://www.ghostscript.com/) " delegate. It is also a major format for video image processing such as from the "[ffmpeg](http://ffmpeg.org/) " command. Any 'quality' or value range can be used on input (up to 16 bit or 65535 'depth'). For example, here is a highly unusual value range of 5, to generate a 'step gradient'. I know of no other image format that allows you to use such an odd-ball quality range. echo "P2 6 1 5 0 1 2 3 4 5" | \\ magick - -scale 120x20 pgm\_step\_gradient.gif [![[IM Output]](pgm_step_gradient.gif)](pgm_step_gradient.gif) Also look at [Resized Gradients](../canvas/#gradient_resize) were NetPBM text images are used to create very small (2 to 4 pixel) images. The above also demonstrates just how useful the 'ASCII' sub-formats can be. Espectally as a way of added images into shell scripts, or as a means of generating images from an array of numbers. For example see [TXT: Enumerated Pixel Format](../files/#txt) . One example of this usage is shown in the [Histogram Redistribution Methodology](../color_mods/#redist_method) examples. #### PbmPlus/NetPBM vs ASCII Data Format Its ASCII output is probably the cleanest method of extracting the color values from a specific image, which again makes it idealy suitable for script and simple image processing. magick -size 20x2 xc: +noise random -channel G -separate +channel \ -depth 16 -compress none pgm_random_values.pgm [![[IM Text]](pgm_random_values.pgm.gif)](pgm_random_values.pgm) Note that when the output is plain text, and lines are not written so as to line up with the images row length. But you can re-format the output using the various UNIX text utilities. For example you can use the "`tr`" text utility to replace and compress multiple commas and spaces to single newline, will place all values one value per line, making it easier for a script to process. Also with IM you can only specify 'depth' of 8 or 16 for the output quality for PGM and PPM. While the PbmPlus formats allows the use of any 'maxval' for its values, even one that is not a power of two! It does have a hard limit of 16 bit depth (maxval 65535). A finer control of the actual 'maxval' of the NetPBM image is currently not possible, though could be added via a special coder setting in the future. (if requested). Here is another example outputing a 9x9 array of grayscale values from 0 to 255, extracted from the rose built-in image. I used "`pnmtopnm -plain`" so we get a newline at the end of each pixel row. magick rose:[9x9+0+0] -colorspace gray -transpose -depth 8 PGM:- |\ pnmtopnm -plain [![[IM Text]](pgm_array.pgm.gif)](pgm_array.pgm) Older variants of this NetPBM command include "`pnmnoraw`" and "`pnmtoplainpnm`", to do the same thing as "`pnmtopnm -plain`". Check your NetPBM packages man page, as the developers can't seem to make up their minds as to how it should be done. Any of these PbmPlus programs will output a newline at the end of 'image row', which the ImageMagick coder does not do. This can make image processing in scripts a lot easier. Here is an example of outputing a very small ASCII PBM bitmap. magick label:O pbm: | pnmtopnm -plain [![[IM Text]](pbm_array.pbm.gif)](pbm_array.pbm) Note that PBM bitmaps does not even need to output spaces between values, though they are allowed (IM outputs them, PbmPlus utilities do not). Also note that for bitmaps white='`0`' (background) and black='`1`' (foreground). This is a standard for bitmaps formats like XBM and PBM, and ImageMagick understands this convention. If this is not desirable [Negate](../color_mods/#negate) the image, or use [Level Images by Color](../color_mods/#level-colors) to set the desired colors of the bitmap image. #### PbmPlus/NetPBM Depth Control Sometimes you want more control of the depth of PGM and PPM images, for example to use a percentile range of values from 0 to 99. One method is to use the NetPBM program "`pamdepth`", which can magick images to any range (up to internal limits of 65335). Here for example is an image array of values but using a 0 to 99 range of output values. magick -size 9x9 radial-gradient: -depth 16 PGM:- |\ pamdepth 99 | pnmtopnm -plain [![[IM Text]](pgm_percent.pgm.gif)](pgm_percent.pgm) Here is another example but this time using the [Reversed Level](../color_mods/#level_plus) operator to set output value range. This can give you more control over the transformation of values, but the 'maxval' in the PGM image does not match the max value of the image. magick -size 9x9 radial-gradient: +depth +level 0,99 PGM:- |\ pnmtopnm -plain [![[IM Text]](pgm_percent_2.pgm.gif)](pgm_percent_2.pgm) The "`[+depth](https://imagemagick.org/script/command-line-options.php?#depth) `" in the above command is vital to set the image file depth to the same as the IM quality level. All that is needed is to reset (or ignore) the third line to a value of '`99`', and optionally compress the image back to a 'raw' binary NetPBM image format. However because PbmPlus/NetPBM has a maximum depth of 65535 (16 bit) this would only work for IM Q8 or Q16 versions. #### PbmPlus/NetPBM Comments IM will read, write, and preserve 'comment' lines in the header of the PbmPlus/NetPBM file format. For example... magick -size 2x2 xc:grey -set comment "by Anthony" -compress none PGM:- [![[IM Text]](pgm_comment.pgm.gif)](pgm_comment.pgm) However that said most applications including PbmPlus itself will ignore such comments, and even lose them when it processes the file. magick -size 2x2 xc:grey -set comment "by Anthony" PGM:- | pnmtopnm -plain [![[IM Text]](pgm_comment_2.pgm.gif)](pgm_comment_2.pgm) #### PbmPlus/NetPBM vs ImageMagick The PbmPlus/NetPBM image processing suite was once a rival of ImageMagick for command-line image processing, but uses a completely different (more low level) pipeline filtering philosophy, for image handling and processing. This makes it easy to use in shell scripts, but more difficult to use for general or very complex image processing. It also means the image is converted to and from the image file format a lot more frequently, and generally requires the use of many temporary files. PbmPlus/NetPBM images do not generally deal with Transparency (though the newer PAM format does), and does not provide a general way of passing image meta-data with the image data. All the PbmPlus/NetPBM formats (like the ImageMagick internal format, see [MIFF Image Streaming](../files/#miff_stream) ) can handle a stream of multiple images, simply by concatenating or appending the images together, one after the other. This makes it very well suited for pipelined, multi-image streaming, methods of image processing, such as for video processing. However be warned that some PbmPlus/NetPBM programs only deal with single images and will not handle a stream of multiple images. However as it is more low-level, and pre-dates ImageMagick, it is often selected for raw image outputs such as video image output and handling. PbmPlus images is also more often used for scientific data, and as such images are typically stored as 'linear-RGB' colorspace rather than the more common non-linear 'sRGB' colorspace. Caution is advised. Both packages can co-exist, and I have been known to use a PbmPlus/NetPBM implementation for some things, instead of ImageMagick. Typically when using a specific low level image processing, or scripting using arrays of values stored in an image form. The two packages work together well, and recommend both be installed and used for serious image work. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _I was actually the one to make the vital 1995 patch release of NetPBM, during a time when little work was being done on that software. Because of this I have a good understanding of the PbmPlus software and its simple image file format.

Since then it has been redeveloped a number of times by different people, and finally seems to have become a proper open source project. The various programs seem to be maturing and start to work together better.

However its main problems: an of lack of meta-data and complexity; remain. But its simplicity as a file format is its biggest advantage, making it ideal for very low level image and data manipulation.

_ | * * * ### TIFF The TIFF format is the propriety format for PhotoShop. However it is so bloated with features, and has been modified by just about every application that has cared to use it, that no program, not even photoshop can handle ALL its variations. Photoshop however has the best chance at reading it. I would steer clear of the TIFF image file format unless you are specifically working with photoshop, or the application accepts no other, better defined, image file format. I don't use the TIFF image file format, or Photoshop. If you use this format with IM extensively, perhaps you would like to submit your findings to me, to include here. That way you can help your fellow TIFF users. Whether a specific software package can read a TIFF, all you can do is try it and see. That is, the problem with this format. TIFF and Density (resolution) in photoshop... See [Photoshop and Density](../basics/#density_photoshop) for the details and solutions to this problem JPEG to TIFF conversion... magick image.jpg image.tif This will either save the image inside the TIFF file using JPEG compression (which was inherited from the JPEG input. Or it will error such as... Error: "JPEG compression support not configured" This is caused by the TIFF library not including JPEG compression support. Either way THIS IS BAD. You can get around this problem by changing the setting to use a different compression algorithm: magick image.jpg -compress zip image.tif magick image.jpg -compress lzw image.tif magick image.jpg +compress image.tif WARNING: -compress Group4 with a TIFF works, but ONLY if you remove all transparent and semi-transparent pixels from the image. Typically you can make sure this is done the same way as JPEG images above, using -background {color} -alpha remove See [Removing Transparency from Images](../masking/#remove) just before the final save (the first only works for single images). TIFF (and MIFF) floating point precision files (Add to IM v6.2.6-5)... This is especially good for HDRI image processing (which uses floating point inside IM itself) For single precision (float) set... -depth 32 -define quantum:format=floating-point For do8uble precision (doubles) set... -depth 64 -define quantum:format=floating-point 14 bit TIFF images... magick logo: -sharpen 0x1 -depth 14 logo.tif tiffinfo logo.tif Image Width: 640 Image Length: 480 Resolution: 72, 72 (unitless) Bits/Sample: 14 Compression Scheme: LZW Photometric Interpretation: RGB color FillOrder: msb-to-lsb Orientation: row 0 top, col 0 lhs Samples/Pixel: 3 Rows/Strip: 2 Planar Configuration: single image plane DocumentName: logo.tif Software: ImageMagick 6.2.8 07/27/06 Q16 https://imagemagick.org 12 bit TIFF images... To magick 16-bit TIFF images to 12-bit: magick image.tif -depth 12 image-12.tif Pure black and white images... magick image ... -type truecolor -type bilevel image.tiff Results in normal images and the smallest filesize, and correct black/white handling in Photoshop, Microsoft Windows Picture and Fax Viewer. [TIFF discussion](https://magick.imagemagick.org/viewtopic.php?p=51723) , _[RQuadling](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=7913) _. Enden and fill-order The order in which TIFF data values are stored is controled by -endien Global order of the bytes -define tiff:endian Tiff format container endian -define tiff:fill-order Bit order within a byte Each takes a value of either MSB (default) or LSB, however the "tiff:fill-order" will be set to the value of "tiff:endian" if that is defined, but not from the global endian value. The "tiff:endian" property is the endianess of the image container. The "-endian" property is the endianess of the image pixels. They may differ. Save a TIFF file format with only one row pre strip -define tiff:rows-per-strip=1. To save more rows per stripe increase the number -define tiff:rows-per-strip=8 You can also specify the 'endian' ordering for binary integers in the format -endian MSB -endian LSB For smaller TIFF images (other than by compression, you can also try to use options and settings like -depth 8 to reduce the color quality or -alpha off to remove the alpha or transparency channel from the image. IM will save a greyscale image as a greyscale TIFF, if no non-grayscale colors are present. You can force it to save as non-greyscale with -depth 8 -type TrueColor Added IM 6.6.4-3 Allow you to set the "Software Creation:" meta-data (property) to something other than "Image Magick 6.\*\*" -set tiff:software "My Software" Windows Picture and Fax Viewer, Windows Explorer These can can only display TIFFs that have certain Photometric Interpretation values, such as RGB. IM Options... -compress LZW -type TrueColor toggle the photometric interpretation (Added IM 6.3.2-10) -define quantum:polarity=min-is-black -define quantum:polarity=min-is-white Multi-Page TIFF If you want to split a multi-page tiff into separate pages, IM may have problems as it will still use up a lot of memory to hold previous pages even if you use a command like... magick "a.tif\[i\]" b%03d.tif This might be regarded as a bug, or perhaps a future improvement. The better solution may be the non-IM "`tiffsplit`" program. TIFF and EXIF profiles Cristy reported: The libtiff delegate library supports the EXIF profile but it was unreliable and caused faults too often so we commented out the call. To get the EXIF attributes try this. magick identify -verbose -define tiff:exif=true image.tif The TIFF format can have a bitmap mask in the form of a clip path, which can be enable using the "`[-clip](https://imagemagick.org/script/command-line-options.php?#clip) `" operator. You can use that 'clip' mask your image with that path using... magick image\_clip.tif -clip \\ ...do\_various\_operations... \\ +clip-mask image\_masked.png See [Write or Clip Masks](../masking/#clip-mask) for more details. * * * ### BMP, Windows Bitmap The Windows desktop icon image format BMP (short for bit-mapped) is a very unfriendly image format and should probably be avoided if possible. ImageMagick supports 8, 24, and 32-bit BMP images. Add -colors 256 to the end your command line (before the output image filename) to create a 8 bit colormapped BMP image rather than a 24 bit BMP format. Extra colors can be added to images after performing operations like rotates, and resize. See Color Quantization for more info on -color. The presence of any transparency controls whether it uses a 24 (RGB) or 32 bit (RGBA) format BMP image. You can use "-alpha off" to turn off transparency in an image. If all colors are gray-scale a 'directcolor' greyscale image is generated. I think -type truecolor will stop this behaviour. If you have an older program cannot read the default BMP4 images written by ImageMagick, (for example a Windows Background Image), you can enforce the generation of a BMP3 format image using... magick image BMP3:image.bmp This format should have no transparency and should be a 'printable image', whatever that means. In other words 'Windows' compatible. However, if a PNG input file was used and it contains a gAMA and cHRM chunk (gamma and chromaticity information) either of which forces "magick" to write a BMP4. To get a BMP3 you need to get rid of that information. One way may be to pipeline the image though a minimal 'image data only' image file format like PPM and then re-save as BMP3. Messy, but it should work. magick image.png ppm:- | magick - BMP3:image.bpm IM can not produce BMP's at depth levels other than 8. However you can use NetPBM image processing set to do the final conversion to other depth levels (This needs at least a Q16 version of IM)... magick image -alpha off -colors 16 ppm:- |\\ pnmdepth 4 | ppm2bmp > image.bmp Format limitations.... The header for a BMP2: format only allows the description of the width, height and bit depth (bits per pixel) of an image. The bit depth can be one of 1, 4, 8 or 24. For comparison, the bmp3: format allows bit depths of 0, 1, 4, 8 ,16, 24 and 32 and has extra fields which specify x and y resolution (in pixels per metre) and compression of the image data. * * * ### ICO To create a multi-resolution ICO format image simply create all the image sizes you require and write them all to the same ICO file. magick icon-16.bmp icon-32.bmp icon-64.bmp \\ icon-128.bmp icon-256.bmp myicon.ico Update magick icon-256.png \\ -define icon:auto-resize="256,128,96,64,48,32,16" \\ myicon.ico You can now add this to you web pages using However many web browsers will now accept most image formats, not just the ICO format. * * * ### RAW Camera Image Formats (CRW,CR2,NEF,X3F,etc.) Most digital cameras, with the exception of the Sigma Foveon sensor and some Sony cameras, magick the image produced by the lens into digital data by using millions of sensors which detect the brightness of one specific colour, Red, Green or Blue. In order for the camera to respond to colour in approximately the same way that the human eye does, there are twice as many green sensors as there are of red or blue because our eye is much more sensitive to green light. The sensors are arranged in what is called a Bayer array. For a description and diagrams of this arrangement see, for example, [Understanding Digital Camera Sensors](http://www.cambridgeincolour.com/tutorials/camera-sensors.htm) . The conversion of the data from a Bayer array into the more familiar RGB pixels requires a process called demosaicing. Once this operation has been done we still do not have an image worth displaying. Even with the extra green pixels, the camera's sensor still does not perceive colour the way we do. If you take a piece of white paper and look at it in bright sunlight and then go indoors and look at it under a fluorescent light, it will look white under both conditions. But if you photograph the sheet of paper under those same conditions using default camera settings, the paper will show slightly different colours when displayed on a screen. The reason is that although the back of our retinas will "see" the same light reflected off the paper as does the camera, our brain will interpret that light for us and we will perceive the paper as white. The camera simply measures the amount of red, green and blue light reflecting off the paper and under a fluorescent light there will be more blue light than there is under sunlight so the paper in that image will look bluer than the one taken in sunlight. To produce images which both show a white sheet of paper requires that they be "white balanced", also referred to as gray balanced or colour balanced. For more about white balancing see [Understanding White Balance](http://www.cambridgeincolour.com/tutorials/white-balance.htm) There are still other aspects of the raw file which must be done, such as setting a correct gamma, but without going into further detail it is clear that the raw file needs a lot of processing before it can become an image that we can view on a monitor. Camera raw files are often referred to as digital negatives. If you take a photo and have the camera generate a JPG image, it will have done the demosaicing and all the other adjustments. But if, for example, you forgot to set the correct white balance in the camera before taking the photo, you can't really do much with the JPG to correct the situation because so much information about the original image has been lost. If, on the other hand, you had produced a raw file from the camera instead of a JPG, during the conversion from raw you can choose a particular white balance setting along with other parameters and if the resulting image doesn't look right you can go back, change the settings and magick it again until it does look right. This is similar to the ability to produce more prints from film negatives. Without the film negative you wouldn't be able to get an 8x10 blowup of one of the 4x6 snapshots you get when the film was first developed. While ImageMagick can handle a large variety of different formats, it does not 'know' how to magick raw camera files, so IM uses the "`[dcraw](http://www.cybercom.net/~dcoffin/dcraw/) `" program as a delegate program to magick the raw file into a format that it does understand, either a TIFF (with the '`-T`' flag) or PNM. Note that it is designed for raw _camera_ images, and not those from, for example, a scanner. The "`[dcraw](http://www.cybercom.net/~dcoffin/dcraw/) `" program can handle a large number of different raw formats including those from cameras manufactured by Canon, Fuji, Kodak, Nikon and Sony. You can determine whether "`dcraw`" will recognize your raw files by asking it to identify a sample. For example the command: dcraw -i CRW_9641.CRW Which returns... CRW_9641.CRW is a Canon EOS 10D image. When IM calls dcraw to do a conversion, using the [delegate](../files/#delegate) (list using "`-list delegate`"), specifies two flags which affect image processing: dcraw -w -4 -O output_file input_file The '`-w`' flag means that dcraw will use the white balance information in the raw file if it can be found. If the info can't be found, dcraw will use an average of the whole image as a basis for white balancing. The '`-4`' flag means that dcraw will only de-mosaic and white balance the raw photo and output the result as a _16-bit linear image_ (48 bits per pixel), suitable for the default Q16 version of IM. Because '`-w`' and '`-4`' are the only two image processing flags specified, there are some defaults that dcraw will use. The output colour space will be sRGB and no ICC profiling is done (on my system, dcraw was compiled without the LCMS library so it can't do profiling). The fact that the '`-4`' flag is set means that many processing steps have been omitted, including levels adjustment and gamma correction, and so the resulting image _will look dark_. The intention is that the user is going to process the image with an image editor such as "Photoshop" or "Paint Shop Pro", or even "ImageMagick" and do their own adjustment of the levels, gamma and so on. In this case, the image should be output to a format that supports 16 bits per colour. (For example [TIFF](#tiff) ). _Note_ that just because dcraw produces a 16-bit file doesn't mean that all 16 bits contain useful data. For example, a raw image from a Canon 10D digital SLR has 10 bits per colour. More recent cameras by Canon and other manufacturers have 14 bits per colour. If you want your raw photos converted completely you will have to remove the '`-4`' flag so that dcraw does the de-mosaicing, white balance, brightness and gamma correction and so on. In this case dcraw outputs an _8-bit file_ (24 bits per pixel). If you are going to do further processing of this image it would be best to output it as a [PNG](#png) and avoid the [JPEG compression artifacts](#jpg) . The JPEG format should only be used as a final step for actual use. In fact, it is always a good idea to use a lossless format such as PNG (or IM internal format MIFF) for intermediate steps in image processing. A special [DCRaw Delegate](../files/#delegate_dcraw) can be added which will let you control how you read the 'raw' camera image formats. For further information look on the [DCRaw WebSite](http://www.cybercom.net/~dcoffin/dcraw/) , and also the [DCRaw Tutorial Website](http://www.guillermoluijk.com/tutorial/dcraw/index_en.htm) which has some information about many of dcraw's optional flags and including histograms of raw images using various flags. Also see [DCRaw by Example](http://www.camerahacker.com/Digital/dcraw_by_example.shtml) . The above notes were first extracted from an IM Forum Topic [Converting RAW images](https://magick.imagemagick.org/viewtopic.php?p=38051) , by _[jhfry](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=11359) _, with major re-writes by _[el\_supremo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=3499) _. * * * ### MPEG, M2V and AVI Movies IM is not very efficient at creating movies. It will do the job though requires the external program "mpeg2encode" to do much of the dirty work. The problem is that IM is not designed to handle video, but static images or small sequences of images. That is, not to say it can't do it, but that is not its goal. In particular it generally reads in all images into memory and process them from there. For a large or long video this is not very efficient. For processing on a small sequence of frames however it really can't be beat. In fact just about every Linux Video manipulation program uses ImageMagick to generate titles, fancy scene changes, and other effects to complete the post-processing development of a larger video development. The process however is kept to small video sequences. However lets have a look at what IM can do. **Frames to Video** There are some reports that unless the images are the right aspect ratio is correct this will fail on older mpeg players, use the MPEG II extension (m2v:) instead. Also use m2v to avoid heavy compression pixelization that can occur using... magick \*.jpg glacier.mpg EG instead use... magick \*.jpg m2v:glacier.mpg Note you may need lots of temporary space to do a large animations You can specify a different directory from the normal /tmp using... setenv MAGICK\_TMPDIR /data magick -limit memory 0 -limit map 0 \*.jpg image.m2v Alternatives... To converting PNG images to MPEG2 Video streams, instead of MNG Multi PNG-files, use the following delegation... png2yuv -j file%08d.png -I p -f 25 -b 1 | \\ mpeg2enc -f 3 -q 3 -b 5000 -o out.m2v For more info see [mjpeg.sf.net](http://mjpeg.sf.net/) IM forums reported decent results with an open source project called "[ffmpeg](http://ffmpeg.org/) ", which seems to be a fairly standard linux package install. ffmpeg -f image2 -i %03d.jpg -vcodec mjpeg -y anim.mpg Extracting an MVG with a transparent background magick -background none -size 320x240 sample.mvg out.png Michael Lenh wrote... I finally was able to create a very sexy video using mplayer mencoder "mf://data/p\*.png" -mf fps=40 -o particle.avi -ovc lavc You can see the results at... http://www.mathematik.uni-ulm.de/~lehn/particle.avi http://www.mathematik.uni-ulm.de/~lehn/temperature.avi [mabu](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=19117) in a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?f=1&t=18724) said to "_USE MENCODER, wow it's like 1000 times faster and actually WORKS_"... mencoder -nosound mf://\*.jpg -mf w=800:h=371:type=jpg:fps=15 -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2160000:mbd=2:keyint=132:v4mv:vqmin=3:lumi\_mask=0.07:dark\_mask=0.2:mpeg\_quant:scplx\_mask=0.1:tcplx\_mask=0.1:naq -o output.mpg It probably has extra options I don't need but it makes a nice time-lapse from .jpg files. Dean S. Messing uses transcode... find . -type f -name '\*.png' | sort > filelist transcode -x imlist,null\\ --use\_rgb\\ -y raw,null\\ -f 60\\ -i filelist\\ -g 4096x2160 \\ -j 540,1024,540,1024\\ -o video.avi\\ -H 0 You can leave out -j (clip window) if you want. -g is output size. Wolfgang Hugemann suggests a new alternative known as 'VirtualDub' under Windows Vista, which will let you run a video, or magick directly from a folder of image frames. WARNING: "`mplayer`" apparentally does not like mpeg file with only one frame. "`ffplay`" however seems to have no problems. **Video to Frames** Both "`[mplayer](http://www.mplayerhq.hu/) `" and "`mencode`" are more efficient at converting video into a series of frames than IM is. On top of this is can handle just about any video (and audio) codec available. For example to grab 5 frames from 1 1/2 minutes into a video, scaled to 320x240, you can use... mplayer file.mov -vf scale=320x240 -ss 01:30 -ao null \\ -vo png:z=3 -frames 5 Other alternatives include the "`[ffmpeg](http://ffmpeg.org/) `" open source library, though that is also part of the "`[mplayer](http://www.mplayerhq.hu/) `" handling. * * * ### MNG, Multiple-image Network Graphics _Contributed by [Barry Loo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=20882) from the [Example Ming Animation](https://magick.imagemagick.org/viewtopic.php?f=2&p=82783) discussion._MNG (pronounce ming) is an open format based on PNG, and provides an animated bitmap alternative to GIF and others. It allows for transparency (both semi and full), compression (both lossy and lossless), and up to 32-bit color depth. The increased color depth is what really sets this format apart from others. GIF only supports up to 256 colors total, which is fine for many graphics; however, photographs and gradients will suffer. Most animation options that can be used in creating GIF animations can also be used to create MNGs. magick -size 101x101 radial-gradient: \\ \\( -clone 0 -level 00,100% +level-colors ,#F00 \\) \\ \\( -clone 0 -level 10,100% +level-colors ,#F12 \\) \\ \\( -clone 0 -level 20,100% +level-colors ,#F24 \\) \\ \\( -clone 0 -level 30,100% +level-colors ,#F36 \\) \\ \\( -clone 0 -level 40,100% +level-colors ,#F46 \\) \\ -delete 0 -duplicate 1,-2-1 -set delay 1x30 -loop 0 pulsing.mng [![[IM Output]](../img_www/doc_video.png)](pulsing.mng) The above command generates a radial-gradient image, which is then cloned and adjusted to create a red to brighter red-orange pulse. This is then duplicated to create a reversed [Patrol Cycle](../anim_mods/#patrol) before creating a 30 second, looped MNG animation. Unfortunately, most Web browsers do not currently support MNG, and many video players only show one pass though the looped animation. If you click on the above missing image frame, you can download the animation and view it using IM [Animate Command](../basics/#animate) . For more information on the MNG format, visit [MNG Web Site](http://www.libpng.org/pub/mng) . * * * ### DPX, Digital Picture Exchange Format This format is used in Motion Picture and Effects industry that makes particular use of the extensive header information and the format's flexibility in being able to handle high dynamic range and logarithmic colour values at a variety of bit depths using RGB or YCbCr pixel descriptions. It is based on, but largely supersedes, Kodak's Cineon format that has more a more film specific header. One example of it's use would be when scanning film for use in post production. Each frame would be stored as an individual .dpx file ranging from 2k (2048 pixels wide) to 8k (8192 pixels wide - for IMAX frames) at anything between 8 to 64 bits per colour component. A sequence of these might then be processed using compositing software, altering the colour or adding visual effects. Once complete they might then be recorded digitally to tape or projected back on to film. The colour values for each pixel are often stored logarithmically (particularly if the sequence is destined to be transferred back on to film) which more naturally reflects the density of how colour information is stored in the emulsion on the original film. When viewed without alteration logarithmic files appear to have very low contrast, and so require a 'look up table' to translate the logarithmic image to something that resembles what you might see if the image was transferred back to film and projected in a cinema. Apart from making the image linear (like most typical computer images) and adjusting the gamma level this table sets where the black and white point lies. For a 10 bit logarithmic image where each colour component value ranges from 0 to 1023 the black and white points are normally set at 95 for black and 685 for white. What this means is that the logarithmic file stores colour values that are lighter than what the linear version will display as pure white and darker than what it will display as pure black. This extra information therefore remains available for an effects artists who might wish to alter the brightness of the image after it has been stored as a dpx file. As an example, had this information been lost, reducing the brightness of an image uniformly would result in highlights becoming darker, whereas with this extra information the highlights instead reduce in size and start showing details that were previously too bright to be seen. The latter is far closer to what happens in the real world. The header can contain Film and/or Television specific data related to a production. For example the television header can contain a SMPTE time code so that shots exported as a dpx sequence from a production's edit can be easily replaced once any effects have been added. The film header holds information about the reel of film the frames originated from and various camera settings that were used while filming. All these details will then stay with the images as they are passed between post-production companies. ### Adding a time code to DPX files You can add a time code to any dpx file using the following: magick -define dpx:television.time.code=10000215 \ originalFile.00001.dpx alteredFile.00001.dpx Carrying out this command for each of several thousand files that form a sequence from a film or animation would clearly take a very long time. A simple script can be used with ImageMagick to automatically increment the time code for each frame in a sequence. For example see the Perl Script [dpx\_timecode.pl](../scripts/dpx_timecode.pl) . A copy of the above was added to the main IM documentation at [Introduction to Motion Picture Formats](https://imagemagick.org/script/motion-picture.php) . The above is courtesy of Seth Dubieniec , from a long IM Forum Discussion on the DPX Format. He is currently developing DPX applications, so more DPX info is likely to be coming. **Extra Notes (unformatted)...** Adding -depth 10 causes IM to output a 10 bit DPX file. -- James Fancher If you want to set the gamma, for example, in the output DPX image... -define dpx:television.gamma=1.7 The colorspace of the DPX image is defined by the image element descriptor and transfer-characteristic. If the transfer characteristic is PrintingDensityColorimetric we set the colorspace to LogColorspace. Only if the colorspace is Log do we apply the gamma and black/white points to convert to the RGB colorspace. Its possible the program you are using is not conforming to the SMPTE standard or ImageMagick is not interpreting the standard correctly. Post an URL to your two DPX images and we will download and try to determine if ImageMagick has a bug or if the program you are using is buggy. The following will work with ImageMagick 6.3.8-3 magick -colorspace log AfterEffectsFile.dpx -set gamma 0.5 \\ -set reference-black 95 -set reference-white 685 image.jpg Alternatively, take a look at the SMTPE documentation -- Cristy You can add text user data to the dpx file by using magick image.dpx -set dpx:userdata "some text" new.dpx -- Cristy * * * ### PSD A PSD image file is the Photoshop Working image file format, just as XCF is the GIMP working file format, and [MIFF](../files/#miff) is ImageMagick's own working file format. They usually contain multi-images, with first image being an all-in-one merger of the current working image. That makes it useful for seeing the working image as it currently stands and is typically used for 'thumbnailing'. All the other images in the multi-image file format are the images that are used to generate that first combined image. That is, the individual working layer images, the user was working on at the time it was saved. So if you just want the 'final' image I suggest you append a " `'[0]'` " to the input filename to junk the working images, and just use the all-in-one first image. However if you plan to work with the individual layer images then use " `'[1--1]'` " to skip the first image. If no extra layer images are found than the first image will be returned instead. I do NOT recommend using "`-delete 0`" as that will return no images at all if no layer images follow that first image. Extra notes... If you can provide more information or like to submit a summary of using IM for this format, then please do... For PSD with a CMYK image you may need to get IM to use the right provide when converting (make sure you IM was installed with the LCMS delegate library) .... magick Test\_CMYK.psd -strip -profile USWebCoatedSWOP.icc \\ -profile sRGB.icc Test\_RGB.png See [Profiles](#profiles) above for more info. If a PSD image contain a 'preview' image. This image is returned as the last image of a two image read. To ensure IM never reads the last image use... magick test.psd\[0--2\] -flatten test.jpg That is, read all images, except the last. But always read the first. This can not be done after the read using a "-delete". * * * ### WMF Another vector format often used for scalable clipart used by the Microsoft Office set of programs. The input can be scaled changing the "`[-density](https://imagemagick.org/script/command-line-options.php?#density) `" before reading the image. See also [Vector Image Formats](#vector) . * * * ### Flash Animations (SWF) Flash animations are currently not supported by IM. But just for completeness _Scott Bicknell_ reports that the [SWF Tool](http://www.swftools.org/) utility "`swfextract`" It can extract jpeg or png frames from a flash animation. _Wolfgang Hugemann_ also thinks the Windows freeware tool "`IrfanView`" may be able to do this as well. Sounds like a good delegate candidate to me. * * * ### Webpage Conversion to Image (HTML) If IM loads a HTML it will look for a html2ps to magick the html to postscript which it can then render as an image. This does not work very well, but does work. Using a full web browser is a much better method as it is designed to do the task in the best possible way. The simplest method to use a browser is to just load the page in a browser and then take a screen shot of it. This gets a perfect image of the page but limited to the window size of the browser. Another variation is to have the browser output the page as postscript rather than have IM magick it. This should page the website into smaller pages quite nicely. Under LINUX you can to start a virtual X windows Display server that is large enough to run a browser that shows the whole web site. This can be a VERY tall display. The browser is then run in it and set to fill the entire display. The web site is loaded and again grabs a screen shot. I have seen a script that can even automate that whole complex process. However you can end up with a VERY long image. It is also difficult to know just how big to make the display. Basically it is NOT easy and the best solutions only use IM for the final image processing, not the html to image generation. * * * ### PCL Printing Format IM PCL is version 6 PCL by default. For version 5 you need to magick your image to black and white. For example... magick image.png -monochrome image.pcl * * * ### Kodak PhotoCD or ProPhotoCD (PCD) The Kodak PhotoCD file is a multi resolution image file format. That is, each file contains the same image at 6 different sizes forming something known as a 'pyramid image'. First image in the file is the lowest resolution (smallest size) and the last the highest resolution (largest size at 3072×2048 pixels). As users typically what the largest resolution image for processing the way to magick a PCD image to some other format like JPG is to grab the sixth or (index 5) from the image file. For example... magick -colorspace RGB image.pcd[5] image.jpg The "`-colorspace RGB`" option is needed in order to get the colors right. Information courtesy of Wolfgang Hugemann from the Magick-Users Mailing list. * * * ### Raw RGB, and Gray Data Imagemagick has a some file formats for dealing with raw image data, specifically "`RGB:`", and "`GRAY:`". As well as provide settings defining that data. For example to output RGB raw data... magick image.jpg -depth 8 image.rgb The "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" setting specifies the size of the integers written (and later read). In this case 8 bit values with 3 bytes per pixel for RGB, (a 24 bit image). Specifying an appropriate depth is always recomended for handlign raw image data. A "`[-depth](https://imagemagick.org/script/command-line-options.php?#depth) `" of 16 bits, will produce 2 bytes per value, in which case you may also need to specify the "`[-endian](https://imagemagick.org/script/command-line-options.php?#endian) `" or byte order, to be either '`MSB`' (most significate byte first), or '`LSB`' (least significate byte first, the default). Note that rgb is purely the image data, it does not even contain the width and the height of the image! Some applications 'assume' the data is a specific size, so you may need to use IM to ensure that data is this size. For example This resizes and pads the image to ensure it is 512x512 pixels in size. magick image.jpg -resize \>512x512 \ -background black -gravity center -extent 512x512 \ -depth 8 image.rgb When reading raw RGB (or GRAY) data into ImageMagick you will need to specify how big the image is. For example.. magick -size 512x512 -depth 8 image.rgb image.png This will exactly define how much data Imagemagick will read in. Sometimes the raw data may have some extra header information attached. To allow IM to skip over this information you can specify an 'byte\_offset' in the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting. For example skip a 48 byte header... magick -size 512x512+48 -depth 8 image.rgb image.png This is the only time I know of where IM will make use of a third number in the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting. For more examples of using raw image data (grayscale) see the IM Discussion forum topic [How to convert raw image to compressed tif?](https://magick.imagemagick.org/viewtopic.php?f=1&t=20324&p=80891) . #### Floating Point Data You can also read (and write) RGB using normalized floating point numbers. This however requires the use of special coder -define settings. See HDRI floating point file formats https://imagemagick.org/Usage/basics/#hdri\_formats RGB floating point Image generated using C Code (HDRI)... float red = 1.0f; float green = 1.0f; /\* appropriate data \*/ float blue = 1.0f; /\* for exach pixel in image... \*/ fwrite (&red, sizeof(float), 1, file); fwrite (&green, sizeof(float), 1, file); fwrite (&blue, sizeof(float), 1, file); Reading Options.... magick -size 200x100 -depth 32 -define quantum:format=floating-point -define quantum:scale=65536.0 -endian lsb input.rgb output.png The quantum:format defines to read floating point numbers from the file. While the -depth defines the floating point size (32 = floats, 64 = doubles). The quantum:scale defines how to scale the floating point numbers from normalized 0.0 to 1.0 values to the in-memory 16bit Quality levels needed by my Q16 version of IM. * * * --- # ImageMagick Examples -- Repository Links ImageMagick Examples -- Repository Links ======================================== **Index** [![](img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](.) [![](img_www/granitesm_right.gif) IM Script Repositories](#script) * * * Sources of ImageMagick Scripts ------------------------------ There is NO official repository for scripts. However, individuals create some repositories, of various stuff. However what one person finds useful, others may need to modify for their own use. So caution is recommended. Ideally the scripts should be self-documenting and clearly written, and the ones here are generally like that. This includes... * Some Examples Scripts installed in '/usr/share/docs/...'   as part of the IM installation (or in the IM sources). * [IM Examples, Shell Scripts Area](scripts) , for scripts detailed in or used by these example pages. * [Ron Savages Perl 'Hax'](http://savage.net.au/ImageMagick.html) . Are raw tar file collections of very small IM scripts. It is very very old, but the concepts are still there. * [Fred Weinhaus's ImageMagick Scripts](http://www.fmwconcepts.com/imagemagick/) provides a large collection of complex shell scripts for filtering and distorting images in various ways. * [RubbleWebs](http://www.rubblewebs.co.uk/imagemagick/imagemagick.php) which uses PHP scripts calling the ImageMagick Command Line API. This was created by the regular IM Discussion Forum user '[Bonzo](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=6256) '. * [RMagick Examples](https://github.com/rmagick/rmagick/tree/master/examples) , which includes the original script that was incorporated into IM as the [Polaroid](transforms/#polaroid) transform. * [Tom Watson's ImageMagick Scripts](http://toms.homeip.net/image_scripts/a_README.html) provides TCSH scripts using IM. Mostly they are for handling of digital camera photos. * * * --- # Backgrounds -- ImageMagick Examples ImageMagick Examples -- ![](../../w_images/space.gif) Background Examples =========================================================================== [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) This is a table of applying various transforms against some 'random' canvases, showing methods of producing interesting random backgrounds at whatever size you desire, whether it is a single large image, or a background tile for a web page. The table starts with the method used to generate the initial 'random' image used to generate all the other images shown. Just insert the various image 'transform' into the command, to magick the raw image into something similar to that shown. From there you can adjust the various setting yourself to produce exactly the type of background image you want. Be sure to read the notes at the end, before attempting to create your own examples. and please mail any interesting variations you may come across.Input Images :- Generator, Transform and Post-processing _Images results shown here were generated with a "`-noop`" null transform operator_Plasma Fractal _(non-tiling canvas image)_ magick -size 120x120 plasma:fractal fractal.png magick fractal.png {..transform..} \ -shave 20x20 +repage -auto_level {result} [![[IM Output]](fractal_noop.png)](fractal_noop.png) Random Noise _(tilable background image)_ magick -size 80x80 xc: +noise Random noise.png magick noise.png -virtual-pixel tile {..transform..} \ -auto_level {result} [![[IM Output]](noise_noop.png)](noise_noop.png) Random Hex Tile _(hex tile background image)_ magick -size 50x80 xc: +noise Random -write mpr:rand \ -extent 100x80 -page +50-40 mpr:rand \ -page +50+40 mpr:rand -flatten hextile.png magick hextile.png -virtual-pixel tile {..transform..} \ -auto_level {result} [![[IM Output]](hextile_noop.png)](hextile_noop.png)  Basic Transformsblur\_raw _(no post -auto-level)_ -blur 0x1 [![[Fractal]](fractal_blur_raw.png)](fractal_blur_raw.png) [![[Noise]](noise_blur_raw.png)](noise_blur_raw.png) [![[Noise]](hextile_blur_raw.png)](hextile_blur_raw.png) blur\_1 -blur 0x1 [![[Fractal]](fractal_blur_1.png)](fractal_blur_1.png) [![[Noise]](noise_blur_1.png)](noise_blur_1.png) [![[Noise]](hextile_blur_1.png)](hextile_blur_1.png) blur\_3 -blur 0x3 [![[Fractal]](fractal_blur_3.png)](fractal_blur_3.png) [![[Noise]](noise_blur_3.png)](noise_blur_3.png) [![[Noise]](hextile_blur_3.png)](hextile_blur_3.png) blur\_5 -blur 0x5 [![[Fractal]](fractal_blur_5.png)](fractal_blur_5.png) [![[Noise]](noise_blur_5.png)](noise_blur_5.png) [![[Noise]](hextile_blur_5.png)](hextile_blur_5.png) blur\_10 -blur 0x10 [![[Fractal]](fractal_blur_10.png)](fractal_blur_10.png) [![[Noise]](noise_blur_10.png)](noise_blur_10.png) [![[Noise]](hextile_blur_10.png)](hextile_blur_10.png) intensity -blur 0x10 -colorspace Gray [![[Fractal]](fractal_intensity.png)](fractal_intensity.png) [![[Noise]](noise_intensity.png)](noise_intensity.png) [![[Noise]](hextile_intensity.png)](hextile_intensity.png) channel -blur 0x10 -fx G [![[Fractal]](fractal_channel.png)](fractal_channel.png) [![[Noise]](noise_channel.png)](noise_channel.png) [![[Noise]](hextile_channel.png)](hextile_channel.png) hues -blur 0x10 -auto-level -separate -background white \\ -compose ModulusAdd -flatten -channel R -combine +channel \\ -set colorspace HSB -colorspace RGB [![[Fractal]](fractal_hues.png)](fractal_hues.png) [![[Noise]](noise_hues.png)](noise_hues.png) [![[Noise]](hextile_hues.png)](hextile_hues.png) Shade Transformsshade\_raw _(no post -auto-level)_ -shade 120x45 [![[Fractal]](fractal_shade_raw.png)](fractal_shade_raw.png) [![[Noise]](noise_shade_raw.png)](noise_shade_raw.png) [![[Noise]](hextile_shade_raw.png)](hextile_shade_raw.png) shade -shade 120x45 [![[Fractal]](fractal_shade.png)](fractal_shade.png) [![[Noise]](noise_shade.png)](noise_shade.png) [![[Noise]](hextile_shade.png)](hextile_shade.png) shade\_dimmed _(no post -auto-level)_ -shade 120x45 -auto-level -fill grey -colorize 40% [![[Fractal]](fractal_shade_dimmed.png)](fractal_shade_dimmed.png) [![[Noise]](noise_shade_dimmed.png)](noise_shade_dimmed.png) [![[Noise]](hextile_shade_dimmed.png)](hextile_shade_dimmed.png) shade\_1 -blur 0x1 -shade 120x45 [![[Fractal]](fractal_shade_1.png)](fractal_shade_1.png) [![[Noise]](noise_shade_1.png)](noise_shade_1.png) [![[Noise]](hextile_shade_1.png)](hextile_shade_1.png) shade\_2 -blur 0x2 -shade 120x45 [![[Fractal]](fractal_shade_2.png)](fractal_shade_2.png) [![[Noise]](noise_shade_2.png)](noise_shade_2.png) [![[Noise]](hextile_shade_2.png)](hextile_shade_2.png) shade\_5 -blur 0x5 -shade 120x45 [![[Fractal]](fractal_shade_5.png)](fractal_shade_5.png) [![[Noise]](noise_shade_5.png)](noise_shade_5.png) [![[Noise]](hextile_shade_5.png)](hextile_shade_5.png) shade\_10 -blur 0x10 -fx G -shade 120x45 [![[Fractal]](fractal_shade_10.png)](fractal_shade_10.png) [![[Noise]](noise_shade_10.png)](noise_shade_10.png) [![[Noise]](hextile_shade_10.png)](hextile_shade_10.png) Emboss Transformsemboss\_1 -blur 0x5 -emboss 1 [![[Fractal]](fractal_emboss_1.png)](fractal_emboss_1.png) [![[Noise]](noise_emboss_1.png)](noise_emboss_1.png) [![[Noise]](hextile_emboss_1.png)](hextile_emboss_1.png) emboss\_1g -blur 0x5 -emboss 1 -fx G [![[Fractal]](fractal_emboss_1g.png)](fractal_emboss_1g.png) [![[Noise]](noise_emboss_1g.png)](noise_emboss_1g.png) [![[Noise]](hextile_emboss_1g.png)](hextile_emboss_1g.png) emboss\_0s -blur 0x3 -emboss .5 -shade 120x45 [![[Fractal]](fractal_emboss_0s.png)](fractal_emboss_0s.png) [![[Noise]](noise_emboss_0s.png)](noise_emboss_0s.png) [![[Noise]](hextile_emboss_0s.png)](hextile_emboss_0s.png) emboss\_1s -blur 0x5 -emboss 1 -shade 120x45 [![[Fractal]](fractal_emboss_1s.png)](fractal_emboss_1s.png) [![[Noise]](noise_emboss_1s.png)](noise_emboss_1s.png) [![[Noise]](hextile_emboss_1s.png)](hextile_emboss_1s.png) emboss\_1gs -blur 0x5 -emboss 1 -fx G -shade 120x45 [![[Fractal]](fractal_emboss_1gs.png)](fractal_emboss_1gs.png) [![[Noise]](noise_emboss_1gs.png)](noise_emboss_1gs.png) [![[Noise]](hextile_emboss_1gs.png)](hextile_emboss_1gs.png) emboss\_5gs -blur 0x10 -emboss 5 -fx G -shade 120x45 [![[Fractal]](fractal_emboss_5gs.png)](fractal_emboss_5gs.png) [![[Noise]](noise_emboss_5gs.png)](noise_emboss_5gs.png) [![[Noise]](hextile_emboss_5gs.png)](hextile_emboss_5gs.png) Edging Transformscharcoal -blur 0x2 -charcoal 10 -negate [![[Fractal]](fractal_charcoal.png)](fractal_charcoal.png) [![[Noise]](noise_charcoal.png)](noise_charcoal.png) [![[Noise]](hextile_charcoal.png)](hextile_charcoal.png) charcoal\_10s -blur 0x2 -charcoal 10 -negate -shade 120x45 [![[Fractal]](fractal_charcoal_10s.png)](fractal_charcoal_10s.png) [![[Noise]](noise_charcoal_10s.png)](noise_charcoal_10s.png) [![[Noise]](hextile_charcoal_10s.png)](hextile_charcoal_10s.png) charcoal\_1s -blur 0x2 -charcoal 1 -negate -shade 120x45 [![[Fractal]](fractal_charcoal_1s.png)](fractal_charcoal_1s.png) [![[Noise]](noise_charcoal_1s.png)](noise_charcoal_1s.png) [![[Noise]](hextile_charcoal_1s.png)](hextile_charcoal_1s.png) edges -blur 0x2 -edge 10 [![[Fractal]](fractal_edges.png)](fractal_edges.png) [![[Noise]](noise_edges.png)](noise_edges.png) [![[Noise]](hextile_edges.png)](hextile_edges.png) edge\_grey -blur 0x2 -edge 10 -fx G [![[Fractal]](fractal_edge_grey.png)](fractal_edge_grey.png) [![[Noise]](noise_edge_grey.png)](noise_edge_grey.png) [![[Noise]](hextile_edge_grey.png)](hextile_edge_grey.png) mesas -blur 0x2 -edge 10 -fx G -shade 120x45 [![[Fractal]](fractal_mesas.png)](fractal_mesas.png) [![[Noise]](noise_mesas.png)](noise_mesas.png) [![[Noise]](hextile_mesas.png)](hextile_mesas.png) Line Generating Transformslines -blur 0x10 -emboss 4 -edge 1 [![[Fractal]](fractal_lines.png)](fractal_lines.png) [![[Noise]](noise_lines.png)](noise_lines.png) [![[Noise]](hextile_lines.png)](hextile_lines.png) loops -blur 0x10 -edge 15 -edge 1 -blur 0x1 [![[Fractal]](fractal_loops.png)](fractal_loops.png) [![[Noise]](noise_loops.png)](noise_loops.png) [![[Noise]](hextile_loops.png)](hextile_loops.png) engrave\_loops -blur 0x10 -edge 15 -edge 1 -blur 0x1 -fx R+B+G -shade 280x45 [![[Fractal]](fractal_engrave_loops.png)](fractal_engrave_loops.png) [![[Noise]](noise_engrave_loops.png)](noise_engrave_loops.png) [![[Noise]](hextile_engrave_loops.png)](hextile_engrave_loops.png) engrave\_loop -blur 0x10 -edge 15 -edge 1 -blur 0x1 -fx G -shade 280x45 [![[Fractal]](fractal_engrave_loop.png)](fractal_engrave_loop.png) [![[Noise]](noise_engrave_loop.png)](noise_engrave_loop.png) [![[Noise]](hextile_engrave_loop.png)](hextile_engrave_loop.png) color\_contours -blur 0x10 -normalize -fx 'sin(u\*4\*pi)\*100' -edge 1 -blur 0x1 [![[Fractal]](fractal_color_contours.png)](fractal_color_contours.png) [![[Noise]](noise_color_contours.png)](noise_color_contours.png) [![[Noise]](hextile_color_contours.png)](hextile_color_contours.png) contours -blur 0x10 -normalize -fx 'sin(g\*4\*pi)\*100' \\ -edge 1 -blur 0x1 -shade 280x45 [![[Fractal]](fractal_contours.png)](fractal_contours.png) [![[Noise]](noise_contours.png)](noise_contours.png) [![[Noise]](hextile_contours.png)](hextile_contours.png) Complex Textured Blob Transforms_(using a strange '`-edge 1`' effect)_blobs -blur 0x10 -edge 1 [![[Fractal]](fractal_blobs.png)](fractal_blobs.png) [![[Noise]](noise_blobs.png)](noise_blobs.png) [![[Noise]](hextile_blobs.png)](hextile_blobs.png) blobs\_grey -blur 0x10 -edge 1 -fx '(R+G+B)/3' [![[Fractal]](fractal_blobs_grey.png)](fractal_blobs_grey.png) [![[Noise]](noise_blobs_grey.png)](noise_blobs_grey.png) [![[Noise]](hextile_blobs_grey.png)](hextile_blobs_grey.png) pits -blur 0x10 -edge 1 -fx G -shade 280x45 [![[Fractal]](fractal_pits.png)](fractal_pits.png) [![[Noise]](noise_pits.png)](noise_pits.png) [![[Noise]](hextile_pits.png)](hextile_pits.png) ridges -blur 0x10 \\( +clone -negate \\) -edge 1 -fx u.G+v.G -shade 280x45 [![[Fractal]](fractal_ridges.png)](fractal_ridges.png) [![[Noise]](noise_ridges.png)](noise_ridges.png) [![[Noise]](hextile_ridges.png)](hextile_ridges.png) mottled -blur 0x10 -write mpr:save -negate -edge 1 -negate -fx G \\ \\( mpr:save -edge 1 -fx G \\) -shade 280x45 -evaluate-sequence mean [![[Fractal]](fractal_mottled.png)](fractal_mottled.png) [![[Noise]](noise_mottled.png)](noise_mottled.png) [![[Noise]](hextile_mottled.png)](hextile_mottled.png) Paint Transformspaint\_raw10 _(no post -auto-level)_ -paint 10 [![[Fractal]](fractal_paint_raw10.png)](fractal_paint_raw10.png) [![[Noise]](noise_paint_raw10.png)](noise_paint_raw10.png) [![[Noise]](hextile_paint_raw10.png)](hextile_paint_raw10.png) paint\_areas -paint 10 -blur 0x5 -paint 10 [![[Fractal]](fractal_paint_areas.png)](fractal_paint_areas.png) [![[Noise]](noise_paint_areas.png)](noise_paint_areas.png) [![[Noise]](hextile_paint_areas.png)](hextile_paint_areas.png) paint\_raw10s -paint 10 -shade 120x45 [![[Fractal]](fractal_paint_raw10s.png)](fractal_paint_raw10s.png) [![[Noise]](noise_paint_raw10s.png)](noise_paint_raw10s.png) [![[Noise]](hextile_paint_raw10s.png)](hextile_paint_raw10s.png) paint\_8 -blur 0x5 -paint 8 [![[Fractal]](fractal_paint_8.png)](fractal_paint_8.png) [![[Noise]](noise_paint_8.png)](noise_paint_8.png) [![[Noise]](hextile_paint_8.png)](hextile_paint_8.png) paint\_8s -blur 0x5 -paint 8 -shade 120x45 [![[Fractal]](fractal_paint_8s.png)](fractal_paint_8s.png) [![[Noise]](noise_paint_8s.png)](noise_paint_8s.png) [![[Noise]](hextile_paint_8s.png)](hextile_paint_8s.png) paint\_3 -blur 0x10 -paint 3 [![[Fractal]](fractal_paint_3.png)](fractal_paint_3.png) [![[Noise]](noise_paint_3.png)](noise_paint_3.png) [![[Noise]](hextile_paint_3.png)](hextile_paint_3.png) paint\_3s -blur 0x10 -paint 3 -shade 120x45 [![[Fractal]](fractal_paint_3s.png)](fractal_paint_3s.png) [![[Noise]](noise_paint_3s.png)](noise_paint_3s.png) [![[Noise]](hextile_paint_3s.png)](hextile_paint_3s.png) paint\_3d -blur 0x10 -paint 3 \\( +clone -shade 120x45 \\) \\ +swap -compose overlay -composite [![[Fractal]](fractal_paint_3d.png)](fractal_paint_3d.png) [![[Noise]](noise_paint_3d.png)](noise_paint_3d.png) [![[Noise]](hextile_paint_3d.png)](hextile_paint_3d.png) Gradient Transformslevels _(no post -auto-level)_ -blur 0x12 -fx intensity -normalize \\ -size 1x9 gradient:navy-lavender \\ -interpolate integer -fx 'v.p{0,G\*(v.h-1)}' [![[Fractal]](fractal_levels.png)](fractal_levels.png) [![[Noise]](noise_levels.png)](noise_levels.png) [![[Noise]](hextile_levels.png)](hextile_levels.png) levels\_3d _(no post -auto-level)_ -blur 0x12 -fx intensity -normalize \\ -size 1x9 gradient:navy-lavender \\ -interpolate integer -fx 'v.p{0,G\*(v.h-1)}' \\ \\( +clone -shade 120x45 -normalize \\) \\ -compose overlay -composite [![[Fractal]](fractal_levels_3d.png)](fractal_levels_3d.png) [![[Noise]](noise_levels_3d.png)](noise_levels_3d.png) [![[Noise]](hextile_levels_3d.png)](hextile_levels_3d.png) zebra -blur 0x12 -normalize \\ -size 1x19 pattern:gray50 -fx 'v.p{0,G\*(v.h-1)}' [![[Fractal]](fractal_zebra.png)](fractal_zebra.png) [![[Noise]](noise_zebra.png)](noise_zebra.png) [![[Noise]](hextile_zebra.png)](hextile_zebra.png) midlevel -blur 0x12 -normalize \\ \\( -size 1x9 xc: -draw 'color 0,4 point' -negate \\) \\ -fx 'v.p{0,G\*(v.h-1)}' [![[Fractal]](fractal_midlevel.png)](fractal_midlevel.png) [![[Noise]](noise_midlevel.png)](noise_midlevel.png) [![[Noise]](hextile_midlevel.png)](hextile_midlevel.png) edged\_level _(no post -auto-level)_ -blur 0x12 -normalize \\ \\( -size 1x9 xc: -draw 'color 0,4 point' \\) \\ -fx '(.6+.2\*v.p{0,G\*(v.h-1)})' \\ \\( +clone -normalize -edge 1 \\) -fx 'u+v' [![[Fractal]](fractal_edged_level.png)](fractal_edged_level.png) [![[Noise]](noise_edged_level.png)](noise_edged_level.png) [![[Noise]](hextile_edged_level.png)](hextile_edged_level.png) layered\_levels _(no post -auto-level)_ -blur 0x12 -normalize \\ \\( -size 1x9 xc: -draw 'color 0,4 point' \\) \\ -fx '(.5+.3\*v.p{0,u\*(v.h-1)})' \\ \\( +clone -normalize -edge .3 -fx 'R+G+B' \\) \\ -fx 'intensity+v' -fill skyblue -tint 100 [![[Fractal]](fractal_layered_levels.png)](fractal_layered_levels.png) [![[Noise]](noise_layered_levels.png)](noise_layered_levels.png) [![[Noise]](hextile_layered_levels.png)](hextile_layered_levels.png) Miscellaneousfilaments -blur 0x5 -normalize -fx g \\ -sigmoidal-contrast 15x50% -solarize 50% [![[Fractal]](fractal_filaments.png)](fractal_filaments.png) [![[Noise]](noise_filaments.png)](noise_filaments.png) [![[Noise]](hextile_filaments.png)](hextile_filaments.png) If you have or come up with a nice background generator or image transform, please let me know so it can be added here to share with others. ### Final Important Notes The two [Random Noise Images](../canvas/#random) , being so 'random' are tilable, and we use "`[-virtual-pixels](https://imagemagick.org/script/command-line-options.php?#virtual-pixels) `" to ensure that they remain tilable during the transformation. However the [Plasma Image](../canvas/#plasma) is not tilable to start with, so a enlarged version with the edges "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) `" off afterward is used to remove the unwanted edge effect of many operations. These technique is discussed further in [Modifying Tile Images](../canvas/#tile_mod) . Note that the final "`[-auto_level](https://imagemagick.org/script/command-line-options.php?#normalize) `" is applied to most images to enhance the contrast of the results, unless the transform is marked as not requiring it so as to preserve and coloring or shadings that resulted from the transformation. Because many image transformations such as, "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `", "`[-emboss](https://imagemagick.org/script/command-line-options.php?#emboss) `", and "`[-edge](https://imagemagick.org/script/command-line-options.php?#edge) `" are grey-scale transformations, they work on the three color channels, completely independently of each other. As a result, in many of the images, the result looks like three separate images have been overlaid, then shaded. The final example "`layered_levels`" was designed to works on each of the three levels simultaneously, while keeping them separate, until the final step where they are added together and color tinted. This triple effect can be removed by either applying an initial gray-scaling operation, or extracting just one of the channels when finished. Typically I extract the '`green`' or '`G`' channel as it is normally the strongest channel in a grey scale image anyway, though any of the three channels can be used. * * * --- # Color Basics and Channels -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Color Basics and Channels ============================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) What is to Color](#intro) * [What is Color?](#intro) * [RGB color space](#rgb) * [CMY color space](#cmy) * [CMYK color space](#cmyk) * [Other Color Spaces](#other) [![](../img_www/granitesm_right.gif) Gamma Correction and sRGB Colorspace](#perception) * [Human Color Perception](#perception) * [Gamma Correction](#gamma) * [Gamma of your Monitor](#monitor) * [sRGB Colorspace Correction](#srgb) * [**Processing Real Images**](#processing) [![](../img_www/granitesm_right.gif) Color Specification](#colors) * [Colors by Name](#color_names) * [Color Name Conflicts](#color_conflicts) * [Semi-Transparent Colors](#color_semitrans) [![](../img_www/granitesm_right.gif) Color Channels](#channels) * [ColorSpace - How Color is Stored](#colorspace) * [Separating Channel Images](#separate) * [Grayscale Channels from Colorspaces](#grayscale) * [Other Channel Separation Methods](#channel_other) * [Combining RGB Channel Images](#combine) * [Combining non-RGB Channel Images](#combine_other) * [Zeroing Color Channels](#zeroing) [![](../img_www/granitesm_right.gif) Colorspaces](#colorspaces) * [Hue based Colorspaces (HSL, HSB)](#hue_colorspaces) * [Generating a HSL ColorWheel](#colorwheel) * [Perceptual Colorspaces (Lab, Luv)](#colorspace_LAB) * [The LCH ColorWheel](#colorwheel_LCH) [![](../img_www/granitesm_right.gif) Replacing Colors in an Image](#replace) ![](../img_www/space.gif) (replacing specific colors) * [Replace a Specific Color](#opaque) * [Replace a Color in the Image](#replace_draw) * [Floodfill Draw](#floodfill_draw) * [Floodfill Operator](#floodfill) * [Fuzz Factor, Matching Near Colors](#fuzz) * [Fuzz Factor Distance](#fuzz_distance) * [Fuzz Factor and Transparent Colors](#fuzz_alpha) Raster Images, which is what ImageMagick deals with (in general) basically consists of an array of individual points or pixels of color. Modifying the individual points and how they are represented is what we will look at in this section. In the next section we will look at more general global modification of the colors in an image as a whole. * * * What is Color? -------------- To really understand color, you need to know exactly what color is. In the physical world color is actually an illusion. We see color because our eyes sense the physical world in very special limited way. Basically in our eyes we have special sensors for Red, Green, Blue, and a minor lesser sensor for peripheral and low light conditions. The later is why we see only grey colors at night. ![IM Diagram](../img_diagrams/human_eye_response.gif) For more info see [Wikipedia, Cone Cells](http://en.wikipedia.org/wiki/Cone_cell) , the graph right which is the response of a typical human eye to different wavelengths of light. Because of this we only sense the world in terms of Red, Green and Blue electromagnetic wave lengths, and this is why images and image processing is generally all about Red, Green, and Blue, or RGB. However it isn't quite as simple as that either. Each of our color sensors actually respond to a range of wavelengths. For example when we see a yellow light, we actually sense the light using both red and green sensors. If our color sensors were strictly pure red and green detectors, we would not see any yellow colors at all. Rainbows would in fact show 'gaps' in it. That means a TV or computer display is actually fooling us into seeing yellow by the monitor emitting just the right mix of red and green light, rather than actual yellow light. Our color sensors see the same intensity as it would for a pure yellow light, and as a result we see yellow, even though in reality we are really seeing two different color frequencies. We just can not tell the difference between a pure yellow, and a mix of red and green light. In a similar way blue-red (purple) colors do not actually exist as a single specific wavelength, but only as a mix of at least two color frequencies, though strictly speaking violet is a specific frequency we do react to, mostly by blue, and very slightly by the other two sensors. Note we actually have a forth vision sensor, but it is not color, but a low light detector, which is used for night vision, when cone sensors no longer work very well. This is why night time looks monochromatic, and moon light is all grays. This sensor is also probably the reason why sRGB colorspace (see below) has an odd linear component for very dark colors in it. ASIDE: Other animals have different sensors to us. Bees and most other insects have sensors for ultra violet, as such to them our printed images, TVs, and billboards would probably make very little sense. More than likely these artificial images would probably look more like a rather horrible false color image, than the near perfect color we humans are fooled into seeing. Some animals have 4 color sensors, while others only have one (black and white) or two. Also some animals see movement far better than any specific color. A bull for example, can not see red, but blue-violet and green wavelengths, but a flapping cap would show as a blaze of a 'movement' color. To a bull, a monitor's 50/60Hz update cycle, would probably look like a blaze of 'movement' rather than any sort of sensible image! For more information see [Wikipedia, Color Vision](http://en.wikipedia.org/wiki/Color_vision) and [Wikipedia, Color](http://en.wikipedia.org/wiki/Color) . ### RGB Color Space, and Channels So RGB color space is really a way of representing images using three values Red, Green, and Blue, that will fool us into thinking we are seeing something in the real world. Images can thus be stored as an 3 arrays values, with each of the three values forming a single pixel, or point of color, to be displayed. Each of the three arrays of values are known as a channel, which is simply a gray-scale image representing the amount of light to create for just one of our color sensors. For example, here are the red, green, and blue components of a rose image. | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](../images/rose.gif)](../images/rose.gif)

Rose | ![==>](../img_www/right.gif) | [![[IM Output]](separate_RGB_0.gif)](separate_RGB_0.gif)

Red | [![[IM Output]](separate_RGB_1.gif)](separate_RGB_1.gif)

Green | [![[IM Output]](separate_RGB_2.gif)](separate_RGB_2.gif)

Blue | Note how the 'Red' image is much brighter to display a rose, than the other two color components. But all three images are bright for the white patch near the bottom. **RGB are Additive Colors**Now Red, Green, and Blue colors are termed 'additive' colors. That is, the colors are added together to form the final color image. This is because those are the dominant colors our eyes see, and by combining them together we can effectively generate almost every color our eyes can see. They are additive in that starting with black, such as a blank monitor, you would then add red, green, and blue light to generate the appropriate colors for the image we see. The key to this is that you start with a black, or the absence of light, and then add appropriate amounts of red, green, and blue. You can also get the same effect by shining three torches with red, green and blue cellophane taped over the ends, in a dark room. When the three colors shine on the same spot say on a white wall, we see white. It is because of how our eyes actually see these 'primary' colors, that color images are generally expressed in terms of RGB values, which are also termed 'color channels'. ### CMY color space When you are printing you have a different problem. A piece of paper can not generate light, only reflect it. As such you need to start with a surface that reflects all the light that hits it, in all directions. That is, what a white surface is. Hopefully the light it is reflecting is itself a pure white light either from the sun shining in the window, or being generated by the lights in our artificially lit rooms. Now to create an image on that paper you need to apply ink to that surface, which actually removes particular wavelengths of light. As we 'sense' red, green, and blue colors, those are the colors we want to selectively remove from the light reflecting from that white piece of paper. Consequently we use a cyan ink to remove red light, magenta to remove green light, and yellow to remove blue light. The amount of Cyan, Magenta, and Yellow ink needed to generate a specific color produces what is termed CMY colorspace. Here I generate an ink masks is needed to generate a rose image using just cyan, magenta and yellow inks (assuming the inks are 'linear') | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](../images/rose.gif)](../images/rose.gif)

Rose | ![==>](../img_www/right.gif) | [![[IM Output]](separate_CMY_0.gif)](separate_CMY_0.gif)

Cyan | [![[IM Output]](separate_CMY_1.gif)](separate_CMY_1.gif)

Magenta | [![[IM Output]](separate_CMY_2.gif)](separate_CMY_2.gif)

Yellow | That is, the brighter the cyan mask values, the more cyan ink will be needed to remove more of the red. In other words a cyan mask is the exact negative of the mount of red light we want the paper to reflect. In fact all three of the above channel images are the exact negative of what was generated for RGB color-space. So really to magick a RGB image to a CMK image all that you need to do is [Negate the Image](../color_mods/#negate) and then declare the image to be in CMY color-space. As we are selectively removing wavelengths, Cyan, magenta, and Yellow are known as 'subtractive colors'. ### CMYK color space The major problem with selectively removing wavelengths, is that just removing all red, green, and blue light, by applying all three cyan, magenta, and yellow inks, does not actually remove all the light that is being reflected. As a result you will be left not with a black color, but a horrible looking muddy brown color. The inks (or light filters) are not perfect, just as our own eyes are not perfect. As I mentioned before, each of our color sensors does not see just one wavelength of light, but a range of wavelengths that we interpret as being 'red' 'green' or 'blue' (or a mix of those colors). So much so that our 'blue' light sensor can actually see (though not very well) a little ultra violet. ASIDE: the filter of a 'black light' is purposefully imperfect, so that we can 'just see' the light from such a lamp, so we can know if it is on or not. It is because of this 'leakage' of color from the CMY inks, and our own imperfect eyes, that we also add a pure black ink to the mix, allowing it to be used to wipe out ALL light that could be reflected from paper. To prevent it being confused with blue the black ink or channel is assigned the letter K. As such for printing we use four colored inks: Cyan, Magenta, Yellow, and blacK; and define images using these inks, to form a CMYK color space. For example, here are the appropriate CMYK components separated out from this image. | | | | | | | | --- | --- | --- | --- | --- | --- | | [![[IM Output]](../images/rose.gif)](../images/rose.gif)

Rose | ![==>](../img_www/right.gif) | [![[IM Output]](separate_CMYK_0.gif)](separate_CMYK_0.gif)

Cyan | [![[IM Output]](separate_CMYK_1.gif)](separate_CMYK_1.gif)

Magenta | [![[IM Output]](separate_CMYK_2.gif)](separate_CMYK_2.gif)

Yellow | [![[IM Output]](separate_CMYK_3.gif)](separate_CMYK_3.gif)

blacK | Note how the amount of cyan, magenta, and yellow has been reduced and is now darker than in CMY colorspace, as there use was replaced by an appropriate amount of black. That is, when all three inks are present for a particular pixel, black is used instead. As such to print say pure black, you only use pure black ink, and no other inks. Remember the 'blacK' in the above is the amount of black ink to apply to a piece of paper, so the brighter the greyscale channel image is, the more black ink should be used. As such it is also a negative looking image, just like the other three images. Of course adding a pure black in a color printer makes printing black text, a lot simpler, as you no longer need to print three different inks, overlaid perfectly on the same spot, to generate pure black lines, letters, and shapes. This means far less ink, with the paper becoming less 'wet' and less likely to run or smuge, which is especially good for printers. For another similar discussion of how RGB and CMYK colors work see the introduction page of. [XaraXone Workbook, Defining Color](http://archive.xaraxone.com/webxealot/workbook40/page_1.htm) . ### Other Color Spaces Other colorspaces are just other ways of representing those same colors, or some of the others beyond strict RGB that our imperfect eyes can also make out. However such color spaces have little bearing on either displaying those colors using a monitor, or in printing. They basically represent other ways of handling and/or processing the colors of an image, so as to enhance or highlight specific things such as... * Better non-linear handling of Dark Colors ([sRGB](http://en.wikipedia.org/wiki/SRGB) ) * Color rainbows and hues ([HSB,HSL,HSI,OTHA](http://en.wikipedia.org/wiki/HSL_and_HSV) color spaces - intensity not preserved) * Standardized definition colors ([XYZ](http://en.wikipedia.org/wiki/CIE_1931_color_space) ) * Precise or Perceptual Color Differences ([LAB](http://en.wikipedia.org/wiki/Lab_color_space) and [LUV](http://en.wikipedia.org/wiki/Luv_color_space) colorspace, and their LCHab and LCHuv cyclic hue equiv) * Expanded High-Dynamic Ranges (for use with HDRI images) ([scRGB](http://en.wikipedia.org/wiki/ScRGB) ) * Better compression of color values (such as in [YIQ](http://en.wikipedia.org/wiki/YIQ) and [YUV](http://en.wikipedia.org/wiki/YUV) ) * Transmission for TVs (YCbCr, YPbPr, where Y = BW signal) One final colorspace I have yet to mention is 'GrayScale', but that is just a simple single array of pixel values. How you interpret these values is variable as they could represent many different things. Typically such an image is considered to be Linear-Grayscale and similar to linear RGB, (as apposed to non-linear sRGB). IM version 6 actually does not have such a grayscale color space, and only fakes, it with linear RGB color space, setting all RGB settings to the same value. If the three values are not the same, the image is no longer grayscale. IM version 7 Greyscale is a single channel image (much smaller memory usage). | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The above changes to the 'colorspace' of an image is only a gross arrangement of the colors of an image within memory. It also provides very basic (simplistic) color conversions between different colorspaces.

For exact color specifications and color conversions [Color Profiles](../formats/#color_profile)
should be used instead, but only works when using image file formats that can handle color profiles.

_ | * * * Gamma Correction and sRGB Colorspace ------------------------------------ ### Human Color Perception In the above we saw that you can represent images in many different ways. All the color-spaces we looked at above are known as 'linear' colorspaces, which means that the actual value used represents the actual 'intensity' values of the color in an image.However real life is never quite so simple. It never is! For example lets generate and save an image with a simple a linear sequence of gray values... magick -size 100x100 gradient:'gray(100%)-gray(0)' \\ -set colorspace sRGB gradient.gif [![[IM Output]](gradient.gif)](gradient.gif) Notes... * The use of "`gradient:'gray(100%)-gray(0)'`" ensures IM generates a gradient of linear RGB data, which will be in linear RGB colorspace. * The "-set colorspace sRGB" tells IM that this 'linear' gradient is actually in "sRGB" and thus does not need 'correction' when saving into a GIF image file format that can only store sRGB colorspace values. Now the actual color values used in this image are a linear gradient that should smoothly change from white at the top to black at the bottom, with a perfect mathematically exact 50% gray in the middle. However if you look at the image you will see that the image actually seems to contain a lot more dark (near black) colors than light (near white) colors. Why? Well human vision when given a light intensity that is only half of its maximum range ('white') does not see the pure mid-tone grey that the color value indicates, but a much darker color. As a result the above linear gradient does not look like an uniform linear spread of colors from white to black, but has far more darker colors than it should. The actual image value to perceived value is roughly a 'power function' of the form... `**_perceived_grey_ = _value_2.2**` The value '`2.2`' is the average gamma function value, typical of most human beings. ### Gamma Correction Gamma Correction is a way of adjusting the color values that are actually saved, so that the final image looks much more uniform in its spread of colors. Basically while human vision makes light look darker using a power factor of `2.2`, to make a linear image 'look' linear we need to reverse that power function, using a value of `1/2.2`. That is, to make an image look linear, we need to correct it using the following formula... `**_gamma_corrected_value_ = _value_1/2.2**` IM provides Gamma correction via either the [Level Operator, Gamma Argument](../color_mods/#level) , or more specifically using the [Gamma Operator](../color_mods/#gamma) . However you could also directly modify the image values using the [Evaluate POW function](../transform/#evaluate_pow) . So lets apply it and see the result of a 'gamma corrected image'.. magick -size 100x100 gradient:'gray(100%)-gray(0)' -gamma 2.2 \\ -set colorspace sRGB gradient\_gamma.gif [![[IM Output]](gradient_gamma.gif)](gradient_gamma.gif) Note how the image now has far more equal amounts of light and dark colors. However the actual values within the image is no longer 'linear', which can cause problems when processing this image later. Gamma correction is only a rough 'quick' method of adjusting the colors to make an image 'look' correct. It is not the usual or even the best method of correcting an image for human response. For a more specific examples of doing gamma correction for image processing see [Resize with Gamma Correction](../#resize_gamma) For more information on Gamma Correction see * [Gamma Correction (Wikipedia)](http://en.wikipedia.org/wiki/Gamma_correction) * [Gamma error in picture scaling](http://www.4p8.com/eric.brasseur/gamma.html) (includes a section IM usage) * [Gamma FAQ, Image Processing](http://www.poynton.com/notes/colour_and_gamma/GammaFAQ.html#linear) You may also like to look at the "`[-auto-gamma](https://imagemagick.org/script/command-line-options.php?#auto-gamma) `" operator, which tries to adjust gamma to produce a linear-RGB image, with equal amounts of light and dark (in linear space). ### Gamma of your Monitor Stand back from your monitor a few meters (yards) and look at the image to the left. If your monitor (and web browser) is displaying the sRGB image correctly, the point where the central 'hash' pattern is about equal brightness to the surrounding sRGB gradient should be in the very middle. Most computer monitors fail this test!However HDMI TV's should come out perfect. The image was created using... magick -size 45x256 gradient: -size 10x256 pattern:gray50 \\ -duplicate 1,0 +append -set colorspace sRGB -colorspace RGB \\ monitor\_sRGB.png [![[IM Output]](monitor_sRGB.png)](monitor_sRGB.png) Here are some similar images with differnent 'gamma' levels so you can see how close your monitor is to a correct '2.2' gamma display for human perception. for gamma in 1.6 1.8 2.0 2.2 2.4 do magick -size 45x256 gradient: -size 10x256 pattern:gray50 \ -duplicate 1,0 +append -gamma $gamma monitor_g$gamma.png done | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](monitor_g1.6.png)](monitor_g1.6.png)

Gamma 1.6 | [![[IM Output]](monitor_g1.8.png)](monitor_g1.8.png)

Gamma 1.8 | [![[IM Output]](monitor_g2.0.png)](monitor_g2.0.png)

Gamma 2.0 | [![[IM Output]](monitor_g2.0.png)](monitor_g2.0.png)

Gamma 2.2 | [![[IM Output]](monitor_g2.4.png)](monitor_g2.4.png)

Gamma 2.4 | The image that (when you stand back) where the point of equal brightness is about the 50% mark, tells you about the rough gamma level of your monitor. If properly tuned, your monitor should have a gamma level of 2.2 which very closely matches that of sRGB colorspace. When I wrote this my old screen (provided by work) was extremely poor. It has a Gamma setting of about 1.8, and actually has a different Gamma at the top of the display (darker) than that at the bottom of the display (lighter). Something that has caused me problems when comparing images at different locations on the screen, as the same image looks different, when placed in different positions vertically! On the other hand my personal laptop (at that time) as a very uniform display, with a reasonable 2.0 gamma setting according to the above. ### sRGB Colorspace Correction Saving an image using a sRGB Colorspace is very similar to Gamma correcting an image, but is slightly more complicated so as to better reproduce the actual response of the human eye, specifically with very dark shades of color.So lets save our linear gradient in a sRGB corrected colorspace. magick -size 100x100 gradient:'gray(100%)-gray(0)' \\ -set colorspace RGB -colorspace sRGB gradient\_sRGB.gif [![[IM Output]](gradient_sRGB.gif)](gradient_sRGB.gif) ![](../img_www/warning.gif)![](../img_www/space.gif)_As of IM v6.7.7 the above is simplified to just_ magick -size 100x100 gradient:white-black gradient\_sRGB.gif _This is because the linear gradient will always be generated in a linear (RGB) colorspace (which is the only sensible way for the operator to work). However as sRGB colors 'white-black' is being requested, the linear-data gradient will be automatically converted to sRGB colorspace, producing non-linear data values, and a perceptually linear gradient. _![](../img_www/warning.gif)![](../img_www/space.gif)_Before IM version 6.7.5 the above would have failed as IM had the meanings of 'sRGB' and 'RGB' colorspace reversed. As such on older versions of IM the two colorspace names needed to be swapped. For example..._ magick -size 100x100 gradient: -set colorspace sRGB \\ -colorspace RGB gradient\_sRGB.gif _This colorspace handling weirdness was considered a long time IMv7 bug, though was ment to be fixed in IMv7 only, it was backported to IMv7. _Note that the above (or any other gradient) is not a perfect, as perfection is simply impossible, everyone sees things in there own way with slight differences. Simply put: _what you see, is never exactly what other people see_ (its actually very Zen). All sRGB is, is a very good approximation for the majority people, according to numerious surveys, and a lot of print/paint/color experts. For details of the exact sRGB formula see [Wikipedia, sRGB Colorspace](http://en.wikipedia.org/wiki/SRGB_color_space) . A more complete an accurite 'human luminance response was developed, and can be seen on line in the thesis [Human Vision, Just Noticeable Difference](http://www.cg.tuwien.ac.at/research/theses/matkovic/node16.html) . This includes adaptive response in situations of major lighting changes. The World Wide Web has standardized on the use of [sRGB](#sRGB) as the recommended (and still reasonably simple) default color space, and should thus be used for all images that do not contain any colorspace profile information. That is, for images such as GIF, PNG, JPEG and TIFF. All these formats (except GIF) allow the use of [Color Profiles](../formats/#color_profile) to definitivally specify the colorspace the image. However image file formats such as [PbmPlus](../formats/#pbmplus) are typically not regarded as being in sRGB colorspace. As such when working with such file formats it is typically a good idea to use "`-set colorspace ...`" to ensure the colorspace is as you are expecting. And here are all three images together so you can compare them. | | | | | --- | --- | --- | | [![[IM Output]](gradient.gif)](gradient.gif)

Linear | [![[IM Output]](gradient_gamma.gif)](gradient_gamma.gif)

Gamma | [![[IM Output]](gradient_sRGB.gif)](gradient_sRGB.gif)

sRGB | As you can see Gamma and sRGB corrected images are nearly identical, and the difference when graphed is actually extremely minor. As such while using [sRGB](#sRGB) is the more correct method, using [Gamma Correction](#gamma) is probably easier to apply. The biggest differences between sRGB and Gamma image are in extreme dark pictures. For a 8-bit Gray value of 1, sRGB is 60 times brighter than the equivelent Gamma. A value of 8 is 5 times brighter. This will not make any noticeable difference in most cases but it can, when a very dark picture is handled. ### Processing Real Images Most image processing operators do not care what colorspace an image is using, it just applies its operations to the channel data regardless of its colorspace. Though some have to make special effort for handling the extra channel data for 'Black', and as you will see later 'Alpha' (or 'Alpha' transparency). However the colorspace of an image can greatly influence the final result of many operations. As such doing image processing in a different color space can generate improved results. This example more clearly shows why processing in sRGB is not a good idea. From a discussion on [Color Blurs](https://magick.imagemagick.org/viewtopic.php?t=30974&p=140758) and 'Broken Colors', on the IM Users Forum.We take two colors using different color channels and blur them together so that within the channel the color is blurring to zero (a low color value). First lets do thus using the default sRGB input channel. magick -size 40x80 xc:red xc:lime +append \\ -blur 0x20 blur\_sRGB.png [![[IM Output]](blur_sRGB.png)](blur_sRGB.png) If you look at the results, it looks like the colors are blurring from red through black and then to green. That is, because the values to our eyes appear darker than they should be in sRGB colorspace.Here I blur the same image again but using a linear RGB colorspace. magick -size 40x80 xc:red xc:lime +append \\ -colorspace RGB -blur 0x20 -colorspace sRGB blur\_RGB.png [![[IM Output]](blur_RGB.png)](blur_RGB.png) As you can see this time we get a much more sensible result with the red and green colors blurring though orange. You also get similar results by using other linear color spaces such as LAB or LUV, which we will look at in more detail below. Basically when processing images that involve mixing colors, for example in operations such as [Color Quantization](../quantize/#quantize) (color reduction), but also in [Image Resizing](../resize/) and more generally [Image Distorting](../distorts/) , you should process the images in a linear colorspace for the more accurate results, though in reality few people do this. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Helmut Dersch (of Barrel Distortion and Len Correction fame) recommends that you should consider using the linear '`LAB`' colorspace for processing images, especially for resizing and image distortions.

I only recommend that you move from the 'input' sRGB colorspace to some other 'linear' colorspace, when doing drawing, compositions, resizing or distortions of images. Whether this is linear-RGB, LAB, or LUV, should not matter that much.

_ | Here for example are red-blue blurs in the 3 main linear colorspaces. I picked these colors as they appear to show the greatest difference, in the intermedite colors generated. for colorspace in RGB LUV LAB do magick -size 80x40 xc:red xc:blue -append \ -colorspace $colorspace -blur 0x30 -colorspace sRGB \ colorspace_$colorspace.png done | | | | | --- | --- | --- | | [![[IM Output]](colorspace_RGB.png)](colorspace_RGB.png)

RGB | [![[IM Output]](colorspace_LUV.png)](colorspace_LUV.png)

LUV | [![[IM Output]](colorspace_LAB.png)](colorspace_LAB.png)

LAB | For more examples of processing images with regard to colorspace see [Resizing with Colorspace Correction](../resize/#resize_colorspace) . Also see warnings about color names and drawing in linear colorspace, in [Drawing with Gamma and Colorspace Correction](../draw/#colorspace) * * * Color Specification ------------------- Colors in IM can be specified in many ways. The best guide on this is on the Official IM Website [Color Names](https://imagemagick.org/script/color.php) . ### Colors by Name Many colors have been given specific names, which make then easier to use. For example "`RoyalBlue`" is a very nice bright off blue color. [![[IM Output]](named_colors.png)](named_colors.png) To the right is an image containing all the named colors, including those with numbers, that is available in ImageMagick. The colors were first sorted into 3 groups, Off-Whites, Mid-Tones, and Dark Colors, and then plotted in three separate HSL color-wheels, each with a different vertical offset. Pure white and black colors appear as there own separate spots at the very top and bottom of the chart, to form the extremes of the vertical range. The script that generated it is "`[hsl_named_colors](../scripts/hsl_named_colors) `" and follows a technique looked at in [Programmed Positioning of Layered Images](../layers/#example) . | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Technically as I draw the HSL colors in the 3-dimensional form of a 'bi-cone' rather than a 'cylinder', the radius of each color spot has been set equal to the 'Chroma' of the color ('Saturation'/'Brightness'), rather than just its 'Saturation'. See [Wikipeadia: HSL and HSV](http://en.wikipedia.org/wiki/HSL_and_HSV#Basic_idea)
.

To be even more correct, Hexagonal Pyramids should also have be used instead of Cones, though that is much harder to calculate, for little gain.

_ | As you can see you there a lot of color names associated with red to yellow and a smaller group in the cyan to green hues. With a similar cluster in off-white yellows and cyans. But there is little in the way of named off-green colors. Essentially there are some areas of the HSL color space that have very few named colors. It can be difficult to find a specific named color to use. But by loading the image to the right in the IM "`[display](../basics/#display) `" program you can use the middle mouse button to look at the ImageMagick color name for the specific color that has been plotted. ### Special Color Names There are a few special colors, which are used for special purposes within ImageMagick. '`None`' or '`Transparent`', is a fully transparent black color, and generally used to specify background transparency, such as when creating a [Solid Color Canvas](../canvas/#solid) , or when using [Image Layers](../layers/#flatten) . '`Opaque`' is just an alias for '`Black`', and as such is rarely used. It is typically only used when want to mean ANY opaque color, such as when doing Alpha Channel Processing. ### Color Name Conflicts Color Names can come from three different sources, SVG, X11, and XPM, and most names produce the same color regardless of the defining source. But there are a few colornames which produce different colors, depending on the color specification being used. The biggest problem is the SVG color '`Green`' (half bright green) which is is different to the X11/XPM color '`Green`' (pure RGB green). If you want a pure green, you are better off using the SVG color name '`Lime`' which has no conflict. Wikipedia has an excellent article on the color name conflicts, as well as a good table of the actual color names, in [X11 color names](http://en.wikipedia.org/wiki/X11_color_names) . You may also like to look at the article [Web Colors](http://en.wikipedia.org/wiki/Web_colors) , which provide a set of nicely ordered table of some color ranges. The most notable conflicts are in four specific colors. Here is a table of the known color name conflicts. Remember the SVG color is what IM will use by default. | Conflict
Color Name | SVG Result
(IM default) | | X11 Result
for Name | | X11 Equivelent
Name | | Alternative
Color Name | | | --- | --- | --- | --- | --- | --- | --- | --- | | Green | | #008000 | | #00FF00 | | | | Lime | | Maroon | | #800000 | | #B03060 | | FireBrick | | | | Purple | | #FF00FF | | #A020F0 | | Magenta | | | | Gray | | #7E7E7E | | #BEBEBE | | | | Grey | Notes about the above... * The X11 '`Grey`' is a visual mid-gray color. It is also very close (but not exactly the same) as the X11 color '`Gray74`' and SVG color '`Silver`' ('`gray(192)`'). * The default (SVG) '`Gray`' is very close to a perfect mathematical gray which is better specified using the color names '`Gray50`' or '`gray(128)`' (for 8-bit use). * As all named colors are specified using 8-bit (0-255) values, none of them will generate a perfect 16-bit pure gray color! * When a gray is needed for mathematical processing such as [FFT DC Phase](../fourier/#fft_constant) [Edge Detection](../convolve/#edgedet) , [Shade Images](../transform/#shade) , [Composition Lighting Effects](../compose/#light) , and [Relative Displacement Maps](../mapping/#displacement_maps) you are much better off using the color formula '`gray(50%)`' which does generate a perfect mathematical mid-tone gray at any color bit depth. **Caution is recommended when selecting a color for a specific purpose**. ### Colors and Colorspace While many colors have names, most colors found in images do not, they are just a set of values, usually 3, that specify a specific color. However three values on there own does not fully define a color, you also need to specify the 'colorspace' or 'color system' that those values belong. All the above 'named' colors are in sRGB colorspace, which is the colorspace they were defined in. But sometimes you want to define a color in a different colorspace. For example, in HSL, or CYMK, or even as a XYZ color. Imagemagick can do this and you can see the details of these specifications in [ImageMagick Color Names](https://imagemagick.org/script/color.php#models) . _Future: Examples of using other colorspaces (still in development)_ | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _While RGB in ImageMagick represents a linear-RGB colorspace, it is an accepted practice that a colorname of '`rgb(value,value,value)`' is actually defining a **sRGB color**.

To actually define a linear-RGB color instead of sRGB color use the color formula, '`icc-color(RGB,value,value,value)`' (see next)._ | As of IM v6.7.8-3, you can use the function '`icc-color(colorspace,color...)`' to define a color, or re-define the colorspace, of a specific color. _Future: Examples of use_ ### Semi-Transparent Colors You can directly specify semi-transparent colors directly in only two different ways. The most common method of setting a semi-transparent color is to use a hex value. For example, here are some color specifications showing various levels of color transparency. I have displayed the generated color images on a background pattern so that you can see that pattern though the image transparency. magick -size 50x50 xc:'#00FF00FF' color\_hex\_1.png magick -size 50x50 xc:'#00FF00C0' color\_hex\_2.png magick -size 50x50 xc:'#00FF0090' color\_hex\_3.png magick -size 50x50 xc:'#00FF0060' color\_hex\_4.png magick -size 50x50 xc:'#00FF0030' color\_hex\_5.png magick -size 50x50 xc:'#00FF0000' color\_hex\_6.png [![[IM Output]](color_hex_1.png)](color_hex_1.png) [![[IM Output]](color_hex_2.png)](color_hex_2.png) [![[IM Output]](color_hex_3.png)](color_hex_3.png) [![[IM Output]](color_hex_4.png)](color_hex_4.png) [![[IM Output]](color_hex_5.png)](color_hex_5.png) [![[IM Output]](color_hex_6.png)](color_hex_6.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.3.0, the last set of hex digits contained the colors transparency in the form of a 'matte' or 'opacity' value. That is, the final hexadecimal '`00`' represented 'opaque' and '`FF`_' was transparent.

However after IM v6.3.0, this value was inverted so as to represent an 'alpha' transparency value, to bring IM in line with SVG standards and other graphics packages. In other words '`FF`' now represented fully-opaque and '`00`' is fully transparent. | You can also specify colors using the special '`rgba()`' color function. Where RGB values goes from 0 to 255, and the alpha channel is specified as a decimal fraction between 0.0 (transparent) to 1.0 (opaque). magick -size 50x50 xc:'rgba(255,0,0, 1.0)' color\_rgba\_1.png magick -size 50x50 xc:'rgba(255,0,0, 0.8)' color\_rgba\_2.png magick -size 50x50 xc:'rgba(255,0,0, 0.6)' color\_rgba\_3.png magick -size 50x50 xc:'rgba(255,0,0, 0.4)' color\_rgba\_4.png magick -size 50x50 xc:'rgba(255,0,0, 0.2)' color\_rgba\_5.png magick -size 50x50 xc:'rgba(255,0,0, 0.0)' color\_rgba\_6.png [![[IM Output]](color_rgba_1.png)](color_rgba_1.png) [![[IM Output]](color_rgba_2.png)](color_rgba_2.png) [![[IM Output]](color_rgba_3.png)](color_rgba_3.png) [![[IM Output]](color_rgba_4.png)](color_rgba_4.png) [![[IM Output]](color_rgba_5.png)](color_rgba_5.png) [![[IM Output]](color_rgba_6.png)](color_rgba_6.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version 6.2.7, the '`rgba()`' also used a matte value for the alpha channel value. That is, a value of 0 for fully opaque and 255 for fully-transparent. This was changed as defined by the "W3C CSS3 Color Module recommendation for specifying colors", as part of IM becoming more compliant with other image standards, particularly for WWW and SVG use._ | It is currently impossible to directly specify a semi-transparent color by name, with an extra alpha value setting. However you can fudge it by generating that named color, then modifying the transparency of the image. You also have the added complication that you must [Set the Alpha Channel](../masking/#alpha_set) , before you can actually set the colors transparency. magick -size 50x50 xc:RoyalBlue color\_name\_1.png magick -size 50x50 xc:RoyalBlue -alpha set \\ -channel A -evaluate set 80% color\_name\_2.png magick -size 50x50 xc:RoyalBlue -alpha set \\ -channel A -evaluate set 60% color\_name\_3.png magick -size 50x50 xc:RoyalBlue -alpha set \\ -channel A -evaluate set 40% color\_name\_4.png magick -size 50x50 xc:RoyalBlue -alpha set \\ -channel A -evaluate set 20% color\_name\_5.png magick -size 50x50 xc:RoyalBlue -alpha set \\ -channel A -evaluate set 0 color\_name\_6.png [![[IM Output]](color_name_1.png)](color_name_1.png) [![[IM Output]](color_name_2.png)](color_name_2.png) [![[IM Output]](color_name_3.png)](color_name_3.png) [![[IM Output]](color_name_4.png)](color_name_4.png) [![[IM Output]](color_name_5.png)](color_name_5.png) [![[IM Output]](color_name_6.png)](color_name_6.png) Yes this is a pain, and it would be nice if transparency could set as part of the color name specification. If you like to see this make a request on the [IM Developers Forum](https://magick.imagemagick.org/viewforum.php?f=2) . It is also posible to draw a named fill color using [MVG Drawing Settings](../draw/#mvg_settings) , though you will need a transparent starting canvas for this to work correctly. For example... magick -size 50x50 xc:none \\ -draw "fill Tomato fill-opacity 0.5 rectangle 0,0 49,49" \\ color\_name\_draw.png [![[IM Output]](color_name_draw.png)](color_name_draw.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that a fully-transparent colors while completely invisible, still has a color. However most IM operators recognise that any color that is fully-transparent, is the same as any other fully-transparent color. Because of this and the way the internal mathematics works, many operators will often replace a fully-transparent color with fully-transparent black, (also known as the special color '`none`')._ | * * * Color Channels -------------- The actual color data of an image is stored as arrays of values, known as channels. Typically an image will have at least 3 channels, representing red, green, and blue color values. But as you saw above the values stored could represent other colorspaces. ### Colorspace, and Channel Naming The primary purpose of "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" operator is to change the way IM stores the colors of an image within memory. Normally each image has 3 (or 4) channels of image data. The current 'color space' of an image determines what the data of each channel represents. Now normally the channels are named 'Red', 'Green', 'Blue', as that is normally the type of image data that is stored in those channels. However that is not always the case. Don't think of the 'R' or 'Red' channel as being red, think of it as 'channel 1' which could contain data for 'red', 'hue', 'cyan', or other things depending on the colorspace of the the image. 'Red' is just a label for the channel typically used for 'red', or the first channel. The second most common colorspace used is '`CMYK`', which defines the amount of color 'ink' that should be applied to a darken a 'white' piece of paper (a subtractive colorspace). Note that K is short for "blacK", which a negated intensity values of the image. As this is very common the 'RGB' channels also have an alternative naming of 'Cyan', 'Magenta', and 'Yellow', or just the letters 'C', 'M' and 'Y', though in reality they refer to the same set of channels that is used for '`RGB`' images. A special fourth color channel is also added for the 'Black' or 'K' color channel. This basically means that the color channel for "`Green`" actually refers to the exact same color channel as would be used for "`Magenta`". Whether the data itself is 'green' or 'magenta' depends NOT on the name of the channel, but the 'colorspace' of the image in memory. The same thing happens for other colorspaces. For example using a '`LAB`' color space means the 'Red' channel contains the 'Lightness' value, while 'Green' channel holds the 'A' (or red-green) value, and 'Blue' channel holds the 'B' (or blue-yellow) value. In a similar way, the channel names '`Alpha`' ('`A`'), '`Opacity`' ('`O`'), and '`Matte`', are all aliases for the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting referring to the images transparency information. It does not matter that an 'alpha' channel is the inverse of a 'matte' channel, it still refers to the same channel, and produces the same result, the [Internal Matte Channel](../masking/#matte) of the image. Whether an operator treates the internal alpha channel data as a 'alpha' or value depends of the operator. Low level channel operators like "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" work on the raw 'matte' data of the channel in memory. However most higher level operators like "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" and "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" treat that data as representing 'alpha' data, for operation purposes. There is one another method of controlling the colorspace of the stored image data. The "`[-set](https://imagemagick.org/script/command-line-options.php?#set) colorspace`" (Added IM v6.4.3-7) will change just the in-memory 'colorspace' setting. That is it can magick a RGB image into a HSL image but without changing or modifying the actual pixel data that the image is using. The most typical use of this is when you are manually [Combining Channel Data](#combine) to set what is the final colorspace of the combined image. So lets look at how we can manipulate color channels. Remember each channel is just an array of values. All the channels would then combine together to represent that actual color of each pixel within the image. ### Separating Channel Images The easiest way separating out the individual color channels is to use the "`[-separate](https://imagemagick.org/script/command-line-options.php?#separate) `" operator to extract the current contents of each channel as a gray-scale image. magick rose: -channel R -separate separate\_red.gif magick rose: -channel G -separate separate\_green.gif magick rose: -channel B -separate separate\_blue.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](separate_red.gif)](separate_red.gif) [![[IM Output]](separate_green.gif)](separate_green.gif) [![[IM Output]](separate_blue.gif)](separate_blue.gif) Notice how the red rose is prominent in the red channel image, while it is quite dark in the blue and green channels. On the other hand the green leaves are prominent in the green channel but not the others. The white near the bottom of the image is bright in all the channels. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _In IM v5 and before "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel)
" was not only a setting for later image operations but also on occasion an 'image operator' that converted the specified channel into a grey scale image. Very confusing!_

_The IM v6 the "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate)
", was created to 'separate' these two very different different tasks. The "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel)
" option is only a setting that is used by later image operations, while "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate)
" will extract the specified channels into separate gray-scale and fully opaque images._ | As of IM v6.2.9-3, the "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate) " operator will let you separate multiple color channels according to the "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel) " setting. The number of items in the "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel) " setting will determine the number of images created (in RGBA order). For example as the default "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel) " setting is '`RGB`' the default action is to create three images, which I output below. magick rose: -separate separate\_RGB\_%d.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](separate_RGB_0.gif)](separate_RGB_0.gif) [![[IM Output]](separate_RGB_1.gif)](separate_RGB_1.gif) [![[IM Output]](separate_RGB_2.gif)](separate_RGB_2.gif) And here we use the "[`-colorspace`](https://imagemagick.org/script/command-line-options.php?#colorspace) " operator to magick the way IM is storing the color data of the image into a [CMYK color representation](#cmyk) . Then we extract the four color channels involved. magick rose: -colorspace CMYK -separate separate\_CMYK\_%d.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](separate_CMYK_0.gif)](separate_CMYK_0.gif) [![[IM Output]](separate_CMYK_1.gif)](separate_CMYK_1.gif) [![[IM Output]](separate_CMYK_2.gif)](separate_CMYK_2.gif) [![[IM Output]](separate_CMYK_3.gif)](separate_CMYK_3.gif) The last image (the '`Black`' or '`K`' channel) is especially interesting as it appears to be a negated gray-scale image of the original image. In reality it represents the amount of 'ink' a CMYK printer should deposit on the paper, reducing the amount of color needed by the other color channels. Note that by default the "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel) " setting does not include the special [Matte Transparency Channel](../masking/#matte) of the image. If you want to always generate all channels that is present, you can use a "`-channel ALL`" channel setting, or use '`RGBA`' or '`CMYKA`' "[`-channel`](https://imagemagick.org/script/command-line-options.php?#channel) " setting. ### Grayscale Channels from Colorspace Representations You can extract specific channel values from colorspaces for special purposes. For example, here we extract the images grayscale brightness or intensity from the rose image, using a number of different representations. magick rose: -colorspace Gray channel\_gray.gif magick rose: -grayscale Rec709Luma channel\_luma709.gif magick rose: -grayscale Rec601Luma channel\_luma601.gif magick rose: -colorspace HSI -channel B -separate channel\_average.gif magick rose: -colorspace HSL -channel B -separate channel\_lightness.gif magick rose: -colorspace HSB -channel B -separate channel\_brilliance.gif magick rose: -colorspace CMYK -channel K -negate -separate channel\_black.gif magick rose: -colorspace LAB -channel R -separate channel\_lab\_light.gif | | | | | | | | | | --- | --- | --- | --- | --- | --- | --- | --- | | [![[IM Output]](channel_gray.gif)](channel_gray.gif)

Gray
Gray | [![[IM Output]](channel_luma709.gif)](channel_luma709.gif)

Rec709Luma | [![[IM Output]](channel_luma601.gif)](channel_luma601.gif)

Rec601Luma (Y)
YUV/YIQ | [![[IM Output]](channel_average.gif)](channel_average.gif)

Average (I)
HSI/OHTA | [![[IM Output]](channel_lightness.gif)](channel_lightness.gif)

Lightness
HSL | [![[IM Output]](channel_brilliance.gif)](channel_brilliance.gif)

Brightness
HSB | [![[IM Output]](channel_black.gif)](channel_black.gif)

Neg Black
CMYK | [![[IM Output]](channel_luma709.gif)](channel_lab_light.gif)

Luminance\*
LAB / LUV | For the actual formulas see, the official reference to the "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" option. Note as of IM v6.7.7 the grayscale images stored without gamma or sRGB modifications, both in memory and when saved. As such they tend to be darker than they did before this version. Note that 'Gray' (also known as 'Intensity' or more exactly 'Luminance') and the 'Luma' of the YUV colorspace are equivalent. Similarly 'Brightness' of HSB colorspace, and the Negated 'blacK' channel of CMYK colorspace, are equivalent (and typically overly bright for grey-scale usage). Note the 'Lightness\*' channel from the LAB (and also LUV) colorspace (not to be confused with 'Lightness' from HSL) is thought to be best match to the human visual perception, though it is not commonly used for generating grayscale images. Note that if given a grayscale image, all the colorspace grayscale images produce exactly the same image as the input greyscale image, with the exception of 'Lightness\*' ('`R`') channel image for a LAB / LUV colorspace. ### Other Channel Separation Methods One method is to copy one channel to all the other channels, to generate a grayscale gray-scale image, just as what the [Separate Operator](#separate) generates. A simple, but slow, method is to use the [FX DIY Operator](../transform/#fx) . magick rose: -fx R channel\_red.gif magick rose: -fx G channel\_green.gif magick rose: -fx B channel\_blue.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](channel_red.gif)](channel_red.gif) [![[IM Output]](channel_green.gif)](channel_green.gif) [![[IM Output]](channel_blue.gif)](channel_blue.gif) This is often regarded as the 'simplest' solution to understand, and has been used in other IM tutorials. Other methods involve using a multitude of techniques to 'zero' out the unwanted channels. These are listed in [Zeroing Color Channels](#zeroing) below, and are usally a lot faster that using "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `". ### Combining RGB Channel Images Once you have separated out all the image color channels, and processed them, you will also need to be able to rejoin the images back together again. This can be done using the special list operator "`[-combine](https://imagemagick.org/script/command-line-options.php?#combine) `", which is basically exactly the reverse of "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate) ". magick separate\_red.gif separate\_green.gif separate\_blue.gif \\ -combine -set colorspace sRGB rose\_combined.gif [![[IM Output]](separate_red.gif)](separate_red.gif) [![[IM Output]](separate_green.gif)](separate_green.gif) [![[IM Output]](separate_blue.gif)](separate_blue.gif) ![==>](../img_www/right.gif) [![[IM Output]](rose_combined.gif)](rose_combined.gif) These then "`[-combine](https://imagemagick.org/script/command-line-options.php?#combine) `" to create an image that is declared as being a sRGB colorspace image. An user wanted to be able to swap the red and blue channels of an image, this makes it easy, separate the channels, swap, and re-combine. magick rose: -separate -swap 0,2 -combine rose\_rb\_swap.gif [![[IM Output]](rose_rb_swap.gif)](rose_rb_swap.gif) Remember the default "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting is '`RGB`', and defines what images channel images are being joined together. If not all the channels being combined together are defined, the other channels are set using the color values from the current "[`-background`](https://imagemagick.org/script/command-line-options.php?#background) " setting. You should however note that both "`[-combine](https://imagemagick.org/script/command-line-options.php?#combine) `" and "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate) " will ignore the order in which channels are defined by the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `". Channels will always be processed and generated in the standard '`Red,Green,Blue,Matte`' channel order, for each channel set in the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting. As such, even if you use a "`-channel BR`" setting or just "`blue,red`", the "[`-combine`](https://imagemagick.org/script/command-line-options.php?#combine) " operator will still expect the two images be red first then the blue. The green and alpha values (if images have transparency) will be set from the current "[`-background`](https://imagemagick.org/script/command-line-options.php?#background) " setting values. For Example... magick separate\_red.gif separate\_blue.gif -background black \\ -channel blue,red -combine rose\_red\_blue.gif [![[IM Output]](separate_red.gif)](separate_red.gif) [![[IM Output]](separate_blue.gif)](separate_blue.gif) ![==>](../img_www/right.gif) [![[IM Output]](rose_red_blue.gif)](rose_red_blue.gif) ### Combining non-RGB Channel Images As of IM v6.4.3-7, you can also "`[-combine](https://imagemagick.org/script/command-line-options.php?#combine) `" channel images that represent other colorspaces, but you need to tell IM what colorspace the resulting image should be. This is done by using the special "`[-set](https://imagemagick.org/script/command-line-options.php?#set) colorspace`" operator. This basically changes the colorspace of an image in memory but without mapping the images pixel data, leaving it as is. Once the image has been combined in the right colorspace you can use a normal "`[-colorspace](https://imagemagick.org/script/command-line-options.php?#colorspace) `" operator to map the pixel data back to normal RGB data. magick separate\_HSB\_?.gif -set colorspace HSB -combine \\ -colorspace sRGB rose\_HSB\_combined.gif [![[IM Output]](rose_HSB_combined.gif)](rose_HSB_combined.gif) This method also works for CMYK images, which is often difficult to handle due to the need for a fourth color channel. magick separate\_CMYK\_?.gif -set colorspace CMYK -combine \\ -colorspace sRGB rose\_CMYK\_combined.gif [![[IM Output]](rose_CMYK_combined.gif)](rose_CMYK_combined.gif) An alternative workaround (for earlier versions of IM) is to load one image (the red channel) and changing it so that it is in the right colorspace. After that each individual channel image can be loaded and [Channel Copied](../compose/#channel) into that pre-prepared image. magick separate\_HSB\_0.gif -colorspace HSB \\ separate\_HSB\_0.gif -compose CopyRed -composite \\ separate\_HSB\_1.gif -compose CopyGreen -composite \\ separate\_HSB\_2.gif -compose CopyBlue -composite \\ -colorspace sRGB rose\_HSB\_combined\_alt.gif [![[IM Output]](rose_HSB_combined_alt.gif)](rose_HSB_combined_alt.gif) Of course if you used "`[-set](https://imagemagick.org/script/command-line-options.php?#set) colorspace`" operation, the data for the first channel will already be in place, as this does not change the actual pixel data, only the way the data is interpreted. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The last example will not work for '`CMYK`' images, as the '`Black`' channel image does not actually contain a black channel! As such "`-compose CopyBlack`" will fail to find valid data to copy. I regarded this as a bug, but is currently unlikely to be fixed._ | Using other colorspaces can be useful. For example, here I take the built-in rose image and want to negate the luminance channel of the image in '`Lab`' colorspace. When finished I re-combine to build a sRGB image again. magick rose: -colorspace Lab -separate \\ \\( -clone 0 -negate \\) -swap 0 +delete \\ -combine -set colorspace Lab \\ -colorspace sRGB rose\_light\_neg.gif [![[IM Output]](rose_light_neg.gif)](rose_light_neg.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Previously this example used '`HSL`' colorspace, but that is a linear colorspace, and we want to negate in a 'perceptual colorspace' as provided by '`Lab`'.

_ | Note that the image still has the same colors, but the brightness (lightness) of the colors were reversed, producing a weird effect. You can replace the "[`-negate`](https://imagemagick.org/script/command-line-options.php?#negate) " with your own set of operations to adjust an images brightness levels. However as "[`-negate`](https://imagemagick.org/script/command-line-options.php?#negate) " is itself a channel controlled operator we did not have to "[`-separate`](https://imagemagick.org/script/command-line-options.php?#separate) " out the luminance channel in order to negate it. magick rose: -colorspace Lab \\ -channel R -negate +channel \\ -colorspace sRGB rose\_light\_neg2.gif [![[IM Output]](rose_light_neg2.gif)](rose_light_neg2.gif) As you can see this simplifies things, but it may not always be practical, for the effect you want to achieve. ### Zeroing Color Channels Sometimes you have an image (RGB or some other colorspace) where you just want to clear or 'zero' one or two of the color channels but leave all the other channels as is. For example, to make a greyscale image without using a RGB [Gray-Scaling Techniques](../color_mods/#grayscale) , you could 'zero' the Saturation channel ('`G`') in a HSL colorspace so as to make a gray scale image. The 'Hue' value has no meaning when saturation is zero, so you are left with a greyscale image. The most direct technique, is often to use the [Evaluate Operator](../transform/#evaluate) to zero all the values in the unwanted channel... magick rose: -colorspace HSL \\ -channel G -evaluate set 0 +channel \\ -colorspace sRGB rose\_grey.gif [![[IM Output]](rose_grey.gif)](rose_grey.gif) However there are many not so obvious ways you can do this... # Evaluate (fast and direct) -channel G -evaluate set 0 +channel # FX zeroing (direct simple, but slow) -channel G -fx 0 +channel # Separate the channels you want to keep, # then combine using a background color to set the other channels -channel RB -separate -background black -combine +channel # Gamma which is a miss-use of the operator, but works VERY well! # ( 1 = leave alone; 0 = zero channel; -1 = maximize channel ) # This is short, simple , needs no channel setting, but very obtuse! -gamma 1,0,1 # Threshold channels to zero -channel G -threshold 101% +channel # Threshold to maximum value then negate to zero -channel G -threshold -1 -negate +channel # Multiply with an appropriate primary/secondary color # The color specifies the channels to preserve! 'magenta' = 'red'+'blue' \\( +clone +level-colors magenta \\) -compose multiply -composite # Colorize specific channels to black # (0 = leave alone; 100% set from fill (black) ) -fill black -colorize 0,100%,0 _Can you think of another ways or zeroing (or maximizing) a color channel which I have not listed above? -- mail me_ * * * Colorspaces ----------- So far we have concentrated on the '`sRGB`', '`RGB`' and '`CMYK`' colorspaces. That is, because these are the colorspaces that is typically used for display, printing and traditional storage of images in files. But while these colorspaces are practical, they are not representive of how we as humans actually view the world. Our eyes may see in red, green and blue wavelengths, but our brains interpret these as: color hue (what color), grayness (how colorful), and intensity (how bright/dark). Because of this many colorspaces and color systems have been developed, often from completely indepenant requirements. Painters for example developed a system of colors (based on color sources like lapus luzuli), shades and tinting. Later computer systems using RGB, needed better ways for users to select or modify colors, in ways that was not to computationally intensive. ### Hue Based Colorspaces Probably one of the most well known alternative is the cyclic-hue, based system, which was developed as a color selection interface for RGB colors. Basically the RGB color cube was rotated in 3 dimentions so that the black-gray-white diagonal axis of the cube became on axis of the colorspace. And this specified how dark or light a color was. The key feature of this change was an simple conversion from RGB values that spaced the primary colors equally around this axis, so as to form a Hue that cycles from red, though green, then blue and back to red. How far away the color was from this axis (radially) was known as saturation or chroma. For example lets [Separate](#separate) the channels of the builtin '`rose:`' image afetr transforming it into the '`HSB`' (Hue, Saturation, Brilliance, also known as HSV, with V for Value), colorspace. magick rose: -colorspace HSB -separate separate\_HSB\_%d.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](separate_HSB_0.gif)](separate_HSB_0.gif) [![[IM Output]](separate_HSB_1.gif)](separate_HSB_1.gif) [![[IM Output]](separate_HSB_2.gif)](separate_HSB_2.gif) Or a similar but not quite the same '`HSL`' (Hue, Saturation, Lightness). magick rose: -colorspace HSL -separate separate\_HSL\_%d.gif [![[IM Output]](../images/rose.gif)](../images/rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](separate_HSL_0.gif)](separate_HSL_0.gif) [![[IM Output]](separate_HSL_1.gif)](separate_HSL_1.gif) [![[IM Output]](separate_HSL_2.gif)](separate_HSL_2.gif) Note that how 'Hue' channel image in both colorspaces is the same mottle of almost pure black and white colors. That is, because a Hue is actually circular. That is, both black and white in the above channel image are actually representations of a 'Red' Hue, and slight variations cause the hue to flip from one side of red (producing white) to the other (producing black). If this is a problem you can rotate the hue setting using the [Modulate Operator](../color_mods/#modulate) so that red becomes represented by some other hue value. The real difference between '`HSL`' and '`HSB`' is how bright the primary colors are defined. But to see this we are better off looking at more practical represntations of the colorspace, using colorwheels. If you look at the last 'brightness/lightness' images in the above separations, you will see that '`HSB`' treats a strong (near primary) 'red' color as almost white, while '`HSL`' treats it as more like a mid-tone gray intensity. ### Generating a HSL Color Wheel The above raw separations of the color from an image is still difficult to understand. To better understand the colorspace, we need to try and view it The colorspace is more usually represented as a circular polar gradient, showing some part of the colorspace. You can generate the separate channel value images, and [Combine](#combine) them images to generate specific types of images which are hard to generate in other ways. For example, here we generate perfect '`HSL`' color wheel. magick -size 100x300 gradient: -rotate 90 \\ -distort Arc '360 -90.1 50' +repage \\ -gravity center -crop 100x100+0+0 +repage angular.png magick -size 100x100 xc:white solid.png magick -size 100x100 radial-gradient: -negate radial.png magick angular.png solid.png radial.png \\ -combine -set colorspace HSL \\ -colorspace sRGB colorwheel\_HSL.png | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](angular.png)](angular.png)

Hue | [![[IM Output]](solid.png)](solid.png)

Saturation | [![[IM Output]](radial.png)](radial.png)

Luminance | ![==>](../img_www/right.gif) | [![[IM Output]](colorwheel_HSL.png)](colorwheel_HSL.png)

HSL Colorwheel | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The grey scale images are generated as a linear gradient using sRGB values. As such the gradients tend to look a little darker than they should. It is however tha values in the input images that is important here, not the viewing colorspace.

On the other hand the resulting image while generated in linear RGB colorspace, is being saved as sRGB colorspace to ensure that browsers and other image display programs, display the gradient in a way that works well visually._ | Also note that the Hue is a 'modulus' value, that wraps around at red (hue value = 0). This can be a pain when doing image processing as you have two red colors that visually are identical, but in terms of value are a maximum hue distance apart. This is not a good colorspace to use when working on color differences. Actually the lightness/brilliance channels of HSB and HSL colorspaces is not very useful as the various Hue's are not handled equally. Basically it 'equalizes' the intensity of primary colors. For example Rotating a 'yellow' hue to become a 'blue' hue for example will make the very bright color, very dark, and visa-versa. For more details see [HSL Disadvantages](http://en.wikipedia.org/wiki/HSL_and_HSV#Disadvantages) . Caution is advised. There are a number of colorpsaces that also use this same 'hex cone' based, hue system. HSB, HCL and HCLp (perceptual HCL) . Here are colorwheels of all four of these 'hex-cone' colorspaces. magick angular.png solid.png radial.png \\ -combine -set colorspace HSL \\ -colorspace sRGB colorwheel\_HSL.png magick angular.png solid.png radial.png \\ -combine -set colorspace HSB \\ -colorspace sRGB colorwheel\_HSB.png magick angular.png solid.png radial.png \\ -combine -set colorspace HCL \\ -colorspace sRGB colorwheel\_HCL.png magick angular.png solid.png radial.png \\ -combine -set colorspace HCLp \\ -colorspace sRGB colorwheel\_HCLp.png | | | | | | --- | --- | --- | --- | | [![[IM Output]](colorwheel_HSL.png)](colorwheel_HSL.png)

HSL | [![[IM Output]](colorwheel_HSB.png)](colorwheel_HSB.png)

HSB | [![[IM Output]](colorwheel_HCL.png)](colorwheel_HCL.png)

HCL | [![[IM Output]](colorwheel_HCLp.png)](colorwheel_HCLp.png)

HCLp | Remember all colors shown in the above are generated at a maximum color saturation. However the '`HSB`' colorspace will produce primary colors at maximum lightness (HSL generated these at half intensity). Because of this white can only be generated when saturation is zero. As a result instead of a white area around the edges, you get fully-saturated colors, instead. The '`HCL`' colorspace uses the same 'hex-cone' hue calculations but it adjusts the 'lightness' channel so as to use color intensity, rather than direct linear-RGB values. As a result when using a the '`HCL`' The primary colors are located at different intensity levels, with blue closer toward the central black color, and red colors much brighter and further out. The 50% intensity area of the '`HCL`' colorspace does not produce strong colors but instead generates more natural pastel colors. For example, here is a comparison of the saturated hues between HSL and HCL colorspaces at a 50% intensity. magick -size 100x100 xc:black \\ -fill white -draw 'circle 49.5,49.5 40,4' \\ -fill black -draw 'circle 49.5,49.5 40,30' \\ -alpha copy -channel A -morphology dilate diamond anulus.png magick hue\_angular.png -size 100x100 xc:white xc:gray50 \\ -combine -set colorspace HSL -colorspace RGB \\ anulus.png -alpha off -compose Multiply -composite \\ anulus.png -alpha on -compose DstIn -composite \\ -colorspace sRGB hues\_HSL.png magick hue\_angular.png -size 100x100 xc:white xc:gray50 \\ -combine -set colorspace HCL -colorspace RGB \\ anulus.png -alpha off -compose Multiply -composite \\ anulus.png -alpha on -compose DstIn -composite \\ -colorspace sRGB hues\_HCL.png | | | | --- | --- | | [![[IM Output]](hues_HSL.png)](hues_HSL.png)

HSL/HSB | [![[IM Output]](hues_HCL.png)](hues_HCL.png)

HCL | That is, not to say '`HCL`' does not contain pure colors, they are just not 'forced' into a common plane as they are in '`HSL`' colorspace. In particular note how all the shades in HCL have the same 50% intensity (as requested), unlike the results of the HSL colorspace hues. Green is probably the closest of all the main colors to a 50% intensity, so has a good response in 50% hues. It is recommended you use this colorspace for hue rotations, so as to preserve the general brightness of all the colors in the image. See the examples in [Modulate in HCL Colorspace](../color_mods/#modulate_HCL) . _HWB Colorspace ???_ #### Perceptual Colorspaces The colorspaces '`Lab`' and '`Luv`' are designed, such that they fully separate the greyscale intensity from the color components of an image. Unlike '`RGB`' and '`sRGB`' colorspaces. This makes the colorspace a lot easier to process and modify in general, once you get the hang of it. More specifically '`Luv`' was designed to be 'perceptually linear'. That is, that a small change in color in one part of the colorspace looks to be about the same, as a similar change in another part of the colorspace. This make Luv colorspace much better suited for image difference comparisons. The two colorspaces are very similar, and generally produce similar results when processing image. Here we separate the channels for the colorspaces '`Lab`' and '`Luv`', just to show just how similar the two colorspaces actually are. magick rose: \\( -clone 0 -colorspace LAB -separate +append \\) \\ \\( -clone 0 -colorspace LUV -separate +append \\) \\ -delete 0 -append -set colorspace sRGB separate\_lab\_luv.png | | | | | | --- | --- | --- | --- | | [![[IM Output]](../images/rose.gif)](../images/rose.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](separate_lab_luv.png)](separate_lab_luv.png) | Lab


Luv | Other better examples of the '`Lab`' and '`Luv`' colorspace can be seen using its cylindrical '`LCHab`' '`LCHvu`' variation, in [The LCH Color Wheel](#colorwheel_LCH) below. For practical example of using these colorspace see [Resizing in Lab colorspace](../resize/#resize_lab) . #### Lab and Luv, based Color Spaces The '`HCL`' colorspace is based on the '`LCHuv`' colorspace, which is a cylindrical representation of the '`Luv`' colorspace, though with a simpler formula for the lightness channel, so as to generate pure white at maximum lightness. For completeness here are the cylindrical representations of the '`Lab`' and '`Luv`' colorspaces, which are known as '`LCHab`' and '`LCHuv`' respectively. However note that the order of the channels is the reverse of the equivalent '`HCL`' colorspace shown above. magick radial.png solid.png angular.png \\ -combine -set colorspace LCHab \\ -colorspace sRGB colorwheel\_LCHab.png magick radial.png solid.png angular.png \\ -combine -set colorspace LCHuv \\ -colorspace sRGB colorwheel\_LCHuv.png | | | | | | | | --- | --- | --- | --- | --- | --- | | [![[IM Output]](radial.png)](radial.png)

Lightness\* | [![[IM Output]](solid.png)](solid.png)

Chroma | [![[IM Output]](angular.png)](angular.png)

Hue | ![==>](../img_www/right.gif) | [![[IM Output]](colorwheel_LCHab.png)](colorwheel_LCHab.png)

LCHab | [![[IM Output]](colorwheel_LCHuv.png)](colorwheel_LCHuv.png)

LCHuv | Note that '`LCH`' colorspace is an alias for '`LCHab`'. In the above you can see that '`LCHuv`' has a discontinuity where unrealistic colors are being set using the colorwheel process. Normal conversions of images will not generate these colors. ### scRGB High-DynamicRange Colorspace Wikiepedia: http://en.wikipedia.org/wiki/ScRGB This is essentially a method of storing a High dynamic range color (with negatives and up to 10 times linear RGB range) in a 16 bit integer, with only 1/2 the color resolution of a normal 16-bit sRGB image. As it is using 16bit integers it can be stored in image files formats that can save such images (PNG, PPM, MIFF), though a color profile, or some other method should be used to mark those images as holding scRGB colorspace data. You would have to be very careful, with many image processing operators in this colorspace as it has an 'offset' to allow it to handle negative numbers. And while some operators like resize and distort can be used directly on this colorspace, it is probably a better idea to use a HDRI version of ImageMagick, and magick to linear RGB (with negatives), for more general image processing. _Examples and more information on using this colorspace would be good_ * * * Replacing Colors in Images -------------------------- ImageMagick naturally provides a number of options to replacing a specific and near match colors with another color. This is great when dealing with icons and 'bitmap' type images that contain very few colors, but tends to fail when dealing with images containing shades of colors or anti-aliasing edge pixels. Basically you need to remember that colors are replaced by a single shade. So if you replace a set or neighbourhood of colors, all those colors are replaced by one specific single color and not by a matching range of colors. That is not to say it is impossible to do a shaded color replacement, just not simple to do at this time, without a lot of work. Even so, GIF images does not allow the use of semi-transparency, so replacing colors in this way is a good method for controlling GIF background transparency (See [GIFs on a Background Pattern](../formats/#bg_pattern) for examples) The other aspect is that while you can map all 'close colors' to a given colormap, using [Pre-Defined Color Maps](../quantize/#map) , there is no operator to do a direct one-to-one mapping of a large set of colors to another completely different set of colors. This is a short coming that may change in a future version of IM. With that caveat, lets look at the ways IM does provide for the direct replacement of one specific colors with another color. ### Replace a Specific Color The "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" and "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `" operators are designed for replacing one color in an image with another. For example to replace a '`blue`' color with say '`white`' you would use a command like this... magick balloon.gif -fill white -opaque blue balloon\_white.gif [![[IM Output]](../images/balloon.gif)](../images/balloon.gif) ![==>](../img_www/right.gif) [![[IM Output]](balloon_white.gif)](balloon_white.gif) Basically any color that was 'blue' has been replaced with the current "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color. However as of IM v6.2.7, this operator is limited by the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting. As such, to magick a color (say blue) to transparency, you will need to specify a "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" to include the alpha channel to make colors transparent. You will also need to ensure the image has a 'matte' or [alpha channel](../basics/#alpha) enabled, to hold the transparency information. magick balloon.gif -alpha set -channel RGBA \\ -fill none -opaque blue balloon\_none.gif [![[IM Output]](../images/balloon.gif)](../images/balloon.gif) ![==>](../img_www/right.gif) [![[IM Output]](balloon_none.gif)](balloon_none.gif) Because replacing a color with transparency is such a common operation the above has its own special replace with transparency operator "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `". magick balloon.gif -transparent blue balloon\_trans.gif [![[IM Output]](../images/balloon.gif)](../images/balloon.gif) ![==>](../img_www/right.gif) [![[IM Output]](balloon_trans.gif)](balloon_trans.gif) As of IM version 6.3.7-10, the 'plus' versions of these operators inverts the color selection. That is, the colors that do NOT match the given color will be replaced. For example, here I replace any color that is NOT pure-black, with white, leaving just the pure black borders of the image. magick balloon.gif -fill white +opaque black balloon\_borders.gif [![[IM Output]](../images/balloon.gif)](../images/balloon.gif) ![==>](../img_www/right.gif) [![[IM Output]](balloon_borders.gif)](balloon_borders.gif) This may not seem like much, but when you combine it with a [Fuzz Factor](#fuzz) (see below), this becomes a very powerful tool.![](../img_www/warning.gif)![](../img_www/space.gif)_Before IM v6.3.7-10, the inverse operation required the use of some trickiness using image masks. Basically you replace the color you want to preserve with transparency, then "`[-colorize](https://imagemagick.org/script/command-line-options.php?#colorize) `" all the other colors to the desired color to create an overlay mask. This is then overlaid on the original image to 'mask out' the colors that did not match!_ magick balloon.gif \\ \\( +clone -alpha set -transparent black \\ -fill white -colorize 100% \\) \\ -composite balloon\_mask\_non-black.gif [![[IM Output]](../images/balloon.gif)](../images/balloon.gif) ![==>](../img_www/right.gif) [![[IM Output]](balloon_mask_non-black.gif)](balloon_mask_non-black.gif) _As you can see the 'plus' form of the operator simplified the 'not this color' replacement operation enormously._For more advanced replacement techniques, I suggest you look at [Background Removal](../masking/#bg_remove) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Be warned that as all matching colors (especially 'fuzzy matched colors', see below) is replaced with a single uniform color, you will not get any anti-aliasing of the edges of the colored areas. And you will lose any an all shadow or other shading effects that may be present. This can have a seriously detrimental effect to the look off any non-simple non-cartoon like images.

This type of color replacement is not designed with practical real world images in mind, but more for image masking effects. Caution is advised._ | The "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" color replacement cannot replace a color with a tiled pattern. It will only replace colors with another single specific color. However both the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" and "`[-floodfill](https://imagemagick.org/script/command-line-options.php?#floodfill) `" color replacement methods can (see below). ### Replace using a Color in the Image You can also use [Draw Color Replacement](../draw/#color) to recolor images based on colors present in the image itself, rather than a specific color. magick present.gif -fill red -draw 'color 0,0 replace' present\_blue.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_blue.gif)](present_blue.gif) Note that I never specified the color to be replaced, only the location of the color to be replaced. It is the color at that location that is used for 'matching' what areas is to be filled, regardless of what that color is. You can see in the above example the problem with color replacement, the specific color may appear in other places that you intend, giving us a line of red pixels within the 'present' image above. Transparency also presents no problem, though some internal parts of the image was also made transparent just as they became red in the above... magick present.gif -alpha set -fill none \\ -draw 'color 0,0 replace' present\_none.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_none.gif)](present_none.gif) Note however that unlike "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" and "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `" the [Draw Color Replacement](../draw/#color) , does not let you invert the 'matching colors' to be replaced. Draw also has a special [Matte Replacement](../draw/#matte) , where only the transparency of the fill color is replaced. That is, you can make all matching colors transparent, or semi-transparent, without actually changing the color of the pixel itself. With the appropriate file format of course. magick present.gif -alpha set -fill '#00000080' \\ -draw 'matte 0,0 replace' present\_semi.png [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_semi.png)](present_semi.png) This becomes much more useful when a [Fuzz Factor](#fuzz) is also specified. The biggest advantage of using "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" is that you can also replace the color with a tile pattern. For example.. magick present.gif -tile pattern:right30 \\ -draw 'color 0,0 replace' present\_tile.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_tile.gif)](present_tile.gif) For more advanced replacement techniques, I suggest you look at [Background Removal](../masking/#bg_remove) . ### Floodfill Draw The [Draw Color](../draw/#color) methods also provide you with a simple method of replacing a color by 'floodfilling'. That is, rather than replacing ALL the matching colors within the image, you can select just the colors which are 'connected to' or 'attached' to the specified point in the image. The specified point will not only specify the stating (seed point) but also the color that you are trying to replace. magick present.gif -fill red -draw 'color 0,0 floodfill' present\_fill.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_fill.gif)](present_fill.gif) Note that the red areas which was not 'attached' to the 0,0 pixel was not replaced. For background replacing that can be a problem, but the solution is just as easy. Expand the image slightly so the floodfill can 'leak' into the image from all directions, then remove that extra space when finished. magick present.gif -bordercolor white -border 1x1 \\ -fill red -draw 'color 0,0 floodfill' \\ -shave 1x1 present\_bgnd.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_bgnd.gif)](present_bgnd.gif) Of course you can adjust what colors are 'matched' using the [Fuzz Factor](#fuzz) control setting below, which is especially important for [JPEG](../formats/#jpeg) images. ### Floodfill Operator The "`[-floodfill](https://imagemagick.org/script/command-line-options.php?#floodfill) `" operator was added to make floodfilling slightly easier, especially when you what to exactly specify the color that you specifically want to replace. This can be especially important when using [Fuzz Factor](#fuzz) color matching. However be warned that if that seed point is not within a [Fuzz Factor](#fuzz) match of the color you are looking for then "`[-floodfill](https://imagemagick.org/script/command-line-options.php?#floodfill) `" does nothing. This can be regarded as the operators feature as well as its curse. **A small [Fuzz Factor](#fuzz) is recommened for flood filling. Or ensure seed point exactly matches looked for color.** For example, add a border of known color to flood fill from edges... magick present.gif -bordercolor white -border 1x1 \\ -fill red -floodfill +0+0 white \\ -shave 1x1 present\_floodfill.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_floodfill.gif)](present_floodfill.gif) This will replace any color that is 'white' to 'red' that is directly part of the area surrounding the seed pixel starting at +0+0, which is guranteed to be 'white' due to the added border. You can also floodfill with a tile pattern. magick present.gif -bordercolor white -border 1x1 \\ -tile pattern:left30 -floodfill +0+0 white \\ -shave 1x1 present\_pattern.gif [![[IM Output]](../images/present.gif)](../images/present.gif) ![==>](../img_www/right.gif) [![[IM Output]](present_pattern.gif)](present_pattern.gif) The '_color_' argument can sometimes be a pain, in that it must match color of the seed point, or no action will take place. But this can also be useful, as it will ensure the floodfill does exactly what you wanted, and not the unexpected. For example, here I try to fill white disks with various colors... magick disks.gif \\ -fill Red -floodfill +30+50 white \\ -fill Green -floodfill +60+60 white \\ -fill Blue -floodfill +10+40 white \\ floodfill\_hit\_miss.gif [![[IM Output]](floodfill_hit_miss.gif)](floodfill_hit_miss.gif) In this case only the '`Green`' and '`Blue`' flood-fill operations 'hit a disk' (and filled it), while the '`Red`' flood-fill, did not match a disk, so no disk was filled, without accidentally filling the background of the image. It also means that if you already filled a specific area, later fills will not 're-fill' the same area if two points hit that area. that can save a lot of time. You may also like to look at [Conditional Dilation](../morphology/#dilate_conditional) which represents a lower level floodfill operation from multiple 'seed' points in the image. ### Fuzz Factor - Matching Similar/Multiple Colors The overall results of just selecting a single color to replace, as shown in the previous examples is usually not very nice. The edges or areas of solid colors generally have a mix of colors at the edge, due to anti-aliasing (See [Anti-Aliasing](../antialiasing/) for more information). As such you should avoid direct color replace if possible. For example, here I take what looks like a simple black and white 'cow' and try to make it a red cow. magick cow.gif -fill red -opaque black cow\_replace\_red.gif [![[IM Output]](../images/cow.gif)](../images/cow.gif) ![==>](../img_www/right.gif) [![[IM Output]](cow_replace_red.gif)](cow_replace_red.gif) As you can see only the center parts of the 'black' areas actually became red. That is, because, while the image appears to be black and white it is really a gray-scale image with almost all the edges various shades of gray. That is, they are not exactly pure-black in color. The fuzz factor, ("`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `") represents a 'similarity' match in multi-dimensional spherical distance between colors, using whatever color space the image is using. Well okay lets try that in plain English. You have a specific color. Another color will be treated as being _same_ as the color being looked for, if the difference between these colors is less than the fuzz factor setting. The larger the 'fuzz factor' and more 'near' colors will match and be replaced. So lets try that on our cow image so as to magick not only pure-black but also near-black colors to red. magick cow.gif -fuzz 40% -fill red -opaque black cow\_replace\_fuzz.gif [![[IM Output]](../images/cow.gif)](../images/cow.gif) ![==>](../img_www/right.gif) [![[IM Output]](cow_replace_fuzz.gif)](cow_replace_fuzz.gif) As you can see we now replaced all the 'dark' pixels of the image to red. But the result is still very bad, with a grayish tinge to the edge, and strong [Aliasing effects](../filter/#aliasing) . Direct color replacement is not a good solution for this image, even though you can make it work using a large 'fuzz factor' . See the examples in [Level adjustments by Color](../color_mods/#level-colors) for the ideal solution for this image. This problem is even worse for images where you are trying to replace a background color with transparency. You basically end up with a 'halo' around the object on that background color. This is very difficult to solve, and problems like this are looked at in detail in [Background Removal](../masking/#bg_remove) . **What operations use fuzz factor** The "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" operator effects just about any operator which compares specific colors within an image. This includes: "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `", "`[-transparent](https://imagemagick.org/script/command-line-options.php?#transparent) `", "`[-floodfill](https://imagemagick.org/script/command-line-options.php?#floodfill) `", "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `", "`[-deconstruct](https://imagemagick.org/script/command-line-options.php?#deconstruct) `", "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) 'color'`", "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) 'matte'`", and probably others. It also effects GIF "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) [OptimizeTransparency](../anim_opt/#opt_trans) `", and "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) [ChangeMask](../compose/#changemask) `" handling. It also effects the results of "`magick compare`" and specifically the "`[-metric](https://imagemagick.org/script/command-line-options.php?#metric) AE`" or Absolute Error Pixel Count. #### Fuzz Factor Distance The "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" setting is actually a form of color 'distance' setting. Any color that is within the given distance of the color being looked for, will match that color, even though it is not an exact match. A value of '`200`' represents a distance of 200 color units in the current color depth of the IM being used. For an IM Q16 ([16 bit quality](../basics/#quality) for color store) this is quite small, for an IM Q8 this is VERY large, and will cause a lot of colors to match each other.Here for example I change all the colors that are within 30,000 color units (for IM Q16) of '`blue`' to white. With my Q16 ImageMagick programs, that represents approximately the distance from '`blue` to '`navy`' (half dark blue), magick colorwheel.png \\ -fuzz 30000 -fill white -opaque blue \\ opaque\_blue.jpg [![[IM Output]](opaque_blue.jpg)](opaque_blue.jpg) To make this easier to understand here I invert the matched colors turning the unmatched colors to white. magick colorwheel.png \\ -fuzz 30000 -fill white +opaque blue \\ opaque\_blue\_not.png [![[IM Output]](opaque_blue_not.png)](opaque_blue_not.png) If your IM is older than version 6.3.7-10 when the 'plus' form of the "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" operator was added, you can use this masking method to invert the result of the color match... magick colorwheel.png \\ \\( +clone -fuzz 30000 -transparent blue \\ -channel RGB +level-colors white +channel \\) \\ -composite opaque\_blue\_inv.png [![[IM Output]](opaque_blue_inv.png)](opaque_blue_inv.png) Or this method that limits all modifications to just the 'alpha channel', so that all the original colors, are left as is. That is, you create a negated mask from the color selection, so as to make all non-selected colors fully-transparent. They remain present, just transparent! magick colorwheel.png -fuzz 30000 -transparent blue \\ -channel A -negate +channel opaque\_blue\_inv\_alpha.png [![[IM Output]](opaque_blue_inv_alpha.png)](opaque_blue_inv_alpha.png) An advantage of these alternative methods, is that you can expand them to generate a '_not multiple colors_' technique. All that you need to do is add more colors to the list being made transparent, before negating the mask, and posibly removing the negated transparency. magick colorwheel.png \\ -fuzz 25000 -transparent blue -transparent red -transparent lime \\ -channel A -negate +channel \\ -background white -alpha remove opaque\_multi\_inv.png [![[IM Output]](opaque_multi_inv.png)](opaque_multi_inv.png) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _As a matter of interest, in an IM with a Q8 compilation setting, a "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" factor of 256 (28) will make the colors '`black`' and '`blue`' equivelent. For an IM with a Q16 setting this number is 65536 (216).

To make '`blue`' and '`red`' colors match this number must be multiplied by the square root of 2, or 362 for IM Q8, and with 92682 for IM Q16.

To make all colors match (eg colors '`black`' and '`white`') you will need to multiply by the square root of 3. In other words, a fuzz factor setting of 444 for IM Q8 and 113512 for IM Q16._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _It is likely that better and more realistic color distances can be defined using a 'perceptual' colorspace, such as '`LAB`', or '`LUV`'. Just magick images into that colorspace before performing fuzzy color matching. This will make colors like pure-blue and black much closer, and yellow and white closer, than they are in '`sRGB`' or 'linear-`RGB`' colorpsaces._ | As you can see from the above formulas, direct color distances is definitely not a nice way of setting the fuzz factor to use, as it is also dependant on exactly what compile time [Quality Setting](../basics/#quality) is used. Setting the "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" factor as a percentage, makes its use a lot simpler. In this case '`100%`' represents a large enough fuzz factor to cover all colors. That is, it represents the color distance from '`black`' to '`white`', across the 3 dimensional diagonal of the RGB color cube.Here we replace any color within 90% of the distance from white to black, with white. This should result in only the last 10% colors near '`black`' to be left on the image, as black is on the opposite side of the RGB color cube. magick colorwheel.png -fuzz 90% -fill white -opaque white opaque\_w90.jpg [![[IM Output]](opaque_w90.jpg)](opaque_w90.jpg) Note that this 90% represents a sphere of colors around 'white' in the RGB color cube. However this is is not the same as replacing the colors that are not within a 10% sphere of black. magick colorwheel.png -fuzz 10% -fill white +opaque black opaque\_k10.jpg As you can see 10% sphere of colors near the black is much more uniform, than selecting a 90% sphere of the colors around white. Think about how a large sphere centered on the white corner of a cube fills that cube. Then think about a small sphere centered on the black corner, and you will be able to understand the difference between the two images.[![[IM Output]](opaque_k10.jpg)](opaque_k10.jpg) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _A "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" factor of 100%, equates to the RGB color cube distance from '`black`' to '`white`'. From this we can calculate that a percentage of about 57.7% is the distance between '`black`' and '`blue`', and 81.6% is the distance from '`blue`' to '`red`' or from either of those colors to '`white`'.

In summary, anything larger than about 25%, (just short of the RGB distance from '`blue`' to '`navy blue`' represents a very large color change._ | To demonstrate the color distances more, lets use a progressively larger fuzz factor percentage around the blue colors... magick colorwheel.png -fuzz 10% -fill white -opaque blue opaque\_b10.jpg magick colorwheel.png -fuzz 25% -fill white -opaque blue opaque\_b25.jpg magick colorwheel.png -fuzz 57% -fill white -opaque blue opaque\_b57.jpg magick colorwheel.png -fuzz 81% -fill white -opaque blue opaque\_b81.jpg magick colorwheel.png -fuzz 95% -fill white -opaque blue opaque\_b95.jpg [![[IM Output]](opaque_b10.jpg)](opaque_b10.jpg) [![[IM Output]](opaque_b25.jpg)](opaque_b25.jpg) [![[IM Output]](opaque_b57.jpg)](opaque_b57.jpg) [![[IM Output]](opaque_b81.jpg)](opaque_b81.jpg) [![[IM Output]](opaque_b95.jpg)](opaque_b95.jpg) From this you can clearly see that it isn't '`black`', or '`white`' that is the most distant color from '`blue`', but that it is actually '`yellow`' that is most distant within RGB color space. Also note that a 81% color difference will just miss matching a pure '`red`' color, however while pure red does not match other reds, (excluding orange-red colors) do match. That is, again due the to 'spherical' nature of the color matching. The moral is that you are probably better off either using multiple small "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" factored matches or a smaller 'inverted match', than a single large value. Here we compare the colors in the image with another color, the 'near-perfect gray' color, changing similar colors to that same gray color, as the 'fuzz factor' increases. magick colorwheel.png -fuzz 25% -fill gray50 -opaque gray50 opaque\_g25.jpg magick colorwheel.png -fuzz 30% -fill gray50 -opaque gray50 opaque\_g30.jpg magick colorwheel.png -fuzz 35% -fill gray50 -opaque gray50 opaque\_g35.jpg magick colorwheel.png -fuzz 45% -fill gray50 -opaque gray50 opaque\_g45.jpg magick colorwheel.png -fuzz 51% -fill gray50 -opaque gray50 opaque\_g51.jpg [![[IM Output]](opaque_g25.jpg)](opaque_g25.jpg) [![[IM Output]](opaque_g30.jpg)](opaque_g30.jpg) [![[IM Output]](opaque_g35.jpg)](opaque_g35.jpg) [![[IM Output]](opaque_g45.jpg)](opaque_g45.jpg) [![[IM Output]](opaque_g51.jpg)](opaque_g51.jpg) As you can see colors in the colorwheel image only just start to match at a fuzz factor just before 30%, and slowly increase until at 45% all but the most extreme colors have disappeared. By 51% all the colors in the image has matched the near-perfect gray. What you are seeing is the result of the way RGB colors are arranged into a cube in 3-dimensional space. The 'color wheel' image however only contains 'fully saturated colors', which basically means all the extreme colors that are located on the outside faces of the RGB color cube. A perfect gray is however located in the center of the cube, quite distant from all the 'saturated colors'. As such it is not until you reach a large fuzz factor of 28%, that the color in the middle of the cube faces start to match. As the fuzz factor gets larger more and more colors will match until only the colors at the extreme corners of the color cube remain. At around 50% the corner colors will also start to match, and so at 51% every opaque RGB color will have matched. #### Fuzz Factor and Transparent colors Using a "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" factor becomes more complicated when matching involves transparent and semi-transparent colors. For example, here I create a gradient between black and white, across the image, but then add a transparent gradient vertically. I then do a fuzzy color match for a perfect gray color (that is 50% gray). In later images I make the color being match more transparent until it is fully-transparent, however the [Fuzz Factor](#fuzz) remains a constant 20%. magick -size 100x100 gradient: \\( +clone -rotate 90 \\) +swap \\ -compose CopyOpacity -composite trans\_gradient.png magick trans\_gradient.png -channel RGBA \\ -fuzz 20% -fill Gray50 -opaque 'GrayA(50%,1.0)' fuzz\_trans\_100.png magick trans\_gradient.png -channel RGBA \\ -fuzz 20% -fill Gray50 -opaque 'GrayA(50%,.75)' fuzz\_trans\_75.png magick trans\_gradient.png -channel RGBA \\ -fuzz 20% -fill Gray50 -opaque 'GrayA(50%,.40)' fuzz\_trans\_40.png magick trans\_gradient.png -channel RGBA \\ -fuzz 20% -fill Gray50 -opaque 'GrayA(50%,0.0)' fuzz\_trans\_00.png [![[IM Output]](trans_gradient.png)](trans_gradient.png) ![==>](../img_www/right.gif) [![[IM Output]](fuzz_trans_100.png)](fuzz_trans_100.png) [![[IM Output]](fuzz_trans_75.png)](fuzz_trans_75.png) [![[IM Output]](fuzz_trans_40.png)](fuzz_trans_40.png) [![[IM Output]](fuzz_trans_00.png)](fuzz_trans_00.png) Note the use of "`-channel RGBA`" in the above is not for color matching, but for specifying the color channels to be 'filled'. That is without it, the above will still match the same colors, but gray 'fill' will remain semi-transparent, and not be set to an opaque gray color. If you want to match all colors regardless of their transparency, then you will need to [Turn Off Transparent Channel](../masking/#alpha_off) of the image, at least temporarilly. You can turn it back on again afterward, though your fill color will again have the same transparency as the original color. In the first image matching with a fully-opaque gray color (alpha='`1.0`') you get a very spherical match of all the near opaque gray colors. However as the color being matched gets more semi-transparent, the number of matching semi-transparent colors that match will seem to become larger, until a fully-transparent grey will match any near-transparent color. What is happening is that as transparency increases, the distance between the semi-transparent colors decreases. The more transparent two colors are the closer the colors will be, compared to their opaque counterparts. When both colors are fully transparent, the two colors will be regarded as a perfect, or '0' distance, match. The other thing to notice is that (as of IM v6.6.6-4) the distance from a fully-transparent color (grey or otherwise) is purely a function of the colors transparency (alpha value). The last image in the above matched all pixels that was within 20% of being fully-transparent, regardless of actual color.This also means that a large [Fuzz Factor](#fuzz) with a fully-transparent color (like 'none'), can be used to match all, or almost-all semi-transparent colors. For example... magick trans\_gradient.png -channel RGBA \\ -fuzz 95% -fill Gray50 -opaque None \\ -alpha off fuzz\_trans.jpg [![[IM Output]](fuzz_trans.jpg)](fuzz_trans.jpg) Notice that only the top 5% of the near opaque colors in the above did not match, while all the other semi-transparent colors, was turned grey. The final "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) off`" removes the last bit of semi-transparency from the image. Because of this the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) RGBA`" setting is not actually needed, but is recommended for completeness. This example is essentially equivalent to a threshold of the alpha channel, before adding a gray color underlay (to make transparent colors grey) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.6.6-4 fuzz color matching did not match fully-transparent with opaque colors equally. In fact Black was much closer match than White. As such the last example will fail. See [Fuzz Distance and Transparent Colors Bug](../bugs/fuzz_distance/)
for more details._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Worse still before IM v6.2.6-2 fuzz color matching did not regard all fully-transparent colors as being the same color. That is, fully-transparent black (also known as 'None') was not the same as fully-transparent white (or color '#FFF0'), even though they are both fully-transparent._ | * * * **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Color maths (get the average of two or more colors).... Example Averaging two colors... Say '#000000' and '#DDDDDD' Generally the colors are added to images, and the result output as a single pixel 'txt:-' image, which which the color can be extracted. \* use -resize to merge the colors magick -size 2x1 xc:'#000000' -fill '#DDDDDD' \\ -draw 'point 0,0' -resize 1x1 txt:- \* Use -evaluate-sequence mean on them! magick -size 1x1 xc:'#000000' xc:'#DDDDDD' \\ -evaluate-sequence mean txt:- Or for a lot of colors you can use the 'Box' resize filter magick rose: -filter Box -resize 1x1\\! txt: # ImageMagick pixel enumeration: 1,1,255,RGB 0,0: (145, 89, 80) #915950 \* Use -fx to apply whatever formula you want magick -size 1x1 xc:'#000000' xc:'#DDDDDD' \\ -fx '(u+v)/2' txt:- With an ImageMagick API the results can be more directly retrieved from the image. * * * --- # Masks -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Masks ========================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif)Alpha (Matte) Channel](#alpha_channel) * [Internal Matte Channel](#alpha) * [Alpha Channel Operator](#alpha) [`Off`](#alpha_off)  (or [`-alpha off`](#alpha_off) ),  [`Set`](#alpha_set)  (or [`-alpha set`](#alpha_set) ),  [`On`](#alpha_on) ,  [`Activate`](#alpha_activate) ,  [`Discrete`](#alpha_discrete) ,  [`Opaque`](#alpha_opaque) ,  [`Transparent`](#alpha_transparent) ,  [`Extract`](#alpha_extract) ,  [`Copy`](#alpha_copy) ,  [`Shape`](#alpha_shape) ,  [`Remove`](#alpha_remove) ,  [`Background`](#alpha_background) * [Remove Transparency of an Image](#remove) * [Boolean Alpha Transparency](#boolean_transparency) * [Outline or Halo Transparency](#outline) [![](../img_www/granitesm_right.gif) Using Masks with Images](#masks) * [Editing an Image Mask](#editing) * [Masks as Colored Shapes](#shapes) * [Mathematical Composition](#compose) * [Masked Alpha Composition](#masked_compose) * [Aligning Two Masked Images](#aligning) (under construction) [![](../img_www/granitesm_right.gif) Special Image Masks](#special_masks) * [Write Mask - Protect Pixels form Change](#write_mask) * [Clip Mask and Clip Paths](#clip_mask) * [Read Masks - Ignore Pixel Input](#read_mask) [![](../img_www/granitesm_right.gif) Regions and Region Sub-Images](#regions) * [Warping a Local Region](#region_warping) * [How Regions Work, and its Problems](#region_internals) [![](../img_www/granitesm_right.gif) Background Removal](#bg_remove) * [Simple Backgrounds (floodfill)](#floodfill) * [Masking Bordered Objects](#border_cut) * [Removing a Known Background](#known_bgnd) * [Difference Image Masking and Feathering](#difference) * [Recovering Semi-Transparent Edges](#semi-trans) * [Background Removal using Two Backgrounds](#two_background) [![](../img_www/granitesm_right.gif) Hole\_Filling](#hole_filling) * [Creating a Hole to Fill](#create_a_hole) * [Filling using a Blur](#blur_fill) (Under Construction) In these examples we look at the special handling of transparency, the transparency channel, using masks, and ultimately the removal of unwanted backgrounds, or other elements, such as signs, text, spam. * * * Alpha Channel ------------- The transparency (alpha) channel of an image is completely optional, and often requires special handling separate to the normal 'color' channels. See [Image Color Space](../color_basics/#colorspace) above. The existence of a transparency channel can also effect how the various operators treat the other color channels, generally because a fully-transparent color should often be completely ignored by an operation. If this was not the case you get 'Black Halos' around images, such as was seen in major IM Bugs in the early days of IM v6. For example the [Resize Halo Bug](../bugs/resize_halo/) , and the [Blur with Transparency Bug](../bugs/blur_trans/) . To make matters worse, this channel is also sometimes referred to at an image's 'transparency' or 'opacity' channel, or even the image's 'mask'. All however refer to the same, special, fourth channel of the image. [![[IM Output]](../images/moon.png)](../images/moon.png) To explain the difference we need a working example image and for this I'll use a PNG image of a 'crescent moon' image (from a [CopyOpacity Composition](../compose/#copyopacity) example). Now as you can see this image has a lot of areas which are fully transparent. Not only that I needed to save the image using the 'PNG' image format which is one of the small number of image formats that properly understands and handles transparent and semi-transparent colors.I can demonstrate this transparency by overlaying the image onto the IM built-in checkerboard pattern, using [Alpha Composition](../compose/) . magick composite -compose Dst\_Over -tile pattern:checkerboard \\ moon.png moon\_background.jpg [![[IM Output]](moon_background.jpg)](moon_background.jpg) ### Internal Alpha Channel Now internally IM v7 stores the transparency information in a 'alpha' channel, which just like the color channel is just a plain grey scale image of values which range from white, for fully-transparent (or clear), to black for fully-opaque. It is sort of like what you would get if you look at a silhouette of the original image. Low level operators such as "`[-level](https://imagemagick.org/script/command-line-options.php?#level) `" and "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" handle the data as alpha. Check the [Official Option Reference](option_link.cgi) if you are unsure. * * * Here is a very old way to extract a 'alpha' transparency values from an image. It saves the transparency channel as a 'alpha' image file format, and required two separate steps, and commands to define the right image file format. magick moon.png alpha:moon.matte magick MIFF:moon.alpha moon\_matte2.png # You can join those two steps in a pipeline as well... magick moon.png alpha:- | magick - moon\_matte3.png [![[IM Output]](moon_matte3.png)](moon_matte3.png) This technique for extracting the 'alpha' of an image was common when IM v5 was in use. Basically it was the only method provided to get access to the transparency of an image. It is now very rarely used. ### Controlling Image Transparency There are two operators that give you low-level control of the transparency channel of an image in memory. The newer operator "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) `" methods are now the recommended method of control, though many IM Examples still show and use the older "`-matte`" operator. An image cannot only have alpha channel data, but it also has a 'switch' that defines if the channel data is viewable or valid. This means images can have three states with regards to the alpha channel. | | | | | --- | --- | --- | | Switch | | **Channel Data** | | alpha off | no alpha data (no memory has been allocated) | | alpha deactivate | old alpha data present (but not in use) | | alpha on | alpha data that is currently in use | This needs to be remembered as how the various methods behave depends on which of the above three states the image was in. If the 'switch' is off operators will not touch the alpha data, as it may not actually exist at all. In such a case old alpha could still be present, unmodified, and thus out-of-date. As you will see this is actually sometime useful in some situations. Note however that some operators may automatically turn on, or turn off the alpha switch for one reason or another. For example, "`-compose CopyOpacity -composite`" will always turn on the alpha channel in the resulting image, as it is the operator's job to copy data into an alpha channel. As such it must exist in the final result. However its existence in the input data can have other consequences. See [Copy\_Opacity Composition Method](../compose/#copyopacity) for more details. Similarly creating a canvas using the color '`None`' will also automatically create and enable the transparency channel, so as to ensure the blank image really is transparent. On the other hand, creating a canvas using some other [Color Name](../color_basics/#color) will generally not create any transparency channel as images are opaque by default. Here are the various "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) `" methods and examples of how they effect images and their transparency. #### Alpha Off or "`-alpha off`" This is just a simple switch on the image, which turns off any effect the transparency has on the image. It does not actually delete or destroy the alpha channel attached to the image, it just turns off any effect that channel has on the image. Similarly no operator will effect the attached alpha channel while it has been turned off. For example let's use the 'crescent moon' image (from a [CopyOpacity Composition](../compose/#copyopacity) example), and simply turn the image alpha channel off. magick moon.png -alpha off alpha\_off.png [![[IM Output]](../images/moon.png)](../images/moon.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_off.png)](alpha_off.png) Note that the moon shape completely vanished when the transparency was turned off, though that is actually rarely the case. Basically even the 'transparent' areas have color, which is just not normally visible, in this case the hidden color was the fractal canvas image that was used to create the moon image. This hidden color could be anything, from a simple [GIF Transparency Color](../formats/#gif_trans) , that the GIF format uses to represent transparency in its color table, to garbage colors left behind during the images creation, as above. More typically the transparency color is simply pure-black for any pixel that was fully-transparent. Note that pixels close to the edge may be semi-transparent, and thus still have a valid color that is only partially visible. The "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) Off`" operation in the above will have simply 'deactivate' or 'turn off' the channel. The transparency data itself has not been cleared or removed from the image data stored in-memory. It is still present, just unavailable for the moment. But... If the image is saved, while the transparency data is turned off, none of the transparency data will be saved into the image file format. As such the turned-off alpha data is not present in the saved copy of the image, even though it is present (just turned off) in the in-memory version. Also as many file formats do not allow transparency (such as JPEG), these file formats automatically do the equivalent of a "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) Off`" when the image is saved (without actually doing so). Generally this results in all transparent areas typically turning black when saved as a JPEG image. See [Alpha Remove - Removing Transparency](#alpha_remove) below for the correct way to remove transparency before saving to a JPEG file format. The "`[+alpha](https://imagemagick.org/script/command-line-options.php?#alpha) `" operator is an older command that is exactly the same as "`-alpha Off`". That is it just turns off the transparency channel. Note that turning off alpha, is often required before using a gray-scale mask image with the [CopyOpacity](../compose/#copyopacity) Alpha composition method. If you don't do this the compostion operator will copy the enabled transparency (opacity channel) rather that use the intended grayscale colors. #### Alpha Set or "`-alpha set`" The '`Set`' alpha method is the same as the older "`[-alpha on](https://imagemagick.org/script/command-line-options.php?#alpha) `" option. This ensures that the image has a 'transparency' or alpha channel, but if it was not present or turned off, that it is initialised to be fully-opaque (See the [Alpha Opaque](#alpha_opaque) method below). However if the image already has an alpha channel present and enabled, it will do nothing. In other words this operator ensures an alpha channel is present, without modifying the look of the image as it is currently in memory. As such on its own this operator does not show any change to the image, but has real effects when combined with other operators. So if you turn off the alpha channel using [Alpha Off](#alpha_off) , and then enable it again using [Alpha Set](#alpha_set) , the image will have an alpha channel, but it will be fully-opaque, just as the image looked, when '`Set`' operation was requested. magick moon.png -alpha off -alpha set alpha\_set.png [![[IM Output]](alpha_set.png)](alpha_set.png) If applied to an image that has an enabled alpha channel, no change is made. magick moon.png -alpha set alpha\_noset.png [![[IM Output]](alpha_noset.png)](alpha_noset.png) In summery, this operator should never change the appearance of the image, at the time the operator is applied. It just ensures the alpha channel set up such that the image is left _as is_. This is typically used **after reading images** from an unknown image file format, or input source, which may or may not have an alpha channel present. This operator will then ensure that the image does have an alpha channel (for image formats like JPEG), but leaving any enabled and existing alpha channel alone (such as for GIF or PNG formats). This is the recommended way of ensuring an image has an alpha channel after reading it into memory, or more importantly, after an image has been processed and you want to re-enable a clean alpha channel. #### Alpha On The "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) On`" is the exact opposite to the previously looked at [Alpha Off](#alpha_off) method. Typically this is _too simplistic_ for the purpose you are wanting and as such **should be very RARELY used**. You should use "`[-alpha Set](#alpha_set) `" in almost all cases. Basically '`On`' method just flips the switch so that the image transparency data is visible again. Any existing transparency data is not modified, so if the in-memory image still has some old alpha channel data, that data will suddenly be visible again. For example, here we turn '`Off`' the transparency data, then immediately turn it back '`On`, reproducing the original image. magick moon.png -alpha off -alpha on alpha\_on.png [![[IM Output]](alpha_on.png)](alpha_on.png) However if the image does not have any previous alpha data (yet) it will initialize it to be fully-opaque. Which is the logical thing to do. As such for new images just read into memory, it is equivalent to [Alpha Set](#alpha_set) , but it should not be used for this purpose. The only time [Alpha On](https://imagemagick.org/script/command-line-options.php?#alpha) should be used is when you previously, and _purposefully turned off alpha_ for some reason, and now wish to restore that data. For example turning the alpha channel off then on can be used to preserve the alpha channel data before applying some very specific operators, such as "`[-shade](https://imagemagick.org/script/command-line-options.php?#shade) `". For an example of this special usage see [Shaded Shape Images](../transform/#shade_shape) . #### Alpha Activate/Deactivate enables and disables the alpha channel, respectively, with persistence. This is like on/off in Imagemagick 6. In Imagemagick 7, -alpha off will remove the alpha channel permanently such that -alpha on will not re-enable it. #### Alpha Discrete treat the alpha channel independently (do not blend). #### Alpha Opaque This method not only ensures the alpha channel is 'active' but that it is also completely opaque, regardless of if the image had transparency 'activated/on' or 'deactivated/off'. For example... magick moon.png -alpha opaque alpha\_opaque.png [![[IM Output]](alpha_opaque.png)](alpha_opaque.png) On older versions of IM, this was equivalent to using both "`[-alpha off](https://imagemagick.org/script/command-line-options.php?#alph) `" to turn off the alpha channel, then using "`[-alpha on](https://imagemagick.org/script/command-line-options.php?#alpha) `" to turn it on, while resetting it to be opaque. magick moon.png -alpha off -alpha on alpha\_opaque\_matte.png [![[IM Output]](alpha_opaque_matte.png)](alpha_opaque_matte.png) The original 'shape' of the image can no longer be recovered after this operation as the original alpha channel data has been overwritten. Of course that is also equivalent to using "`-alpha off -alpha set`", though you may as well use "`-alpha opaque`" in that case. #### Alpha Transparent Similarly this ensures the alpha channel is 'active' but also fully transparent. magick moon.png -alpha transparent alpha\_transparent.png [![[IM Output]](alpha_transparent.png)](alpha_transparent.png) The color data of the image is still present, so turning off transparency afterward will again show the images existing colors. magick moon.png -alpha transparent -alpha off alpha\_transparent\_off.png [![[IM Output]](alpha_transparent_off.png)](alpha_transparent_off.png) Of course the original 'shape' of the image was actually destroyed, so it can no longer be recovered after this operation. Other ways of making an image fully transparent is presented in [Transparent Canvas](../canvas/#transparent) . #### Alpha Extract The '`Extract`' method will simply copy the 'alpha' mask of the image as a gray-scale channel mask. magick moon.png -alpha extract alpha\_extract.png [![[IM Output]](../images/moon.png)](../images/moon.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_extract.png)](alpha_extract.png) Note that fully-opaque is white, while fully-transparent is pure black. As image contained some semi-transparent pixels along the edges (for anti-aliasing providing the images shape with a smoother look), this image is not pure black and white, but also contains some gray colored pixels around the edges. If your ImageMagick is an old IMv7 version, this is a (near) equivalent technique, using channel extraction. magick moon.png -channel a -separate +channel -negate alpha\_extract.png The '`[Extract](#alpha_extract) `' method will also turn '`[Off](#alpha_extract) `' the alpha, but it is not cleared, so turning the alpha channel back '`[On](#alpha_extract) `' will re-create a shape mask of the original image. magick moon.png -alpha extract -alpha on alpha\_extract\_on.png [![[IM Output]](alpha_extract_on.png)](alpha_extract_on.png) Note that all the original colors will have been replaced with white with various shades grays around the edges. We can see this if we remove the transparency with a white background, (See [Alpha Remove](#alpha_remove) method below) magick alpha\_extract\_on.png -background white -alpha remove alpha\_edge.png [![[IM Output]](alpha_edge.png)](alpha_edge.png) These 'gray' pixels are actually used to good effect in [Edge Outlines from Anti-Aliased Shapes](../transform/#edge_jitter) to generate a smooth edge or outline from an image shape. This side-effect of saving the alpha channel, has particular benefits when Using the [Shade Operator](../transform/#shade) , which does not understand or use the alpha channel of an image. See the sub-section, [Masking Shaded Shapes](../transform/#shade_mask) . #### Alpha Copy The '`Copy`' method is the reverse of '`[Extract](#alpha_extract) `', and essentially performs a [CopyOpacity](../compose/#copyopacity) against itself. That is, it will turn a gray-scale image (regardless if its alpha channel is enabled or not) into a shape mask image. magick alpha\_extract.png -alpha copy alpha\_copy.png [![[IM Output]](alpha_extract.png)](alpha_extract.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_copy.png)](alpha_copy.png) It does not matter if the image had an existing alpha channel or not, all it does is create the images transparency from the image gray-scale values. Once you have a shape mask, you can use various [Color Tinting](../color_mods/#tinting) or [Duff-Porter](../compose/#duff-porter) alpha composition methods, to color it. For examples of using a shape mask see [Masks as Colored Shapes](#shapes) . #### Alpha Shape To make use of a gray-scale image easier, the '`Shape`' method not only creates a shape mask (as per [Alpha Extract](#alpha_extract) , but will also color it using the current background color. magick alpha\_extract.png -background Yellow -alpha shape alpha\_shape.png [![[IM Output]](alpha_extract.png)](alpha_extract.png) ![==>](../img_www/right.gif) [![[IM Output]](alpha_shape.png)](alpha_shape.png) This means you can very quickly color a gray-scale mask simply by shaping the image, then flattening it onto a different background color magick alpha\_extract.png -background Yellow -alpha shape \\ -background Blue -alpha remove alpha\_colormask.png [![[IM Output]](alpha_colormask.png)](alpha_colormask.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Background is not actually the right color to use for this 'shape' coloring operation. It should be using the 'fill' color to set the shapes foreground color. As such which color should be used is likely to change. Background is only used due to internal difficulties in accessing the current fill color. This change will likely happen as part of IMv7._ | Of course a faster and better way to map a black and white image, directly to specific colors is by using the more specialised [Level Adjustment by Color](../color_mods/#level-colors) . This will avoid the need to enable or even modify the existing images transparency channel. magick alpha\_extract.png +level-colors Blue,Yellow level\_color.png [![[IM Output]](level_color.png)](level_color.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The above will map the colors using a linear colorspace, and may need to be converted to sRGB at some point to get a more visually correct gradient of colors._ | #### Alpha Remove The "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) **Remove**`" method (added to IMv6.7.5) is designed to remove the transparency from an image, using the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `". magick moon.png -background tan -alpha remove alpha\_remove.png [![[IM Output]](alpha_remove.png)](alpha_remove.png) Note that while transparency is 'removed' the alpha channel will remain turned on, but will now be fully-opaque. If you no longer need the alpha channel you can then use [Alpha Off](#alpha_off) to disable it. This operation is simple and fast, and does the job without needing any extra memory use, or other side effects that may be associated with alternative transparency removal techniques. It is thus the preferred way of removing image transparency. For other techniques, or if your ImageMagick is older that v6.7.5, then look at the larger discussion [Removing Transparency from Images](#remove) ) below. #### Alpha Background As of IM v6.5.2-10, a '`Background`' method was made available that will set the hidden color of fully-transparent pixels to the current background color. Normally this color is of no consequence, as it can only be seen if the alpha channel is [turned off](#alpha_off) . However the color of fully-transparent pixels is saved in PNG Image file format, and for large images, having random unknown fully-transparent colors can significantly effect its compression handling. See [PNG with Better Compression](../formats/#png_compress) and the IM Forum Discussion [Eliminating alpha channel garbage](https://magick.imagemagick.org/viewtopic.php?t=13746) for more details. Note that no color mixing is applied, only a direct color assignment to any fully-transparent color. The pixels however will still remain fully-transparent, and as such you will see not change to the image.For example, here I use it to set all fully-transparent pixels to '`HotPink`'. magick moon.png -background HotPink -alpha Background moon\_hotpink.png [![[IM Output]](moon_hotpink.png)](moon_hotpink.png) As you can see this made no change to the actual look of the image. To see the change we will now [turn off](#alpha_off) the alpha channel. magick moon\_hotpink.png -alpha off moon\_hotpink\_off.png [![[IM Output]](moon_hotpink_off.png)](moon_hotpink_off.png) **This is not the same as [Removing Transparency](#alpha_remove) ** The edges of the shape will have made all semi-transparent pixels opaque, and as a result produced some strong aliasing (stair-cased) edge effects. Note that even the normally opaque only format PNG24, can still save boolean transparency if all the fully transparent colors are the same. For details see the example in [PNG Sub-Formats](../formats/#png_formats) . This process of replacing the colors is actually almost the same as doing a "`-channel RGB -fill _color_ -opaque None +channel`". See [Direct Color Replacement](../color_basics/#replace) . Note that many other image processing operators will also magick any fully-transparent pixels, to fully-transparent black (color '`None`'), as this is the color equivalent of a mathematical zero. Here is a summary of some image operations that are known to do this, though none are as direct or as fast as using this operator. magick moon.png \\( +clone -alpha off \\) \\ -compose SrcIn -composite moon\_black.png magick moon.png -channel RGBA -blur 1x.000000001 moon\_black.png magick moon.png -channel RGBA -gaussian 1x0 moon\_black.png magick moon.png -fuzz 0% -transparent none moon\_black.png That last method (see [Fuzz Factor and Transparent colors](../color_basics/#fuzz_alpha) is particularly useful as you cannot only set all transparent colors to full-transparent-black ('`None`'), but also all near-fully-transparent colors (which otherwise does have a valid but practically invisible color), simply by specifying a fuzz factor. It will produce some data loss, but may improve compression in images with lots of near-fully-transparent colors. Often these nearly total transparent pixels can have very odd or wrong colors, and this method will allow you to remove such odd pixels before they cause other problems. ### Removing Transparency from Images While the [Alpha Off](#alpha_off) will simply flip a switch and turn off the transparency channel. You can also get the same effect if you attempt to save the image into a file format that does not allow the use of transparency. For example by saving to JPEG... magick -size 70x60 xc:none -font Candice -pointsize 50 \\ -fill Black -annotate +10+45 'A' -channel RGBA -blur 0x5 \\ -fill white -stroke black -draw "text 5,40 'A'" a.png magick a.png a.jpg [![[IM Output]](a.png)](a.png) ![==>](../img_www/right.gif) [![[IM Output]](a.jpg)](a.jpg) Remember the [JPEG File Format](../formats/#jpg) , does not save the alpha (transparency) channel, and as such simply turned it off. In this case transparent parts just became black (a typical result). But depending on the image source the transparent areas could have just as easily become some other random, or other inappropriate color. Also in many cases semi-transparent pixels can have some very odd colors that is typically not visible because they are almost completely transparent. Simply turning off transparency will make these pixels stand out like a sore thumb, making the result look even worse than you may have expected. See for example the top-left edges of 'A' in the above. In either case simply turning off transparency is typically NOT what is wanted. The _best solution_ is to use the [Alpha Remove](#alpha_remove) method to quickly and simply replace the transparency with a background color underlay... magick a.png -background skyblue -alpha remove -alpha off a\_remove.jpg [![[IM Output]](a_compose.jpg)](a_compose.jpg) Strictly speaking the [Alpha Off](#alpha_off) is not needed in this case, as the save to JPEG does this automatically. Alternative techniques of removing transparency, is to somehow generate a new 'background' or 'canvas' image and [Over Compose](../compose/#over) your image onto that background so that the transparency is replaced. Preferably while preserving the original image's meta-data, such as profiles, labels, captions and comments that may be present. Methods for generating such a canvas is exampled in [Creating Image Canvases of Same Size](../canvas/#blank) . Here is one such method... magick a.png \\( +clone -alpha opaque -fill SkyBlue -colorize 100% \\) \\ +swap -geometry +0+0 -compose Over -composite \\ -alpha off a\_compose.jpg [![[IM Output]](a_compose.jpg)](a_compose.jpg) Other simpler ways to do this, is to use an operation that internally creates a '_cloned background canvas_' for you, generating it as part of the larger image processing operation that the operator is performing. The most common method is to [Flatten](../layers/#flatten) the image. This operator is so often used for this purpose that the process of removing transparency has often erroneously been called 'flattening'. For example... magick a.png -background skyblue -flatten -alpha off a\_flatten.jpg [![[IM Output]](a_flatten.jpg)](a_flatten.jpg) However this will not work with "`[mogrify](../basics/#mogrify) `" or with a sequence of multiple images, basically because the "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" operator is really designed to merge multiple images into a single image. The other common method that does work with multiple images is to give the image a zero sized [Border](../crop/#border) with the appropriate "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `". For example... magick a.png -bordercolor skyblue -border 0 -alpha off a\_border.jpg [![[IM Output]](a_border.jpg)](a_border.jpg) Other image processing operators which are closely related to the above methods, can also remove transparency from an image. These include: [Mosaic](../layers/#mosaic) , [Merge](../layers/#merge) , and [Frame](../crop/#frame) . The [Extent](../crop/#extent) operator can also be used, and allows you to expand or crop images at the same time as you remove the transparency, but only if you know the size of final image you desire. You do not have to replace transparency with a solid color. If you use a DIY composition (as shown above) you can use any image for the replacement background. One simple example of this is to use the "`[composite](../basics/#composite) `" command to [Tile](../compose/#tile) an image 'under' the original, (using [Dst\_Over](../compose/#dstover) ). This compose method ensures the original images meta-data and size is preserved. magick composite -compose Dst\_Over -tile pattern:checkerboard \\ a.png a\_undertile.jpg [![[IM Output]](a_undertile.jpg)](a_undertile.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Many of the above methods, are either effected by, or may destroy any virtual canvas information an image may have, as part of its processing. When the virtual canvas is involved, you may need to look at the details of individual operators more closely. In many cases the virtual canvas effects can be useful to your overall image processing.

_ | ### Boolean Alpha Transparency For some image file formats you don't need to completely remove the alpha channel, but only allow pure on/off or boolean transparency. Index (Palette) image file formats such as [GIF](../formats/#gif) and [PNG8](../formats/#png_formats) , are typical of this. Examples are currently looked at in [GIF Boolean Transparency](../formats/#boolean_trans) , but should eventually move here. ### Outline or Halo Transparency Sometimes you will like to add an outline around an image containing transparency. One way is to use [EdgeOut Morphology](../morphology/#edgeout) to quickly get all the neighbouring pixels to the original image, color them, and then [Under (DstOver) Compose](../compose/#dstover) it with the original image. magick knight.png \\( +clone \\ -channel A -morphology EdgeOut Diamond +channel \\ +level-colors red \\ \\) -compose DstOver -composite knight\_outlined.png [![[IM Output]](../images/knight.png)](../images/knight.png) ![==>](../img_www/right.gif) [![[IM Output]](knight_outlined.png)](knight_outlined.png) This can be particularly useful when creating GIF format images from PNG images containing semi-transparent edge pixels. It provides a minimal amount of background color, but leave the rest of the image fully-transparent. See [GIFs on a Background Pattern](../formats/#bg_pattern) for more about this problem. An alternative method is to generate a soft semi-transparent halo around the shape. To do this we [Blur](../blur/#blur) and recolor the image, then again [Under (DstOver) Compose](../compose/#dstover) it with the original. magick knight.png \\( +clone \\ -channel A -blur 0x2.5 -level 0,50% +channel \\ +level-colors red \\ \\) -compose DstOver -composite knight\_halo.png [![[IM Output]](knight_halo.png)](knight_halo.png) This last is actually similar to using a [Soft Outline Compound Font](../fonts/#soft_outline) effect, but using a shaped image rather than annotated text. * * * Using Masks with Images ----------------------- ### Masking An Image As shown previously there are a couple of ways to mask an image, so as to make part of the image transparent. And which method you choose depends on the whether your image mask is a grayscale mask, or a shaped mask. ### Editing an Image Mask The mask of an image is a really useful thing to have. We can for example erase parts of an image very easily by modify a mask of the original image. Remember the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator cannot draw nothing, and currently has no erase option. Here we create an image, then by extracting and modifying its mask, before restoring it to the original image. magick -size 100x100 xc:none -stroke black -fill steelblue \\ -strokewidth 1 -draw "circle 60,60 35,35" \\ -strokewidth 2 -draw "line 10,55 85,10" drawn.png magick drawn.png -alpha extract mask.png magick mask.png -fill black -draw "circle 40,80 60,60" mask\_bite.png magick drawn.png mask\_bite.png \\ -alpha Off -compose CopyOpacity -composite \\ drawn\_bite.png [![[IM Output]](drawn.png)](drawn.png) ![==>](../img_www/right.gif) [![[IM Output]](mask.png)](mask.png) ![==>](../img_www/right.gif) [![[IM Output]](mask_bite.png)](mask_bite.png) ![==>](../img_www/right.gif) [![[IM Output]](drawn_bite.png)](drawn_bite.png) Remember "black" in a mask is transparent, while white is opaque, so all we need to do is draw black over anything we don't want visible. Don't forget the "`-alpha Off`" operation in the above as it is vital to ensure the grayscale image does not contain unneeded transparent channel. And Presto we took a bite out of the original image. We can also re-add a part of the image we removed. For example, here I re-add part of the 'bite' I removed from the original image, by drawing white area onto the mask. The mask is then again returned to the original image using [CopyOpacity Channel Composition](../compose/#CopyOpacity) . magick mask\_bite.png -fill white \\ -draw "circle 50,70 60,60" \\ -draw "roundRectangle 78,5 98,25 5,5" \\ -alpha off mask\_bite2.png magick composite -compose CopyOpacity mask\_bite2.png drawn.png drawn\_bite2.png [![[IM Output]](mask_bite.png)](mask_bite.png) ![==>](../img_www/right.gif) [![[IM Output]](mask_bite2.png)](mask_bite2.png) ![==>](../img_www/right.gif) [![[IM Output]](drawn_bite2.png)](drawn_bite2.png) Just a word of warning about re-adding parts. Typically ImageMagick replaces any fully-transparent color with black, usually because that is how the mathematics behind operators work. It is after all fully-transparent and thus its color should not normally matter. That means that if we make a part of the image we haven't drawn before opaque, then it will generally be black, since that is the color under the image's transparency. However in the above example you will have noticed that the PNG image file format correctly preserved the original (made transparent) color of the image. As such the color of the re-added part remained the original '`SteelBlue`' color of the original image. You should not count on this if the image was saved to some other file format or further modified. Here is an alternative method of erasing parts out of an image but rather than extracting and modifying a Grayscale Mask, we instead use a Shape mask as a sort of 'erase' tool using [DstOut Composition Method](../compose/#dstout) . magick -size 100x100 xc:none -draw "circle 40,80 60,60" mask\_shape.png magick drawn.png mask\_shape.png -compose DstOut -composite drawn\_bite3.png [![[IM Output]](drawn.png)](drawn.png) ![-](../img_www/minus.gif) [![[IM Output]](mask_shape.png)](mask_shape.png) ![==>](../img_www/right.gif) [![[IM Output]](drawn_bite3.png)](drawn_bite3.png) As you can see sometimes Shape Masks are easier to handle, as you avoid the need to extract and restore the alpha channel. However the [Duff-Porter Alpha Composition Methods](../compose/#duff-porter) , which is what I am using, will never allow you to restore colors that have been made transparent. With these methods, anything that has been made transparent (and thus undefined in color), stays transparent. In actual fact erasing parts of an image using [Alpha Composition Methods](../compose/#duff-porter) will actually destroy the underlying color of fully-transparent pixels. It will not preserve it. After all, a transparent color is actually not a real color! ### Masks as Colored Shapes An alternative to just using the mask to add or re-add transparency to an image is to actually combine the mask directly with images in various ways. For example suppose we just want to use a mask as a symbol or shape we want to overlay onto an image in various colors. For this we need a mask, which I'll extract from a special 'symbol' font. magick -font WebDings -pointsize 24 label:Y \\ +trim +repage -negate heart\_mask.gif [![[IM Output]](heart_mask.gif)](heart_mask.gif) Note that I negated the label image to make it proper mask image, consisting of a white foreground (opaque) on black background (transparent). As of IM v6.4.3-7 the simplest way to magick a grayscale mask, into a colored shape is to use the [Alpha Shape](#alpha_shape) operator, This is exactly like [Alpha Copy](#alpha_copy) , but with an extra step to color the final shape. magick heart\_mask.gif -background Red -alpha Shape heart\_red.png [![[IM Output]](heart_red.png)](heart_red.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note the use of 'PNG' image format for generated shaped image rather than GIF so as to avoid problems with [GIF Boolean Transparency](../formats/#trans)
._ | Before this the simplest solution was to negate the alpha mask into a matte [Channel Image](../color_basics/#channels) then use [Combine](../color_basics/#combine) to generate the shaped image. magick heart\_mask.gif -negate \\ -background Gold -channel A -combine heart\_gold.png [![[IM Output]](heart_gold.png)](heart_gold.png) The color of the shaped mask in this case is defined by the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color which [Combine](../color_basics/#combine) used to fill in the undefined channels of the new image. An older but more complicated way is to use '`[CopyOpacity](../compose/#copyopacity) `' composition method to set an image's transparency to the given mask, then use [Uniformly Color Tinting](../color_mods/#colorize) to color the resulting shape. This works and for a long time was the best technique to use, but is no longer recommended. magick heart\_mask.gif \\( +clone \\) -alpha off \\ -compose CopyOpacity -composite \\ -fill HotPink -colorize 100% heart\_hotpink.png [![[IM Output]](heart_hotpink.png)](heart_hotpink.png) Now that you have a 'shaped' image, you can just simply overlay the image on any background we want, such as the built-in rose image, using one of the many [Image Layering Techniques](../layers/) and [Alpha Composition Methods](../compose/) . magick rose: -page +2+2 heart\_gold.png \\ \\( +clone -repage +7+29 \\) \\ \\( +clone -repage +52+14 \\) \\ -flatten rose\_with\_love.gif [![[IM Output]](rose_with_love.gif)](rose_with_love.gif) This is fine if we want all our symbols the same color, but would require multiple intermediate images if we want to use multiple colors, making it impractical for overlaying lots of symbols with lots of different colors. One way you can make multi-colored overlays is to re-color the shaped image immediately after reading in the image. magick rose: \\( heart\_gold.png -repage +2+2 \\) \\ \\( +clone -fill Red -colorize 100% -repage +7+29 \\) \\ \\( +clone -fill HotPink -colorize 100% -repage +52+14 \\) \\ -flatten rose\_colored\_love.gif [![[IM Output]](rose_colored_love.gif)](rose_colored_love.gif) Note we only read in one shaped image, then recolored a [Clone](../basics/#clone) of that image for each new 'layer' to be overlaid. For more examples of re-coloring a base image, see the whole section on [Color Modifications](../color_mods/) . See also [Drawing Symbols](../draw/#symbols) for an alternative method of marking specific locations in an image. As well as a [Pinning Maps Laying Example](../layers/#layer_pins) for a more automated layering techniques. ### Mathematical Composition Rather than overlaying the mask onto some background, you may only be interested in coloring the image with just the white or black parts of the mask itself. This is relatively straight forward, simply by using some [Mathematical Alpha Composition Methods](../compose/#math) to change the color of the mask to match a color, tile or other image. For example the '`[Multiply](../compose/#multiply) `' compose method will replace the white areas (multiply value of 1) with the overlay image, while leaving the black areas (multiply value of 0), black. The '`[Screen](../compose/#screen) `' operator is exactly the same as '`[Multiply](../compose/#multiply) `' but with the images negated so it effectively replaces the black areas of the image. For example, let's use the larger mask image from above, to overlay a larger image generated with a tile pattern. magick mask\_bite.png -size 100x100 tile:tile\_disks.jpg \\ -compose Multiply -composite compose\_multiply.png magick mask\_bite.png -size 100x100 tile:tile\_water.jpg \\ -compose Screen -composite compose\_screen.png [![[IM Output]](mask_bite.png)](mask_bite.png) ![==>](../img_www/right.gif) [![[IM Output]](compose_multiply.png)](compose_multiply.png) [![[IM Output]](compose_screen.png)](compose_screen.png) The '`[Multiply](../compose/#multiply) `' alpha composition method is especially useful for replacing the background of text images (IE: black text on white background), such as images generated from [Postscript Documents](../text/#postscript) . ### Masked Alpha Composition The special three image form of [Masked Alpha Composition](../compose/#mask) allows you use the same mask to directly merge two images together. magick -size 100x100 tile:tile\_water.jpg tile:tile\_disks.jpg \\ mask\_bite.png -composite compose\_masked.png [![[IM Output]](compose_masked.png)](compose_masked.png) The first image will replace the black background parts of the mask, while the second image replaces the white foreground parts of the mask. The mask itself is given as the third image. The mask is used to select and mix two different images together to generate the final result. It is actually rather like a mapped [Blend](../compose/#blend) of the two images. Remember the final size and meta-data of the resulting image will come from the first 'background' image of the above operation (black parts), so swap images and [Negate](../color_mods/#negate) the mask if you want it the other way around. And finally remember that if you use the "`[composite](../basics/#composite) `" command instead of "`[convert](../basics/#convert) `", the 'overlay' image (white parts) is given first with the 'background' image (black parts) second. In other words the first two images need to be swapped for that command. ### Aligning Two Masked Images **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** On aligning two masked images... If your masks are pure boolean, you should have no problems however you apply them. However masks containing 'anti-aliased', 'gray', or 'semi-transparent' edging to make them 'smooth looking' can be serious headache if you do not handle them properly and with care. The rest of this discussion is on 'anti-aliased' masks. Anti-Aliased Masks which join together come in two styles... \* Ones which fit together like jigsaw puzzle pieces OR like a shaped peg into a shaped hole (shared boundary) \* Masks that are ment to overlay a solid area (layered) The latter is easy to handle and is the normal effect you get when you overlay some colored shape over a fully-opaque image. Essentially you would use 'over' composition to compose the shape. The former 'jigsaw' masks however is harder. Such masks are not meant to either overlap, or underlap each other. And yet if you try to join them using the obvious and normal 'over' composition you will end up with a semi-transparent join where 'anti-aliased edges' are merged. _Example of a bad 'jigsaw mask' join (over)_ The correct way to join masks and shaped 'jigsaw' images is to use **Plus** composition to 'add' the images together, with either a black or fully-transparent background. _Example of a correct 'jigsaw mask' join (plus)_ For another example of DIY image joining, using 'Dst-In', 'Dst-Out', and 'Plus' composition, see examples in... https://imagemagick.org/Usage/compose/#dstin I also go though this joining detail in the bug report of 3 image alpha composition [Composite Mask Bug\ - Fixed](../bugs/composite_mask/#correct) . For more on the difference between 'over' and 'plus' see ['Blend' (plus) vs 'Dissolve' (over)](../compose/#blend_dissolve) Examples of correctly joining edge aligned pieces is shown in [3d Cubes - Affine](../distorts/#cube3d) and again in [3d Boxes - Perspective](../distorts/#box3d) and in Isometric Cube using Shears https://imagemagick.org/Usage/warping/#sheared\_cube The Major problems in these examples is that the individual parts were NOT generated using the same mask, but distorted to their final positions. As such they do not quite fit together properly and joined together. These examples need to be updated to use a 'Plus' composition method. To generate improved results, but even then they will still probably not be quite 'right' as the masks do not exactly 'fit' together. #### Generating Correct Edge Aligned Masks The best idea is to use the same mask (negated) for BOTH pieces, rather than attempting to draw the two masks separately. Otherwise you have the two masks overlap, OR leave a gap, exactly as you have seen. Correct methods of mask joining.. \* use mask to set transparency on one piece use negated mask to set transparency of other piece 'Plus' the two pieces together. \* Use mask to Add transparency to just one piece, then 'Over' compose that piece over a complete image. \* use a three image masked composition see https://imagemagick.org/Usage/compose/#mask and https://imagemagick.org/Usage/masking/#masked\_compose Which uses the mask to select results from two different images. Remember, 'Over' only needs the 'source' or 'overlay' image masked, the background image should not have aligned semi-transparent edges. But a 'plus' composition needs both images masked with and exact negative mask of each other align the joined edge. WARNING: Draw does NOT currently allow you to generate two shapes that will fit together properly without overlap!!!! See [Draw Fill Bounds](../draw/#bounds) for details. I have not checked SVG to see if it has the same problem. * * * Special Image Masks ------------------- ### Write Masks - Protecting Pixels from Change A 'write' or 'clip-mask' is a special greyscale image that is added to an existing image of the size size. It defines areas of the image which are to be classed a 'immutable' or 'not-writable' by most image processing operators. The operator "`[-mask](https://imagemagick.org/script/command-line-options.php?#mask) `" takes an external image to be linked to the images in memory. The 'plus' form of the operator "`[+mask](https://imagemagick.org/script/command-line-options.php?#mask) `" removes the mask from the image. For example, here I use a 'write mask' to protect the background pixels from being written to, while rotating the hues, to re-color a the foreground red rose to a blue rose. magick rose: -mask rose\_bg\_mask.png \\ -modulate 110,100,33.3 +mask rose\_blue.png [![[IM Output]](../images/rose.png)](../images/rose.png) [![[IM Output]](../images/rose_bg_mask.png)](../images/rose_bg_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_blue.png)](rose_blue.png) The mask is bit rough, but it worked well. Just remember that a 'write mask' is used to specify the part to be protected or preserve. Remember, in IMv7... **The "`[-mask](https://imagemagick.org/script/command-line-options.php?#mask) `" operator defines a 'write-protect' mask** For more advanced example see [Chroma Key Masking](../photos/#chroma_key) , which is more about generating the mask, rather that applying it as a write mask. Write or clip masks are designed to work when the pixels in an image are being directly modified. EG: negate, level, color tinting, modulate, drawing, composite, morphology, convolutions. For operators that generate NEW images (resize, distorts, extent, etc) it will fail to preserve original pixels, as the mask will not be able to correspond to the new image size. Such operations will also have the side-effect of removing or unsetting the images 'write-mask'. Here is another example... magick -size 70x70 xc:red red\_image.png magick -size 70x70 xc: -draw 'circle 35,35 30,5' write\_mask.png magick red\_image.png -mask write\_mask.png \\ -fill blue -opaque red +mask masked\_color\_replace.png [![[IM Output]](red_image.png)](red_image.png) [![[IM Output]](write_mask.png)](write_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](masked_color_replace.png)](masked_color_replace.png) Note that the edges of both the mask and the resulting image is smooth (anti-aliased) that is because the mask is not simply a boolean mask but a blending mask. The 'write-mask' is a blending mask in that 'grey' pixels in the mask will produce a blending of the new pixels with the old image values, by the amount of gray that is present. This produces very smooth edges, and also allows you to generate a gradient across the image between modified and un-modified areas. However a blending mask while suitable for a single operation, may not be good when used for multiple operations as its blending effect will then be applied multiple times. This problem is especially prevalent in a looped operation such as morphology. But only if you use a non-boolean blending mask. If this is a problem, it will probably be better to simply do all the operations against a copy of the image, then use [Masked Alpha Composition](#masked_compose) against the original image. Caution is advised. This use of masking is actually exactly how [Composition Masking](../compose/#mask) actually works! But only for the duration of the composition operator being applied. magick -size 70x70 xc:green green\_image.png magick red\_image.png green\_image.png write\_mask.png \\ -composite masked\_composite.png [![[IM Output]](red_image.png)](red_image.png) [![[IM Output]](green_image.png)](green_image.png) [![[IM Output]](write_mask.png)](write_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](masked_composite.png)](masked_composite.png) Is equivalent (with a negated mask) to... magick write\_mask.png -negate -write MPR:mask +delete \\ red\_image.png -mask MPR:mask \\ green\_image.png -composite +mask masked\_composite\_equiv.png [![[IM Output]](masked_composite_equiv.png)](masked_composite_equiv.png) That is, the mask is negated, then applied to the first 'destination' image. the second is then composed over the first image, modifying only the 'white' areas of the original mask image. **A three image "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" operation uses a 'write' mask** In morphology write masks are typically used to generate a [Conditional or Constrained Morphology](../morphology/#conditional) form of an operation. One such example was discussed in the IM Discussion forum, [Cleaning up noise around text](https://magick.imagemagick.org/viewtopic.php?f=1&t=18707) , to limit the effects of a dilation. _NOTE: -crop should be able to preserve the image mask of individual images, by also cropping the mask and assigning to the new images. This however is currently not done._ ### Clip Mask and Clip Paths The "`[-clip-mask](https://imagemagick.org/script/command-line-options.php?#clip-mask) `" form of this operator, is almost exactly the same as the above but only provides a boolean (all-or-nothing) style of masking. As a result you cannot achieve a 'blended' or smoothed result. For example... magick red\_image.png -clip-mask write\_mask.png \\ -fill blue -opaque red +clip-mask clipped\_modulate.png [![[IM Output]](clipped_modulate.png)](clipped_modulate.png) As you can see the result is highly aliased (with stair-cased edges), as a "`[-clip-mask](https://imagemagick.org/script/command-line-options.php?#clip-mask) `" does not produce a blended result as "`[-mask](https://imagemagick.org/script/command-line-options.php?#mask) `" does. The only good thing about this is that it is slightly faster (though not very much). It was provided originally to allow the handling of [Clip Paths in TIFF image files](#clip-path) , and is a very old operator (IMv5). The newer "`[-mask](https://imagemagick.org/script/command-line-options.php?#mask) `" operator should be used instead. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _In IMv7, a 'write-mask' and 'clip-mask' are implemented side-by-side, even though they technically do exactly the same function. As such you could apply both masks simultaneously.

However using both at the same time is not recommended, and results are not defined. Also this 'boolean mask' form has been removed from IMv7.

_ | ### Clip Paths for TIFF images A 'clip path' is part of TIFF image file format, and defines a vector path that is used define a 'shaped area' within the TIFF image. In IM the operators "`[-clip](https://imagemagick.org/script/command-line-options.php?#clip) `" and "`[-clip-path](https://imagemagick.org/script/command-line-options.php?#clip-path) `", reads this 'clip-path' and converts it into a [Clip mask](#clip_mask) (above). As such it defines a 'write mask' that will protect the shape from modification. A clip-path stored in the TIFF image is defined as a [SVG Path Drawing](../draw/#paths) , which you can extract from a TIFF image file format using... magick identify -format '%\[8BIM:1999,2998:#1\]' image\_clip.tiff The biggest problem people often have is making everything that is not clipped transparent. Which requires you to write the areas the mask write protects! This is one solution, which converts the whole image to transparency, then turn on the 'clip path' then make the now writable parts opaque (visible) again. magick input.tiff -alpha transparent -clip -alpha opaque -strip out.tiff The "`[+clip](https://imagemagick.org/script/command-line-options.php?#clip) `" operator also turns off and remove the clip mask (just as "`[+clip_mask](https://imagemagick.org/script/command-line-options.php?#clip_mask) `" does). However no file format saves the current clip mask with the image for any image file format. (At least in IMv7) ### Read Masks - Ignore Pixel Input It is important to note that a write mask will limit what pixels will be written to an image. It does not however limit what pixels are being 'read' as part of the operation being performed, to create the new pixel data being written. This basically means that if you use a 'area effect' or 'neighbourhood' type of operator, such as [Blurs](../blur/) , [Morphology](../morphology/) , or [Convolution](../convolution/) , then 'writable pixels' close to the edge may include color values from the masked, or un-writable area. For instance, here we write protect the foreground rose, before blurring the image. That is, we want to only blur the background part of the image, rather heavily in this case. magick rose: -mask rose\_fg\_mask.png \\ -blur 0x8 +mask rose\_bg\_blur\_fail.png [![[IM Output]](../images/rose.png)](../images/rose.png) [![[IM Output]](../images/rose_fg_mask.png)](../images/rose_fg_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_bg_blur_fail.png)](rose_bg_blur_fail.png) The result is using a **Write-Protect Mask** and is not what was wanted. As you can see even though the foreground colors were protected by the mask, the colors were still used as part of blurring the background around the rose. Because of this the blurred background close to the foreground has a distinct reddish tint or halo. Put in another way the foreground colors 'leaked' into the surrounding background. This is generally not what people intend doing when they want to blur the background of an image, such as part of a lens focus effect. What people really want is to get blur to completely 'ignore' the foreground pixels, and only allow the colors of the background to part of the blurring process. That is, they wanted to prevent blur from 'reading' the foreground pixels. #### Read Mask Solution for IMv7 In IMv7 the only way to make a pixel color pixel unreadable, is to make the pixel transparent. Transparent pixels have no color by definition, and as such the 'hidden color' is not part of the calculations made by the blur operation. This gives us a 'cheat'. Make foreground pixels transparent, apply the blur (or other) operation, and turn off transparency (it isn't really wanted in this case). Then we can restore the foreground part of the image. If that sounds complex, it is. Here are the steps involved, while showing intermediate images to try and make the technique clear... magick rose: rose\_bg\_mask.png -alpha off \\ -compose CopyOpacity -composite +compose rose\_bg\_only.png magick rose\_bg\_only.png -channel RGBA -blur 0x8 rose\_bg\_blurred.png magick rose\_bg\_blurred.png -alpha off rose\_bg\_blur\_opaque.png magick rose\_bg\_blur\_opaque.png \\ rose: rose\_fg\_mask.png -composite rose\_bg\_blur\_good.png [![[IM Output]](../images/rose.png)](../images/rose.png) ![==>](../img_www/plus.gif) [![[IM Output]](../images/rose_bg_mask.png)](../images/rose_bg_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_bg_only.png)](rose_bg_only.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_bg_blurred.png)](rose_bg_blurred.png) [![[IM Output]](rose_bg_blurred.png)](rose_bg_blurred.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_bg_blur_opaque.png)](rose_bg_blur_opaque.png) ![==>](../img_www/plus.gif) [![[IM Output]](../images/rose.png)](../images/rose.png) [![[IM Output]](../images/rose_fg_mask.png)](../images/rose_fg_mask.png) ![==>](../img_www/right.gif) [![[IM Output]](rose_bg_blur_good.png)](rose_bg_blur_good.png) The result is the removal of the red halo effect that was previously being 'leaked' into the blurred background. Here is a side-by-side comparison of the write masked and read masked versions of the background blur, so you can clearly see how we removed the 'leakage' of the foreground color into the background. | | | | --- | --- | | [![[IM Output]](rose_bg_blur_fail.png)](rose_bg_blur_fail.png)

Write | [![[IM Output]](rose_bg_blur_good.png)](rose_bg_blur_good.png)

Read | | Masking Method Differences | | The above example assumes that original image has no alpha. If an image also contains an alpha channel, then you need to separate and process alpha separately, creating double the effort. One example of this is shown in a 'distort resize' discussion, which wanted to ignore the virtual pixels that surround the image being resize using distort. See [Correct Resize (using distorts)](https://magick.imagemagick.org/viewtopic.php?p=68362) for detail. Note that the above is also very closely related to a blurred [Hole Filling](#hole_filling) technique. The only difference is that it is the background that is being preserved from modification, not the foreground. Which makes it a little simpler. True 'read masks' should be available IMv7 to make the above simply adding both a 'read mask' and optionally a 'write mask'. * * * Regions and Region Sub-Images ----------------------------- Regions are another way of limiting the effects of operations to a smaller area of an image. For example, here I color tint the whole rectangular region red... magick koala.gif -region 40x33+15+5 -fill red -colorize 50% \\ koala\_region\_red.gif [![[IM Output]](koala_region_red.gif)](koala_region_red.gif) You can also make a region transparent... magick koala.gif -alpha set \\ -region 40x33+15+5 -alpha transparent koala\_region\_trans.gif [![[IM Output]](koala_region_trans.gif)](koala_region_trans.gif) Note that I needed to ensure the original image has an alpha channel enabled before making the 'region image' transparent. If that was not done, IM would make any transparency in the 'region image', see-thru, and you would see no change. See [How Regions Work](#region_internals) below for details. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.6.9-5 transparency preservation was broken, and the results of transparency in a region was always "see-thru to original". As such the result of the above would not include any transparent pixels, even though the image allowed the use of transparency._ | The biggest reasons for using [Regions](#region) is that it doesn't just simply limit its effect to a small area, it actually extracts that rectangular area of the image, and applies all the [Simple Operations](../basics/#option_simple) that follow to that smaller area. This means that if your are only modifying one very small area of a very large image, say for example doing red-eye removal, then you not only limit the scope of the operations to that area, but perform it _much faster_ too, and the extracted region image is itself smaller. In summary... A [Write Mask](#write_mask) will perform operations over the whole image, but limit what pixels are actually changed, But [Regions](#regions) use a smaller extracted sub-image. Note that there is nothing preventing you from using both of these methods together. Though if you apply a clipping mask to a region, the clipping mask should match the size of the region image that was extracted. ### Warping a Local Region As a 'image region' actually extracts a 'small sub-image' of the original for processing, you can make use of the special 'localised' [Circular Distortions](../warping/#circular) to warp small regions of the original image. For example, here we have a line of stripes. magick -size 600x70 xc:darkred \\ -fill white -draw 'roundrectangle 5,5 595,65 5,5' \\ -fill black -draw 'rectangle 5,25 595,31' \\ -fill red -draw 'rectangle 5,39 595,45' \\ lines.gif [![[IM Output]](lines.gif)](lines.gif) Now by defining regions we can distort the line in different ways in different areas. magick lines.gif \\ -region 90x70+10+0 -swirl 400 \\ -region 90x70+100+0 -swirl 400 \\ -region 90x70+190+0 -swirl -400 \\ -region 120x70+280+0 -implode 1.5 \\ -region 100x70+380+0 -implode -7 \\ -region 101x70+480+0 -wave 10x50 -crop 0x70+0+10\\! \\ +region lines\_regions.gif [![[IM Output]](lines_regions.gif)](lines_regions.gif) Note that the "[`-implode`](https://imagemagick.org/script/command-line-options.php?#implode) " and "[`-swirl`](https://imagemagick.org/script/command-line-options.php?#swirl) ", fit into the use of regions very well, as they have the property that the outside edge of the distorted image matches up to the rest of the image outside the defined region. That is, they are actually designed to perform '_localized image warping_'. Note that when I used the [Wave Distortion](#wave) , I had to crop the size of the resulting 'wave' image so that it would again fit into the original area from which it was extracted. Remember [Regions](#region) only work when used with [Simple Image Processing Operators](../basics/#option_simple) . Any other operator including another "[`-region`](https://imagemagick.org/script/command-line-options.php?#region) " operator will cancel the region processing, before that operation is applied. ### How Regions Work, and its Problems In reality the way regions work is... * Extract from the image a smaller image according to the "[`-region`](https://imagemagick.org/script/command-line-options.php?#region) " operator, using a simple crop with the region argument. * Apply any [Simple Image Processing Operators](../basics/#option_simple) , that follow, to the smaller image. * When a non-Simple Image Operator is seen, OR another "[`-region`](https://imagemagick.org/script/command-line-options.php?#region) " operator is found, OR the region is turned off using "[`+region`](https://imagemagick.org/script/command-line-options.php?#region) ", then the extracted region is overlaid on the original image at its extracted location. Region works in a way that is similar to using [Image Stack Operators](../basics/#option_sequence) , though it existed in ImageMagick a long time before those operators. It was for example an integral part of IM version 5. For example, if you have this [Region Operation](#region) ... ... -region WxH+X+Y ...simple-operators... +region ... the result is equivalent to this (for a single image)... ... \\( +clone -crop WxH+X+Y ...simple-operators... \\ \\) -geometry +X+Y -composite ... Or this (for multiple images)... ... \\( -clone 0--1 -crop WxH+X+Y ...simple-operators... \\ null: +insert \\) -geometry +X+Y -layer composite ... How the 'region image' is actually overlaid onto the 'original image' is a little tricky... If the original image has the no [Transparency Channel](#alpha) enabled, the 'region image' is composed using [Over Composition](../compose/#over) . That means that transparent areas in the region image will become see-thru, allowing you to see the original image behind it. For example, here I purposefully turned off the transparency in the original image, but then [Rotate](../warping/#rotate) the region so as to produce some areas of transparency in the corners. magick koala.gif -alpha off -region 30x30+10+10 \\ -alpha on -background None -rotate 30 koala\_region\_rotate\_1.gif [![[IM Output]](koala_region_rotate_1.gif)](koala_region_rotate_1.gif) As you can see the corners of the rotated area (which was transparent in the 'region image') shows the 'original image'. Basically as the original image cannot handle transparency, the region image is simply overlaid, with see-thru corners. If the original image does contain active [Transparency](#alpha) then the transparency in the modified region image can also be modified, so transparency is just 'copied' as is. magick koala.gif -alpha set -region 30x30+10+10 \\ -background None -rotate 30 koala\_region\_rotate\_2.gif [![[IM Output]](koala_region_rotate_2.gif)](koala_region_rotate_2.gif) As you can see IM uses a [Copy Composition](../compose/#copy) , so that any transparency that exists in the region image, will also be copied to the original image. If for some reason you want the original image to preserve its original transparency, [Turn off the Alpha](#alpha_off) first, then after the region image has been restored, [Turn it on again](#alpha_on) so as to restore it. Region Images which are enlarged or shrunk, may not 'fit' back into the original. For example, here I resize (and color) the region image so it becomes smaller... magick koala.gif -region 30x30+10+10 \\ -resize 75% -fill red -colorize 30% koala\_region\_shrink.gif [![[IM Output]](koala_region_shrink.gif)](koala_region_shrink.gif) As you can see the original region was not covered by the region image that was restored. As such those parts not covered were not replaced. In a similar way, if the region becomes larger, more of the original image may become covered by the overlaid region image. magick koala.gif -region 30x30+10+10 \\ -resize 150% -fill red -colorize 30% koala\_region\_enlarge.gif [![[IM Output]](koala_region_enlarge.gif)](koala_region_enlarge.gif) In both cases the top-left offset of the region, does not move. You cannot just shrink an region image and center it within the region area, nor can you position the region image in another position. Caution should be exercised to prevent region images from changing size. Though in some special circumstances you can still handle a resized region. For an example of this look at the 'wave distortion' example above. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Like "`[mogrify](../basics/#mogrify) `" you cannot merge multiple sub-images as that requires the use of a non-simple image operation. However you can use "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" as an alternative composition method. See [Alpha Composition in Mogrify](../basics/#mogrify_compose)
for an example.

_ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _At the time of writing, the 'region image' still contains the [Crop Virtual Canvas Offset](../crop/#crop)
from its extraction from the original image. This may, or may not be regarded as a bug, depending on if you find this information useful or not. The offset is currently not used when a region image is restored.

If the offset is not wanted (as it interferes with an operator such as [Distort](../distorts/#distort)
), follow the "`[-region](https://imagemagick.org/script/command-line-options.php?#region) `" option by a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator to remove the offset, from the region images. Its removal or modification will not effect its restoration back onto the original image.

_ | * * * Background Removal ------------------ One of the most common problems in image processing is mask generating from a existing fully-opaque image. Such images are commonly downloaded from the World Wide Web, or generated by programs, or in image formats that don't provide any form of transparency. It may also be that you have a photo of some object, and want to remove the background. Remember photos do not have any understanding of transparency, so you need to remove the unwanted parts yourself. Unfortunately there is no general solution to this problem, especially when you also want to retain any semi-transparent edging to the image. Consequentially their are hundreds of ways and variations on doing this task, all dependant on the exact situation. Closely related to image masking is transparency adjustments to match a background that an image is going to be overlaid on. This is talked about in detail as part of saving to the [GIF Image File Format](../formats/#gif) which only allows Boolean transparency. ### Masking Simple Backgrounds (floodfill) When an images background is a simple single solid color, you can often generate simple masks (and background removal) by just doing [Replacing Colors in Images](../color_basics/#replace) . For example, here is a direct floodfill masking of an image with a solid color background. magick cyclops.png -alpha set -channel RGBA \\ -fuzz 1% -fill none -floodfill +0+0 white \\ cyclops\_flood\_1.png [![[IM Output]](cyclops_flood_1.png)](cyclops_flood_1.png) Well that did not work, as the floodfill 'seed' point in the top-right corner does not actually reach all parts of the image!!! The solution to this is to enlarge the image slightly, so as to provide a path for the floodfill to reach all the outside edges of the image. However for this you need to know the color of the background. magick cyclops.png -bordercolor white -border 1x1 \\ -alpha set -channel RGBA -fuzz 1% \\ -fill none -floodfill +0+0 white \\ -shave 1x1 cyclops\_flood\_2.png [![[IM Output]](cyclops_flood_2.png)](cyclops_flood_2.png) Of course we did not specify a very good [Fuzz Factor](../color_basics/#fuzz) . The problem with this is that you get a halo around the object within the image. This is because most images contain special pixels along the edges which smooths the look of the image. However as this image has a good black border to it, relative to the background, using a nice large fuzz setting can be used to nicely separate the image from the background. magick cyclops.png -bordercolor white -border 1x1 \\ -alpha set -channel RGBA -fuzz 20% \\ -fill none -floodfill +0+0 white \\ -shave 1x1 cyclops\_flood\_3.png [![[IM Output]](cyclops_flood_3.png)](cyclops_flood_3.png) This technique has some problems with it. First it is an all or nothing masking of the image, producing edges that are aliased, staircase-like and often horrible looking. This is fine for the limited GIF image file format, but not very good if you plan to overlay that image onto another background. It is also very very difficult to get every anti-aliasing edge pixel. As such if I overlay the above image on a black background, you may see some pixels that are much whiter that normal. magick cyclops\_flood\_3.png -background black -flatten \\ cyclops\_flood\_3\_over.png [![[IM Output]](cyclops_flood_3_over.png)](cyclops_flood_3_over.png) Also if you do manage to use a high enough fuzz factor, you are likely to have the problem of having very little edging pixels left, or 'leaking' into the center of the image. Finally a direct flood fill like this does not work for a background that isn't a simple single solid color. ### Cutting Out Bordered Objects Images with an existing single color border has a distinct advantage for these methods of background removal, as the border provides a definite boundary between what is 'inside' and what is 'outside' the image, and that in turn allows use a better method of specifying the boundary of the background image. That is, rather than specifying what colors should be regarded as background, we can instead specify what colors mark the border of the object being masked. Further more, as the border color is known, only two specific colors will have been mixed together around the edges of the image. That is, both colors are known, and so exactly how transparent the edges should be is also very well known. **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** ### Removing a Known Background While removal of a simple background to a 'Boolean' mask, is relatively straight forward, things get more complicated when the background is not so simple. However if the background itself is known. you can use that to help in its removal from other images. As of IM v6.3.4 a special [Alpha Composition](../compose/compose) method was added called '`[ChangeMask](../compose/#changemask) `' which allows for the direct removal of a known background from an image. For example, here we have an unaltered background image, and one that has been overlaid by a GIF image with a simple Boolean (straight on/off) transparency. By using '`[ChangeMask](../compose/#changemask) `' we can recover that original overlaid image (if it is very different to the background). magick overlay\_figure.gif overlay\_bgnd.gif \\ -compose ChangeMask -composite overlay\_removed.png [![[IM Output]](../images/overlay_figure.gif)](../images/overlay_figure.gif) [![[IM Output]](../images/overlay_bgnd.gif)](../images/overlay_bgnd.gif) ![==>](../img_www/right.gif) [![[IM Output]](overlay_removed.png)](overlay_removed.png) Basically what this does is determine how 'different' the pixels are from one image to the other, and is the difference is less than the current [Fuzz Factor](../color_basics/#fuzz) , then make that pixel transparent. Only fully transparent pixels are added to the image, otherwise the original image is left as is, transparency and all. We can simulate the operator by using the older '`[Difference](../compose/#difference) `' composition method to generate a [Comparison Difference Image](../compare/#difference) ... magick composite overlay\_figure.gif overlay\_bgnd.gif \\ -compose Difference overlay\_difference.png [![[IM Output]](../images/overlay_figure.gif)](../images/overlay_figure.gif) ![==>](../img_www/bar.gif) [![[IM Output]](../images/overlay_bgnd.gif)](../images/overlay_bgnd.gif) ![==>](../img_www/right.gif) [![[IM Output]](overlay_difference.png)](overlay_difference.png) As you can see the difference image is black for all the unchanged parts and a mix of colors for the parts which has changed.By separating and adding the individual color channels together and thresholding we get a mask of any difference in any channel between the two images. magick overlay\_difference.png -channel RGB -separate +channel \\ -evaluate-sequence add -threshold 0 overlay\_mask.png [![[IM Output]](overlay_mask.png)](overlay_mask.png) Using this mask we can set anything that has not changed to transparency. magick overlay\_figure.gif overlay\_mask.png \\ -alpha off -compose CopyOpacity -composite \\ overlay\_removed.png [![[IM Output]](overlay_removed.png)](overlay_removed.png) As you can see the '`[ChangeMask](../compose/#changemask) `' composition method makes this process a lot easier. However this only presents a 'on/off' style of background masking. It does not allow for fuzzy or anti-aliased edges, or transparent feathering of the result. ### Difference Image Masking and Feathering The above can be taken further to images that have aliased edges. as well as non-simple backgrounds. For example, Here we have a 'Cyclops' on a white background, which we want to extract. We then generate gray-scale image of the differences between this image and the background color (as defined by top-left most pixel). magick cyclops.png \\( +clone -fx 'p{0,0}' \\) \\ -compose Difference -composite \\ -modulate 100,0 -alpha off difference.png [![[IM Output]](cyclops.png)](cyclops.png) [![[IM Output]](difference.png)](difference.png) Of course this difference image is no good as a mask directly. If you did use it you will effectively make most of your image semi-transparent, instead of just the surrounding background. However from this difference image, huge number of different transparency masks can be created, depending on exactly what you are trying to achieve. We can adjust the above difference image to produce a mask of all pixels that are even the smallest amount different from the background color. magick difference.png -threshold 0 boolean\_mask.png magick cyclops.png boolean\_mask.png \\ -alpha off -compose CopyOpacity -composite \\ cyclops\_boolean.png [![[IM Output]](boolean_mask.png)](boolean_mask.png) [![[IM Output]](cyclops_boolean.png)](cyclops_boolean.png) As you can see a boolean 'any difference' resulted in a good amount of the original background being included. This is because the original image is either 'anti-aliased' or blurred slightly with the background (in this case it was caused by the original image being resized from a JPEG format image). This would not be a problem if the original image was itself a Boolean overlay (EG a GIF format image, overlaid on a background). In that case your result will be perfect (see the 'ChangeMask' example above). By varying the "`[-threshold](https://imagemagick.org/script/command-line-options.php?#threshold) `" you can add a 'fuzz factor' to the boolean (on/off only) mask, so as to get the mask closer to the image proper. magick difference.png -threshold 15% threshold\_mask.png magick cyclops.png threshold\_mask.png \\ -alpha Off -compose CopyOpacity -composite \\ cyclops\_threshold.png [![[IM Output]](threshold_mask.png)](threshold_mask.png) [![[IM Output]](cyclops_threshold.png)](cyclops_threshold.png) Notice that the eye of the cyclops image is now also regarded as being a transparent **hole**! This 'hole' highlights the biggest drawback with this whole technique. Parts of the image object which are close to the background color, or worse still, exactly matches the background, will be thought of as being the same as the background. Of course this may be desirable in images of 'holey' object, such as a donut, but for our cyclops, a 'holey eye' is definitely a mistake. The original 'halo' effect can also be desirable for some things like text to make it more readable when you want to overlay it again on some other 'noisy' background. You can enhance the halo effect by blurring the mask a little before applying it, so that the resulting 'halo' becomes diminished by distance. magick difference.png -bordercolor black -border 5 \\ -threshold 10% -blur 0x3 halo\_mask.png magick cyclops.png -bordercolor white -border 5 halo\_mask.png \\ -alpha Off -compose CopyOpacity -composite cyclops\_halo.png [![[IM Output]](halo_mask.png)](halo_mask.png) [![[IM Output]](cyclops_halo.png)](cyclops_halo.png) The resulting 'halo' effect can be further modified by using more [Histogram Adjustments](../color_mods/#histogram) on the mask image, giving you very precise control of the results for specific images. With the right parameters you can adjust the surrounding halo until it is practically non-existent, though eliminating it completely in this way is difficult. See next section for an improved technique. A small amount of blurring (say "`-blur 0x0.707`" or square rot of 2) is actually recommended when generating threshold masking, just to smooth out the edging of the mask. Of course the result will not be boolean, so don't try to save it to a GIF format image file. This is also an example of [Blur Feathering](../blur/#feathering) . But be warned that it is not quite the same as true [Feathering Shapes using Distance](../morphology/#distance_feather) . However when dealing with 'bitmap' or 'threshold masks' such as we created above, a small amount of blur feathering, followed by a larger amount of distance feathering, will probably result in the best overall result. ### Recovering Semi-Transparent Edges The [Difference Masking](#difference) technique that we used above can be used with the previous [FloodFill Masking](#floodfill) technique to solve most of the problems we have seen with simpler masking techniques. Here we look at a multi-layered masking technique, but one that should produce near ideal removal of the images background, while preserving the anti-alias shading pixels along the edge. However this is limited to images on a known background, and having a good contrasting 'edge' to the foreground pixels. For this example I decided to use something that was very hard to separate, but which showed a LOT more shaded pixels around the edges than you would typically have for anti-aliasing purposes. A shape with a shadow effect. magick -size 70x60 xc:none -font Candice -pointsize 50 -stroke black \\ -fill black -annotate +12+42 'A' -channel RGBA -blur 0x3 \\ -fill tile\_disks.jpg -annotate +10+40 'A' \\ tile\_water.jpg -compose DstOver -composite letter.png [![[IM Output]](letter.png)](letter.png) First we will need to generate a difference image, and lucky for us we do know what the background image is. Of course it will work just as well for a plain colored background too, as long as their is a good contrast to let use generate two masks. Basically by using a difference image we can remove any influence of the background image, and from that generate the masks we will be using. magick letter.png tile\_water.jpg \\ -compose Difference -composite \\ -modulate 100,0 -channel B -evaluate set 0 \\ -alpha Off diff\_mask.png [![[IM Output]](diff_mask.png)](diff_mask.png) Note that this time I processed the grayscale difference image slightly, limiting it to red and green channels, while clearing out the blue channel, producing a black-yellow difference image. This is tricky as it frees 'blue' channel to allow the generation of a clean floodfill mask, separate to the difference image itself. Technically I could clear the green channel as well so I can use it for the second mask. But lets not get ahead of ourselves. Now we need two masks: an outside mask, defining of all areas that will definitely be transparent; and a mask which defines the inside of the object in the image, without generating any unwanted 'holes'. So lets flood fill the image from the outside inward, using a number of different fuzz factors, so we can pick the two inside and outside masks we will use. for fuzz in 01 03 06 28 32 34; do \ magick diff_mask.png -fill blue -fuzz $fuzz% \ -bordercolor black -border 1x1 -floodfill +0+0 black \ -shave 1x1 diff_mask_$fuzz.png; \ done | | | | | | | | | --- | --- | --- | --- | --- | --- | --- | | [![[IM Output]](diff_mask_01.png)](diff_mask_01.png)

\-fuzz 1% | [![[IM Output]](diff_mask_03.png)](diff_mask_03.png)

\-fuzz 3% | [![[IM Output]](diff_mask_06.png)](diff_mask_06.png)

\-fuzz 6% | ![==](../img_www/bar.gif) | [![[IM Output]](diff_mask_28.png)](diff_mask_28.png)

\-fuzz 28% | [![[IM Output]](diff_mask_32.png)](diff_mask_32.png)

\-fuzz 32% | [![[IM Output]](diff_mask_34.png)](diff_mask_34.png)

\-fuzz 34% | The blue areas in the above images is the area being masked. Remember we cleared the blue channel for this purpose. The first mask should mask the areas of the image we definitely want to make full-transparent. That is, the parts we definitely expect to be fully transparent on the final image. The area inside the mask should still contain most of the black halo shadow of the image. In this case we have a lot of interaction between the image proper and the rest of the background so I chose a [Fuzz Factor](../color_basics/#fuzz) of '`1%`' which still contained a large area surrounding the image. In a more typical non-shadowed case this area can be even smaller, down to a non-percentile value such as 5 or 10. The second mask should have large enough 'fuzz' so as to eat up all the semi-transparent pixels that is present. That is, right up to and preferably actually into border of the image without completely removing the border, or 'leaking' into the image proper (see last image above). The negative of this mask will actually represent all the pixels that will be fully-opaque (and thus represent the inside) in the final image. This selection can be difficult and may require a lot of trial and error to figure out the best value to use. For this image a very high fuzz '`32%`' was able to be chosen without any major problems. Basically you want to try and get it high enough that the final image will not contain any of the original 'background' pixels in it, but without the mask eating away (or leaking into) the inside the image. It may even require a little hand editing to get the mask just right when you have a gap in the surrounding 'edge' color. We can now use this mask to extract the 'core' or inside of our image. That is the parts we are sure does not contain any semi-transparency through to the background pattern we are removing. magick diff\_mask\_32.png -channel blue -separate +channel -negate \\ letter.png +swap -alpha Off -compose CopyOpacity -composite \\ letter\_inside.png [![[IM Output]](letter_inside.png)](letter_inside.png) Note how I extracted the blue mask from the flood-filled masked images. Also due to the all-or-nothing nature of flood-filling, the mask will show heavy stair-casing or alias effects around the edges. This is the problem the second mask will allow us to fix. Remember this image is only of the pixels that we know does not interact with the original background, and will be left as is, in the final image. It does not include any of the shadow effects, and anti-aliasing pixels that I am specifically attempting to recover. Recovering those pixels is where the real work lies. By negating and subtracting (multiplying) the masks we can generate a new mask which defines the area where we want to extract semi-transparent edging or shadowing pixels... magick diff\_mask\_01.png -negate diff\_mask\_32.png \\ -channel blue -separate +channel -compose multiply -composite \\ mask\_aliasing\_area.png [![[IM Output]](mask_aliasing_area.png)](mask_aliasing_area.png) This area is then used to extract the anti-aliasing pixels from the difference mask, which defines how transparent the pixels should be. We normalize those pixels to get a smooth transition from opaque to transparency. magick diff\_mask.png -channel red -separate +channel \\ mask\_aliasing\_area.png -alpha Off -compose CopyOpacity -composite \\ -background gray30 -compose Over -flatten -normalize \\ mask\_antialiased\_pixels.png [![[IM Output]](mask_antialiased_pixels.png)](mask_antialiased_pixels.png) The lighter the color in the above mask, the more opaque the pixel will be. Similarly the darker the color, the more transparency it will be. Note that I used a gray background here to ensure that the transparent colors that is present in the image will not interfere with the [Normalization](../color_mods/#normalize) of the image. Without this this normalization will fail. The flat gray color itself is not important as they are outside the mask area, so will be ignored later. Now that we have the right transparency level, we need to know what color should be used for these semi-transparent pixels. This color will usually be the same as the edge color of the image, in this case simply, black. However because of the interaction of the original background I decided to go for a dark grey color for the shadow | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _You will need to somehow figure out what color the semi-transparent pixels should be, so you can set the correct color for the anti-aliasing pixels.

This could be_

1. _A fixed edge color (EG: near-black, as in this example)_
2. _Use the color of nearest fully-opaque edge pixels (using morphology. See [Sparse Color as a Fill Operator](../canvas/#sparse_fill)
_
3. _Calculated: Once you know th alpha and the background color, you can subtract the background color to correct the pixel color. See [Background Removal using Two Backgrounds](#two_background)
below._

_Basically it depends on your image._ | While we are at it lets also re-mask the image to leave just these special edging pixels. magick mask\_antialiased\_pixels.png mask\_aliasing\_area.png \\ -compose multiply -composite -negate \\ -background '#444' -channel A -combine letter\_edging.png [![[IM Output]](letter_edging.png)](letter_edging.png) All that is needed is to now layer the inside 'core' of the image with the semi-transparent edging pixels. magick letter\_inside.png letter\_edging.png \\ -background none -flatten letter\_recovered.png [![[IM Output]](letter_recovered.png)](letter_recovered.png) And hey presto, we have an image with the background removed to produce a perfect anti-aliased image, with correctly recovered semi-transparent edging and shadowing You can even overlay it onto a completely different background. magick letter\_recovered.png tile\_aqua.jpg \\ -background none -compose DstOver -flatten letter\_on\_aqua.png [![[IM Output]](letter_on_aqua.png)](letter_on_aqua.png) The image I used for this example is very difficult with a large 'edge' region. Most images are not nearly so bad, but this method is probably the best and most universal background removal technique. This has now been placed into a shell script called "`**[bg_removal](../scripts/bg_removal) **`", which uses a single command, no temporary files, and has a number of extra options on the methods by which the masking is performed. ### Background Removal using Two Backgrounds The major problem with the previous techniques is that you really do not have enough information to completely recover all the information about the foreground object. You really need to recover two pieces of information, how transparent each pixel in the foreground object is, and what is its original color. And you can not perfectly recover both pieces of information from just one image. Even when you know exactly what the background image looks like, you cannot just subtract it from the foreground object, unless the two are very different and known colors. The problem is you simply cannot be sure if the color that is visible is really the color given (opaque), or it is some blending of some other color and the background (semi-transparent). You cannot separate the original color from the alpha value needed, unless you have a source of some extra information. The one situation in which you can completely recover all the details of a foreground object, is when you have two images containing two very different but completely known background colors. In that situation you do have enough information to recover both the color and its transparency of the foreground object, for a perfect background removal. The important factor in selecting two images, is that the background colors are as different as possible over the whole image. That is, the colors are not only color complementary, but negative in intensity in all channels. For example... [![[IM Input]](../images/match_navy.gif)](../images/match_navy.gif) [![[IM Input]](../images/match_gold.gif)](../images/match_gold.gif) While a different background color is used, both images contain exactly the same object. The object shown is not simple, but contains lots of semi-transparent colors. You can see this in the way the dark blue background is visible in the flames of the image, though this transparency is all but invisible in the lighter yellow background. By using two colors, the semi-transparent pixels of the overlaid object will become mixed with two very different colors, as a result be slightly different colors in the two images. By measuring how different each pixel is, you can determine exactly what pixels are semi-transparent, and by how much. Essentially there is enough information to allow you to perfectly recover the transparency of the overlaid object. Recovery the transparency or 'mask' is of course the first step, and is actually a very straight forward step. Generate a difference image, then merge and maximize the differences found in each channel. magick match\_navy.gif match\_gold.gif \\ -compose difference -composite -separate \\ -evaluate-sequence max -auto-level -negate \\ match\_alpha.png [![[IM Output]](match_alpha.png)](match_alpha.png) This resulting image is a perfect map of how transparent each pixel is. It is essentially the 'alpha mask' of the original object in the source images. However it will only work if the overlay image contains both areas of full-transparency, and full-opacity. If that is not the case instead of the normalization step ("`-evaluate-sequence max -auto-level`") in the above , you will need to divide each channel by the difference of the two background colors. That is, divide by a value between 0.0 and 1.0, the larger the difference the better. If the two background colors is pure black and pure white, then no normalization, is needed, just the difference of the two images. The difference is then [Negated](../color_mods/#negate) so tha a maximum difference produces zero alpha or full-transparency, and no difference produces maximum alpha or full opacity. The next task is harder, as the colors of each semi-transparent pixel is modified by the background, you cannot just use the alpha mask to extract the object from one of the source images. For example... magick match\_navy.gif match\_alpha.png \\ -alpha Off -compose Copy\_Opacity -composite \\ match\_bad\_colors.png [![[IM Output]](match_bad_colors.png)](match_bad_colors.png) Basically what we got was a horrible halo of the background color in the semi-transparent 'flame' of the image. Not a nice result at all. This is known as 'color spill' (a term from [Chroma Key Masking](http://en.wikipedia.org/wiki/Chroma_key) , also known as the Blue or Green Screen technique) and this can be a major problem. What we need to do is remove the background color from the semi-transparent pixels. However as we have already recovered the original images alpha channel, we know exactly how much color needs to be removed from each pixel, so as to restore the original color overlaid. To do this we not only need one of the source images, and the alpha channel we just extracted, but we also need to know the exact color of the background, in that source image. A relative easy problem when using a solid color background, as in these examples. For example, here I restore the original colors... magick match\_navy.gif match\_alpha.png -alpha Off \\ -fx "v==0 ? 0 : u/v - u.p{0,0}/v + u.p{0,0}" \\ match\_alpha.png -compose Copy\_Opacity -composite \\ match\_recovered.png [![[IM Output]](match_recovered.png)](match_recovered.png) I used top-left corner pixel (FX formula '`u.p{0,0}`') in the source image as the background color to remove from semi-transparent pixels. Adjust this or directly substitute the color to remove if needed. The key to the color restoration, is the complex [FX](../transform/#fx) blended subtraction operation in the above. This will enhance the original color ('`u`') of the source image according to the alpha mask ('`v`'), then subtract the background color (`u.p{0,0}` or the top-left corner pixel) from the final result. The formula is not straight forward, and major thanks does to [HugoRune](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=14154) , in the IM Forum discussion [Undo a Composite -dissolve](https://magick.imagemagick.org/viewtopic.php?t=18235) for determining the mathematics needed. The discussion also goes on to exactly how all the steps work, were derived, and even how you can also extract the overlay from any two known but different background patterns. Here is the whole sequence all in one command. magick match\_gold.gif match\_navy.gif -alpha off \\ \\( -clone 0,1 -compose difference -composite \\ -separate -evaluate-sequence max -auto-level -negate \\) \\ \\( -clone 0,2 -fx "v==0?0:u/v-u.p{0,0}/v+u.p{0,0}" \\) \\ -delete 0,1 +swap -compose Copy\_Opacity -composite \\ match\_recovered\_2.png [![[IM Output]](match_recovered_2.png)](match_recovered_2.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _In IM v6.6.8-3, if FX references a transparent pixel using 'p{}' it gets zero values rather than the actual fully-transparent color values! This is a bug and was reported and fixed in IM v6.6.8-5. It is not known when the bug was introduced.

This was only a problem, if you decide to merge the alpha image into the source image first, then try to fix semi-transparent or 'spill' colors, using the known background color._ | This time the 'gold' background image was used for the color extraction, and was selected by the '`0`' in the second "`[-clone](https://imagemagick.org/script/command-line-options.php?#clone) `" operation, but either source image could have been used. Just one warning. The above assumes the top-left pixel is the unadulterated background color. If it isn't you may have to modify the command to specify a specific pixel color, or use a third image that does contain the correct background color information. The latter method is vital if the background color is not constant across the image, though even that complication can be fixed. Here is the simpler sequence for images overlaid on a pure black and a pure white background color. In this case the colors are always recovered from the black background image, as it is just a simple division, and thus a faster [Divide Composition](../compose/#divide) can be used instead of the painfully slow [FX DIY Operator](../transform/#fx) . magick match\_black.gif match\_white.gif -alpha off \\ \\( -clone 0,1 -compose difference -composite -negate \\) \\ \\( -clone 0,2 +swap -compose divide -composite \\) \\ -delete 0,1 +swap -compose Copy\_Opacity -composite \\ match\_recovered\_3.png [![[IM Input]](../images/match_black.gif)](../images/match_black.gif) [![[IM Input]](../images/match_white.gif)](../images/match_white.gif) ![==>](../img_www/right.gif) [![[IM Output]](match_recovered_3.png)](match_recovered_3.png) **Studio photos for background recovery**The ideal backgrounds are a matte (non-reflective) black, and simple pure (non-reflective) white. The background should also be as smooth and unvarying shade as possible. For making photos specifically for background removal, using two complementary colors may work better. Say taking photos with a green and magenta backdrop. Basically you will need to some how replace the background color screen before taking the second photo. Note that order of the two photos does not matter in the background removal, but they should be a clean and uniform as possible, and the primary object and camera must remain perfectly steady and fixed. A better method may be to simply place a white screen well distanced behind the object and uniformly light that screen using two different colored lamps so as not produce any shadows from the object. With this technique you can switch to the other background color, without needing any physical change in the studio to take two photos with two different backgrounds. These two color background techniques should work well for transparent objects, but reflections, and or background warping or 'lens' effects by the object being photographed will not be recorded by the technique, only its transparency. On the other hand reflections of a constant light source on the object will be preserved! _If you try this please let us know, and give an example of your source photos and results for inclusion here. You will be named with a pointer to your site for people to look at._ **Video background recovery**If you have a large enough series of images with many different but complex backgrounds (such as a video), you can try taking a minimum and maximum value of all the images to generate a near pure black and white background image for use. The more images, the better this works. With those two images any constant logo and its semi-transparency can be extracted, and the same technique can then be used to remove it from all the frames. However it will only work for a constant semi-transparent overlay, and may not work for logos that use color or hue distortions, or even a solid color logo. But it will will at least let you determine the exact logo shape. For logos that are fully opaque or more difficult, hole filling (see next) can then be used to fill in missing detail from surrounding colors. See the [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=18235) for more details. * * * Hole Filling ------------ While masking, adding transparency, and removing background provide one way of dealing with unwanted elements, often a 'hole' is not what you actually want as a result. Sure you can just overlay images with holes over other images to fill them, but that may not provide a seamless result. To erase elements from an image, you don't just want to cut them out, but replace them with colors, shades, and textures of parts that surround the hole. The following are various techniques for determining what to use to fill-in that hole. ### Creating a hole to fill Suppose we have an image with some ugly text... magick zelda\_tn.gif -gravity Southwest -annotate +8+20 Zelda zelda\_text.jpg Well what we really want to do is remove that text, and the simplest way is to mask it, so as to leave a 'hole' where the text was. This simplifies the problem, as it no longer matters what was removed. We just have a hole to be filled.[![[IM Output]](zelda_text.jpg)](zelda_text.jpg) For this case however I'll create a mask using a drawn line that covers the 'ugly text', as if an user had quickly used an image editor. magick -size 120x90 xc:black -stroke white -strokewidth 7 \\ -draw 'stroke-linecap round line 9,62 36,63' \\ -threshold 10% zelda\_text\_mask.gif [![[IM Output]](zelda_text_mask.gif)](zelda_text_mask.gif) Just the creating of the 'hole' itself can be a tricky matter, and an automated solution may depend on exactly what you are trying to remove, or even involve comparing hundreds of images with the same 'text' or 'logo' to locate it exactly. Note that a smaller the hole is the better the final result. The more information that can be preserved from the original image, the better the result will be. A rough oddly shaped hole is also better than a very smoothly outlined hole. So taking your time to make the smallest hole that removes all unwanted effects, can make a big difference.Now lets use the mask to cut a hole out of the image, which will also check that it covers all the unwanted parts. magick zelda\_text.jpg \\( zelda\_text\_mask.gif -negate \\) \\ -compose CopyOpacity -composite zelda\_text\_hole.png So here we have an image with a 'hole' in it that needs to be filled.[![[IM Output]](zelda_text_hole.png)](zelda_text_hole.png) ### Blurred Fill So we have a hole, that needs to be fill with some color. Something that will not look like we have actually removed somethign from the image.One of the simplest methods is to simply blur the image, allowing the colors around the hole to 'spread' into the hole, and then remove the transparency. magick zelda\_text\_hole.png -blur 0x1 -alpha off zelda\_text\_fill.png The amount of blur you use depends on the size of the hole used.[![[IM Output]](zelda_text_fill.png)](zelda_text_fill.png) Now how we can [underlay](../compose/#dstover) this blurred image to 'fill the hole' that we previously made... magick zelda\_text\_hole.png zelda\_text\_fill.png \\ -compose Dst\_Over -composite zelda\_text\_removed.png [![[IM Output]](zelda_text.jpg)](zelda_text.jpg) ![==>](../img_www/right.gif) [![[IM Output]](zelda_text_hole.png)](zelda_text_hole.png) [![[IM Output]](zelda_text_fill.png)](zelda_text_fill.png) ![==>](../img_www/right.gif) [![[IM Output]](zelda_text_removed.png)](zelda_text_removed.png) And the text has been removed. This isn't perfect, as the blurring of colors in that area makes it obvious that something was removed. For example if you closely look at the window frame next to Zelda's head, you can see the effects of the blur. Also the area looks 'smoother' than the rest of the image, which is particularly noticeable on photos. But it is a wide spread and fast technique, and you will often see this in videos, where they have attempted to remove the logos some TV broadcaster had added as a copyright prevention method. An alternative to trying to hide the removal is to make the actual removal noticeable. For example if you want to [Protect Someone's Anonymity](../photos/#anonymity) . **![](../img_www/const_barrier.gif) Under Construction ![](../img_www/const_hole.gif)** Links to other methods. Resize blurring hole filling method... [Sparse Color, Shepard's Method (fast)](../canvas/#sparse_blur) . See also [snibgo, Filling holes](http://im.snibgo.com/fillholes.htm) Blurring Edge Pixels only...[Sparse Color as a Fill Operator](../canvas/#sparse_fill) . See also [snibgo, Filling holes in priority order](http://im.snibgo.com/fillholespri.htm) I would like to use a morphology operator that sets color in the color channels while working out distance in a hidden background channel. This should generate a very fast no-leak Shepard's like fill known as, '**Color Diffusion**'. See the paper [Diffusion Curves](http://artis.imag.fr/Publications/2008/OBWBTS08/) which makes heavy use of this technique. A large and old discussion on hole filling (text removal) is on the IM Users Forums [Text Removal Discussion](https://magick.imagemagick.org/viewtopic.php?p=41498) . A newer discussion is [Fill area with nearest colour from boundary](https://magick.imagemagick.org/viewtopic.php?p=138971) , which is more about filling without blurring. Some other non-IM methods of 'hole filling' to erase parts of images is shown on [Stack Overflow, Remove text from jpeg](https://stackoverflow.com/questions/52461350/remove-text-from-jpeg) . For example Using [Python Skimage](http://scikit-image.org/docs/dev/api/skimage.restoration.html#inpaint-biharmonic) . Or using [Python OpenCV inpainting](https://docs.opencv.org/3.0-beta/modules/photo/doc/inpainting.htmlhttps://docs.opencv.org/3.4.0/df/d3d/tutorial_py_inpainting.html) --- # Cutting and Bordering -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Cutting and Bordering ========================================================================= **Index** [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) [![](../img_www/granitesm_right.gif) Crop (cutting up images in a free form way)](#crop) * [The basic crop operator](#crop) * [The Missed Image (from a bad crop)](#crop_missed) * [Crop an Image with Existing Virtual Canvas](#crop_page) * [Removing Virtual Canvas from Results](#crop_repage) using +repage **\*\*\*** * [Viewport Crop with Virtual Canvas Adjustments](#crop_viewport) * [Crop Relative to Gravity](#crop_gravity) * [Crop a Percentage of an Image](#crop_percent) * [Tile Cropping, sub-dividing one image into multiple images](#crop_tile) * [Centered Tile Cropping, leaving remainders around the edge](#crop_tile_centered) * [Strip Cropping, cropping out rows and columns](#crop_strip) * [Quadrants, cutting around a single point](#crop_quad) * [Using Negative Offsets, remove bottom or left edge](#crop_neg_offset) * [Cropping into roughly Equally Sized Divisions](#crop_equal) * [Separating Spaced-out Tiling Images](#crop_spaced) [![](../img_www/granitesm_right.gif) Adding/Removing Image Edges](#border) * [Border, adding space around the edge of an image](#border) * [Frame, adding 3D-like borders to images](#frame) * [Shave, removing the edges from images](#shave) * [Extent, direct image size adjustment](#extent) [![](../img_www/granitesm_right.gif) Adding/Removing Rows, Columns and Edges](#splice) * [Splice, adding a row, column or edge](#splice) * [Chop, removing a row, column or edge](#chop) [![](../img_www/granitesm_right.gif) Advanced Cropping Techniques](#advanced) * [Crop to a Given Aspect Ratio](#crop_aspect) [![](../img_www/granitesm_right.gif) Trim, the 'Auto-Crop' Operator](#trim) * [Using Trim](#trim) * [Trimming with a Specific Color](#trim_color) * [Trimming just One Side of an Image](#trim_oneside) * [Trimming 'Fuzzy' Images](#trim_fuzz) -- Low Quality JPEG Images * [Trimming 'Noisy' Images](#trim_noisy) -- Scanned or Video Images 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](https://imagemagick.org/script/command-line-options.php?#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. magick rose: rose.gif magick rose: -crop 40x30+10+10 crop.gif magick rose: -crop 40x30+40+30 crop\_br.gif magick rose: -crop 40x30-10-10 crop\_tl.gif magick rose: -crop 90x60-10-10 crop\_all.gif `magick rose: -crop 40x30+90+60 crop_miss.gif` [![[IM Output]](rose.gif)](rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](crop.gif)](crop.gif) [![[IM Output]](crop_br.gif)](crop_br.gif) [![[IM Output]](crop_tl.gif)](crop_tl.gif) [![[IM Output]](crop_all.gif)](crop_all.gif) [![[IM Output]](crop_miss.gif)](crop_miss.gif) Just so you can check on exactly what happened here is output from "`magick identify`" on the results of the crop above. magick identify rose: crop.gif crop_br.gif crop_tl.gif \ crop_all.gif crop_miss.gif [![[IM Text]](crop_indent.txt.gif)](crop_indent.txt) Notice that the size of the displayed image (its [Virtual Canvas](../basics/#virtual_canvas) ) has not been effected by the "`[-crop](https://imagemagick.org/script/command-line-options.php?#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](../basics/#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 (using [image layering operators](../layers/#flatten) back over the original, it will fit back exactly where the sub-image originally came from. That is, IM retains the 'virtual canvas', 'page', or 'layering' information of the image so as to preserve it for later use. This is especially important for the correct working for GIF animation handling. For more information on this see. [Deconstruct GIF Animations](../anim_basics/#deconstruct) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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](https://imagemagick.org/script/command-line-options.php?#repage) `" immediately after the "`[-crop](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#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.

_ | Note, the behavior of cropping can be affected by these defines: | | | | --- | --- | | trim:percent-background=X% | Set the amount of background that is tolerated in an edge. It is specified as a percent. 0% means no background is tolerated. 50% means an edge can contain up to 50% pixels that are background per the fuzz-factor. | | trim:edges={north,east,south,west} | Only trim the specified edges of the image. | | trim:minSize=geometry | Limit the trim to the specified size. | | type:features=string | Add a font feature to be used by the RAQM delegate during complex text layout. This is usually used to turn on optional font features that are not enabled by default, but can be also used to turn off default font features. Features include those to control kerning, ligature and Arabic. | | type:hinting=false | Disable font hinting. Proper glyph rendering needs the scaled points to be aligned along the target device pixel grid, through an operation often called hinting. One of its main purposes is to ensure that important widths and heights are respected throughout the whole font. (For example, it is very often desirable that the ‘I’ and the ‘T’ glyphs have their central vertical line of the same pixel width. Hinting also manages features like stems and overshoots, which can cause problems at small pixel sizes. | ### 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](#crop) , [Trim](#trim) , [Layer Comparison](../anim_basics/#compare) , and even [GIF Animation Optimizations](../anim_opt/#optframe) , that generate empty or non-sensible results. For example in the previous example above, the "`[-crop](https://imagemagick.org/script/command-line-options.php?#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]](crop_error.txt.gif)](crop_error.txt) 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](https://imagemagick.org/script/command-line-options.php?#crop) `", but as no image format can output an image of 'zero' dimensions, a single transparent pixel image is used instead. Just so you can see more clearly, here is the "`[identify](../basics/#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. magick identify crop_miss.gif [![[IM Text]](crop_miss_ident.txt.gif)](crop_miss_ident.txt) magick crop\_miss.gif crop\_miss\_data.txt [![[IM Text]](crop_miss_data.txt.gif)](crop_miss_data.txt) This 'missed' image is basically same as creating a "`[null:](../files/#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](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#quiet) `" [Operational Control Setting](../basics/#controls) 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:](../files/#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 Virtual Canvas If an image already has an existing [Virtual Canvas](../basics/#virtual_canvas) , (for example a frame of a GIF animation), then the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operation will be applied relative to the virtual canvas, and NOT to the actual image. That is, it will try to preserve the offset of the actual pixel data of the cropped image on the canvas. That is, a specific pixel before the crop should still be located at the same offset relative to the virtual canvas afterward. In this way cropping of layered images, or 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. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -crop 32x32+16+16 crop_page.gif magick paged.gif -crop 32x32+0+0 crop_page_tl.gif magick paged.gif -crop 32x32+32+32 crop_page_br.gif magick paged.gif -crop 60x60+2+2 crop_page_all.gif magick paged.gif -quiet -crop 32x32+56+56 crop_page_miss.gif magick identify paged.gif crop_page.gif crop_page_tl.gif crop_page_br.gif \ crop_page_all.gif crop_page_miss.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](crop_page.gif)](crop_page.gif) [![[IM Output]](crop_page_tl.gif)](crop_page_tl.gif) [![[IM Output]](crop_page_br.gif)](crop_page_br.gif) [![[IM Output]](crop_page_all.gif)](crop_page_all.gif) [![[IM Output]](crop_page_miss.gif)](crop_page_miss.gif) [![[IM Text]](crop_page_ident.txt.gif)](crop_page_ident.txt) That last example in the above was of course, the special [Missed Image](#crop_missed) . Note that I suppressed the normal warning message from IM using a "`[-quiet](https://imagemagick.org/script/command-line-options.php?#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. magick paged.gif -page 64x64+32+32 -size 32x32 xc:'#fff8' \\ -alpha set -background none -mosaic crop\_area\_br.png [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](crop_area_br.png)](crop_area_br.png) ![==>](../img_www/right.gif) [![[IM Output]](crop_page_br.gif)](crop_page_br.gif) 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 Virtual Canvas from Results If this [Virtual Canvas](../basics/#virtual_canvas) information is not wanted, then you can use the special "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator to reset the page canvas and position to match the actual cropped image. magick rose: -crop 40x30+10+10 +repage repage.gif magick rose: -crop 40x30+40+30 +repage repage\_br.gif magick rose: -crop 40x30-10-10 +repage repage\_tl.gif magick rose: -crop 90x60-10-10 +repage repage\_all.gif magick rose: -quiet -crop 40x30+90+60 +repage repage\_miss.gif [![[IM Output]](rose.gif)](rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](repage.gif)](repage.gif) [![[IM Output]](repage_br.gif)](repage_br.gif) [![[IM Output]](repage_tl.gif)](repage_tl.gif) [![[IM Output]](repage_all.gif)](repage_all.gif) [![[IM Output]](repage_miss.gif)](repage_miss.gif) This is of course the result new users of IM would normally have expected from the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator. It is actually such a common thing to do that you could call it a rule of thumb. **Always use "`[+repage](https://imagemagick.org/script/command-line-options.php?#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 image](#crop_missed) , but I supressed the warning message using the "`[-quiet](https://imagemagick.org/script/command-line-options.php?#quiet) `" operational setting. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _For IM version 5 and earlier the "`[+repage](https://imagemagick.org/script/command-line-options.php?#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. But that was only usable when either reading or writing the image to a file, preventing its use between multiple image processing operations.__With IM version 6, [command line restructure](../basics/#cmdline)
, the "`[-page](https://imagemagick.org/script/command-line-options.php?#page) `" option became purely an image read/create setting for use in creating [GIF animations](../anim_basics/#gif_anim)
and [Layers of Images](../layers/#flatten)
. As such separate "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `" and "`[-set](https://imagemagick.org/script/command-line-options.php?#set) page`" operators were added to allow users to set or change the virtual canvas information._ | ### Viewport Cropping with Virtual Canvas Adjustments From ImageMagick version 6.2.4-5, you can add a new special flag to the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument. This flag '`!`' will tell crop to adjust the [Virtual Canvas](../basics/#virtual_canvas) 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... magick rose: -crop 40x30+10+10\\! crop\_vp.gif magick rose: -crop 40x30+40+30\\! crop\_vp\_br.gif magick rose: -crop 40x30-10-10\\! crop\_vp\_tl.gif magick rose: -crop 90x60-10-10\\! crop\_vp\_all.gif magick rose: -quiet -crop 40x30+90+60\\! crop\_vp\_miss.gif `magick identify rose.gif crop_vp.gif crop_vp_br.gif crop_vp_tl.gif \ crop_vp_all.gif crop_vp_miss.gif` [![[IM Output]](rose.gif)](rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](crop_vp.gif)](crop_vp.gif) [![[IM Output]](crop_vp_br.gif)](crop_vp_br.gif) [![[IM Output]](crop_vp_tl.gif)](crop_vp_tl.gif) [![[IM Output]](crop_vp_all.gif)](crop_vp_all.gif) [![[IM Output]](crop_vp_miss.gif)](crop_vp_miss.gif) [![[IM Text]](crop_vp_ident.txt.gif)](crop_vp_ident.txt) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#repage) `" after cropping to reset page/canvas information. However you can follow a 'viewport crop' with a [Flatten](../layers/#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](https://imagemagick.org/script/command-line-options.php?#background) `" color 'viewport'.For example when [Padding out an Image](../thumbnails/#pad) . magick rose: -crop 100x100-15-25\\! -background skyblue -flatten \\ crop\_viewport.gif [![[IM Output]](crop_viewport.gif)](crop_viewport.gif) Flattening an image after a viewport crop is actually equivalent to using the [Extent Operator](#extent) (see below), to provide a 'padded crop'. 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](../anim_mods/#crop_viewport) . In many ways a 'viewport crop' is closely related to the special [Viewport Distort Setting](../distorts/#distort_viewport) in that both act is if they are a 'window' into the resulting image. Both can be used as a 'cropping' method. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The '`!`' flag can NOT be used when generating multi-image [Tiled crops](#crop_tile)
, or with equal-area tile cropping, where it has a different meaning. See the appropriate sections below._ | ### Crop relative to Gravity The offset position of the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" by default is relative to the top-left corner of the image. However by setting the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting, you can tell "`[-crop](https://imagemagick.org/script/command-line-options.php?#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. magick rose: -gravity Center -crop 32x32+0+0 +repage crop\_center.gif [![[IM Output]](crop_center.gif)](crop_center.gif) The "`[-gravity](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#gravity) `" of '`South`', and offset of '`+0+5`' will offset the crop area upward, instead of downward as it normally would. magick rose: -gravity South -crop 20x20+0+5 crop\_south.gif [![[IM Output]](crop_south.gif)](crop_south.gif) Note the position of the crop example above. I purposely left off the "`[+repage](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#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. magick rose: -crop 50%x+0+0 crop\_half.gif [![[IM Output]](crop_half.gif)](crop_half.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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. magick rose: -crop 50%x+30+20 crop\_percent.gif [![[IM Output]](crop_percent.gif)](crop_percent.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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. magick rose: -gravity Center -crop 50x80%+0+0 crop\_percent\_center.gif [![[IM Output]](crop_percent_center.gif)](crop_percent_center.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The percentage symbol '`%`' can appear anywhere in an 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 virtual 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. magick rose: -gravity Center -crop 50%\\! crop\_percent\_vp.gif [![[IM Output]](crop_percent_vp.gif)](crop_percent_vp.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _You can not use percent sizes for tile cropping (see next). As such if the offset is not provided, and a percent size is given (as above) an offset of +0+0 is assumed.

_ | The '`!`' flag means a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" is not needed. Caution however is still recommended, for input images that may also have virtual canvas size and offsets. ### 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.. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif +gravity -crop 32x32 tiles_%d.gif magick identify paged.gif tiles_?.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](tiles_0.gif)](tiles_0.gif) [![[IM Output]](tiles_1.gif)](tiles_1.gif) [![[IM Output]](tiles_2.gif)](tiles_2.gif) [![[IM Output]](tiles_3.gif)](tiles_3.gif) [![[IM Text]](tiles_ident.txt.gif)](tiles_ident.txt) If you just want to extract a specific number of tiles from an image have a look at [Cropping into roughly Equally Sized Divisions](#crop_equal) below. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _It is a good idea to make sure gravity is turned off using "`[+gravity](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#mosaic) `" or "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" image layering operators, (see [Layer Flatten](../layers/#flatten) ) you can layer these images all on top of each other, restoring the original image. magick tiles\_\[0-3\].gif -background white -mosaic tiles\_mosaic.gif [![[IM Output]](tiles_mosaic.gif)](tiles_mosaic.gif) However as you can see the virtual canvas of the image has been filled with the background color by "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `". An alternative is to use "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) merge`" (see [Layer Merge](../layers/#merge) ), which merges the multiple layer images into a new layer image just large enough to hold all the given images. That is, the virtual canvas is not filled in, as "`[-mosaic](https://imagemagick.org/script/command-line-options.php?#mosaic) `" or "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" layering methods would. magick tiles\_\[0-3\].gif -background none -layers merge tiles\_layered.gif `magick identify tiles_layered.gif` [![[IM Output]](tiles_layered.gif)](tiles_layered.gif) [![[IM Text]](tiles_layered_ident.txt.gif)](tiles_layered_ident.txt) If you had reset the the canvas and offset information using "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" then the images no longer contain the offset from where they were cropped, nor the original size of the source image. In that case you can re-join all the images together again using the special '`concatenation`' mode of "`magick montage`". You will need to tell montage how many rows or columns of images were extracted from the original image. magick rose: -crop 20x20 +repage +adjoin rose\_tiles\_%02d.gif montage -mode concatenate -tile 4x rose\_tiles\_\*.gif rose\_rejoined.gif | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](rose_tiles_00.gif)](rose_tiles_00.gif)
[![[IM Output]](rose_tiles_01.gif)](rose_tiles_01.gif)
[![[IM Output]](rose_tiles_02.gif)](rose_tiles_02.gif)
[![[IM Output]](rose_tiles_03.gif)](rose_tiles_03.gif)

[![[IM Output]](rose_tiles_04.gif)](rose_tiles_04.gif)
[![[IM Output]](rose_tiles_05.gif)](rose_tiles_05.gif)
[![[IM Output]](rose_tiles_06.gif)](rose_tiles_06.gif)
[![[IM Output]](rose_tiles_07.gif)](rose_tiles_07.gif)

[![[IM Output]](rose_tiles_08.gif)](rose_tiles_08.gif)
[![[IM Output]](rose_tiles_09.gif)](rose_tiles_09.gif)
[![[IM Output]](rose_tiles_10.gif)](rose_tiles_10.gif)
[![[IM Output]](rose_tiles_11.gif)](rose_tiles_11.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](rose_rejoined.gif)](rose_rejoined.gif) | Note that the names of the individual images is from "`rose_tiles_00.gif`" to "`rose_tiles_11.gif`", which simply the sequence number of the tiles in memory. This is not very nice as the filenames give no easy indication of the actual position each tile belongs to, or the total number of tiles per row and column. As of IM v6.4.8-4 you can also use special [Filename Percent Escapes](../files/#save_escapes) to generate and include special labels into the output filename. Using this with [FX Percent Escapes](../transform/#fx_escapes) you can calculate a different 'tile position' for each image. For example... magick rose: -crop 20x20 \\ -set filename:tile "%\[fx:page.x/20+1\]\_%\[fx:page.y/20+1\]" \\ +repage +adjoin "rose\_tile\_%\[filename:tile\].gif" | | | | | | --- | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | ![==>](../img_www/space.gif) | [![[IM Output]](rose_tile_1_1.gif)](rose_tile_1_1.gif)
[![[IM Output]](rose_tile_2_1.gif)](rose_tile_2_1.gif)
[![[IM Output]](rose_tile_3_1.gif)](rose_tile_3_1.gif)
[![[IM Output]](rose_tile_4_1.gif)](rose_tile_4_1.gif)

[![[IM Output]](rose_tile_1_2.gif)](rose_tile_1_2.gif)
[![[IM Output]](rose_tile_2_2.gif)](rose_tile_2_2.gif)
[![[IM Output]](rose_tile_3_2.gif)](rose_tile_3_2.gif)
[![[IM Output]](rose_tile_4_2.gif)](rose_tile_4_2.gif)

[![[IM Output]](rose_tile_1_3.gif)](rose_tile_1_3.gif)
[![[IM Output]](rose_tile_2_3.gif)](rose_tile_2_3.gif)
[![[IM Output]](rose_tile_3_3.gif)](rose_tile_3_3.gif)
[![[IM Output]](rose_tile_4_3.gif)](rose_tile_4_3.gif) | Will generate the tile image filenames "`rose_tile_1_1.gif`" to "`rose_tile_4_3.gif`", which is a much better file naming scheme. Tricky but it does work. Unfortunately you can not format the number generated by a [Percent Escapes](../basics/#arg_percent) , to include padding with zeros or specify an exact number of floating point digits. At least not at this time. ### Centered Tile Cropping In a [IM Forum Discussion](https://magick.imagemagick.org/viewtopic.php?t=16276) a request was made to center the tile cropping so as to distributed he 'remainder images' evenly around the edges. By doing this we maximize the effect of the complete tiles by placing them in the center of the image. Of course you also end up with more incomplete edge tiles. The solution was to center the input image on a virtual canvas, that was some multiple of the tile size wanted. For example to tile crop the "`rose:`" image (`70x46` pixels in size) into the maximum number of full `30x20` tiles, in the center of the image (and surrounded by reminder tiles) you would do the following. 1. First calculate the number of full tiles you can get from the image by dividing the image sizes... 70x46 / 30x20 => 2x2 full tiles + remainder 2. Now add 2 more rows and columns to hold the remainder images (if needed) 2x2 + 2x2 => 4x4 tile images 3. Multiply the tile size by this to get the virtual canvas size. 30x20 \* 4x4 => 120x80 canvas size 4. Subtract the original image size and divide into two for the centering offset. ( 120x80 - 70x46 ) / 2 => +25+17 So the virtual canvas and centering offset is `120x80+25+17`. And here we use the above calculations perform a Centered Tile Crop... magick rose: -repage 120x80+25+17 -crop 30x20 +repage rose\_30x20\_%02d.gif | | | | | | --- | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | ![==>](../img_www/space.gif) | [![[IM Output]](rose_30x20_00.gif)](rose_30x20_00.gif)
[![[IM Output]](rose_30x20_01.gif)](rose_30x20_01.gif)
[![[IM Output]](rose_30x20_02.gif)](rose_30x20_02.gif)
[![[IM Output]](rose_30x20_03.gif)](rose_30x20_03.gif)

[![[IM Output]](rose_30x20_04.gif)](rose_30x20_04.gif)
[![[IM Output]](rose_30x20_05.gif)](rose_30x20_05.gif)
[![[IM Output]](rose_30x20_06.gif)](rose_30x20_06.gif)
[![[IM Output]](rose_30x20_07.gif)](rose_30x20_07.gif)

[![[IM Output]](rose_30x20_08.gif)](rose_30x20_08.gif)
[![[IM Output]](rose_30x20_09.gif)](rose_30x20_09.gif)
[![[IM Output]](rose_30x20_10.gif)](rose_30x20_10.gif)
[![[IM Output]](rose_30x20_11.gif)](rose_30x20_11.gif)

[![[IM Output]](rose_30x20_12.gif)](rose_30x20_12.gif)
[![[IM Output]](rose_30x20_13.gif)](rose_30x20_13.gif)
[![[IM Output]](rose_30x20_14.gif)](rose_30x20_14.gif)
[![[IM Output]](rose_30x20_15.gif)](rose_30x20_15.gif) | If you want to preserve the original offset location of the tiles, but remove the centering offset, you can do a relative offset adjustment using "`-repage -25-17\!`" (replacing the "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" in the above). If you did not add two columns and rows to the number of tiles and thus generate a negative offset you can effectively ignore the remainder edge tiles, and only output full and complete tiles that exist in the image. magick rose: -repage 60x40-5-3 -crop 30x20 +repage rose\_ctiles\_%d.gif | | | | | | --- | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | ![==>](../img_www/space.gif) | [![[IM Output]](rose_ctiles_0.gif)](rose_ctiles_0.gif)
[![[IM Output]](rose_ctiles_1.gif)](rose_ctiles_1.gif)

[![[IM Output]](rose_ctiles_2.gif)](rose_ctiles_2.gif)
[![[IM Output]](rose_ctiles_3.gif)](rose_ctiles_2.gif) | Basically as the remainders are now 'outside' the calculated virtual canvas the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator does not know they were there and ignores them. Again replacing the "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" in the above, with a relative offset adjustment using the negated offset values "`-repage +5+3\!`" will restore the original offset locations from which the tiles were cropped. An alternative for a centered tile crop and ignoring reminders is to simply replace the virtual canvas setting with an appropriate crop. magick rose: -gravity center -crop 60x40+0+0 +gravity +repage \\ -crop 30x20 +repage rose\_ctiles2\_%d.gif | | | | | | --- | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | ![==>](../img_www/space.gif) | [![[IM Output]](rose_ctiles2_0.gif)](rose_ctiles2_0.gif)
[![[IM Output]](rose_ctiles2_1.gif)](rose_ctiles2_1.gif)

[![[IM Output]](rose_ctiles2_2.gif)](rose_ctiles2_2.gif)
[![[IM Output]](rose_ctiles2_3.gif)](rose_ctiles2_2.gif) | The above is easier to understand, but is also a little slower, as you are now performing two crops. However less calculations are needed. But if you want to recover the original tile offsets, you will still need to calculate the relative offset you needed, in which case you may as well do the task by the former faster method using the images virtual canvas. ### Strip Cropping, cropping out rows and columns With IM version 6.1.1, a "`[-crop](https://imagemagick.org/script/command-line-options.php?#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. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -crop 20x0+30+0 strip_column.gif magick paged.gif -crop 0x20+0+30 strip_row.gif magick identify paged.gif strip_column.gif strip_row.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](strip_column.gif)](strip_column.gif) [![[IM Output]](strip_row.gif)](strip_row.gif) [![[IM Text]](strip_ident.txt.gif)](strip_ident.txt) If you remove both offsets as well as one size argument, you can divide the image into a series of strips or columns, instead of tiles. magick rose: -crop 40x30+10+10 crop.gif magick crop.gif -quiet -crop 20x strips\_%d.gif `magick identify crop.gif strips_?.gif` [![[IM Output]](crop.gif)](crop.gif) ![==>](../img_www/right.gif) [![[IM Output]](strips_0.gif)](strips_0.gif) [![[IM Output]](strips_1.gif)](strips_1.gif) [![[IM Output]](strips_2.gif)](strips_2.gif) [![[IM Output]](strips_3.gif)](strips_3.gif) [![[IM Text]](strips_ident.txt.gif)](strips_ident.txt) 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 [crop missed image](#crop_missed) is generated. The warning that IM would have normally produced was suppressed using a "`[-quiet](https://imagemagick.org/script/command-line-options.php?#quiet) `" setting. This is not recommended unless you are expecting such an event, and are prepared for it, such as in a script. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _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 part of the image.

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

The "`[-crop](https://imagemagick.org/script/command-line-options.php?#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 by using "`[+repage](https://imagemagick.org/script/command-line-options.php?#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](../scripts/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. For example, here I crop the image into quadrants around the point 30,40 magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -crop 30x40+0+0 quadrant\_tl.gif magick paged.gif -crop 0x40+30+0 quadrant\_tr.gif magick paged.gif -crop 30x0+0+40 quadrant\_bl.gif magick paged.gif -crop +30+40 quadrant\_br.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](quadrant_tl.gif)](quadrant_tl.gif) [![[IM Output]](quadrant_tr.gif)](quadrant_tr.gif) [![[IM Output]](quadrant_bl.gif)](quadrant_bl.gif) [![[IM Output]](quadrant_br.gif)](quadrant_br.gif) 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](#crop_missed) images. ### Using Negative Offsets, remove bottom or left edge Their is no reason that you can not use a negative offset with "`[-crop](https://imagemagick.org/script/command-line-options.php?#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 an image size to "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument, so it will default to the images canvas size. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -crop -10-10 neg\_offset\_1.gif magick paged.gif -crop -20-20 neg\_offset\_2.gif magick paged.gif -crop -30-30 neg\_offset\_3.gif magick paged.gif -crop -40-40 neg\_offset\_4.gif magick paged.gif -crop -50-50 neg\_offset\_5.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](neg_offset_1.gif)](neg_offset_1.gif) [![[IM Output]](neg_offset_2.gif)](neg_offset_2.gif) [![[IM Output]](neg_offset_3.gif)](neg_offset_3.gif) [![[IM Output]](neg_offset_4.gif)](neg_offset_4.gif) [![[IM Output]](neg_offset_5.gif)](neg_offset_5.gif) 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](#crop_missed) will be generated. It's a bit like using a "`[-chop](https://imagemagick.org/script/command-line-options.php?#chop) `" operator but without a "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting. See [Chop, Removing Edges](#chop) . Of course by using "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" you may need to use a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" operator to adjust the canvas/page information, where a "`[-chop](https://imagemagick.org/script/command-line-options.php?#chop) `" automatically performs such an adjustment. That's life. ### Cropping into roughly Equally Sized Divisions The biggest problem with [Tile Cropping](#crop_tile) is that you can only define the final size of each tile. This works great when the image size is an exact multiple of the desired tile size, but as you have seen if this is not the case you can end up with 'short' tiles on the right and bottom edges. For example lets again divide the built in rose image, but try to divide it into 3x3 tiles. The original image is 70x46 pixels so divided by 3 make each tile 23x15 pixels... magick rose: -crop 23x15 +repage +adjoin rose\_23x15\_%02d.gif | | | | | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](rose_23x15_00.gif)](rose_23x15_00.gif)
[![[IM Output]](rose_23x15_01.gif)](rose_23x15_01.gif)
[![[IM Output]](rose_23x15_02.gif)](rose_23x15_02.gif)
[![[IM Output]](rose_23x15_03.gif)](rose_23x15_03.gif)

[![[IM Output]](rose_23x15_04.gif)](rose_23x15_04.gif)
[![[IM Output]](rose_23x15_05.gif)](rose_23x15_05.gif)
[![[IM Output]](rose_23x15_06.gif)](rose_23x15_06.gif)
[![[IM Output]](rose_23x15_07.gif)](rose_23x15_07.gif)

[![[IM Output]](rose_23x15_08.gif)](rose_23x15_08.gif)
[![[IM Output]](rose_23x15_09.gif)](rose_23x15_09.gif)
[![[IM Output]](rose_23x15_10.gif)](rose_23x15_10.gif)
[![[IM Output]](rose_23x15_11.gif)](rose_23x15_11.gif)

[![[IM Output]](rose_23x15_12.gif)](rose_23x15_12.gif)
[![[IM Output]](rose_23x15_13.gif)](rose_23x15_13.gif)
[![[IM Output]](rose_23x15_14.gif)](rose_23x15_14.gif)
[![[IM Output]](rose_23x15_15.gif)](rose_23x15_15.gif) | Well as you can see this did not work, because the rose image can not be exactly divided into 3 equally sized tiles. In this case you end up with a 1 pixel 'short' tile. Even if you expand the size of the tile to 24x16 pixels, you will still end up with a tile that is 2 pixels 'shorter' than the other tiles. This situation gets worse as the number of tiles wanted gets larger. For example try sub-dividing a length of 100 into 30 tiles. It is impossible. You either use a length of 3 and get 34 tiles, or 4 and get 25 tiles. Getting exactly 30 equal sized tiles is impossible! As of IM v6.5.8-9 you can now add the special '`@`' flag to the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument. This flag tells the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator to try its best to equally divide the image into the _number of tiles_ given. For example... magick rose: -crop 3x3@ +repage +adjoin rose\_3x3@\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](rose_3x3@_0.gif)](rose_3x3@_0.gif)
[![[IM Output]](rose_3x3@_1.gif)](rose_3x3@_1.gif)
[![[IM Output]](rose_3x3@_2.gif)](rose_3x3@_2.gif)

[![[IM Output]](rose_3x3@_3.gif)](rose_3x3@_3.gif)
[![[IM Output]](rose_3x3@_4.gif)](rose_3x3@_4.gif)
[![[IM Output]](rose_3x3@_5.gif)](rose_3x3@_5.gif)

[![[IM Output]](rose_3x3@_6.gif)](rose_3x3@_6.gif)
[![[IM Output]](rose_3x3@_7.gif)](rose_3x3@_7.gif)
[![[IM Output]](rose_3x3@_8.gif)](rose_3x3@_8.gif) | The result is that the image was divided into tiles which have slightly different sizes. However the tile size will differ by 1 pixel at the most! Check it out! As a bonus, you can also sub-divide the image so that each tile will 'overlap' its neighbours. You do this by not only using a '`@`' flag but also specifying the number of pixels of overlap you want. For example lets divide the rose into quarters but with a 20 pixel overlap. magick rose: -crop 2x2+20+20@ +repage +adjoin rose\_2x2+20+20@\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](rose.gif)](rose.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](rose_2x2+20+20@_0.gif)](rose_2x2+20+20@_0.gif)
[![[IM Output]](rose_2x2+20+20@_1.gif)](rose_2x2+20+20@_1.gif)

[![[IM Output]](rose_2x2+20+20@_2.gif)](rose_2x2+20+20@_2.gif)
[![[IM Output]](rose_2x2+20+20@_3.gif)](rose_2x2+20+20@_3.gif) | Again all the pieces will only differ in size by one pixel at the most! Though in this case the resulting images are the same size, as the rose can divide by 2, equally. That however would not be the case if the overlap or the image was an odd number in size. In that case the bigger element will be along the top and left edge. With three tiles however the bigger (or smaller) element will be placed in the middle! You can even use a negative overlap to 'skip' exactly that many pixels between tiles! Exactly how you should apply the operator depends on exactly what pixels you want to 'overlap', or 'skip'. And that depends on the 'edge' characteristics of the image (see [Separating Spaced-out Tiling Images](#crop_spaced) below). As with any use of the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator, it is recommended you use a "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) ` to remove the 'page' offset if it is not wanted. But the cropped image offset information can be very useful, which is why it is preserved. You can for example use it to name the output files, or find out the size and locations of the tiles that IM calculated. Note that equal sized tile cropping, is the only situation in which the "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator ignores the actual virtual canvas of the image when figuring out what part of the image is cropped. That is, the calculations for tile cropping is based on real image size rather than virtual canvas size. Even so the final tile offsets will still be relative to the original virtual canvas. This crop option can also be used as an alternative to the [Shave Operator](#shave) for 'paged' images. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version v6.6.1-0, equal-sized tile cropping for images with a virtual canvas offset was broken._ | ### Separating Spaced-out Tiling Images Often you have an image that has fixed sized tiles which are separated by a fixed amount of space. The new '`@`' flag crop operator will let you more easily crop out those tiles, either including or skipping the surrounding space. The main problem however is that while the 'tile' images have a fixed amount of space around them the amount of space around the edge is usually not so fixed. This produces three basic styles of edge characteristics to a set of 'spaced' images. and each type need to be handled slightly differently. **Montaged Tiles**Here the original images were simply given a fixed sized border before being appended together. The result is that you will always have an even number of pixel spacing between tiles. More importantly the 'edge spacing' is exactly half the spacing that was placed between the tiles. This is in fact how the "`[montage](../montage/) `" spaces the tiling 'cells', and it was using this command the example shown image below was generated. As the images were just simply tiled together you can use either a normal [Tile Cropping](#crop_tile) (if you know the tile size), or use [Equal Sized Cropping](#crop_equal) (if you know the number of tiles), to separate the sub-images and the surrounding border. There is basically no overlap between the tiles, and a simple [Shave Operator](#shave) , can then be used to remove that border from the resulting tiles. magick montage.gif -crop 5x1@ +repage +adjoin montage\_%d.gif magick montage\_?.gif -shave 3x3 montage-3\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](montage.gif)](montage.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](montage_0.gif)](montage_0.gif)
[![[IM Output]](montage_1.gif)](montage_1.gif)
[![[IM Output]](montage_2.gif)](montage_2.gif)
[![[IM Output]](montage_3.gif)](montage_3.gif)
[![[IM Output]](montage_4.gif)](montage_4.gif) | | | ![==>](../img_www/right.gif) | [![[IM Output]](montage-3_0.gif)](montage-3_0.gif)
[![[IM Output]](montage-3_1.gif)](montage-3_1.gif)
[![[IM Output]](montage-3_2.gif)](montage-3_2.gif)
[![[IM Output]](montage-3_3.gif)](montage-3_3.gif)
[![[IM Output]](montage-3_4.gif)](montage-3_4.gif) | **Same Spacing around Edge**Here the sub-images were not only 'spaced-out' by 6 pixels but also has a 6 pixel spacing around the edge, making it look rather neat and tidy. This is handled by using the default [Equal Sized Cropping](#crop_equal) with the appropriate amount of pixel 'overlap'. For example... magick edged.gif -crop 5x1+6+6@ +repage +adjoin edged+6\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](edged.gif)](edged.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](edged+6_0.gif)](edged+6_0.gif)
[![[IM Output]](edged+6_1.gif)](edged+6_1.gif)
[![[IM Output]](edged+6_2.gif)](edged+6_2.gif)
[![[IM Output]](edged+6_3.gif)](edged+6_3.gif)
[![[IM Output]](edged+6_4.gif)](edged+6_4.gif) | Note how the operator separated the images so that they remain the same size, but with a 6 pixel overlap. This is specifically what it was designed to do. By using a negative offset, you tell IM that the overlapping area (spacing parts) should not be included in the final results. magick edged.gif -crop 5x1-6-6@ +repage +adjoin edged-6\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](edged.gif)](edged.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](edged-6_0.gif)](edged-6_0.gif)
[![[IM Output]](edged-6_1.gif)](edged-6_1.gif)
[![[IM Output]](edged-6_2.gif)](edged-6_2.gif)
[![[IM Output]](edged-6_3.gif)](edged-6_3.gif)
[![[IM Output]](edged-6_4.gif)](edged-6_4.gif) | If I was to go further and subtract more pixels I can even trim some of the white border from the above numbers. magick edged.gif -crop 5x1-8-8@ +repage +adjoin edged-8\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](edged.gif)](edged.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](edged-8_0.gif)](edged-8_0.gif)
[![[IM Output]](edged-8_1.gif)](edged-8_1.gif)
[![[IM Output]](edged-8_2.gif)](edged-8_2.gif)
[![[IM Output]](edged-8_3.gif)](edged-8_3.gif)
[![[IM Output]](edged-8_4.gif)](edged-8_4.gif) | You can even use this as an alternative method for the [Shave Operator](#shave) , by simply specifying a 1 tile crop... magick edged+6\_0.gif -crop 1x1-6-6@ +repage tile-shave.gif | | | | | --- | --- | --- | | [![[IM Output]](edged+6_0.gif)](edged+6_0.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](tile-shave.gif)](tile-shave.gif) | **Simply Spaced Tiles**The simplest spaced-out tiled images has no edge spacing, or has had that edge spacing [Trimmed](#trim) from the image. However for this to be handled you need to tell IM of this special situation, by including BOTH '`@`' and '`!`' flags. magick spaced.gif -crop 5x1+6+6@\\! +repage +adjoin spaced+6\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](spaced.gif)](spaced.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](spaced+6_0.gif)](spaced+6_0.gif)
[![[IM Output]](spaced+6_1.gif)](spaced+6_1.gif)
[![[IM Output]](spaced+6_2.gif)](spaced+6_2.gif)
[![[IM Output]](spaced+6_3.gif)](spaced+6_3.gif)
[![[IM Output]](spaced+6_4.gif)](spaced+6_4.gif) | Note that the images on the edges of this sub-division are slightly shorter than the images in the middle. This is why this special 'mode' of operation is NOT the default, even though it is actually simpler than the previous spaced-out tile category. Also note that when using both '`@`' and '`!`' flags, a single tile crop (vertically in this case) does not have any effect, as both the top and the bottom of the tile are 'edges', and thus has no 'edge space' to be removed. Again by using a negative value for the overlap, you can tell IM not to include the overlapping (spacing) area in the tile crop results. magick spaced.gif -crop 5x1-6-6@\\! +repage +adjoin spaced-6\_%d.gif | | | | | --- | --- | --- | | [![[IM Output]](spaced.gif)](spaced.gif) | ![==>](../img_www/right.gif) | [![[IM Output]](spaced-6_0.gif)](spaced-6_0.gif)
[![[IM Output]](spaced-6_1.gif)](spaced-6_1.gif)
[![[IM Output]](spaced-6_2.gif)](spaced-6_2.gif)
[![[IM Output]](spaced-6_3.gif)](spaced-6_3.gif)
[![[IM Output]](spaced-6_4.gif)](spaced-6_4.gif) | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The '`!`' character has special significance to some UNIX shells, like "`csh`", and must be escaped with a backslash, even when placed inside quotes._ | With these formulas you should should now be able to tile crop images that form a grid, even when the images are overlapping, or spaced out. Even if the specific problem you have does not fall exactly into on of the above cases, you should be able to either add or remove edge pixels appropriately so that the image does fall into one of the above categories of spaced-out images. * * * 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](../layers/#append) , [composing '`Src`' overlays](../compose/#src) , or even just [positioning the image on a larger canvas](../layers/#flatten) . 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](https://imagemagick.org/script/command-line-options.php?#border) `" operation. The color of the space added is "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" setting. Here is some straight forward examples.. magick rose: -bordercolor SkyBlue -border 10x10 border.gif magick rose: -border 15x6 border\_default.gif magick rose: -bordercolor LimeGreen -border 10x0 border\_sides.gif magick rose: -bordercolor Tomato -border 0x10 border\_topbot.gif magick rose: -alpha set -bordercolor none -border 10 border\_none.gif [![[IM Output]](border.gif)](border.gif) [![[IM Output]](border_default.gif)](border_default.gif) [![[IM Output]](border_sides.gif)](border_sides.gif) [![[IM Output]](border_topbot.gif)](border_topbot.gif) [![[IM Output]](border_none.gif)](border_none.gif) 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. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _As shown above the default color used by the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operator is a light gray as it matches nicely the default grey page color of web pages on the WWW._ | You can specify borders as a percentage of the image size... magick rose: -border 10%x10% border\_percent.jpg [![[IM Output]](border_percent.jpg)](border_percent.jpg) Internally what is really happening is that "`[-border](https://imagemagick.org/script/command-line-options.php?#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... magick star.gif -bordercolor LimeGreen -border 0 star\_background.gif [![[IM Output]](../images/star.gif)](../images/star.gif) ![==>](../img_www/right.gif) [![[IM Output]](star_background.gif)](star_background.gif) Of course there are lots of other ways to [Remove Alpha Transparency](../masking/#remove) . | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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](../misc/#border)
._ | #### Border and Alpha Composition The overlay of the image onto the bordercolor canvas is controlled by the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting, which by default is set to '`[Over](../compose/#over) `' alpha compositing. If it is set to come other setting, the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operation may produce unexpected results. For example, here are some of the more interesting uses of "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" with the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" image operator, when applied to an image containing some transparent areas. magick star.gif -bordercolor LimeGreen \\ -compose {_operation_} -border 5 {_result_} [![[IM Output]](border_compose.jpg)](border_compose.jpg) 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. magick star.gif -bordercolor LimeGreen -compose Copy \\ -border 5 star\_border\_copy.gif [![[IM Output]](star_border_copy.gif)](star_border_copy.gif) The '`[Src](../compose/#src) `' compose will add a transparent border to an image (if it has an alpha channel), regardless of the current "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" setting. Basically the background canvas "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" generated is ignored. The '`[Dst](../compose/#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](../canvas/#sized) . For more information on the various "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" methods see the [Alpha Compositing Examples](../compose/) . #### Border and Virtual Canvas When "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" is applied to an image containing a virtual canvas, it will still add the border around the actual image on that virtual canvas, and NOT around the whole canvas. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -border 5x5 paged\_border.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_border.gif)](paged_border.gif) Note that the size of the virtual canvas was also increased by twice the border thickness to accommodate the added border. This of course means you can not simply add a [Border](#border) to a typical GIF animation directly, unless you want to actually identify the individual sub-frames of the animation (for example see the script [Animation Frame Montage](../anim_basics/#montage) which uses this as an option to 'frame' the overlay images). If you want to add a border, you should [Coalesce](../anim_basics/#coalesce) the animation first to remove any [Frame Optimizations](../anim_opt/#frame_opt) it may have first. ### Frame, adding a 3D-like border The "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" operator is very similar to "`[-border](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#mattecolor) `" rather than "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `". Note "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" is still used in the generation framed images, see below. To use "`[-frame](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#frame) `" operator with various settings. magick rose: -frame 10x10 frame.gif magick rose: -frame 15x6+2+2 frame\_wierd.gif magick rose: -mattecolor SkyBlue -frame 6x6+2+2 frame\_blue.gif magick rose: -mattecolor Tomato -frame 10x10+5+5 frame\_red.gif magick rose: -frame 10x10+10+0 frame\_rasied.gif magick rose: -frame 10x10+6+0 frame\_rasied\_part.gif magick rose: -frame 10x10+0+6 frame\_sunken\_part.gif magick rose: -frame 10x10+0+10 frame\_sunken.gif [![[IM Output]](frame.gif)](frame.gif) [![[IM Output]](frame_wierd.gif)](frame_wierd.gif) [![[IM Output]](frame_blue.gif)](frame_blue.gif) [![[IM Output]](frame_red.gif)](frame_red.gif) [![[IM Output]](frame_rasied.gif)](frame_rasied.gif) [![[IM Output]](frame_rasied_part.gif)](frame_rasied_part.gif) [![[IM Output]](frame_sunken_part.gif)](frame_sunken_part.gif) [![[IM Output]](frame_sunken.gif)](frame_sunken.gif) Using multiple frame operations can also produce weirder framing styles. magick rose: -frame 10x10+3+3 frame\_normal.gif magick rose: -frame 3x3+3+0 -frame 7x7+3+0 frame\_popped.gif magick rose: -frame 7x7+0+3 -frame 3x3+0+3 frame\_pressed.gif magick rose: -frame 3x3+3+0 -frame 4x4 -frame 3x3+0+3 frame\_inverted.gif [![[IM Output]](frame_normal.gif)](frame_normal.gif) [![[IM Output]](frame_popped.gif)](frame_popped.gif) [![[IM Output]](frame_pressed.gif)](frame_pressed.gif) [![[IM Output]](frame_inverted.gif)](frame_inverted.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The default "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#mattecolor) `" is a slightly darker gray than that of the default setting of "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `". This also allows it to match the default gray color of web pages on the WWW (used by early browsers such as "`mosaic`" and "`netscape`". (See below)_ | | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _While "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" may actually use the "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#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 "`magick montage`"-like framed image complete with text label. magick 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]](frame_montage.gif)](frame_montage.gif) You can even use a semi-transparent "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#mattecolor) `" for the frame "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" and then 'underlay' an interesting pattern (such as a [Fractal Plasma Canvas](../canvas/#plasma_fractal) ), to produce a more colorful frame. magick rose: -alpha set -mattecolor '#CCC6' -frame 10x10+3+4 \\ \\( -size 100x100 plasma:fractal -normalize -blur 0x1 \\) \\ -compose DstOver -composite frame\_plasma.gif [![[IM Output]](frame_plasma.gif)](frame_plasma.gif) Alternatively you can color the frame separately, (generated using a special '[Dst](../compose/#dst) ' composition setting), then overlay the picture into the frame once you have it colored. But that is getting very tricky indeed. For more advanced techniques of using frames see [Framing Techniques](../thumbnails/#frame) . #### Frame and Alpha Composition Frame is closely related to the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operator. Not only is a frame drawn using the "`[-mattecolor](https://imagemagick.org/script/command-line-options.php?#mattecolor) `", but this operator will also make use of the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" setting to define the background on which the frame is initially drawn. Now for images which have no transparency, the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#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. magick star.gif -frame 6x6+2+2 star\_framed.gif [![[IM Output]](star_framed.gif)](star_framed.gif) In other words "`[-frame](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" which by default is a light grey color. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _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](../misc/#border)
._ | If you want to preserve the transparency of the image, while framing it, you have two solutions. The first is to used transparent "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" such as '`none`'. magick star.gif -bordercolor none -frame 6x6+2+2 star\_framed\_none.gif [![[IM Output]](star_framed_none.gif)](star_framed_none.gif) 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](https://imagemagick.org/script/command-line-options.php?#compose) `" method called '`[Copy](../compose/#copy) `'. magick star.gif -compose Copy -frame 6x6+2+2 star\_framed\_copy.gif [![[IM Output]](star_framed_copy.gif)](star_framed_copy.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The use of "[\-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor)
_" as the background image for both "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" and "`[-frame](https://imagemagick.org/script/command-line-options.php?#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 "`magick montage`" command which makes heavy usage of the internal "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" function in its internal processing. (See [Montage Background and Transparency Handling](../montage/#bg)
) | As you can see the "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" operator, like "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `", also uses the "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting to define how the source image is overlaid onto the background frame. magick star.gif -bordercolor LimeGreen \\ -compose {_operation_} -frame 6x6+2+2 {_result_} [![[IM Output]](frame_compose.jpg)](frame_compose.jpg) The use of a "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" setting of '`[Copy](../compose/#copy) `' becomes very important if you also want to use the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" setting in "`magick montage`" frames. See [Montage Background and Transparency Handling](../montage/#bg) for more details. #### Frame and Virtual Canvas As with [Border and Virtual Canvas](#border_canvas) frame is also applied around the actual image on that virtual canvas, and NOT around the whole canvas. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -frame 5x5+2+2 paged\_framed.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_framed.gif)](paged_framed.gif) Note that the size of the virtual canvas was also increased by twice the border thickness to accommodate the added frame. This of course means you can not simply add a [Frame](#frame) to a typical GIF animation directly, unless you want to actually identify the individual sub-frames of the animation (for example see [Animation Frame Montage](../anim_basics/#montage) ). If you want to add a border, you should [Coalesce](../anim_basics/#coalesce) the animation first to remove any [Frame Optimizations](../anim_opt/#frame_opt) it may have first. ### Shave, removing edges from an image The reverse of the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" or "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `" operators, is "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) `", which if given the same arguments, will remove the space added by these commands. magick border.gif -shave 10x10 shave.gif magick border.gif -shave 10x0 shave\_sides.gif magick border.gif -shave 0x20 shave\_topbot.gif [![[IM Output]](border.gif)](border.gif) ![==>](../img_www/right.gif) [![[IM Output]](shave.gif)](shave.gif) [![[IM Output]](shave_sides.gif)](shave_sides.gif) [![[IM Output]](shave_topbot.gif)](shave_topbot.gif) 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](https://imagemagick.org/script/command-line-options.php?#chop) `" operator instead. (See the [Chop Examples](#chop) below). As before all the operators "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `", "`[-frame](https://imagemagick.org/script/command-line-options.php?#frame) `", and "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) `", only effect the real image on the virtual canvas and not the virtual canvas itself. magick rose: -shave 12x0 -repage 64x64+9+9 paged.gif magick paged.gif -border 5x5 paged\_border.gif magick paged\_border.gif -frame 5x5+2+2 paged\_frame.gif magick paged\_frame.gif -shave 10x10 paged\_shave.gif [![[IM Output]](paged.gif)](paged.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_border.gif)](paged_border.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_frame.gif)](paged_frame.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_shave.gif)](paged_shave.gif) An alternative to using shave is to use the new [Equal Sized Tile Cropping](#crop_equal) operator. The advantage of this operator is that unlike "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) ` it will not modify the canvas size of the resulting image. magick paged\_frame.gif -crop 1x1-10-10@ paged\_tile\_shave.gif [![[IM Output]](paged_frame.gif)](paged_frame.gif) ![==>](../img_www/right.gif) [![[IM Output]](paged_tile_shave.gif)](paged_tile_shave.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version v6.6.1-0, equal-sized tile cropping for images with a canvas offset (such as the above) was broken._ | ### Extent, Direct Image Size Adjustment After some discussions, an operator to directly adjust the final size of an image size was added to IM version 6.2.4. The "`[-extent](https://imagemagick.org/script/command-line-options.php?#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. magick rose: -background skyblue -extent 100x60 extent\_enlarge.gif magick rose: -background skyblue -extent 40x40 extent\_shrink.gif magick rose: -background skyblue -extent 100x40 extent\_wider.gif magick rose: -background skyblue -extent 40x60 extent\_taller.gif [![[IM Output]](extent_enlarge.gif)](extent_enlarge.gif) [![[IM Output]](extent_shrink.gif)](extent_shrink.gif) [![[IM Output]](extent_wider.gif)](extent_wider.gif) [![[IM Output]](extent_taller.gif)](extent_taller.gif) As you can see it will fill any new areas with the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color of any new areas added to the image. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM version v6.3.2, "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `" just cleared the memory of any new areas to zero, or straight black. It did not fill the areas with "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color._ | Also after IM v6.3.2, "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `" will use the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to define where the areas added/removed are positioned relative to the original image. magick rose: -gravity north -extent 100x80 extent\_north.gif magick rose: -gravity south -extent 100x80 extent\_south.gif magick rose: -gravity east -extent 100x80 extent\_east.gif magick rose: -gravity west -extent 100x80 extent\_west.gif magick rose: -gravity center -extent 100x80 extent\_center.gif magick rose: -gravity center -extent 40x80 extent\_center2.gif [![[IM Output]](extent_north.gif)](extent_north.gif) [![[IM Output]](extent_south.gif)](extent_south.gif) [![[IM Output]](extent_east.gif)](extent_east.gif) [![[IM Output]](extent_west.gif)](extent_west.gif) [![[IM Output]](extent_center.gif)](extent_center.gif) [![[IM Output]](extent_center2.gif)](extent_center2.gif) The last example in the above show that extent can also do centered crops, but without the need for a "`[-repage](https://imagemagick.org/script/command-line-options.php?#repage) `", though it does 'flatten' the image with the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color.You can even use offsets, which basically means the [Extent Operator](#extent) is simply a straight forward [Crop](#crop) with background padded fill, regardless of position. magick rose: -background skyblue -extent 100x100-15-25 extent.png [![[IM Output]](extent.png)](extent.png) This ability to both crop and extend an image according to gravity 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](../thumbnails/#pad) . Note that "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `" works by using the same 'overlay' technique that both the [Border](#border) and [Frame](#frame) operators uses. As such by default using it with an image containing transparency will replace the transparency with the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color. magick star.gif -background LimeGreen -extent 80x80-10-10 star\_extent.gif [![[IM Output]](star_extent.gif)](star_extent.gif) Again the solution to this is to either set an appropriate "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" method, or set the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color to '`None`'. * * * Adding/Removing Rows, Columns and Edges --------------------------------------- ### Splice, adding rows, columns and edges The "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `" operator is new to IM version 6, see [Splice, example of the creation of a new image operator](../misc/#splice) . 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](https://imagemagick.org/script/command-line-options.php?#background) `" color setting. magick rose: -background blue -splice 20x10+40+30 splice.gif magick rose: -background blue -splice 20x0+40+0 splice\_column.gif magick rose: -background blue -splice 0x10+0+30 splice\_row.gif magick rose: -background blue -splice 20x10 splice\_topleft.gif [![[IM Output]](rose.gif)](rose.gif) ![==>](../img_www/right.gif) [![[IM Output]](splice.gif)](splice.gif) [![[IM Output]](splice_column.gif)](splice_column.gif) [![[IM Output]](splice_row.gif)](splice_row.gif) [![[IM Output]](splice_topleft.gif)](splice_topleft.gif) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _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](https://imagemagick.org/script/command-line-options.php?#background) `" color, its default value depends on the image, and you could get just about anything._

**Always set "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `", before using an operator that uses it.** | Now while adding a row and column to an image is good, the "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `" operator is ideal for adding space to just one edge of an image. Which edge is determined by using the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" option and the splice geometry setting. magick rose: -background blue -splice 0x10 splice\_top.gif magick rose: -gravity south \\ -background blue -splice 0x10 splice\_bottom.gif magick rose: -background blue -splice 20x0 splice\_left.gif magick rose: -gravity east \\ -background blue -splice 20x0 splice\_right.gif magick rose: -gravity southeast \\ -background blue -splice 20x10 splice\_botright.gif [![[IM Output]](splice_top.gif)](splice_top.gif) [![[IM Output]](splice_bottom.gif)](splice_bottom.gif) [![[IM Output]](splice_left.gif)](splice_left.gif) [![[IM Output]](splice_right.gif)](splice_right.gif) [![[IM Output]](splice_botright.gif)](splice_botright.gif) One of the most common uses of splice is to add space in which to draw a label. (See [Labeling Images](../annotating/#labeling) ) magick rose: -gravity South -background LimeGreen -splice 0x15 \\ -annotate 0x0 'Rose' splice\_label.gif [![[IM Output]](splice_label.gif)](splice_label.gif) ### Chop, removing rows, columns and edges The natural inverse of "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `" is the much older "`[-chop](https://imagemagick.org/script/command-line-options.php?#chop) `" operator. Given the same argument as "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `" and the same "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting, "`[-chop](https://imagemagick.org/script/command-line-options.php?#chop) `" will restore the image to its original form. magick splice.gif -chop 20x10+40+30 splice\_chop.gif magick splice\_chop.gif -chop 20x10+30+20 chop.gif magick chop.gif -background grey \\ -splice 20x10+30+20 chop\_splice.gif [![[IM Output]](splice.gif)](splice.gif) ![==>](../img_www/right.gif) [![[IM Output]](splice_chop.gif)](splice_chop.gif) ![==>](../img_www/right.gif) [![[IM Output]](chop.gif)](chop.gif) ![==>](../img_www/right.gif) [![[IM Output]](chop_splice.gif)](chop_splice.gif) I continued processing the last example to show how you can reverse the order of the "`[-splice](https://imagemagick.org/script/command-line-options.php?#splice) `" and "`[-chop](https://imagemagick.org/script/command-line-options.php?#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... magick frame\_red.gif -chop 0x10 chop\_top.gif magick frame\_red.gif -chop 10x0 chop\_left.gif magick frame\_red.gif -gravity East -chop 10x0 chop\_right.gif magick frame\_red.gif -gravity South -chop 0x10 chop\_bottom.gif [![[IM Output]](frame_red.gif)](frame_red.gif) ![==>](../img_www/right.gif) [![[IM Output]](chop_top.gif)](chop_top.gif) [![[IM Output]](chop_left.gif)](chop_left.gif) [![[IM Output]](chop_right.gif)](chop_right.gif) [![[IM Output]](chop_bottom.gif)](chop_bottom.gif) As an alternative to using "`[-chop](https://imagemagick.org/script/command-line-options.php?#chop) `" for removing a single edge, you can in fact use the more universal "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator instead. This does not require the use of "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" to get the bottom or right edges, however does require you to "`[+repage](https://imagemagick.org/script/command-line-options.php?#repage) `" the canvas of the image afterward. magick frame\_red.gif -crop +0+10 +repage crop\_edge\_top.gif magick frame\_red.gif -crop +10+0 +repage crop\_edge\_left.gif magick frame\_red.gif -crop -10+0 +repage crop\_edge\_right.gif magick frame\_red.gif -crop +0-10 +repage crop\_edge\_bottom.gif [![[IM Output]](frame_red.gif)](frame_red.gif) ![==>](../img_www/right.gif) [![[IM Output]](crop_edge_top.gif)](crop_edge_top.gif) [![[IM Output]](crop_edge_left.gif)](crop_edge_left.gif) [![[IM Output]](crop_edge_right.gif)](crop_edge_right.gif) [![[IM Output]](crop_edge_bottom.gif)](crop_edge_bottom.gif) This relies on the fact that if "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" is not given an 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](https://imagemagick.org/script/command-line-options.php?#crop) `" to 'chop' image edges, was discovered and published by Don Sheythe, and after some discussion was deemed to be a 'feature' of IM, and thus included here. * * * Advanced Cropping Techniques ---------------------------- ### Crop to a Given Aspect Ratio You can crop images to fit a specific aspect ratio, but it is tricky and uses some DIY mathematical techniques. For example you can write a script to do the calculations and then do the [Crop](#crop) . Or in IM v6 you can so calaculations with the [Distort Viewport](../distorts/#distort_viewport) , to extract the desired part of the image during a [No-Op Distortion](../distorts/#distort_noop) , as described in [Centered Square Crop](../distorts/#centered_square) . However in ImageMagick version 7, you can now do mathematical calculations directly in commands like "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" and "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `", thus by-passing the need miss-use "`[-distort](https://imagemagick.org/script/command-line-options.php?#distort) `". This is discussed in detail in the IM Developers Forum [Crop to Aspect Ratio](https://magick.imagemagick.org/viewtopic.php?t=33448) . * * * Trim, the 'Auto-Crop' Operator ------------------------------ The "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" operator is a very close relation to the highly versatile "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" operator discussed [above](#crop) . 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. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Note that in ImageMagick version 5 and before, an auto-crop operation was achieved by using a '`0x0`' argument to the "`[-crop](https://imagemagick.org/script/command-line-options.php?#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. magick logo: -resize 30% -trim trim.gif Two things should be noted from the above. First is like "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `", "`[-trim](https://imagemagick.org/script/command-line-options.php?#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](#trim_blur) for an example of doing this).[![[IM Output]](trim.gif)](trim.gif) Here we trim the image, but only to list the result on what part of the image was trimmed, not the actual trimmed image. magick logo: -resize 30% -trim info:- [![[IM Text]](trim_info.txt.gif)](trim_info.txt) However if you don't care about this information, just junk it by resetting the page information of the image either using a "`[+repage](https://imagemagick.org/script/command-line-options.php?#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. magick logo: -resize 30% -trim +repage trim\_repage.jpg [![[IM Output]](trim_repage.jpg)](trim_repage.jpg) 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](https://imagemagick.org/script/command-line-options.php?#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](https://imagemagick.org/script/command-line-options.php?#trim) `" will trim the image down to a minimal single pixel transparent [Missed Image](#crop_missed) . 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](https://imagemagick.org/script/command-line-options.php?#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. magick -size 32x32 xc:red xc:green xc:blue +append stripes.gif magick stripes.gif -trim +repage stripes\_trimmed.gif As you can see, "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" trimmed not just one color but two colors! In an 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](https://imagemagick.org/script/command-line-options.php?#border) `" of that color to the image. Lets take '`red`' in this case. magick stripes.gif -bordercolor red -border 1x1 \\ -trim +repage stripes\_trim\_red.gif Of course using "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" like this also will change the canvas offset that "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" took great pains to preserve. As such if you look at the result without removing the virtual canvas information you can see that image was shifted.[![[IM Output]](stripes.gif)](stripes.gif) ![==>](../img_www/right.gif) [![[IM Output]](stripes_trimmed.gif)](stripes_trimmed.gif) [![[IM Output]](stripes.gif)](stripes.gif) ![==>](../img_www/right.gif) [![[IM Output]](stripes_trim_red.gif)](stripes_trim_red.gif) magick stripes.gif -bordercolor red -border 1x1 -trim \\ stripes\_trim\_red\_shifted.gif [![[IM Output]](stripes_trim_red_shifted.gif)](stripes_trim_red_shifted.gif) So lets try correcting the virtual canvas size (subtract `_border_width_x2` ) and offset (subtract `_border_width_`)when trimming a specific color. magick stripes.gif -bordercolor red -border 1x1 -trim \\ -set page '%\[fx:page.width-2\]x%\[fx:page.height-2\]+%\[fx:page.x-1\]+%\[fx:page.y-1\]' \\ stripes\_trim\_red\_fix.gif [![[IM Output]](stripes_trim_red_fix.gif)](stripes_trim_red_fix.gif) Note that I am restoring canvas size and offset of the original image, that [Border Operator](#border) enlarged and shifted in the above. The "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" operation itself preverved the image location correctly. It is as you can see a rather un-wieldly adjustment. Alternatively if you do not care about the canvas size (typical in a layered image) you can use a far simplier [Relative Repage](../basics/#page) to only adjusted the image's position on the enlarged canvas. magick stripes.gif -bordercolor red -border 1x1 -trim \\ -repage -1-1\\! stripes\_trim\_red\_fix2.gif [![[IM Output]](stripes_trim_red_fix2.gif)](stripes_trim_red_fix2.gif) ### Trimming Just One Side of an Image As you saw above "`[-trim](https://imagemagick.org/script/command-line-options.php?#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 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 trimming just 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. Normally a single pixel width is all that is needed. magick border.gif -gravity East \\ -background white -splice 5x0 \\ -background black -splice 5x0 trim\_protect.gif magick trim\_protect.gif -trim +repage trim\_oneside.gif magick trim\_oneside.gif -gravity East -chop 5x0 trim\_west.gif Note that I add stripes two different colors! That way if one of the colors matches the existing border color surrounding the image the other will continue to work to protect those three edges. Also only 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 (stripes are added to the bottom or 'South' edge).[![[IM Output]](border.gif)](border.gif) ![==>](../img_www/right.gif) [![[IM Output]](trim_protect.gif)](trim_protect.gif) ![==>](../img_www/right.gif) [![[IM Output]](trim_oneside.gif)](trim_oneside.gif) ![==>](../img_www/right.gif) [![[IM Output]](trim_west.gif)](trim_west.gif) magick border.gif -gravity South \\ -background white -splice 0x1 -background black -splice 0x1 \\ -trim +repage -chop 0x1 trim\_north.gif [![[IM Output]](trim_north.gif)](trim_north.gif) And here is a bottom edge only trim. Of course the "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" settings used in the previous example is not needed and the setting defaults to a '`North-West`' setting for images. magick border.gif \\ -background white -splice 0x1 -background black -splice 0x1 \\ -trim +repage -chop 0x1 trim\_south.gif [![[IM Output]](trim_south.gif)](trim_south.gif) Of course as before with border, splicing extra colors onto an image will again change the virtual image canvas size and the layer images offset. Again this can be fixed using the same methods we showed in the previous section, but it depends on which side you added the extra colors onto to preserve those edges. ### Trimming with fuzzy color selection \-- Low Quality JPEG Images Because JPEG is 'lossy' the colors in the image is generally not a single color but slightly varying band of different colors. because of this "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" will often fail for JPEG or real world images. _FUTURE: Example of failure here_As such you need to tell ImageMagick that colors that are not-exactly the same, but are reasonally close should be treated as being the same. Adding a very small "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" setting will do this. magick image.jpg -fuzz 1% -trim +repage image\_fuzzy\_trim.jpg It is also a very good idea to specify the specific color you want that fuzz to be relative to. This can be added by specifically added a border of that color using the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operator. The border will of course always match the color to be trimmed, so will always be removed by "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `". _FUTURE: Example of fuzzy border trim here_ ### Trimming 'Noisy' Images \-- Scanned 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](../color_basics/#fuzz) 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](https://imagemagick.org/script/command-line-options.php?#trim) `" on this copy, and examining exactly what it did, you can then "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" the original unmodified image by the same amount. Their number of methods of de-emphasizing single pixel errors. These include "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `", "`[-median](https://imagemagick.org/script/command-line-options.php?#median) `", or even using [Basic Morphology Operators](../#morphology/#basic) to remove specific details, such a text and thin lines. This the 'blur' method gives two main controls: * The "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" sigma radius, or the "`[-median](https://imagemagick.org/script/command-line-options.php?#mediam) `" 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](../blur/#blur) . * The second control is the "`[-fuzz](https://imagemagick.org/script/command-line-options.php?#fuzz) `" color factor that controls the amount of color change matched by the "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" operator. That is, how close to the desired image you want the trim to get. For example lets use a smaller "`logo:`" image. magick 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]](noisy.jpg)](noisy.jpg) Here is the result. Note in this case we do not want an image, just the canvas information from the image. magick noisy.jpg -virtual-pixel edge -blur 0x15 -fuzz 15% -trim info: [![[IM Text]](blur_trim_info.txt.gif)](blur_trim_info.txt) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _You may need to check the [Virtual Pixel](../misc/#virtual)
setting to enure that you get the right 'edge effects' with the blur.

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](https://imagemagick.org/script/command-line-options.php?#blur) `" and "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" operators._ | From the above result we can determine that "`[-trim](https://imagemagick.org/script/command-line-options.php?#trim) `" had internally used a "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument of '`89x121+78+23`'. This is the actual size of the trimmed image, and its offset on the virtual 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. magick noisy.jpg -crop 89x121+78+23 +repage noisy\_trimmed.jpg And here we have trimmed our image to just the wizard![![[IM Output]](noisy_trimmed.jpg)](noisy_trimmed.jpg) This can be done in a single line, using a little bit of extra 'UNIX shell scripting', and some formating of the results of that first command. magick noisy.jpg -crop \\ \`magick noisy.jpg -virtual-pixel edge -blur 0x15 -fuzz 15% \\ -trim -format '%wx%h%O' info:\` +repage noisy\_trimmed\_2.jpg See [Image Property Escapes](https://imagemagick.org/script/escape.php) for more information on the "`[-format](https://imagemagick.org/script/command-line-options.php?#format) `" setting used to control the output of "`[info:](../files/#info) `".[![[IM Output]](noisy_trimmed_2.jpg)](noisy_trimmed_2.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The above uses an UNIX command line shell feature for 'command-substitution' method using back-quotes '`` `...` ``' to insert the generated "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" argument into the outer "`magick`" command.

You can do this in a [Windows Batch Script](../api/#windows)
, using a special `FOR..DO` construct. Follow the above link for details._ | 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.The method could be improved by expanding the area trimmed by a small amount (10 pixels in 4 four directions), using some [FX Escape](../transform/#fx_escapes) to do the mathematics... magick noisy.jpg -crop \\ \`magick noisy.jpg -virtual-pixel edge -blur 0x15 -fuzz 15% -trim \\ -format '%\[fx:w+20\]x%\[fx:h+20\]+%\[fx:page.x-10\]+%\[fx:page.y-10\]' \\ info:\` +repage noisy\_trimmed\_3.jpg [![[IM Output]](noisy_trimmed_3.jpg)](noisy_trimmed_3.jpg) If the calculated bounds expands beyond the original image, the [crop operator](#crop) will automatically limit it to the image bounds.In IMv7 (using the "`magick`" command) you can do it all in one command, saving the calculated trim size in a setting for later use. magick noisy.jpg \\ \\( +clone -virtual-pixel edge -blur 0x15 -fuzz 15% -trim \\ -set option:fuzzy\_trim \\ '%\[fx:w+20\]x%\[fx:h+20\]+%\[fx:page.x-10\]+%\[fx:page.y-10\]'\\ +delete \\) \\ -crop %\[fuzzy\_trim\] noisy\_trimmed\_4.jpg [![[IM Output]](noisy_trimmed_4.jpg)](noisy_trimmed_4.jpg) Other methods of fuzzy trimming is using various [Morphological Methods](../morphology/#basic) to remove the unwanted parts of the image, before triming to find the bounds of the area wanted in the original image. An user [HugoRune](https://magick.imagemagick.org/memberlist.php?mode=viewprofile&u=14154) needed to trim an image down to a highly different contrast regaion for scanning purposes. See [Discussion on IM Forums](https://magick.imagemagick.org/viewtopic.php?t=14247) , for details. * * * --- # Canvas Creation -- ImageMagick Examples ImageMagick Examples -- ![](../img_www/space.gif) Canvas Creation =================================================================== **Index** | | | | --- | --- | | [![](../img_www/granitesm_left.gif) ImageMagick Examples Preface and Index](../) | | | [![](../img_www/granitesm_right.gif) Solid Color Canvases](#solid)

* [Direct Generation](#solid)

* [Blanking Existing Images](#blank)

* [Blanking Image with Picked Color](#blank_pick)

* [Overlay a Specific Color](#specific)

* [Other Canvas Techniques](#other)


[![](../img_www/granitesm_right.gif) Gradients of Colors](#gradient)

* [Gradient Image Generator](#gradient)

* [Radial Gradient Generator](#radial-gradient)

* [Gradients with Transparency](#gradient_transparent)

* [Histogram Adjusted Gradients](#gradient_histogram)

* [Evaluated Gradients](#gradient_functions)

* [Distorted Gradients](#gradient_distort)

* [Gradients by Composition](#gradient_compose)

* [Gradients in other Colorspaces](#gradient_colorspace)

* [Resized Image Gradients](#gradient_resize)

* [Interpolated Lookup Gradients](#gradient_interpolate)

* [Roll your own Gradient](#gradient_fx)

* [More Complex DIY Gradients](#gradient_complex)

* [DIY Gradients and Hues](#gradient_complex_hues)

* [Generating the Perfect Gradient](#perfect_gradients)


[![](../img_www/granitesm_right.gif) Sparse Points of Color](#sparse-color)

* [**Barycentric** - The Triangle Gradient](#barycentric)
* [Two Color Gradients](#two_color_gradients)

* [Diagonal Gradients](#diagonal_gradients)

* [Barycentric and Two Color Gradients](#two_point_gradients)

* [**Bilinear** - 4 Point Gradient](#bilinear)

* [**Voronoi** - Nearest Color](#voronoi)

* [**Shepards** - Spotlights of Color](#shepards)

* [**Inverse** - Sharp Points of Color](#inverse)

* [Shepards Power Factor](#shepards_power)

* [Summery of Sparse Color Methods](#sparse_summery)

* [Channel Setting and Sparse Color](#sparse_channel)

* [Sparse Color as a Fill Operator](#sparse_fill)

* [Sparse Color Shepards, a Blur Alternative](#sparse_blur)

* [Shepards Method 'Leaks'](#shepards_leakage) | [![](../img_www/granitesm_right.gif) Plasma Images](#plasma)

* [Plasma Gradients](#plasma_gradients)

* [Fractal Plasma](#plasma_fractal)

* [Gray-scale Plasma](#plasma_greyscale)

* [Seeded Plasma](#plasma_seeded)

* [Problems using Plasma](#plasma_problems)


 

[![](../img_www/granitesm_right.gif) Random Images](#random)

* [Raw Random Noise](#random_noise)
\- pure random
* [Plasma Gradients](#plasma_gradients)

* [Random Speckles](#random_specks)
\- pixel dust
* [Blurred Random Images](#random_blur)
\- random blobs
* [Random Granularity](#granularity)
\- order in the chaos
* [Random Flux](#random_flux)
\- animated randomness
* [Random Ripples](#random_ripples)
\- dispersion maps

 

[![](../img_www/granitesm_right.gif) Tiled Canvases](#tile)

* [Tiled Canvas](#tile)

* [Offset Tiling Canvases](#tile-offset)

* [Tiling with an Image In Memory](#tile_memory)

* [Modifying Built-in Patterns](#pattern)

* [Modifying Tile Images](#tile_mod)

* [Generating Tile Images](#tile_gen)

* [Random Noise Tiles](#tile_random)

* [Hexagonal Tiling](#tile_hex)

* [Triple Hex Tiling](#tile_triple_hex)

* [Diagonal Mirror Tiling](#tile_diagonal) | Canvases are used by ImageMagick both as a starting image for drawing on, backgrounds to overlay images with transparent areas, or even just as part of general image processing. They can be a solid color, or a range of colors, or even a tile of a smaller image. Here we look at just some of the methods that can be used to generate a whole range of canvas images. * * * Solid Color Canvases -------------------- ### Direct Generation Generating a canvas of a specific color and size is very simple to do. You just specify "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" (defaulting to "`1x1`" is no size given), and then use "`canvas:`" to generate an canvas of the color given. If no color is specified a '`white`' canvas is generated.For example... here I generate a '`khaki`' colors canvas. magick -size 100x100 canvas:khaki canvas\_khaki.gif [![[IM Output]](canvas_khaki.gif)](canvas_khaki.gif) More commonly a short hand (and more traditional) format of "`xc:`" (which meant "X Constant Image"). This is generally what I use. For example, here is an image using the X window color of '`wheat`'. magick -size 100x100 xc:wheat canvas\_wheat.gif [![[IM Output]](canvas_wheat.gif)](canvas_wheat.gif) Using some fancy [Image Read Modifiers](../files/#read_mods) we can just specify a solid color canvas image as a single argument. This technique means you can specify a 'xc' canvas image of a specific size and color as a single 'input image' argument to many ImageMagick Scripts. magick 'xc:Salmon\[100x100!\]' canvas\_salmon.gif | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The '!' is needed as the numbers are resize values, otherwise you not get the size requested if it isn't square._ | [![[IM Output]](canvas_salmon.gif)](canvas_salmon.gif) If you have already created a canvas, but need one in a different color you can replace that color using the "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" operator. magick canvas\_khaki.gif -fill tomato -opaque khaki canvas\_tomato.gif [![[IM Output]](canvas_tomato.gif)](canvas_tomato.gif) You can even grab a single pixel from an existing image, and expand it to the canvas size you want. We use "`[-scale](https://imagemagick.org/script/command-line-options.php?#scale) `" for a simple and fast resizing of the single pixel.Here we grab a rose color from the built-in "`rose:`" image. magick rose: -crop 1x1+40+30 +repage -scale 100x100\\! canvas\_rose\_red.gif [![[IM Output]](canvas_rose_red.gif)](canvas_rose_red.gif) ### Create Image of same size One most basic techniques, when using ImageMagick, is to generate a canvas of the same size as some existing image. This can be done by converting that existing image into the canvas needed, but preserving the image's original size. Generally it is not just the images size that needs to be preserved, but all the images meta-data as well. That in things such as labels, comments, color profiles, time delays, as well as the save compression and depth. This meta-data can be important if you want to annotate such information onto the newly blanked canvas, or you plan to overlay the original image onto the new canvas, and need to preserve that information. Naturally IM provides a large number of ways to do this, usually as a side-effect of using various image operations. Only a few are very obvious about there use in clearing an image to a solid color. | | | | --- | --- | | To the left is a test image... Don't worry above how I actually generated this image, it is not important for the exercise. I did design it to contain a range of colors, transparencies and other features, specifically to give IM a good workout when used. _If you are really interested in the commands used to generate this image you can look at the special script, "[generate\_test](../scripts/generate_test)
", I use to create it._ | [![[IM Output]](../images/test.png)](../images/test.png) | ### Overlay a Specific Color As of IM v6.4.2-1 you can use the "`[+level-colors](https://imagemagick.org/script/command-line-options.php?#level_colors) `" with a single color and no comma's, to set all the colors. magick test.png -alpha Opaque +level-colors Sienna color\_levelc.gif [![[IM Output]](color_levelc.gif)](color_levelc.gif) Note the use of the "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) `" operator to set the transparency to something useful before (or after) the color has been added. Altrunativally you could use "`-channel All`" to ensure the transparency channel is also set by the color resetting operation. Another older technique is to use "`[-colorize](https://imagemagick.org/script/command-line-options.php?#colorize) `" to overlay the fill color but with a fully opaque value. However before IM v6.7.9 it did not change the the original images alpha channel, so it is a good idea if to disable the alpha channel first, using "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) [Off](../masking/#alpha_off) `", or make it opaque with "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) [Opaque](../masking/#alpha_off) `" even though you would get the same result without it. magick test.png -alpha off -fill Chocolate -colorize 100% color\_colorize.gif | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) [Off](../masking/#alpha_off) `" (or the older equivelent "`[-alpha off](https://imagemagick.org/script/command-line-options.php?#matte) `") only disables the alpha channel. if you turn it [On](../masking/#alpha_on)
again afterwards, the original alpha channel (which was preserved) will be restored. Before IM v6.7.9 alpha was preserved when using "`[-colorize](https://imagemagick.org/script/command-line-options.php?#colorize) `"._ | [![[IM Output]](color_colorize.gif)](color_colorize.gif) As of IM v6.4.3-0 you can use the "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `" operator to set some point to the color wanted, and have it spread to cover the whole image, using just about any coloring method it provides (see [Sparse Points of Color](#sparse-color) below). magick test.png -alpha Off \\ -sparse-color Voronoi '0,0 Peru' color\_sparse.gif [![[IM Output]](color_sparse.gif)](color_sparse.gif) A more general way is to use "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to directly reset all the colors in the current image to the current "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color. magick test.png -fill Tan -draw 'color 0,0 reset' color\_reset.gif [![[IM Output]](color_reset.gif)](color_reset.gif) This was the recommended method in ImageMagick version 5. The major complaint about all the above 'simple' methods is that none simply resets the image to the current "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color. The next set methods make use of [Alpha Composition](../compose/) to force various operators to replace the image with the desired color. These multi-image techniques work with operators that use "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `".For example you can use the "`[-flatten](https://imagemagick.org/script/command-line-options.php?#flatten) `" (See [Flatten onto Background](../layers/#flatten_bgnd) example), which creates a canvas using the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color. magick test.png -background Wheat \\ -compose Dst -flatten color\_flatten.gif [![[IM Output]](color_flatten.gif)](color_flatten.gif) The above as uses the '`[Dst](../compose/#Dst) `' compose method to only read the background canvas, and ignore the pixel colors of the original image.If you are just wanting to grab the original images meta-data (such as the comment or label data), but replace the image itself with a specific color and size of canvas image, then "`[-extent](https://imagemagick.org/script/command-line-options.php?#extent) `" operator (See [Extent, Direct Image Size Adjustment](../crop/#extent) ) may be the best solution. Again the `[Dst](../compose/#Dst) `' compose method is used to have it ignore the original image pixel data, so as to onlyuse the "`[-background](https://imagemagick.org/script/command-line-options.php?#background) `" color. magick test.png -background LemonChiffon \\ -compose Dst -extent 100x100 color\_extent.gif [![[IM Output]](color_extent.gif)](color_extent.gif) Or you can use "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" (See [Adding a Border](../crop/#border) ), using the "`[-bordercolor](https://imagemagick.org/script/command-line-options.php?#bordercolor) `" as the color source. magick test.png -bordercolor Khaki \\ -compose Dst -border 0 color\_border.gif [![[IM Output]](color_border.gif)](color_border.gif) This last method has the added advantage of also letting you slightly enlarge the image canvas, relative to the original images size. | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" method of generating canvases will not work with versions of IM before version 6.1.4. Before this the background generated by the "`[-border](https://imagemagick.org/script/command-line-options.php?#border) `" operator was not a simple solid color, but a black canvas surrounded by the border color. Not very useful._ | A more flexible (but very slow) method of canvas generation was provided by the "`[FX, DIY Operator](../transform/#fx) `" operator. You will also need to turn off the input image's transparency channel as by default "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" will not touch the transparency channel. magick test.png -alpha off -fx Gold color\_fx\_constant.gif [![[IM Output]](color_fx_constant.gif)](color_fx_constant.gif) The "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator will even let you do a little color mathematics. For example how about a 70% darker gold color... magick test.png -alpha off -fx "Gold\*.7" color\_fx\_math.gif [![[IM Output]](color_fx_math.gif)](color_fx_math.gif) All the above methods cannot only fill using a fully-opaque color, but can also use semi-transparent colors. However it is a good idea to ensure the image you have a transparency channel before hand.Here for example we create a canvas with a semi-transparent red. However when overlaid on the web pages 'bluish' background we get an off purple-pink color. magick test.png -alpha set -fill '#FF000040' -draw 'color 0,0 reset' \\ color\_semitrans.png [![[IM Output]](color_semitrans.png)](color_semitrans.png) Also note that when using "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" operator with transparency, you will need to set "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" to modify all four '`RGBA`' color channels. ### Blanking Image with Picked Color Blanking images using a color from the original image is also posible, though can be tricky. It is an useful technique when you want to use a specific pixel as a 'background color'. For example pixel 0,0 is a common choice.[![[IM Output]](../images/rose.png)](../images/rose.png) In the following examples I will select colors from various pixels from the built in rose image (shown left), as I blank the image. The most obvious (though slow) method is to simply use the "`[FX, DIY Operator](../transform/#fx) `" to select the pixel to use color blanking. magick rose: -fx 'p{0,0}' color\_pick\_fx.png [![[IM Output]](color_pick_fx.png)](color_pick_fx.png) However this can be speed up by only selecting the pixel once. This can be done by using the fx formula as an argument for [Sparse Color](#sparse-color) . It may seem less simple, but it is much faster. magick rose: -sparse-color voronoi '0,0 %\[pixel:p{40,30}\]' color\_pick\_sparse.png [![[IM Output]](color_pick_sparse.png)](color_pick_sparse.png) Another more complex method is to crop out that one pixel and tile it across the image, using techniques described later in detail in [Tiling with an Image already In Memory](#tile_memory) magick rose: \\( +clone -crop 1x1+64+22 -write MPR:pixel +delete \\) \\ -fill mpr:pixel -draw 'color 0,0 reset' \\ color\_pick\_draw.png [![[IM Output]](color_pick_draw.png)](color_pick_draw.png) magick rose: -set option:distort:viewport '%wx%h+0+0' \\ -crop 1x1+10+25 +repage -distort SRT 0 \\ color\_pick\_distort.png [![[IM Output]](color_pick_distort.png)](color_pick_distort.png) ### Other Canvas Techniques Their lots of other ways of generating canvases of very specific colors, but they are rather obtuse. As such without some heavy commenting, it may not be obvious what you are actually doing when you look at your IM script months or years later. I don't recommend these techniques, but are useful to know if you are using older less flexible versions of IM.#### Black Canvas \-threshold", and then turn off the transparency channel. | | | --- | | Traditionally you can create a black canvas by using " | | magick test.png -threshold 100% -alpha off black\_threshold.png | ![[IM Output]](black_threshold.png)\-level" operator with the same argument for both 'black' and 'white' points will have the same effect. | | | --- | | Providing the " | | magick test.png -level 100%,100% -alpha off black\_level.png | ![[IM Output]](black_level.png)\-fx" operator provides a more obvious way of creating a black canvas by clearing all the pixels to zero. However you will also need to reset the alpha channel to make it fully opaque. | | | --- | | The " | | magick test.png -fx 0 -alpha off black\_fx.png | ![[IM Output]](black_fx.png)\-evaluate" version of this should be faster, particularly on larger images. | | | --- | | However the " | | magick test.png -evaluate set 0 -alpha off black\_evaluate.png | ![[IM Output]](black_evaluate.png)\-gamma" operator to make an image all black. | | | --- | | You can also mis-use the " | | magick test.png -gamma 0 -alpha off black\_gamma.png | ![[IM Output]](black_gamma.png)![[IM Output]](black_posterize.png)A less obvious way is to 'posterize' the image with too few color levels, resulting in only one color being used, black. magick test.png -posterize 1 -alpha off black\_posterize.png Alpha Operator | | | --- | | You can ensure the image is fully transparent then '`extract`' the images mask, using the | | magick test.png -alpha transparent -alpha extract black\_alpha.png | ![[IM Output]](black_alpha.png) #### White Canvas \-threshold". The value however must be a negative number, just to be sure that all colors will be mapped to white, in all versions of IM. | | | --- | | The traditional way is again using " | | magick test.png -threshold -1 -alpha off white\_threshold.png | ![[IM Output]](white_threshold.png)\-level" operator with same argument for both 'black' and 'white' points will have the same effect. | | | --- | | Providing the " | | magick test.png -level -1,-1 -alpha off white\_level.png | ![[IM Output]](white_level.png)\-fx" operator. | | | --- | | You can of course set the pixel values directly using the " | | magick test.png -fx 1.0 -alpha off white\_fx.png | ![[IM Output]](white_fx.png)\-evaluate" version of this should be faster, particularly on larger images. | | | --- | | However the " | | magick test.png -evaluate set 100% -alpha off white\_evaluate.png | ![[IM Output]](white_evaluate.png)![[IM Output]](white_posterize.png)Or negate some other black canvas generation method. magick test.png -posterize 1 -alpha off -negate white\_posterize.png Alpha Operator | | | --- | | You can ensure the image is fully opaque (no transparency) then '`extract`' the images mask, using the | | magick test.png -alpha opaque -alpha extract white\_alpha.png | ![[IM Output]](white_alpha.png) #### Transparent Canvas Probably the most important canvas you want to generate from an existing image is a transparent canvas. You can then draw and add things to this canvas, get it the way you want it, the overlay it onto the original image. -alphatransparent" operator (added IM v6.4.3-7). | | | --- | | The fastest and easiest way is to just get IM to directly clear the image to transparency, using the " | | magick test.png -alpha transparent trans\_alpha.png | However as this is a very recent addition it is probably not widely available yet. ![[IM Output]](trans_alpha.png)Clear' alpha composition operator, with any overlay image (a single pixel "`null:`" in this case) as it will be ignored. | | | --- | | We can make a fully-transparent 'black' canvas using the ' | | magick test.png null: -alpha set -compose Clear -composite -compose Over \\
trans\_compose.png | ![[IM Output]](trans_compose.png)\-fill" color setting. In this case make it fully-transparent. | | | --- | | Here we use the "`-draw matte`" operator to replace the matte (transparency) channel value with the transparency value of the current " | | magick test.png -alpha set -fill none -draw 'matte 0,0 reset'
color\_matte.png | ![[IM Output]](color_matte.png)\-fx" operator. | | | --- | | We can also do this more directly with the " | | magick test.png -alpha set -channel A -fx 0 +channel trans\_fx.png | ![[IM Output]](trans_fx.png)\-evaluate" version of this should be faster, particularly on larger images. | | | --- | | Naturally the " | | magick test.png -alpha set -channel A -evaluate set 0 +channel \\
trans\_evaluate.png | ![[IM Output]](trans_evaluate.png)\-threshold" but again limiting its effects to just the transparency channel. | | | --- | | Another way to just make the image fully transparent is to use " | | magick test.png -channel A -threshold -1 +channel trans\_threshold.png | ![[IM Output]](trans_threshold.png)Actually in this case we are mathematically dealing with a 'matte' channel, using threshold to set it to the maximum value, rather than zero as we did with the "[\-fx](https://imagemagick.org/script/command-line-options.php?#fx) " operator. This is why a '`-1`' was used in the above, rather than something like `101%`'. In many of the above image results, the original RGB colors of the original image are still present, they have just been made transparent. For example, here we read in one of the above images and ask IM to turn off the matte/alpha channel in the image so as to make the colors visible again. magick trans\_fx.png -alpha off trans\_fx\_alpha\_off.jpg Note however that not all image file formats and very few image operations will preserve the partially-transparent RGB colors that are still present in the resulting image.[![[IM Output]](trans_fx_alpha_off.jpg)](trans_fx_alpha_off.jpg) As mentioned before, and worth repeating, many of the above methods rely on an image already having an alpha channel. If it doesn't, add one using the "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) [On](../masking/#alpha_on) `", but in that case you may as well just use the "`[-alpha](https://imagemagick.org/script/command-line-options.php?#alpha) Transparent`" operator. See the examples on [Controlling Image Transparency](../masking/#alpha) . #### Miscellaneous Canvas Coloring Other than using a specific color, only the "[\-gamma](https://imagemagick.org/script/command-line-options.php?#gamma) " operator is truly flexible enough to generate a canvas of any primary/secondary color. You basically use `0` to zero out a channel, and `-1` to maximize a channel values.For example, here I generate a yellow canvas... magick test.png -gamma -1,-1,0 -alpha off yellow\_gamma.png [![[IM Output]](yellow_gamma.png)](yellow_gamma.png) As of IM v6.4.2 you can also use the "`[+level](https://imagemagick.org/script/command-line-options.php?#level) `" operator to set a specific grey level for all the color channels. magick test.png +level 40%,40% -alpha off grey\_level.png [![[IM Output]](grey_level.png)](grey_level.png) * * * Gradients of Color ------------------ As you saw above you can create canvases of solid colors easy enough. But sometimes you want something more interesting.One very useful image creation operators is "`gradient:`". For example... magick -size 100x100 gradient: gradient.jpg [![[IM Output]](gradient.jpg)](gradient.jpg) As you can see by default "`gradient:`" will create an image with white at the top, and black at the bottom, and a smooth shading of grey across the height of the image. But it does not have to be only a grey-scale gradient, you can also generate a gradient of different colors by either specifying one color, or both. magick -size 100x100 gradient:blue gradient\_range1.jpg magick -size 100x100 gradient:yellow gradient\_range2.jpg magick -size 100x100 gradient:green-yellow gradient\_range3.jpg magick -size 100x100 gradient:red-blue gradient\_range4.jpg magick -size 100x100 gradient:tomato-steelblue gradient\_range5.jpg [![[IM Output]](gradient_range1.jpg)](gradient_range1.jpg) [![[IM Output]](gradient_range2.jpg)](gradient_range2.jpg) [![[IM Output]](gradient_range3.jpg)](gradient_range3.jpg) [![[IM Output]](gradient_range4.jpg)](gradient_range4.jpg) [![[IM Output]](gradient_range5.jpg)](gradient_range5.jpg) Notice that when given a single color the second color will be either '`white`' or '`black`', which ever produces the largest color distance from the given color. As such '`blue`' produces a '`blue-white`' gradient, while '`yellow`' generated a '`yellow-black`' gradient. The '`red-blue`' gradient shows a much darker band of purple colors in the middle. This darkening is caused by the darker non-linear sRGB colorspace being used, especially with strong primary colors. See [Processing Real Images](../color_basics/#processing) for more details. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _"`gradient:`" currently only understands sRGB [Color Space](../color_basics/#colorspace)
color representations. As such you can not use it to generate a brighter more correct 'purple' gradient using '`red-blue`' colors in a linear LAB colorspace.

It also means you can not generate multi-color 'rainbow' gradients using HSV colorspace.

However you can 'fudge' such gradients relatively simply. See [Gradients in other Colorspaces](#gradient_colorspace)
below._ | | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Gradients cannot currently be specified at other angles or involving more than two colors. However as this ability is in integral part of SVG gradients, this situation will likely change, with a major improvement in gradient options._ | Some particularly nice gradients include... magick -size 10x120 gradient:snow-navy gradient\_ice-sea.jpg magick -size 10x120 gradient:gold-firebrick gradient\_burnished.jpg magick -size 10x120 gradient:yellow-limegreen gradient\_grassland.jpg magick -size 10x120 gradient:khaki-tomato gradient\_sunset.jpg magick -size 10x120 gradient:darkcyan-snow gradient\_snow\_scape.jpg   [![[IM Output]](gradient_ice-sea.jpg)](gradient_ice-sea.jpg) [![[IM Output]](gradient_burnished.jpg)](gradient_burnished.jpg) [![[IM Output]](gradient_grassland.jpg)](gradient_grassland.jpg) [![[IM Output]](gradient_sunset.jpg)](gradient_sunset.jpg) [![[IM Output]](gradient_snow_scape.jpg)](gradient_snow_scape.jpg) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _As of IM v6.3.1 the algorithm used to generate gradients now produce a horizontally uniform colors, such that all the pixels of each row in an image being assigned the same color. That is, one color per row.

Before this version the "`gradient:`" operator worked by ignoring the width of the image, and just assigning the next increment of color, going row-by-row from top-left corner to the bottom-right of the image.

As a result the gradient was a predominately vertical gradient, just as it is now, but not a perfect one. Usually this fact was only important in special case such as test images, and for use in [Image Mapping](../mapping/#intro)
.

_ | Note, the behavior of gradients can be affected by these defines: | | | | --- | --- | | gradient:angle=angle (in degrees) | For a linear gradient, this specifies the direction of the gradient going from color1 to color2 in a clockwise positive manner relative to north (up). For a radial gradient, this specifies the rotation of the gradient in a clockwise positive manner from its normal X-Y orientation. Supported in Imagemagick 6.9.2-5. | | gradient:bounding-box=WxH+X+Y | Limit the gradient to a larger or smaller region than the image dimensions. If the region defined by the bounding box is smaller than the image, then color1 will be the color of the background. Supported in Imagemagick 6.9.2-5. | | gradient:center=x,y | Specify the coordinates of the center point for the radial gradient. The default is the center of the image. Supported in Imagemagick 6.9.2-5. | | gradient:direction=value | Specify the direction of the linear gradient towards the top/bottom/left/right or diagonal corners. The choices are: NorthWest, North, Northeast, West, East, SouthWest, South, SouthEast. Supported in Imagemagick 6.9.2-5. | | gradient:extent=value | Specify the shape of an image centered radial gradient. The choices are: Circle, Diagonal, Ellipse, Maximum, Minimum. Circle and Maximum draw a circular radial gradient even for rectangular shaped images of radius equal to the larger of the half-width and half-height of the image. The Circle and Maximum options are both equivalent to the default radial gradient. The Minimum option draws a circular radial gradient even for rectangular shaped images of radius equal to the smaller of the half-width and half-height of the image. The Diagonal option draws a circular radial gradient even for rectangular shaped images of radius equal to the half-diagonal of the image. The Ellipse options draws an elliptical radial gradient for rectangular shaped images of radii equal to half the width and half the height of the image. Supported in Imagemagick 6.9.2-5. | | gradient:radii=x,y | Specify the x and y radii of the gradient. If the x radius and the y radius are equal, the shape of the radial gradient will be a circle. If they differ, then the shape will be an ellipse. The default values are the maximum of the half width and half height of the image. Supported in Imagemagick 6.9.2-5. | | gradient:vector=x1,y1,x2,y2 | Specify the direction of the linear gradient going from vector1 (x1,y1) to vector2 (x2,y2). Color1 (fromColor) will be located at vector position x1,y1 and color2 (toColor) will be located at vector position x2,y2. Supported in Imagemagick 6.9.2-5. | Radial Gradients ---------------- As of IM v6.4.4 you can also generate radial gradient images in a similar way. magick -size 100x100 radial-gradient: rgradient.jpg [![[IM Output]](rgradient.jpg)](rgradient.jpg) Note that the gradient is centered in the middle of the generated image, and has a diameter set to fit the larger of the X or Y size of the image. So if the size of the image isn't square you will get a 'clipped' radial gradient. magick -size 100x60 radial-gradient: rgradient\_clip.jpg [![[IM Output]](rgradient_clip.jpg)](rgradient_clip.jpg) This lets you easily generate a square radial gradient from the center to a corner by making one edge 1.42 (square root of 2) times larger, and crop it. magick -size 100x142 radial-gradient: \\ -gravity center -crop 100x100+0+0 rgradient\_crop.jpg [![[IM Output]](rgradient_crop.jpg)](rgradient_crop.jpg) The colors of the gradient itself follow the same conventions as the much older linear "`[gradient:](#gradient) `" image generator. magick -size 100x100 radial-gradient:blue rgradient\_range1.jpg magick -size 100x100 radial-gradient:yellow rgradient\_range2.jpg magick -size 100x100 radial-gradient:green-yellow rgradient\_range3.jpg magick -size 100x100 radial-gradient:red-blue rgradient\_range4.jpg magick -size 100x100 radial-gradient:tomato-steelblue rgradient\_range5.jpg [![[IM Output]](rgradient_range1.jpg)](rgradient_range1.jpg) [![[IM Output]](rgradient_range2.jpg)](rgradient_range2.jpg) [![[IM Output]](rgradient_range3.jpg)](rgradient_range3.jpg) [![[IM Output]](rgradient_range4.jpg)](rgradient_range4.jpg) [![[IM Output]](rgradient_range5.jpg)](rgradient_range5.jpg) ### Gradients with Transparency As of IM v6.2.9-8 the "`gradient:`" (and later "`radial-gradient:`") image creation operator understands the use of transparent and semi-transparent colors. magick -size 100x100 gradient:none-firebrick gradient\_transparent.png [![[IM Output]](gradient_transparent.png)](gradient_transparent.png) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before ImageMagick 6.5.4-7 gradients involving a full transparency (such as the last example) would generally produce a black halo.

What was happening is that the gradient generated was from the given color to the special color '`none`' or transparent-black. As a result colors would shade toward a semi-transparent black, before becoming fully-transparent.

The solution to this problem was to generate a transparency gradient and then [Colorize](../color_mods/#colorize)
it with the desired color._ | magick -size 100x100 gradient:none-black \\ -fill firebrick -colorize 100% gradient\_trans\_colorize.png [![[IM Output]](gradient_trans_colorize.png)](gradient_trans_colorize.png) ### Gradients by Histogram Adjustment You can create a non-linear gradient by applying some form of histogram adjustment to a linear gradient. For example you can use a [Sigmoidal Contrast](../color_mods/#sigmoidal) function to create a more natural looking gradient. magick -size 100x100 gradient: -sigmoidal-contrast 6,50% \\ gradient\_sigmoidal.jpg [![[IM Output]](gradient_sigmoidal.jpg)](gradient_sigmoidal.jpg) This type of gradient is especially good for generating [Overlapping Photos](../photos/#overlap) , as it removed the sharp gradient changes at the beginning of the overlapping region. ### Evaluate/Function Gradients You can also use the [Evaluate Operator](../transform/#evaluate) and related [Function Operator](../transform/#function) to modify a simple linear gradient. magick -size 100x100 gradient: -evaluate cos 0.5 -negate \\ gradient\_cosine.jpg [![[IM Output]](gradient_cosine.jpg)](gradient_cosine.jpg) Or take it a step further and make a smooth parabolic peek in the center of the linear gradient. magick -size 100x100 gradient: -function Polynomial -4,4,0 \\ gradient\_peak.jpg [![[IM Output]](gradient_peak.jpg)](gradient_peak.jpg) Or band or a rippled pattern... magick -size 100x100 gradient: -function sinusoid 4,-90 \\ gradient\_bands.jpg [![[IM Output]](gradient_bands.jpg)](gradient_bands.jpg) Both of these closely related operators allow you to modify images and gradients based on Sine Curves, Polynomials, Logarithmic and Power-of mathematical functions. See [Evaluate Math Functions](../transform/#evaluate) and [Function, Multi-Argument Evaluate](../transform/#function) for more examples. ### Distorted Gradients #### Rotated Gradient While the [Sparse Color](#sparse-color) method '`[Barycentric](#barycentric) `' (see below), provides a convenient way to generate gradients at any angle, if your IM is older than version 6.4.3-0 then you may need to use other methods to generate a diagonal or rotated gradient. For example, by increasing the size of the gradient image (multiply by the square root of 2 or 1.42), then rotate it 45 degrees, and crop the image to its final size, you can make a diagonal gradient. magick -size 142x142 gradient: -rotate -45 \\ -gravity center -crop 100x100+0+0 +repage \\ gradient\_diagonal.jpg [![[IM Output]](gradient_diagonal.jpg)](gradient_diagonal.jpg) As of IM v6.3.5 you have a much faster and simpler way of generating a rotated gradient by using a [SRT Distortion](../distorts/#srt) . For example, here is a 100 pixel gradient rotated 60 degrees, in a 100x100 pixel image. magick -size 100x100 gradient: -distort SRT 60 gradient\_srt.jpg [![[IM Output]](gradient_srt.jpg)](gradient_srt.jpg) This uses the default [Virtual Pixel, Edge](../misc/#virtual-pixel) setting to ensure the whole image is covered by the requested gradient. You can also use the expert [Distort Viewport](../distorts/#distort_viewport) setting, to map a gradient onto a larger image, such as for an use in [Overlapping Photos](../photos/#overlap) . #### Warping Gradients But you can use the same distortion methods to do a lot more than simple rotations.The gradient can also be twisted up... magick -size 100x100 gradient: -swirl 180 gradient\_swirl.jpg [![[IM Output]](gradient_swirl.jpg)](gradient_swirl.jpg) You can re-map the gradient into a trapezoidal shape. magick -size 100x100 gradient: -rotate -90 \\ -distort Perspective '0,0 40,0 99,0 59,0 0,99 -10,99 99,99 109,99' \\ gradient\_trapezoid.jpg [![[IM Output]](gradient_trapezoid.jpg)](gradient_trapezoid.jpg) Or wrap the gradient into an arcs and circles using the [General Distortion Operator](../distorts/#distort) ... magick -size 100x100 gradient: -distort Arc '180 0 50 0' \\ gradient\_arc.jpg [![[IM Output]](gradient_arc.jpg)](gradient_arc.jpg) magick -size 100x100 gradient: -distort Arc '360 0 50 0' \\ gradient\_circle.jpg [![[IM Output]](gradient_circle.jpg)](gradient_circle.jpg) Though the new "`[radial-gradient:](#radial-gradient) `" is probably the more simpler method for generating these gradients. A very useful but harder to generate gradient is a polar angle gradient. The exact form of this gradient depends on if the gradient should be centered on an even sized image, or an odd sized image. For example an [Arc Distort](../distorts/#arc) can be used to generate images with an even number of pixel dimensions, 76 pixels in this case. magick -size 1x1000 gradient: -rotate 90 \\ -distort Arc '360 -90 50 0' +repage \\ -gravity center -crop 76x76+0+0 +repage gradient\_angle\_even.png [![[IM Output]](gradient_angle_even.png)](gradient_angle_even.png) The '`-90`' in the above sets the angle for the 'discontinuity' where 'zero' and 'maximum' wraps around to the same value. The value '`50`' should be at more than 1/2 the size of the final cropped image. Note how I used a much longer gradient to generate the smaller image. This improves the overall correctness of the result, especially as the image gets larger The closely related [Polar Distort](../distorts/#polar) can also generate such a gradient, but as it has a control over the exact position of the 'center' of the distortion you can ensure it correctly generates an odd pixel size polar gradient image. In this case a 75 pixel image (radius = '`36.5`' ) magick -size 1x1000 gradient: -rotate 90 \\ +distort Polar '36.5,0,.5,.5' +repage \\ -transverse gradient\_angle\_odd.png [![[IM Output]](gradient_angle_odd.png)](gradient_angle_odd.png) The last two images may seem very similar, except for their size, but the handling of the center-most pixels is slightly different. If you look closely you will see that the last example has a perfect grey center pixel, where the previous example does not have a single center pixel, but four of them. The final size of the image was determined by the value '`36.5`' which is half of the '`75`' pixels wanted. The '`.5`' offsets is the important aspect for correct handling of the polar center. Note that by default the distortion places the discontinuity at the top of the image, as such the [Transverse Warp](../warping/#transverse) corrects the angle and location of the discontinuity to match that produced by the [Arc Distort](../distorts/#arc) . Here is a slightly different variant that generates an angular gradient but with a transparent circular mask. magick -size 50x1000 gradient: -rotate 90 -alpha set \\ -virtual-pixel Transparent +distort Polar 49 +repage \\ -transverse gradient\_angle\_masked.png [![[IM Output]](gradient_angle_masked.png)](gradient_angle_masked.png) The value '`49`' is the radius minus 1 as by default a distort adds a 1 pixel anti-aliasing buffer around the resulting image. As such final image is 100x100 pixels. Circular shapes and gradients can be warped to produce some interesting non-linear gradients. For example arcing it using a [Wave Distortion](../warping/#wave) can generate roughly triangular shaped gradient. magick -size 100x100 radial-gradient: \\ -background black -wave -28x200 -crop 100x100+0+0 +repage \\ gradient\_triangle.jpg [![[IM Output]](gradient_triangle.jpg)](gradient_triangle.jpg) Or a very odd looking bird like shape, generated by polar distortion along the top edge of the circular shape. magick -size 100x100 radial-gradient: \\ +distort Polar '49' +repage \\ gradient\_bird.jpg [![[IM Output]](gradient_bird.jpg)](gradient_bird.jpg) ### Gradients by Composition You can also modify gradients by combining them using various composition methods. For example you can use the [Modulus\_Add](../compose/#modulus_add) compose method to produce Venetian blind types of gradients. magick -size 100x100 gradient: \\( +clone +clone \\) \\ -background gray50 -compose ModulusAdd -flatten \\ gradient\_venetian.jpg [![[IM Output]](gradient_venetian.jpg)](gradient_venetian.jpg) And even do this diagonally. magick -size 100x100 gradient: \\( gradient: -rotate -90 \\) \\ \\( -clone 0--1 -clone 0--1 \\) \\ -background gray50 -compose ModulusAdd -flatten \\ gradient\_vent\_diag.jpg [![[IM Output]](gradient_vent_diag.jpg)](gradient_vent_diag.jpg) Or by blending two plain color gradients using either [Channel Copying](../compose/#channel) , or [Mathematical Blending](../compose/#math) composition methods, you can generate colorful 2 dimensional colormap gradients. magick -size 100x100 gradient:yellow-blue \\ \\( gradient:black-lime -rotate -90 \\) \\ -compose CopyGreen -composite gradient\_colormap.jpg [![[IM Output]](gradient_colormap.jpg)](gradient_colormap.jpg) ### Gradients in other Colorspaces While "`gradient:`" generator currently cannot generate gradients directly in some another [Color Spaces](../color_basics/#colorspace) , (only non-linear sRGB gradient images are created) you can transfer gradients into a different color space to generate interesting effects. For example... magick -size 30x600 xc:red -colorspace HSB \\ gradient: -compose CopyRed -composite \\ -colorspace RGB -rotate 90 gradient\_rainbow.jpg [![[IM Output]](gradient_rainbow.jpg)](gradient_rainbow.jpg) This first converts a highly saturated color ('`red`') into HSL colorspace, any saturated color can be used. This correctly sets the images saturation and brightness channels to the appropriate values. After this a gradient is generated and copied into the 'Hue' (equivalent to the 'red') channel of this HSL colorspace image. And hey presto when we magick the HSL image back to RGB, we get a full rainbow gradient of fully-saturated colors. Another method is to generate a gradient of just the right values for one of these colorspaces, then change the images colorspace (using "`[-set](https://imagemagick.org/script/command-line-options.php?#set) `"). This changes the colorspace without changing the color values that we created in the image. Now when we magick back to RGB we get the same rainbow of values. magick -size 30x600 gradient:'#FFF-#0FF' -rotate 90 \\ -set colorspace HSB -colorspace RGB \\ gradient\_rainbow\_2.jpg [![[IM Output]](gradient_rainbow_2.jpg)](gradient_rainbow_2.jpg) The result is actually exactly the same as the previous method, just a little more direct, in that we generate the right values for the desired colorspace, then set the colorspace those values belong to. Here we take the masked angular gradient (see above) and re-map it into the HSB color space to generate a circular hue of colors. Red (hue=0) is rotated toward to the right, where it is traditionally placed (polar coordinates angle 0). magick -size 100x300 gradient:'#FFF-#0FF' -rotate 90 \\ -alpha set -virtual-pixel Transparent +distort Polar 49 +repage \\ -rotate 90 -set colorspace HSB -colorspace RGB \\ gradient\_hue\_polar.png [![[IM Output]](gradient_hue_polar.png)](gradient_hue_polar.png) A similar example to the above is [Color Wheel](../color_basics/#colorwheel) , which is generated by [Combining Channel Images](../color_basics/#combine) with both a Hue and a Lightness gradient. ### Resized Gradient One trick that was brought up on the by Glenn Randers-Pehrson, was to create a very small image, two pixels across, then expand that to the image size needed using "`[-resize](https://imagemagick.org/script/command-line-options.php?#resize) `". The [Resize Operator](../resize/#resize) tries to smooth out enlarged images, to make them look better at the larger scale. It is this smoothing that we use to generate a non-linear gradient.For example, here we generate the small image using a 'portable bitmap' (or PBM format) image and feed it into IM for enlargement. echo "P1 1 2 0 1 " | \\ magick - -resize 100x100\\! gradient\_resize.jpg [![[IM Output]](gradient_resize.jpg)](gradient_resize.jpg) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Some shells like 'csh' and variants, cannot handle the '`!`' character in the above resize geometry setting very well -- not even in quotes. Hence the backslash '`\`' character may be needed. Caution is advised._ | The gradient produced is not linear, with a smooth start and finish to the colors given, making those colors much more pronounced, than you would get using a normal gradient. The actual function the gradient follows depends on (and is close to) the exact [Resampling Filter](../filter/) that was used by resize.A simple way to generate that initial two-pixel image is actually with gradient itself! This lets you specify the colors directly. Of course that will limit you to a vertical gradient, unless you rotate the result as well. magick -size 1x2 gradient:khaki-tomato \\ -resize 100x100\\! gradient\_resize2.jpg [![[IM Output]](gradient_resize2.jpg)](gradient_resize2.jpg) Of course you are not limited to just a single dimension, with this technique. Here I use a four pixel 'portable greymap' (or PGM image format) to generate a 2-dimensional gradient. echo "P2 2 2 2 2 1 1 0 " | \\ magick - -resize 100x100\\! gradient\_resize3.jpg [![[IM Output]](gradient_resize3.jpg)](gradient_resize3.jpg) As you can see this diagonal gradient is not very linear when compared to the [Rotated Gradient](#gradient_rotate) above. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The [Network Portable Bitmap](http://netpbm.sourceforge.net/)
image formats, are very versatile for generating images from scripts. It is a format that is well worth knowing as a means of generating or manipulating image data._ | If you look carefully you will also see that the gradient also starts from the center of the enlarged pixel, and does not cover the whole image from edge to edge. This becomes more clear if we use a [Triangle Resize Filter](../filter/#triangle) . magick \\( xc:red xc:blue +append \\) \\ \\( xc:yellow xc:cyan +append \\) -append \\ -filter triangle -resize 100x100\\! gradient\_resize4.jpg [![[IM Output]](gradient_resize4.jpg)](gradient_resize4.jpg) The [Resize Operator](../resize/#resize) smoothes the color between these pixels according to the "`[Resampling Filter](../filter/#filter) `" setings. By adjusting the filter you can have the resize gradient generate a more edge to edge effect. magick -size 1x2 gradient: \\ -filter Cubic -resize 100x100\\! gradient\_resize5.jpg [![[IM Output]](gradient_resize5.jpg)](gradient_resize5.jpg) Here is rough "Rainbow Gradient" created using the 'resize' technique. magick xc:black xc:red xc:yellow xc:green1 xc:cyan xc:blue xc:black \\ +append -filter Cubic -resize 600x30\\! gradient\_rs\_rainbow.jpg [![[IM Output]](gradient_rs_rainbow.jpg)](gradient_rs_rainbow.jpg) With this method you can use any color combination and order for the gradients generation. This makes it very well suited to generating [Color Lookup Tables](../color_mods/#color_lut) . ### Interpolated Lookup Gradients For more information on the "`[-interpolate](https://imagemagick.org/script/command-line-options.php?#interpolate) `" setting see [Interpolation Setting](../misc/#interpolate) . Another method of generating gradients is to use the special [Interpolation Setting](../misc/#interpolate) . This setting is used to determine the pixel color returned when the pixel lookup is not an integer, and thus does not exactly match a specific pixel. Interpolation then determines the color based on the pixels that surround the lookup point. The default setting of '`bilinear`' for example will linearly determine the color for a lookup that falls between two pixels. magick -size 600x30 xc: \\( +size xc:gold xc:firebrick +append \\) \\ -fx 'v.p{i/(w-1),0}' gradient\_interpolated.jpg [![[IM Output]](gradient_interpolated.jpg)](gradient_interpolated.jpg) Here the lookup X position '`i/(w-1)`' goes from '`0.0`' to '`1.0`' over the second two-pixel image. The floating point number produces a perfect linear gradient, much like "`[gradient:](#gradient) `" does. The above is actually almost equivalent (see [Perfect Gradients](#perfect_gradients) for difference) to using a [Clut Recolored Images](../color_mods/#clut) " to recolor a gradient image, using interpolated lookup of the two color image. magick -size 30x600 gradient: -rotate 90 \\ \\( +size xc:gold xc:firebrick +append \\) -clut \\ gradient\_clut\_recolored.jpg [![[IM Output]](gradient_clut_recolored.jpg)](gradient_clut_recolored.jpg) Using this method also allows you to generate multi-colored gradients. magick -size 30x600 gradient: -rotate 90 -interpolate Bicubic \\ \\( +size xc:black xc:tomato xc:wheat +append \\) -clut \\ gradient\_clut.jpg [![[IM Output]](gradient_clut.jpg)](gradient_clut.jpg) The limitation however is that the colors can only be defined with equal spacing. You can not simply shift the position of the middle color, except by roughly modifying the input gradient to some non-linear form, so as to shift that center. For more than three color is situation becomes worse. The above is also a good technique for coloring greyscale images using [Duotones](../color_mods/#duotone) , with a guarantee on exactly defining the mid-tone color (unlike using the [Tint Operator](../color_mods/#tint) ). Interpolated lookup gradients can also be expanded to 2 dimensions, and generate square linear gradients ([Bilinear Interpolation](../misc/#bilinear) ), just as easily as purely one dimensions gradients. magick \\( xc:red xc:blue +append \\) \\ \\( xc:yellow xc:cyan +append \\) -append \\ -size 100x100 xc: +swap -fx 'v.p{i/(w-1),j/(h-1)}' \\ gradient\_bilinear.jpg [![[IM Output]](gradient_bilinear.jpg)](gradient_bilinear.jpg) Here is the same example but using [Catrom Interpolation](../misc/#catrom) , and generating using the [Distort Operator](../distorts/#distort) instead of the very slow FX operator. magick \\( xc:red xc:blue +append \\) \\ \\( xc:yellow xc:cyan +append \\) -append \\ -filter point -interpolate catrom \\ -define distort:viewport=100x100 \\ -distort Affine '.5,.5 .5,.5 1.5,1.5 99.5,99.5' \\ gradient\_catrom.jpg [![[IM Output]](gradient_catrom.jpg)](gradient_catrom.jpg) The key point to understanding the above is that we are enlarging the small image based on the centers of its pixels. See [Image Coordinates vs Pixel Coordinates](../distorts/#control_coordinates) for details. Note that most interpolation methods have equivalent [Interpolated Resize Filters](../filter/#interpolate) . But the use of the viewport and pixel coordinates removes the edge effects that is shown in the previous [Resize Gradients](#gradient_resize) caused by extreme upscaling of the very small image. The [Mesh Interpolation](../misc/#mesh) setting however is not available as a [Resize Filter](../filter/#filter) . It is a special 2 dimensional interpolation that divides the intra-pixel area into two flat linear triangles, hinged along the diagonal connecting the corners with the minimal color difference. So by making two colors the same color, and using "`-interpolate mesh`" you can generate a very different 2D gradient. magick \\( xc:red xc:gold +append \\) \\ \\( xc:gold xc:green +append \\) -append \\ -filter point -interpolate mesh \\ -define distort:viewport=100x100 \\ -distort Affine '.5,.5 .5,.5 1.5,1.5 99.5,99.5' \\ gradient\_mesh.jpg [![[IM Output]](gradient_mesh.jpg)](gradient_mesh.jpg) As the two diagonally opposite yellow corners are the same, a diagonal of yellow was used to join them. With the other colors linearly mapped to those triangles. If the two diagonal colors are not the same, you may get a different diagonal division. ### Roll your own gradient The [FX DIY Operator](../transform/#fx) , lets you define your own gradients or other image generation, based on the current pixel position. As this operator requires an image to work with, you can generate your gradients or other images to match that image. That is, you don't have to know the size of the image to generate a gradient for it! For example you can easily generate a linear gradient, sized correctly for the image you may be working on. magick rose: -channel G -fx 'i/w' -separate gradient\_fx\_linear.gif [![[IM Output]](gradient_fx_linear.gif)](gradient_fx_linear.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _When generating gray-scale gradients, you can make the -fx operator 3 times faster, simply by asking it to only generate one color channel only, such as the '`G`' or green channel in the above example. This channel can then be [Separated](../color_basics/#separate)
to form the required gray-scale image. This can represent a very large speed boost, especially when using a very complex "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" formula._ | You can even generate some neat non-linear gradients. magick rose: -channel G -fx '(i/w)^4' -separate gradient\_fx\_x4.gif [![[IM Output]](gradient_fx_x4.gif)](gradient_fx_x4.gif) magick rose: -channel G -fx 'cos(pi\*(i/w-.5))' \\ -separate gradient\_fx\_cos.gif [![[IM Output]](gradient_fx_cos.gif)](gradient_fx_cos.gif) How about a 2-dimensional circular linear radial gradient (a cone). magick -size 100x100 xc: -channel G \\ -fx 'rr=hypot(i/w-.5, j/h-.5); 1-rr\*1.42' \\ -separate gradient\_fx\_radial.gif [![[IM Output]](gradient_fx_radial.gif)](gradient_fx_radial.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _The "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" function '`rr=hypot(xx,yy)`' was added to IM v6.3.6 to speed up the very commonly used expression '`rr=sqrt(xx*xx+yy*yy)`'. It also meant that we no longer need to make extra assignments such as '`xx=i/w-.5`' when creating a radial gradient._ | The value '`1.42`' (or `sqrt(2)`) in the above controls the overall size of the gradient relative to the images dimensions. In this way the radius of the gradient (how far black is from center) is diagonal distance to the corner.You can even remove the '`sqrt()`' (built into the '`hypot()`' function) from the expression to make a more interesting spherical gradient, which can be useful for [3D Shading Effects](../transform/#shade) . magick -size 100x100 xc: -channel G \\ -fx 'xx=i/w-.5; yy=j/h-.5; rr=xx\*xx+yy\*yy; 1-rr\*4' \\ -separate gradient\_fx\_spherical.gif [![[IM Output]](gradient_fx_spherical.gif)](gradient_fx_spherical.gif) Note how I use some assignment expressions to simplify the calculation of the distance from center of the image, then magick it to a gradient. This feature was added in IM v6.3.0.Using a high power function, you can give photos a fade off effect around the rectangular edges of the image. Adjust the power value '`4`' to control the amount of fading. magick -size 100x100 xc: -channel G \\ -fx '(1-(2\*i/w-1)^4)\*(1-(2\*j/h-1)^4)' \\ -separate gradient\_fx\_quad2.gif [![[IM Output]](gradient_fx_quad2.gif)](gradient_fx_quad2.gif) Here is an angular gradient, generated using direct mathematics. magick -size 100x100 xc: -channel G \\ -fx '.5 - atan2(j-h/2,w/2-i)/pi/2' \\ -separate gradient\_fx\_angular.gif [![[IM Output]](gradient_fx_angular.gif)](gradient_fx_angular.gif) Note that the '`atan2(y,x)`' function returns an angle in radians from -PI to +PI (see its manpage), so its output needs to be be scaled and translated to correctly fit a 0.0 to 1.0 color range. This is why the above looks so much more complex than it really is.This last example can be generated faster by [Distorting a Gradient](#gradient_distort) . ### More Complex DIY Gradients _ASIDE: This section was created before the addition of [Sparse Points of Color](#sparse-color) , and the had a direct influence on its creation._ Of course an FX function can generate color gradients. For example, here is a gradient based on distance ratios, using an extremely complex FX expression. magick -size 100x100 xc: +size xc:red xc:yellow -colorspace RGB \ -fx 'ar=hypot( i/w-.8, j/h-.3 )*4; br=hypot( i/w-.3, j/h-.7 )*4; u[1]*br/(ar+br) + u[2]*ar/(ar+br)' \ -colorspace RGB gradient_dist_ratio.gif [![[IM Output]](gradient_dist_ratio.gif)](gradient_dist_ratio.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The image processing was performed in a linear color space (RGB) to avoid 'sRGB darken' during the blending of such strong primary colors. See [Processing Real Images](../color_basics/#processing)
for more details._ | When going from two points to three points the ratio of how much color each 'control point' provides, is a bit more complex, and uses a technique called Inverse Distance Weighted (IDW) Interpolation. You can see more details math for this in [Wikipedia, IDW](http://en.wikipedia.org/wiki/Inverse_distance_weighting) Here is an inverse distance example for three points. magick -size 100x100 xc: +size xc:red xc:yellow xc:lime -colorspace RGB \ -fx 'ar=1/max(1, hypot(i-50,j-10) ); br=1/max(1, hypot(i-10,j-70) ); cr=1/max(1, hypot(i-90,j-90) ); ( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \ -colorspace sRGB gradient_inverse.gif [![[IM Output]](gradient_inverse.gif)](gradient_inverse.gif) And here I use an inverse distance squared which is the more normal method used for an IDW interpolation. This is also known as Shepard's Interpolation method. magick -size 100x100 xc: +size xc:red xc:yellow xc:lime -colorspace RGB \ -fx 'ar=1/max(1, (i-50)*(i-50)+(j-10)*(j-10) ); br=1/max(1, (i-10)*(i-10)+(j-70)*(j-70) ); cr=1/max(1, (i-90)*(i-90)+(j-90)*(j-90) ); ( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \ -colorspace sRGB gradient_shepards.gif [![[IM Output]](gradient_shepards.gif)](gradient_shepards.gif) Note that the '`hypot()`' function was not used in the above as there is no need to generate a square root of the distance. The above has now been implemented using the [Sparse Color](#sparse-color) methods '`[Inverse](#inverse) `' and '`[Shepard's](#shepards) `'. As such the above can now be done far more simply using... magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '50,10 red 10,70 yellow 90,90 lime' \\ -colorspace sRGB gradient\_inverse\_alt.gif magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Shepards '50,10 red 10,70 yellow 90,90 lime' \\ -colorspace sRGB gradient\_shepards\_alt.gif [![[IM Output]](gradient_inverse_alt.gif)](gradient_inverse_alt.gif) [![[IM Output]](gradient_shepards_alt.gif)](gradient_shepards_alt.gif) The problem with using either 'Inverse Distance' or 'Shepard's Method' (inverse squared distance) is that all the 'control points' has a global effect over the whole image. As a result you get a sort of underlying 'average color' in between the points, and especially at a large distance from all control points. This, in turn, produces 'spots' of color rather than a smooth gradient of color. ### DIY Gradients and Hues \-- (Hues are hard to deal with) _ASIDE: This was a sort of failed attempt to generate an interesting rainbow effect. It was a failure, but I learned a lot from that failure, which I present to you here._ The above works well but I wanted to try and to do better. I thought perhaps I could generate a bright rainbow gradient of colors between the points, rather than generating spots that merges into an average color. So to generate a hue gradient, I tried to do the [Inverse Distance Weighted Interpolation](http://en.wikipedia.org/wiki/Inverse_distance_weighting) in HSB colorspace, though I switched the yellow to blue, to make the colors more equally spaced around the hue, and hopefully provide another way of generating a color wheel (see [Gradients in Other Colorspaces](#gradient_colorspace) above). magick -size 100x100 xc: +size xc:red xc:blue xc:lime -colorspace HSB \ -fx 'ar=1/max(1, (i-50)*(i-50)+(j-10)*(j-10) ); br=1/max(1, (i-10)*(i-10)+(j-70)*(j-70) ); cr=1/max(1, (i-90)*(i-90)+(j-90)*(j-90) ); ( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \ -colorspace sRGB gradient_shepards_HSB.gif [![[IM Output]](gradient_shepards_HSB.gif)](gradient_shepards_HSB.gif) As you can see all the colors were nice an bright as we are only generating a hue gradient. However it also appears very strange, which is caused by the 'cyclic' nature of the 'Hue' color channel. As a consequence the area between the blue and the red goes the long way round though a green hue, rather than that the shorter 'modulus' path via a purple hue. After much research I finally discovered how to do the modulus mathematics needed to do the above correctly by using a [Circular Mean](http://en.wikipedia.org/wiki/Circular_mean) for the weighted average of distances. This involves converting the Hue as a polar angle, into X and Y rectangular coordinates. That allows you to perform linear mathematics, letting us perform a linear weighting of the values, appropriately. The result is then then converting back into an angular Hue. magick -size 100x100 xc: +size xc:red xc:blue xc:lime \ -colorspace HSB -channel R \ -fx 'aa=u[1]*2*pi; ba=u[2]*2*pi; ca=u[3]*2*pi; ar=1/max(1, hypot(i-50,j-10) ); br=1/max(1, hypot(i-10,j-70) ); cr=1/max(1, hypot(i-90,j-90) ); nr=ar+br+cr; mod(atan2( ( sin(aa)*ar + sin(ba)*br + sin(ca)*cr )/nr, ( cos(aa)*ar + cos(ba)*br + cos(ca)*cr )/nr )/(2*pi)+1, 1)' \ -separate -background white -combine +channel \ -set colorspace HSB -colorspace sRGB gradient_circular_mean_hue.gif [![[IM Output]](gradient_circular_mean_hue.gif)](gradient_circular_mean_hue.gif) NOTE: The above only performed its operations on the hue channel only. For real image, we would still need to operate (as normal) on saturation and brilliance channels. As you can see we now get a correct gradient between the red and blue, though the method when applied to just primary colors that have a high angular separation, tends to generate very sudden gradient changes in the middle. That is, while the result is correct the angular hue variation is not linear for very large changes in hue effects. It would work well for averaging lots of near hues, but not for these widely spaced primaries. I even switched to using a stronger 'Inverse Weighting' rather than the more usual 'Inverse Squared' or 'Shepard's' method (see above) and while it improved things, the hue changes were still compressing in the center due to the non-linear effects. As the input colors are constant, pre-converting them into hue-x, and hue-y coordinates, doing the shepard's weighting on those channels, then converting back again would actually make the process even faster. That is, convert colors from a HSB colorspace to a Hx,Hy,S,B colorspace, to apply the technique. If this is done, then central point and even gradient between the points, would shade to white (the center point of a HSB colorspace). If this was performed in HSL colorspace that area would shade toward a mid-tone gray. This conversion from a polar Hue to X-Y coordinates would in some ways be similar to just doing the calculations in a non-polar RGB space, which shows that same shade toward gray effects (see previous examples). So if by using a [Circular Mean](http://en.wikipedia.org/wiki/Circular_mean) we are in fact simply converting a HSB colorspace into a highly distorted variant RGB, why not just do the task in a linear RGB colorspace, and saturate the colors, to generate the hue! magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '50,10 red 10,70 blue 90,90 lime' \\ -colorspace sRGB gradient\_inverse\_RGB.png magick gradient\_inverse\_RGB.png -colorspace HSB \\ -channel GB -evaluate set 100% +channel \\ -colorspace sRGB gradient\_inverse\_RGB\_Hue.gif [![[IM Output]](gradient_inverse_RGB.png)](gradient_inverse_RGB.png) ![=>](../img_www/right.gif) [![[IM Output]](gradient_inverse_RGB_Hue.gif)](gradient_inverse_RGB_Hue.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The image processing was performed in a linear color space (RGB) to avoid 'sRGB darken' during the blending of such strong primary colors. See [Processing Real Images](../color_basics/#processing)
for more details._ | As you can see we get practically exactly the same result as before, but with all the complex 'modulus mathematics' removed. However I am still no closer to getting a more linear spread of hues between the starting points of color. The moral of all this is that working with Hues is hard, not only due to the 'red discontinuity', but also because of non-linear effects that happen when colors are very widely spaced. And in the end the result was the same as if I have done the task directly linear RGB space and saturating the colors. Essentially while HSB and HSL colorspaces are fun, they are not linear, realistic, or practical colorspaces to work with. This is also probably why very few operations actually work with hue directly. ### Generating the Perfect Gradient (mathematically) Generating perfect mathematical gradient, such as for [Fourier Transforms](../fourier/) (which is cyclic), [Image Mapping](../mapping/#distort) , or even [Gradient Mathematics](../transform/#gradient_math) ; requires special gradients that is different to the gradients we have so far looked at.What do I mean by this? Well here is a small 1x5 pixel "`gradient:`" image, that I have [Scaled](../resize/#scale) so you can see the individual pixel colors. magick -size 1x5 gradient: -scale 2000% gradient.png [![[IM Output]](gradient.png)](gradient.png) This image creates a gradient that goes from an exact 'white' color along the very top row, to an exact 'black' color along the bottom most row. It is an 'idealized' gradient, and typically exactly what an user wants, as it actually contains the actual colors the user specified. However while this is what an user expects, it is not a mathematically correct gradient. As discussed in [Image Coordinates vs Pixel Coordinates](../distorts/#control_coordinates) pixels actually have an area, and as such the white pixel at the top of the image represents the center of that pixel, while the black represents the center of he bottom most pixel. That is, not the edge of the image but 1/2 pixel away from the edge. Mathematically images start at the edge. As such to generate a perfect mathematical gradient, you need to specify the color locations at the edge of the image, in pixel coordinates. As such in image coordinates, the positions are displaced by 1/2 a pixel, and the image size is exactly the number of pixels in the image (a distance), rather than a location that is 1 pixel smaller that the images size. One way to generate a mathematically perfect gradient is to use [Barycentric Sparse Color](#barycentric) (looked at in detail in the next section) to generate a perfect edge-to-edge gradient... magick -size 1x5 xc: \\ -sparse-color Barycentric '0,-0.5 white 0,%\[fx:h-.5\] black' \\ -scale 2000% gradient\_math.png [![[IM Output]](gradient_math.png)](gradient_math.png) Note that the coordinates used go from `-0.5` to the images height minus `0.5`, That the pixel coordinates of the actual edges of the image. And if you were to look closely at the results you will find that the top and bottom most pixels are _not white or black in color_. The pixel is the color of the gradient at the pixels center. Because this gradient is mathematically correct, this gradient will 'tile' correctly when used in special 'tiling' or 'cyclic' situations. The previous gradient image will not 'tile' correctly. You get a pure-white pixel, next to, the pure-black pixel, so as to generate an one pixel gap or 'disjunction' in the mathematical cycle, in situations where pure white and pure black are typically regarded as equivalent values. A simpler way is to generate a "`[gradient:](#gradient) `" image that is one pixel longer, and chop one pixel, from either end (according to the current "`[-gravity](https://imagemagick.org/script/command-line-options.php?#gravity) `" setting).For example, here chopped the top-most white pixel, as having a black pixel (or zero value) is often more desirable in the final result. magick -size 1x6 gradient: -chop 0x1 -scale 2000% gradient\_chopped.png [![[IM Output]](gradient_chopped.png)](gradient_chopped.png) The resulting gradient image can then be [Rotated](../warping/#rect_rotates) as needed, to then generate the required image for later image processing. However while this gradient will 'cycle' correctly, the actual position of the color is not exactly correct. But in many cases this is good enough. If you need a 'perfect gradient' I recommend you use a sparse color gradient. **In Summery...** A little thought about exactly what you want from your gradient can make a big difference in the accuracy of your final results. But if it does not matter, than don't worry about it, use whatever is simplest for the task at hand. * * * Sparse Points of Color ---------------------- The "**`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `**" operator was added to IM v6.4.3-0 will take an image and set the color given at each of the given floating point '`x,y`' coordinates. That is, of the form... \-sparse-color {method} 'x,y color x,y color x,y color ...' The rest of the pixels (limited according to the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting) will then be mapped according to there relation to these isolated points of color, so as to smooth out the colors between those points. The _method_ defines what that relationship will be. Naturally there are lots of ways to define what the intervening color should be, and which method you choose really depends on what you are attempting to achieve. It can also actually be classed as a completely free-form version of 2-dimensional interpolation (See [Interpolation, Wikipedia](http://en.wikipedia.org/wiki/Interpolation) ). Image enlargement, or [Resize](../resize/#resize) is actually a specialized sub-set of this, but one where you start with a complete fixed grid of pixels to be enlarged. Unfortunately few of the [Resize Filters](../filter/#filter) or [Interpolate Methods](../misc/#interpolate) that are specifically designed to dealing with a grid of points, will translate directly into a free form set of sparsely separated points of color. That is, to say resize involving incomplete grid just does not work. This is also related to "Geographical Information System (GIS)" methods where landscapes are measured using sparsely separated points of height (which are rarely in a strict grid), with the rest of the landscape being determined from those isolated points. In a similar situation meteorology often has isolated points of air pressure and temperature, which then needs to be interpolated. Typically after interpolation the maps are further processed to generate 'iso-lines' showing points of equal value (height, pressure, temperature), producing the various weather maps almost everyone are familiar with. In this case you would think of the generated image as being a simple gray-scale 'height map' of the input data, or perhaps even of all three variables simultaneously, each to a separate image 'channel'. ### Barycentric (triangle gradient) The "`Barycentric`" method, will map three and only three points into a linear triangle of color. The colors outside this triangle continue as before. I have marked the input points with a small circle, so that the colors you see are all the interpolated values that were generated by the [Sparse Color Operator](#sparse-color) . magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Barycentric '30,10 red 10,80 blue 90,90 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82 circle 90,90 90,92' \\ sparse\_barycentric.png [![[IM Output]](sparse_barycentric.png)](sparse_barycentric.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The image processing was performed in a linear color space (RGB) to avoid 'sRGB darken' during the blending of such strong primary colors. See [Processing Real Images](../color_basics/#processing)
for more details._ | If four or more points are given a 'best fit' will be performed, over all the points given, and as a result the actual points may not get the exact color specified for those points. However be warned that the gradient does not just 'stop' but continues to change beyond those points. Traditionally a barycentric gradient will be limited to within the enveloping triangle of the points used to generate it. For example.. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Barycentric '30,10 red 10,80 blue 90,90 lime' \\ -colorspace sRGB -fill white -stroke black \\ \\( -size 100x100 xc:black -draw 'polygon 30,10 10,80 90,90' \\) \\ -alpha off -compose CopyOpacity -composite \\ -draw 'circle 30,10 30,12 circle 10,80 10,82 circle 90,90 90,92' \\ sparse\_bary\_triangle.png [![[IM Output]](sparse_bary_triangle.png)](sparse_bary_triangle.png) This is a faster version from Fred Weinhaus, that creates a triangle mask in the alpha channel, which by default, the [Sparse Color Operator](#sparse-color) will not update (due to the default channel settings). All the colors including fully transparent pixels are however still filled with color, just alpha masked. magick -size 100x100 xc:none -draw "polygon 30,10 10,80 90,90" \\ -colorspace RGB \\ -sparse-color Barycentric '30,10 red 10,80 blue 90,90 lime' \\ -colorspace sRGB sparse\_bary\_triangle\_2.png [![[IM Output]](sparse_bary_triangle_2.png)](sparse_bary_triangle_2.png) | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _The triangular masks used above are 1/2 pixel too big due to the way draw draws an extra line around its shapes. See [Draw Fill Bounds](../draw/#bounds")
for details. This could be a problem when generating a generating a triangular mesh of gradients._ | The '`barycentric`' method is in reality a mapping of a linear affine equation to each of the three color channels separately. As such if I separate each of the color channels of the above three point example, you get three simple linear gradients in each color channel. magick sparse\_barycentric.png -separate sparse\_bary\_%d.gif [![[IM Output]](sparse_barycentric.png)](sparse_barycentric.png) ![=>](../img_www/right.gif) [![[IM Output]](sparse_bary_0.gif)](sparse_bary_0.gif) [![[IM Output]](sparse_bary_1.gif)](sparse_bary_1.gif) [![[IM Output]](sparse_bary_2.gif)](sparse_bary_2.gif) It is only because of the use of primary colors that the above gradients all were mapped parallel to one of the edges of the triangle. That is, not typically the case. But you will always get a simple linear gradient in each separate channel of the image, and a flat plane of values in 3D color space. #### Barycentric and Two Color Gradients This parallel effect of the triangular barycentric gradient is actually very useful. If two of the points were set to the same color, then those to points will define the 'angle' of the gradient between them and the other colored point. For example by making two of the points '`red`' the gradient will be made parallel to the two '`red`' points... magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Barycentric '30,10 red 10,80 red 90,90 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82 circle 90,90 90,92' \\ sparse\_bary\_gradient.png [![[IM Output]](sparse_bary_gradient.png)](sparse_bary_gradient.png) Here is the same example but with one of the angle control points moved to show how it sets the gradient angle. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Barycentric '50,70 red 10,80 red 90,90 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 50,70 50,72 circle 10,80 10,82 circle 90,90 90,92' \\ sparse\_bary\_gradient\_2.png [![[IM Output]](sparse_bary_gradient_2.png)](sparse_bary_gradient_2.png) #### Diagonal Gradients This provides a simple way of generating any linear diagonal gradient using just two colors. For example, here is a particularly nice way of creating a diagonal gradient, going from one corner to another corner, for ANY sized input image. magick -size 600x60 xc: -colorspace RGB \\ -sparse-color barycentric '0,0 skyblue -%w,%h skyblue %w,%h black' \\ -colorspace sRGB diagonal\_gradient.jpg [![[IM Output]](diagonal_gradient.jpg)](diagonal_gradient.jpg) And to align with the other two corners... magick -size 600x60 xc: -colorspace RGB \\ -sparse-color barycentric '0,%h black -%w,0 black %w,0 skyblue' \\ -colorspace sRGB diagonal\_gradient\_2.jpg [![[IM Output]](diagonal_gradient_2.jpg)](diagonal_gradient_2.jpg) These 'diagonal gradients' produce a natural looking gradient even with long images such as the above. Study the locations of the three color points, especially the two points of equal color that define the angle of the gradient between the two corners. Notice that in both cases one of the those points is not even located within the image itself! Also note the use of [Percent Escapes](../basics/#arg_percent) to make the positions automatically adjust to the size of the images on which the gradient is being drawn. #### Two Point Gradients If only two color points are given, IM will generate the third point for you, so that the angle is perpendicular between the two original points. The result is a simple linear gradient over which you have a lot of control. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Barycentric '30,10 red 90,90 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 90,90 90,92' \\ sparse\_bary\_two\_point.png [![[IM Output]](sparse_bary_two_point.png)](sparse_bary_two_point.png) Two point gradients however do not work very well when applied to the corners of very 'wide' or 'tall' images (high-aspect ratio). Basically the gradient is not diagonally aligned, unlike the three point gradients above. It is angled, just not angled enough to make it 'interesting'. magick -size 600x60 xc: -colorspace RGB \\ -sparse-color barycentric '0,0 skyblue %w,%h black' \\ -colorspace sRGB sparse\_bary\_two\_point\_wide.jpg [![[IM Output]](sparse_bary_two_point_wide.jpg)](sparse_bary_two_point_wide.jpg) ### Bilinear (4 point gradient) This method fits an equation to 4 points, over all three color channels to produce an uniform color gradient between the points, and beyond. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Bilinear '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_bilinear.png [![[IM Output]](sparse_bilinear.png)](sparse_bilinear.png) You can see this '4 point fit' by taking the above image and separating out the individual color channel gradients. magick sparse\_bilinear.png -separate sparse\_bilin\_%d.gif [![[IM Output]](sparse_bilinear.png)](sparse_bilinear.png) ![=>](../img_www/right.gif) [![[IM Output]](sparse_bilin_0.gif)](sparse_bilin_0.gif) [![[IM Output]](sparse_bilin_1.gif)](sparse_bilin_1.gif) [![[IM Output]](sparse_bilin_2.gif)](sparse_bilin_2.gif) Note how the equation produces curves (quadratic curves actually). However if the 4 points form parallel lines, the gradient generated will become linear. This method is actually equivalent to the [Bilinear Interpolation](../misc/#bilinear) method (see [Interpolated Lookup Gradients](#gradient_interpolate) below), when the 4 points are aligned to a orthogonal (rectangular) grid. If less than 4 points are given the above function will be replaced by a 3 point '`[Barycentric](#barycentric) `' method (see above). If more than four points are given it will do a best fit of all the points, and thus may not actually match the given color at the point specified. This is not recommended. ### Voronoi (nearest color) The "`Voronoi`" method, just maps each pixel to the closest color point you have provided. This basically divides the image into a set of polygonal 'cells' around each point. For example.. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Voronoi '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_voronoi.gif [![[IM Output]](sparse_voronoi.gif)](sparse_voronoi.gif) As you can see no attempt is made to provide anti-aliasing of the colored 'cells' around each point. The edge of each cell actually falls exactly midway between each point's nearest neighbours. This can be used for example to generate masks to cut up the image in various ways. Just assign one point as white and all the rest as black to extract one single 'cell' from the image. If you want to smooth (anti-alias) the result you can either use some form of [Super Sampling](../distorts/#super_sampling) to smooth the image. For example generate one 4 times as big, and "`[-scale](https://imagemagick.org/script/command-line-options.php?#scale) `" it back to the desired size. magick -size 400x400 xc: -colorspace RGB \\ -sparse-color Voronoi '120,40 red 40,320 blue 270,240 lime 320,80 yellow' \\ -scale 25% -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_voronoi\_ssampled.png [![[IM Output]](sparse_voronoi_ssampled.png)](sparse_voronoi_ssampled.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _All the image processing was performed in a linear color space (RGB) to avoid 'sRGB darken' during the blending of such strong primary colors. See [Processing Real Images](../color_basics/#processing)
for more details._ | The simpler way (though not very nice) is to just simply blur the image very slightly... magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Voronoi '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -blur 1x0.7 -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_voronoi\_smoothed.png [![[IM Output]](sparse_voronoi_smoothed.png)](sparse_voronoi_smoothed.png) By blurring generated image by a large amount you can set up some non-linear gradients between the 'cells' that was generated. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Voronoi '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -blur 0x15 -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_voronoi\_blur.png [![[IM Output]](sparse_voronoi_blur.png)](sparse_voronoi_blur.png) The larger the "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `", the larger the gradient between the various 'cells'. However be warned that this may not preserve small colored cells, or ensure the original point remains the color that was given, if it is close to the edge (and another point) of a different color. By using a special 'linear blur' technique, developed by Fred Weinhaus, you can produce a fixed width linear gradient between the cells. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Voronoi '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -blur 10x65535 -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_voronoi\_gradient.png [![[IM Output]](sparse_voronoi_gradient.png)](sparse_voronoi_gradient.png) The unblurred output could also passed to various [Edge Detection](../transform/#edge) techniques to generate various bounded edges. You can remap the image via a [Raster to Vector Convertor](../transform/#edge_vector) to generate vector lines. However I found the default '`autotrace`' settings may need to be adjusted with "`-corner-threshold 120`" so it will detect the corners better. ### Shepards (spots of color) The "`Shepards`" method uses a ratio of the inverse squares of the distances to each of the given points to determine the color of the canvas at each point. See [More Complex DIY Gradients](#gradient_complex) above for examples of how the mathematics is performed. It is a bit like having spotlights of color at each point which interacts with each other, as the light spreads out to an uniform average of all the given colors at infinity. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards.png [![[IM Output]](sparse_shepards.png)](sparse_shepards.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The image processing was performed in a linear color space (RGB) to avoid 'sRGB darken' during the blending of such strong primary colors. See [Processing Real Images](../color_basics/#processing)
for more details._ | By surrounding a specific area with a similar color you can generate a plateau of that specific color, though the boundaries between the edging points may 'leak', and the center of the 'plateau' may sag to form shallow bowl (depending on distance to other color points). This method is also what is used to generate a displacement field, such as what is used in [Shepards Image Distortions](../distorts/#shepards) . In that case X and Y displacement vectors is what is being mapped rather than color R,G,B values. ### Inverse (sharp points of color) The "`Inverse`" method is practically identical to "`Shepards`", except that it uses a more direct inverse distance weighting of the points given. See [More Complex DIY Gradients](#gradient_complex) above for examples of how the mathematics is performed. This was a much later addition to ImageMagick version 6.6.9-7. For example... magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_inverse.png [![[IM Output]](sparse_inverse.png)](sparse_inverse.png) As you can see it generates sharp points of color, that quickly merges into the background 'average color'. In comparison to [Shepards Method](#shepards) which generates rounded spots, with a 'flat' color around the color points. It does however work better when generating linear gradients where all the control points form a line. That is, for generating 1 dimensional gradients along a specific line in the image. However there is one more point to be made. The speed of how fast these points of color drops to a near 'average' level is controlled my how close they are. Placing two point sources close together, and they drop quickly, the further apart they are and the larger individual colors influence results. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '45,45 red 55,55 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 45,45 45,47 circle 55,55 55,57' \\ sparse\_inverse\_near.png magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '30,30 red 70,70 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,30 30,32 circle 70,70 70,72' \\ sparse\_inverse\_far.png [![[IM Output]](sparse_inverse_near.png)](sparse_inverse_near.png) [![[IM Output]](sparse_inverse_far.png)](sparse_inverse_far.png) Also if you 'double up' a specific point (exactly on, or just near each other) with the same or similar color, you will make that color point, twice as strong. magick -size 100x100 xc: -colorspace RGB \\ -sparse-color Inverse '30,30 red 75,65 lime 65,75 lime' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,30 30,32 circle 75,65 75,67 circle 65,75 65,77 ' \\ sparse\_inverse\_stronger.png [![[IM Output]](sparse_inverse_stronger.png)](sparse_inverse_stronger.png) These effects also applies to '`[Shepards](#shepards) `' method too! ### Shepards Power Factor Both the [Shepards](#shepards) and [Inverse](#inverse) sparse color methods are actually the same but with different 'power levels' applied to the inverse distance weights. (2.0 and 1.0 respectiavally). As of IM v6.8.0-10, you can set this power level using an operational [define](../basics/#define) , '`shepards:power`', which will be used by the '`[Shepards](#shepards) `' method. For example magick -size 100x100 xc: -colorspace RGB -define shepards:power=0.5 \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_pow0.5.png magick -size 100x100 xc: -colorspace RGB -define shepards:power=1 \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_pow1.png magick -size 100x100 xc: -colorspace RGB -define shepards:power=2 \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_pow2.png magick -size 100x100 xc: -colorspace RGB -define shepards:power=3 \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_pow3.png magick -size 100x100 xc: -colorspace RGB -define shepards:power=8 \\ -sparse-color Shepards '30,10 red 10,80 blue 70,60 lime 80,20 yellow' \\ -colorspace sRGB -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_pow8.png | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](sparse_shepards_pow0.5.png)](sparse_shepards_pow0.5.png)

power 0.5 | [![[IM Output]](sparse_shepards_pow1.png)](sparse_shepards_pow1.png)

power 1.0
(inverse) | [![[IM Output]](sparse_shepards_pow2.png)](sparse_shepards_pow2.png)

power 2.0
(shepards) | [![[IM Output]](sparse_shepards_pow3.png)](sparse_shepards_pow3.png)

power 3.0 | [![[IM Output]](sparse_shepards_pow8.png)](sparse_shepards_pow8.png)

power 8.0 | As you can see the 'spots of color' expand from very sharp points, to rounded spots, and on to large areas of color. At very high power levels it will eventually reproduce the same pattern as a [Voronoi Sparse Color Method](#voronoi) . This [\-define](../basics/#define) not only effects [Shepards Sparse Color](#shepards) , but also will have similar effects on [Shepards Distortion Method](../distorts/#shepards) which is based on calculated displacement maps generated by the sparse color method. However it does not effect the [Inverse](#inverse) sparse color method, which always uses a power-level of 1.0. ### Summery of Sparse Color Methods Here is a repeat of the various, 4 point "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `" images, for comparison. | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](sparse_voronoi.gif)](sparse_voronoi.gif)

Voronoi | [![[IM Output]](sparse_voronoi_blur.png)](sparse_voronoi_blur.png)

Voronoi (blurred) | [![[IM Output]](sparse_shepards.png)](sparse_shepards.png)

Shepards | [![[IM Output]](sparse_inverse.png)](sparse_inverse.png)

Inverse | [![[IM Output]](sparse_bilinear.png)](sparse_bilinear.png)

Bilinear | And here is a summery of the various, 3 point methods. | | | | | | | --- | --- | --- | --- | --- | | [![[IM Output]](sparse_voronoi_3pt.gif)](sparse_voronoi_3pt.gif)

Voronoi | [![[IM Output]](sparse_voronoi_blur_3pt.png)](sparse_voronoi_blur_3pt.png)

Voronoi (blurred) | [![[IM Output]](sparse_shepards_3pt.png)](sparse_shepards_3pt.png)

Shepards | [![[IM Output]](sparse_inverse_3pt.png)](sparse_inverse_3pt.png)

Inverse | [![[IM Output]](sparse_barycentric.png)](sparse_barycentric.png)

Barycentric | At this time only '`[Voronoi](#voronoi) `', '`[Shepards](#shepards) `' and '`[Inverse](#inverse) `' methods are suitable for more than four points. _More "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `" methods are planned. If you have any ideas mail them to me._ ### Channel and Sparse Color The "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `" operator is effected by the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting which means you can use that setting to limit its effects to just a single channel, or expand it to the transparency channel. You can also use the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting to speed up processing of gray-scale images by only operating on one channel, then "`[-separate](https://imagemagick.org/script/command-line-options.php?#separate) `" that channel (see [Channel Handling](../color_basics/#channel) for more detail). For example.. magick -size 100x100 xc: -channel G -sparse-color Shepards \\ '30,10 gray70 10,80 black 70,60 white 80,20 gray(33.3333%)' \\ -separate +channel -fill white -stroke black \\ -draw 'circle 30,10 30,12 circle 10,80 10,82' \\ -draw 'circle 70,60 70,62 circle 80,20 80,22' \\ sparse\_shepards\_gray.gif [![[IM Output]](sparse_shepards_gray.gif)](sparse_shepards_gray.gif) As of IM v6.6.8-5 unmodified channels is preserved, as such you can now use [Sparse Color](#sparse-color) with the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting to add a transparent gradient to any image, quickly and easily. For example, here I add a transparent [Diagonal Gradient](#diagonal_gradient) , that is aligned so that 50% transparency is along the diagonal of the built-in "`rose:` image. magick rose: -alpha set -channel A \\ -sparse-color Barycentric \\ '0,0 opaque %w,-%h opaque %w,%h transparent' \\ rose\_alpha\_gradient.png [![[IM Output]](rose_alpha_gradient.png)](rose_alpha_gradient.png) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _The color '`Opaque`' is just another name for '`Black`'. Basically it is used when you are really only interested in specifying a fully-opaque color, but the actual color itself unimportant. Similarly with the color '`Transparent`'. I could have just as easily used '`White`' and '`None`' respectively._ | | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _Before IM v6.6.8-5 any channels not selected by the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting was reset to zero (black) values. This severely limited its effective usefulness_ | [Sparse Color](#sparse-color) also accepts normalized floating point values instead of a color name. Exactly how many values need to be provided to replace the color name depends on the current "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting, and whether that channel is 'active' in the image being processed. The easiest way is to limited the processing to a single channel. Also note that when using raw numbers, rather than color names, transparency values are 'matte' values (0=opaque) and not 'alpha' values (1=opaque) (for IMv7). As such in the above I could have used numbers instead of color names... -channel A -sparse-color Bilinear '0,0 1.0 -%w,%h 1.0 %w,%h 0.0' This may be easier to handle in programmed scripts, and in API's, which may not have access to the 'colorname' translator. ### Sparse Color as a Fill Operator One of the original reasons for creating the [Sparse Color Operator](#sparse-color) , was so that you could give an image containing just a small number of fixed points of color, and from this 'fill-in' the rest of the undefined colors. For example, here I have drawn a small number of pixels. The "`[+antialias](https://imagemagick.org/script/command-line-options.php?#antialias) `" setting was specifically turned off so no semi-transparent, or mixed colors have been drawn, as such the image only contains the four exact colors specified an no others. magick -size 100x100 xc:none +antialias -fill none -strokewidth 0.5 \\ -stroke Gold -draw "path 'M 20,70 A 1,1 0 0,1 80,50'" \\ -stroke DodgerBlue -draw "line 30,10 50,80" \\ -stroke Red -draw "circle 80,60 82,60" \\ sparse\_source.gif [![[IM Output]](sparse_source.gif)](sparse_source.gif) Now we can extract the few non-transparent pixels that are present in this image, then fill in all the other colors using the multi-point sparse color method, '`[Shepards](#shepards) `'. magick sparse\_source.gif sparse-color:- |\\ magick sparse\_source.gif -alpha off \\ -sparse-color shepards '@-' sparse\_fill.png [![[IM Output]](sparse_fill.png)](sparse_fill.png) The "`sed`" command in the above takes the [Enumerated Text File Format](../files/#txt) , deletes the first header line and any line containing transparency, before re-formatting it into a list of pixel coordinates and colors. That list is then 'pipelined' into the [Sparse Color Operator](#sparse-color) using the special "`@-`" argument. Yes the above is very tricky, but works. At least for a very small number of points. However the more points that are provided, the slower the operation becomes. This is because [Sparse Color](#sparse-color) is 'point' orientated in its processing, rather than image or [Morphology](../morphology) orientated. Eventually I hope to be able to provide a set of morphology orientated, 'hole-filling' methods, where you can just give the above image as-is and have it fill in the transparent areas automatically. This point-extraction technique can be combined with the [EdgeIn Morphology Method](../morphology/#edge-in) to extract the pixels around the edges of objects or holes, so that you can then 'fill-in' the missing background or holes (as shown in [Morphology and Channels](../morphology/#channels) ). For example... magick figure.gif -channel A -morphology EdgeIn Diamond shape\_edge\_pixels.gif magick shape\_edge\_pixels.gif txt:- |\\ sed '1d; / 0) /d; s/:.\* /,/;' | \\ magick shape\_edge\_pixels.gif -alpha off \\ -sparse-color shepards '@-' shape\_edge\_in\_lights.png magick shape\_edge\_in\_lights.png figure.gif -composite shape\_in\_lights.png [![[IM Output]](figure.gif)](figure.gif) ![=>](../img_www/right.gif) [![[IM Output]](shape_edge_pixels.gif)](shape_edge_pixels.gif) ![=>](../img_www/right.gif) [![[IM Output]](shape_edge_in_lights.png)](shape_edge_in_lights.png) ![=>](../img_www/right.gif) [![[IM Output]](shape_in_lights.png)](shape_in_lights.png) Note that the resulting image is exactly the same as the input, but with the transparent background replaced with a distance blurred 'edge colors'. This is why the edges of the image have become in-distinct. This image was specifically developed to try and generate better 'edge feathering' techniques. See [Blur Feathering](../blur/#feathering) and [Distance Feathering](../morphology/#distance_feather) for other feathering techniques. ### Sparse Color Shepards, a Blur Alternative One alternative to using "`[-sparse-color](https://imagemagick.org/script/command-line-options.php?#sparse-color) `" is to take the image of pixels on a transparent background, and [Blur](../blur/#blur) it. Afterward the transparency is junked. magick sparse\_source.gif -channel RGBA -blur 0x15 \\ -alpha off sparse\_blur\_simple.png [![[IM Output]](sparse_source.gif)](sparse_source.gif) ![=>](../img_www/right.gif) [![[IM Output]](sparse_blur_simple.png)](sparse_blur_simple.png) The problem with this is that the original colors not preserved, and you also have the problem of exact what '_sigma_' value should be used. Also it does not take into account just now 'near' each color is, as such two colored pixels close together (less than the '_sigma_' value) will swamp each other, and become blurred together. A better method is to generate multiple layers of blurred images with progressively smaller '_sigma_' values, and the original unblurred image on top. for sigma in 64 32 16 8 4 2 1 0; do magick sparse_source.gif -depth 16 \ -channel RGBA -blur 0x$sigma miff:- done | magick - -background none -flatten -alpha off sparse_blur_layered.png [![[IM Output]](sparse_source.gif)](sparse_source.gif) ![=>](../img_www/right.gif) [![[IM Output]](sparse_blur_layered.png)](sparse_blur_layered.png) This layered blurring technique is equivalent to the result of a '`[Shepards](#shepards) `' method on the same image, though not as exact, it is very close. However it is likely to be much faster when a lot of input pixels are involved, as it is image (morphology) oriented, rather than calculating using individual points. An other layered blur method is to use [Resize](../resize/#resize) to generate a 'pyramid' of blurred images. This technique is detailed in [Large Blurs using Resize](../blur/#blur_resize) . magick sparse\_source.gif \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ \\( +clone -resize 50% \\) \\ -layers RemoveDups -filter Gaussian -resize 100x100\\! -reverse \\ -background None -flatten -alpha off sparse\_blur\_pyramid.png [![[IM Output]](sparse_blur_pyramid.png)](sparse_blur_pyramid.png) This will work very fast with very large images without needing large '_sigma_' values (and thus very slow) for each of the blurring steps. Essentially it is using a faster image resizing technique to generate the blurred layers of the previous example. It is not as exact, but will generate a good approximation of the correct result. However it works best for images which are a square, and a power of two in size, or it will be less accurate. The special operator "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) RemoveDups`" in the above will remove any extra 'single average pixel' images that was generated, by the multiple 'clone-resize' operations. The images are then resize back to the original size using a [Gaussian Resize Filter](../filter/#gaussian) (the equivalent to a blur). The image order is then reversed so as to place the original on top, and the more blurry layers underneath, before flattening together as before. It has the advantage of only needing to read the image once, doing all the work in a single command. It also works very quickly even for large images, especially as the resize only halves the image at each step, and thus avoids the slow blurring with a very large sigma. The only disadvantage with this method is that you will need to have a rough idea of the original size of the image to restore the 'blurred' images, and to get at least a rough idea of how many resized clones to generate (Log2 of the largest dimension, plus 1). However overdoing the resize clones is not a major performance hit as the resize simply becomes a 'no-op' when the input image has already been resized down to the minimal 1 pixel image. The extra and useless 'resized image layers' are then dealt with automatically using "`[-layers](https://imagemagick.org/script/command-line-options.php?#layers) RemoveDups`".The only real problem is the possibility of the resized images becoming 'out of sync' when handling an image that is not a power-of-two in size. How severe this problem is is not known, but shouldn't be too great, as those images are also the most blurred. Of course it still has the 'leakage' problem of the '`[Shepards](#shepards) `' method, so lets look at this problem in more detail. ### Shepards Method 'Leaks' The '`[Shepards](#shepards) `' method does not have any understanding of 'boundaries', and as such colors on the far side of some 'line of color' will leak, or 'bleed thru' past that line. Eventually at a large distance you will get a pure average color of all the pixels. This is not always a desirable outcome (though is desirable in some cases). In this example, the closer the '`Red`' curve approaches the '`White`' line, the more the color will 'leak' though the two lines to the far side producing a pink color. magick -size 100x100 xc:none +antialias -fill none -strokewidth 0.5 \\ -stroke Red -draw "path 'M 26,0 A 55,61 0 0,1 26,100'" \\ -stroke White -draw "line 50,0 50,100" \\ sparse\_lines\_near\_source.gif [![[IM Output]](sparse_lines_near_source.gif)](sparse_lines_near_source.gif) magick sparse\_lines\_near\_source.gif txt:- |\\ sed '1d; / 0) /d; s/:.\* /,/;' |\\ magick -size 100x100 xc: -sparse-color shepards '@-' \\ sparse\_lines\_near.png [![[IM Output]](sparse_lines_near.png)](sparse_lines_near.png) This leakage of colors is the main problem with using [Shepards Method](#shepards) for 'hole filling' especially when multiple holes are involved, as the colors involved with one hole, can and will leak into and effect the colors in a completely different hole. And visa-versa. It is an understanding of boundaries that forms the difference between [Shepards Method](#shepards) , and another form of color 'hole-filling' known as '_Color Diffusion_'. Basically with '_Color Diffusion_', colors can not pass though a line of some other defined color. It is achieved by limiting the effect to only colors in 'line of sight', or to those that leak, around the outside of an edge. This requires using distance to the nearest colors to limit what colors influence a pixel. One major use of '_Color Diffusion_' is presented on the [Diffusion Curves](http://artis.imag.fr/Publications/2008/OBWBTS08/) web site. This not only makes heavy use of color diffusion, but also includes information on techniques for generating diffusions very quickly. I hope to implement this into ImageMagick at some point in the future. * * * Plasma Images ------------- ### Plasma Gradients While gradients provide a smooth range of colors, another image creation operator "`plasma:`" provides a different sort of gradient. One that is ideally suited to generating a random backdrop of color for your images. First of all I should point out that "`plasma:`" is a randomized image. As such it can and will produce a different image every time it is run. For example, here we generate three separate 'standard' plasma images, and each image is different from each other, even though the same command was used to generate them. magick -size 100x100 plasma: plasma1.jpg magick -size 100x100 plasma: plasma2.jpg magick -size 100x100 plasma: plasma3.jpg [![[IM Output]](plasma1.jpg)](plasma1.jpg) [![[IM Output]](plasma2.jpg)](plasma2.jpg) [![[IM Output]](plasma3.jpg)](plasma3.jpg) You can also see that plasma images are also a type of randomized gradient of colors, and like "`gradient:`" started with white at the top and black at the bottom. What isn't well document is that you can specify color for the plasma gradient in the exact same way as you can for linear gradients above. magick -size 100x100 plasma:blue plasma_range1.jpg magick -size 100x100 plasma:yellow plasma_range2.jpg magick -size 100x100 plasma:green-yellow plasma_range3.jpg magick -size 100x100 plasma:red-blue plasma_range4.jpg magick -size 100x100 plasma:tomato-steelblue plasma_range5.jpg [![[IM Output]](plasma_range1.jpg)](plasma_range1.jpg) [![[IM Output]](plasma_range2.jpg)](plasma_range2.jpg) [![[IM Output]](plasma_range3.jpg)](plasma_range3.jpg) [![[IM Output]](plasma_range4.jpg)](plasma_range4.jpg) [![[IM Output]](plasma_range5.jpg)](plasma_range5.jpg) You can also see that mid-tone colors like '`tomato`' and '`steelblue`' tend to work better than pure colors like '`red`' and '`blue`'. By using the same color twice with plasma you can produce a background that is predominantly that color, but with random splotches of colors close to those of the original colors. magick -size 100x100 plasma:black-black plasma_black.jpg magick -size 100x100 plasma:grey-grey plasma_grey.jpg magick -size 100x100 plasma:white-white plasma_white.jpg magick -size 100x100 plasma:yellow-yellow plasma_yellow.jpg magick -size 100x100 plasma:tomato-tomato plasma_tomato.jpg magick -size 100x100 plasma:steelblue-steelblue plasma_steelblue.jpg [![[IM Output]](plasma_black.jpg)](plasma_black.jpg) [![[IM Output]](plasma_grey.jpg)](plasma_grey.jpg) [![[IM Output]](plasma_white.jpg)](plasma_white.jpg) [![[IM Output]](plasma_yellow.jpg)](plasma_yellow.jpg) [![[IM Output]](plasma_tomato.jpg)](plasma_tomato.jpg) [![[IM Output]](plasma_steelblue.jpg)](plasma_steelblue.jpg) Again as you can see, mid-tone colors will generate more varieties of color in the resulting image, than an extreme color, like black, white, or yellow. The '`grey`' plasma in the above is particularly nice giving a iridescent 'mother-of-pearl' like effect, basically as grey has total freedom in the colors that the "`plasma:`" will generate.Normalizing a prefect 50% grey plasma will produce a particularly uniform multi-color plasma image, over the full range of colors, including white and black. magick -size 100x100 plasma:grey50-grey50 -auto-level plasma_grey_norm.jpg [![[IM Output]](plasma_grey_norm.jpg)](plasma_grey_norm.jpg) Alternatively you can just spread the contrast of the colors to just make them bolder, but without going to extremes. magick -size 100x100 plasma:grey50-grey50 \ -sigmoidal-contrast 8x50% plasma_grey_contrast.jpg [![[IM Output]](plasma_grey_contrast.jpg)](plasma_grey_contrast.jpg) Compare this image with the 'fractal plasma' images below. ### Fractal Plasma The plasma generator also has a special fractal mode, which produces highly colorful effects. The colors generated are enhanced to produce more exaggerated color changes. magick -size 100x100 plasma:fractal plasma_fractal1.jpg magick -size 100x100 plasma:fractal plasma_fractal2.jpg magick -size 100x100 plasma:fractal plasma_fractal3.jpg [![[IM Output]](plasma_fractal1.jpg)](plasma_fractal1.jpg) [![[IM Output]](plasma_fractal2.jpg)](plasma_fractal2.jpg) [![[IM Output]](plasma_fractal3.jpg)](plasma_fractal3.jpg) In fact this is very similar to the constant color plasma images we have already seen, and in fact these are generated in the same way but with more pronounced color changes. I often find that plasma images are a little 'noisy'. As such they usually will benefit from a little smoothing using "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `".Here I have have smoothed out the noise from the middle plasma image above. magick plasma\_fractal2.jpg -blur 0x2 plasma\_smooth.jpg [![[IM Output]](plasma_smooth.jpg)](plasma_smooth.jpg) You can use "`[-paint](https://imagemagick.org/script/command-line-options.php?#paint) `" to create random blotches of color. magick plasma\_fractal2.jpg -blur 0x1 -paint 8 plasma\_paint.jpg [![[IM Output]](plasma_paint.jpg)](plasma_paint.jpg) Or make the colors more pronounced and circular using the "`[-emboss](https://imagemagick.org/script/command-line-options.php?#emboss) `" image operator, after using "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" to remove the low level noise. magick plasma\_fractal2.jpg -blur 0x5 -emboss 2 plasma\_emboss.jpg [![[IM Output]](plasma_emboss.jpg)](plasma_emboss.jpg) By using a "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" followed by a "`[-sharpen](https://imagemagick.org/script/command-line-options.php?#sharpen) `" you can produce a more pastel color pattern than we produced with "`[-emboss](https://imagemagick.org/script/command-line-options.php?#emboss) `". magick plasma\_fractal2.jpg -blur 0x5 -sharpen 0x15 plasma\_sharp.jpg [![[IM Output]](plasma_sharp.jpg)](plasma_sharp.jpg) I actually find generating a swirled plasma gradient to be particularly nice, as a background pattern. magick -size 160x140 plasma:fractal \ -blur 0x2 -swirl 180 -shave 20x20 plasma_swirl.jpg [![[IM Output]](plasma_swirl.jpg)](plasma_swirl.jpg) ### Greyscale Plasma Now the plasma generator will always generate color, even on a pure black solid color. However it is often useful to generate a pure grey-scale plasma. Well there are two simple ways of doing this.The simplest way is to take the plasma image and converted it to grey scale. magick -size 100x100 plasma:fractal -blur 0x2 \ -colorspace Gray plasma_greyscale.jpg [![[IM Output]](plasma_greyscale.jpg)](plasma_greyscale.jpg) Another way is to copy one of the color channel over the other two, for a stronger, single layer, effect. magick -size 100x100 plasma:fractal -blur 0x2 \ -channel G -separate plasma_grey_copy.jpg [![[IM Output]](plasma_grey_copy.jpg)](plasma_grey_copy.jpg) A final technique is to use "`[-shade](https://imagemagick.org/script/command-line-options.php?#shade) `" on the plasma. magick -size 100x100 plasma:fractal -blur 0x5 \ -shade 120x45 -auto-level plasma_grey_shade.jpg [![[IM Output]](plasma_grey_shade.jpg)](plasma_grey_shade.jpg) You'd probably think you would get a lot of light and shadow effects, but the raw plasma is so random, that "`[-shade](https://imagemagick.org/script/command-line-options.php?#shade) `" only seems to produce a more 'mottled plasma' effect. Instead of using a fractal plasma, with its highly exaggerated color changes, you can create a grey-scale plasma using the constant color plasma method. As a side effect, this method also allows you to control the overall brightness of the grey-scale plasma image generated. magick -size 100x100 plasma:black-black \ -blur 0x2 -colorspace Gray plasma_grey0.jpg magick -size 100x100 plasma:grey25-grey25 \ -blur 0x2 -colorspace Gray plasma_grey1.jpg magick -size 100x100 plasma:grey50-grey50 \ -blur 0x2 -colorspace Gray plasma_grey2.jpg magick -size 100x100 plasma:grey75-grey75 \ -blur 0x2 -colorspace Gray plasma_grey3.jpg magick -size 100x100 plasma:white-white \ -blur 0x2 -colorspace Gray plasma_grey4.jpg [![[IM Output]](plasma_grey0.jpg)](plasma_grey0.jpg) [![[IM Output]](plasma_grey1.jpg)](plasma_grey1.jpg) [![[IM Output]](plasma_grey2.jpg)](plasma_grey2.jpg) [![[IM Output]](plasma_grey3.jpg)](plasma_grey3.jpg) [![[IM Output]](plasma_grey4.jpg)](plasma_grey4.jpg) If this is not quite bold enough, use the channel copy method of grey-scaling the plasma image. magick -size 100x100 plasma:black-black \ -blur 0x2 -channel G -separate plasma_grey5.jpg magick -size 100x100 plasma:grey25-grey25 \ -blur 0x2 -channel G -separate plasma_grey6.jpg magick -size 100x100 plasma:grey50-grey50 \ -blur 0x2 -channel G -separate plasma_grey7.jpg magick -size 100x100 plasma:grey75-grey75 \ -blur 0x2 -channel G -separate plasma_grey8.jpg magick -size 100x100 plasma:white-white \ -blur 0x2 -channel G -separate plasma_grey9.jpg [![[IM Output]](plasma_grey5.jpg)](plasma_grey5.jpg) [![[IM Output]](plasma_grey6.jpg)](plasma_grey6.jpg) [![[IM Output]](plasma_grey7.jpg)](plasma_grey7.jpg) [![[IM Output]](plasma_grey8.jpg)](plasma_grey8.jpg) [![[IM Output]](plasma_grey9.jpg)](plasma_grey9.jpg) These grey-scale plasma images are very useful for further processing, allowing you to generate other image effects. For example, look at the page on [Background Images](../backgrounds/) for a huge number of examples where the plasma fractal was used to produce lots of interesting effects. ### Seeding or Repeating a Plasma Image Remember "`plasma:`" can produce areas of near pure black or pure white, or any other color (though it isn't likely to be pure). And while it is unlikely you will get an image that is all in one color, it is also a possible outcome. So when you get a good result you may like to save it, for later re-use. Because of this, scripts using plasma images, may like to include options to generate and re-use such randomized images. That is, you may like to separate the plasma image generation from other parts that use that image, to allow re-use.A simpler technique however is to 'seed' or initialize the IM random number generator so that '`plasma:`' will generate the same 'randomized' image. That way you can tune a script or program to produce a good or interesting coloration or effect, over and over. magick -size 100x100 -seed 4321 plasma: plasma\_seeded.jpg [![[IM Output]](plasma_seeded.jpg)](plasma_seeded.jpg) The above image will never change, so unless I change the "`[-seed](https://imagemagick.org/script/command-line-options.php?#seed) `" number I will always have a 'red' area in the bottom-right corner. Interestingly using the same seed with different initializing color gradients can produce a set of images, which while random, are similar in their internal pattern. magick -size 100x100 -seed 4321 plasma:grey-grey plasma\_rnd1.jpg magick -size 100x100 -seed 4321 plasma:white-blue plasma\_rnd2.jpg magick -size 100x100 -seed 4321 plasma:green-yellow plasma\_rnd3.jpg magick -size 100x100 -seed 4321 plasma:red-blue plasma\_rnd4.jpg magick -size 100x100 -seed 4321 plasma:tomato-steelblue plasma\_rnd5.jpg [![[IM Output]](plasma_rnd1.jpg)](plasma_rnd1.jpg) [![[IM Output]](plasma_rnd2.jpg)](plasma_rnd2.jpg) [![[IM Output]](plasma_rnd3.jpg)](plasma_rnd3.jpg) [![[IM Output]](plasma_rnd4.jpg)](plasma_rnd4.jpg) [![[IM Output]](plasma_rnd5.jpg)](plasma_rnd5.jpg) As you can see the same pattern of colors is present in all the above images, though the underlying color base can highlight or obscure parts of the shared pattern. Just one final word of warning. Other IM operators can also use the random number generator, such as the "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `" '`rand()`' function, the "`[-virtual-pixel](https://imagemagick.org/script/command-line-options.php?#virtual-pixel) `" '`random`' setting the "`[-random-threshold](https://imagemagick.org/script/command-line-options.php?#random-threshold) `" dither operator, and the "`[-noise](https://imagemagick.org/script/command-line-options.php?#noise) `" operator. As such is a good idea to seed the generator immediately before your specific use of the random number generator. As of IM v6.3.4-3, you can also re-randomize the generator using "`[+seed](https://imagemagick.org/script/command-line-options.php?#seed) `". So placing this setting after your 'seeded plasma' will ensure that any later operators correctly generate a randomized result if desired. By default the seed is randomized when IM starts, so you normally do not need to randomize it yourself using "`[+seed](https://imagemagick.org/script/command-line-options.php?#seed) `" to get a random result. ### Problems using Plasma One problem that you should avoid with "`plasma:`" images is generating them with a high aspect ratio. It tends to distort the normal plasma color effects, pulling the colors out into needle-like streaks. magick -size 200x50 plasma: plasma_high_aspect.jpg [![[IM Output]](plasma_high_aspect.jpg)](plasma_high_aspect.jpg) There is no simple solution to this, so unless this is what you are wanting, caution is advised. There is also a definite top-left to bottom-right diagonal warp in the plasma image that should not exist. That is, there is some sort of 'spatial bias' flaw in the algorithm. For example as Thomas Maus pointed out if you mirror and append the same plasma image, you will always see a distinct 'V' in the resulting image... magick -size 60x60 plasma: \( +clone -flop \) +append plasma_flaw.jpg [![[IM Output]](plasma_flaw.jpg)](plasma_flaw.jpg) This should not happen. But the problem seems to be too deep to be able to fix without basically completely re-writing the whole plasma generator function. * * * Random Images ------------- ### Raw Random Noise As of IM v6.3.5 you can generate a purely random image from an existing image using Noise Generator, "`[+noise](https://imagemagick.org/script/command-line-options.php?#noise) `" method '`Random`'. magick -size 100x100 xc: +noise Random random.png [![[IM Output]](random.png)](random.png) If your IM is older than this you can still generate a pure random noise image using the slower [DIY FX Operator](../transform/#fx) , "`[-fx](https://imagemagick.org/script/command-line-options.php?#fx) `". magick -size 100x100 xc: -fx 'rand()' random_fx.png [![[IM Output]](random_fx.png)](random_fx.png) Or for speed you can use the "`[-spread](https://imagemagick.org/script/command-line-options.php?#spread) `" operator to randomize a gradient (separatally for the three color channels) or by using some other image. magick -size 100x100 gradient: -separate \ -virtual-pixel tile -spread 200 -combine random_spread.png [![[IM Output]](random_spread.png)](random_spread.png) The result may seem very random, but it will produce a more controlled range of colors, (or just color values). ### Random Specks (pixel dust) Generating images of scattered random pixels can also be very useful. . just remember that each of the three [Color Channels](../color_basics/#channels) of a random image can be thought of as separate random gray-scale image and these channels can be merged together in various ways.For example you generate a mask of random dots by first [Thresholding](../quantize/#threshold) a color channel ('`G`' or the green channel), and separating it out as a gray-scale image. magick random.png -channel G -threshold 5% -separate \\ +channel -negate random\_mask.png [![[IM Output]](random_mask.png)](random_mask.png) As each color is a linearly random value, the threshold percentage used in the above directly defines the density of pixels selected. You can go further and use one color color channel ('`G`' or green channel) to select random values from another color channel channel ('`R`' or red channel), by using various [Image Composition](../compose/#compose) methods. magick random.png -channel G -threshold 5% -negate \\ -channel RG -separate +channel \\ -compose Multiply -composite random\_black.png magick random.png -channel G -threshold 5% \\ -channel RG -separate +channel \\ -compose Screen -composite random\_white.png magick random.png -channel G -threshold 5% -negate \\ -channel RG -separate +channel \\ -compose CopyOpacity -composite random\_trans.png [![[IM Output]](random.png)](random.png) ![=>](../img_www/right.gif) [![[IM Output]](random_black.png)](random_black.png) [![[IM Output]](random_white.png)](random_white.png) [![[IM Output]](random_trans.png)](random_trans.png) These types of images are directly usable to generate [Glitter Animations](../anim_mods/#glitter) . But further processing, particularly on the black background version, will let you enlarge the dots based on their gray-scale intensity or generate streaks and or star flares from those dots. For examples see [Star Generators](../advanced/#stars) . Like [Seeded Plasma Images](#plasma_seeded) you can also use the "`[-seed](https://imagemagick.org/script/command-line-options.php?#seed) `" setting to pre-initialise the random number generator. This allows you to generate the same random image(s) repeatably for a particular machine, just as you can for plasma images. ### Blurred Random Images (random blobs) Now while you can make direct use of random images to create speckled effects, purely random images are generally not very useful. But by [Blurring](../blur/#blur) a purely random image you will introduce some 'neighbourhood' order, such that nearby pixels become related. For example, here I blur just one random image, causing the random values to produce larger 'blobs' or mottled colors. magick random.png -virtual-pixel tile -blur 0x1 -auto-level random\_1.png magick random.png -virtual-pixel tile -blur 0x3 -auto-level random\_3.png magick random.png -virtual-pixel tile -blur 0x5 -auto-level random\_5.png magick random.png -virtual-pixel tile -blur 0x10 -auto-level random\_10.png magick random.png -virtual-pixel tile -blur 0x20 -auto-level random\_20.png [![[IM Output]](random.png)](random.png) ![=>](../img_www/right.gif) [![[IM Output]](random_1.png)](random_1.png) [![[IM Output]](random_3.png)](random_3.png) [![[IM Output]](random_5.png)](random_5.png) [![[IM Output]](random_10.png)](random_10.png) [![[IM Output]](random_20.png)](random_20.png) Note however without the [Virtual Pixel Setting](../misc/#virtual-pixel) the "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" operator will have strong edge effects, which are best avoided. As a bonus by changing the "`[-virtual-pixel](https://imagemagick.org/script/command-line-options.php?#virtual-pixel) `" setting to '`tile`', the randomised image remains tilable, with the colors wrapping across the image boundaries. This tiling ability is something that currently not possible with a random [Plasma Images](#plasma) and is an inherent result of pure random images being so random to start with. **Blurred Random Hues**One particular conversion of a blurred random noise image that I found particularly pleasing is to map the values into HSB color hues. magick random_10.png -set colorspace HSB \ -channel GB -evaluate set 100% +channel \ -colorspace RGB random_hues_cyan.png [![[IM Output]](random_hues_cyan.png)](random_hues_cyan.png) The problem with the above is that the blur will tend to create spots of red-yellow (low values) and red-magenta (high values), with bands of green, cyan and blues, in between them. This is simply a consequence of the way the hue values were blurred and leveled. The ideal solution to this would be a type of modulus-blur, that would take into account the cyclic nature of the Hue values. However such an operator is not currently available, and perhaps never will.The best solution I know of is to simply add all three random channels in the image (using [Modulus-Add Composition](../compose/#modulusadd) ) so as to extend the range of values. This also have a side effect of making the blurred spots smaller, but at least you now get a more dynamic range rainbow colors. _Anyone got a better idea?_ magick random_10.png -separate -background white \ -compose ModulusAdd -flatten -channel R -combine +channel \ -set colorspace HSB -colorspace RGB random_hues.png [![[IM Output]](random_hues.png)](random_hues.png) For more methods of processing a random images, see [Plasma Images](#plasma) above, as well as [Generating Backgrounds](../backgrounds/) . **Blurred Random Grays**As you can see from the above you get an image with various blobs of primary colors. That is, because each channel is being processed completely separately to each other as gray-scale images. Lets extract one of the channels of each of the above image so you can see the structure of the blurred image... magick random.png -channel G -separate random\_0\_gray.png magick random\_1.png -channel G -separate random\_1\_gray.png magick random\_3.png -channel G -separate random\_3\_gray.png magick random\_5.png -channel G -separate random\_5\_gray.png magick random\_10.png -channel G -separate random\_10\_gray.png magick random\_20.png -channel G -separate random\_20\_gray.png [![[IM Output]](random_0_gray.png)](random_0_gray.png) [![[IM Output]](random_1_gray.png)](random_1_gray.png) [![[IM Output]](random_3_gray.png)](random_3_gray.png) [![[IM Output]](random_5_gray.png)](random_5_gray.png) [![[IM Output]](random_10_gray.png)](random_10_gray.png) [![[IM Output]](random_20_gray.png)](random_20_gray.png) The first thing that you should notice is that the image will generally (but not always) contain roughly equal amounts of both black and white areas. You can see this if we [Threshold](../quantize/#threshold) the random images at 50% magick random\_0\_gray.png -threshold 50% random\_0\_thres.png magick random\_1\_gray.png -threshold 50% random\_1\_thres.png magick random\_3\_gray.png -threshold 50% random\_3\_thres.png magick random\_5\_gray.png -threshold 50% random\_5\_thres.png magick random\_10\_gray.png -threshold 50% random\_10\_thres.png magick random\_20\_gray.png -threshold 50% random\_20\_thres.png [![[IM Output]](random_0_thres.png)](random_0_thres.png) [![[IM Output]](random_1_thres.png)](random_1_thres.png) [![[IM Output]](random_3_thres.png)](random_3_thres.png) [![[IM Output]](random_5_thres.png)](random_5_thres.png) [![[IM Output]](random_10_thres.png)](random_10_thres.png) [![[IM Output]](random_20_thres.png)](random_20_thres.png) As you can see you get approximately 50% white and 50% black areas, separated by a curvy line. Also the curve of this line varies according to the '_sigma_' value used for the blurring of the purely random image. From individual pixels generating a black and white 'snow' until you get a very uniform (though still random) separation of the image into two black and white areas. For more examples of using random images, see [Background Images](../backgrounds/) or to have a look at generating randomised canvases, see [Random Spots of Solid Color](../misc/#spots) . ### Random Granularity (order in the chaos) Now remember all the blurred random images were generated from the same initial random image, thus they are all related. But every new random image generated will have a completely different pattern, though the patterns will more or less look similar in structure.But first lets give a full example of generating a 'blured random image' from scratch... magick -size 100x100 xc: -channel G +noise Random \ -virtual-pixel Tile -blur 0x5 -auto-level \ -separate +channel random_5_gray.png [![[IM Output]](random_5_gray.png)](random_5_gray.png) The heavy use of the "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" setting to limit operations to the 'Green' channel of the image is important as it speeds up the overall generation of the image by a factor of 3. The [Channel separate](../channel/#separate) will then ensure we get a pure grayscale result. If you want you could leave out both "`[-channel](https://imagemagick.org/script/command-line-options.php?#channel) `" settings, which will result in the generation of 3 completely separate and different 'Blurred Random Images'. The image has some important characteristics, which we can see more clearly if we divide the image up into three equal sets of colors (using a technique called [Posterization](../quantize/#posterize) ), you can see that inside each of the black and white zones you get more circle blobs or 'granules'.For example... magick random\_5\_gray.png -ordered-dither threshold,3 random\_5\_blobs.png [![[IM Output]](random_5_blobs.png)](random_5_blobs.png) First I would like to point out how we get roughly equal amounts of light and dark areas within the image, but that those areas are interconnected by the grey 'middle' colors of the gradient that forms between the light and dark areas. Now the individual blobs or 'granules' varies from area to area across the image, but they all roughy average at about a diameter of about _three to four times_ the value used to blur the initial random image. This blur value is known as the '_granularity_' of the image is a very important value, as it basically represents the average size of the circular structures the random image produces. Some times it is called the 'curviness' of the image. The larger the value the larger and slower these curves are within the image. This is the most important factor describing a Blurred Random image, so lets make it very clear... **The '_Granularity_' of a random image (or blur factor) determines the size of the circular structures within** Of course the smaller the 'blur factor' or '_Granularity_', the smaller or tighter the curves become, until you reach a value of '`0`', at which point, all the clumping or 'blobs' within the image vanishes, and you are least with a purely random 'noise', 'snow', or 'pixel dust' type of effect. ASIDE: Actually the size of the actual 'granules' themselves can vary depending on the threshold factor used to generate them. What the factor really describes is the average distance between centers of the white and black areas. The larger the value the larger the distance, and the larger and more spread out the spots have to be to accomidate that increased distance. This becomes more obvious when we start looking at [Random Ripples](#random_ripples) below. You may also like to try using a 50% [Solarize](../color_mods/#solarize) operation with some extra [Level Adjustments](../color_mods/#levels) to extract both the well separated black and white granules from the image.For example, here is a full example with a granularity of '`8`' and a blob threshold of '`25%`' generating white spots from both black and white parts of the image. magick -size 100x100 xc: -channel G +noise random \ -virtual-pixel tile -blur 0x8 -auto-level \ -solarize 50% -separate +channel \ -threshold 25% -negate random_granules.png [![[IM Output]](random_granules.png)](random_granules.png) Be warned that as the value gets larger, the time to generate the blurred random image also gets much much longer. Also when the value reaches about half that of the size of the smallest image dimension, the effect stops growing as the random image settles into a single white and black spot. Large values are not recommended. [![[IM Output]](animated_granularity.gif)](animated_granularity.gif) To finish with, to the left is shown a [Patrol Cycle Animation](../anim_mods/#patrol) resulting from varying the 'granularity' (random blurring) of a single random image. The animation was generated using the shell script "`[animate_granularity](animate_granularity) `", which you can download, study and play with. Note that as the same random image is used as a source the 'granules' or spots do not really move, but just sort of grow together, or fade away, so as to produce larger 'granules' with increasing granularity. Also remember that while I have reduced the number of colors in the animation, the structure of the full random image is actually smooth gradient between two sets of white and black granules. This gradient is what makes the image useful in other techniques. ### Random Flux (animation cycles) Now as you saw above the granules or spots do not actually move all that much. But for animation effects you want a pattern that moves smoothly in time. Also you don't want that pattern to just simply move back and forth. And finally, you do not want that pattern of movements to suddenly jump or jerk as the animation loops. So what we need is some way to generate a smoothly repeating random pattern. A tall order. Also as you need it to be smooth, you will need to generate all the patterns from the same single random image. Here is an idea that allows you to generate such a random pattern. Rather than think of each random pixel value as being a random intensity, we instead think of that value being a 'time' value defining when that pixel is at its maximum or minimum intensity. That is, we magick that value into a position on a 'wave'. Thus each pixel represents some 'phase' of a sine curve. This sounds complicated, but in reality it isn't. We just use the [Random Image](#random) as a source image for a [Sinusoid Function](../transform/#function_sinusoid) . Now for each image in the time sequence we set the time '_phase_' for that particular point in the time cycle. magick random.png -function Sinusoid 1,_{time}_ \\ ... do granular blurring, and other processing ... Where '`_{time}_`' goes from '`0`' to '`360`' over the complete animation cycle. The result is that instead of each pixel having a 'static' random value, we now have one that cycles in a loop between black and white over a period of time. Each pixel will follow this same cycle, but as each pixel has a completely different 'phase', and will cycle independently of all the other pixels. That is, the image is still random, but smoothly changing with the provided 'time' value. For the scientifically minded this is a bit like looking at the 'quantum flux' that exists at sub-atomic level, where space is far from the 'static' state we see at normal scales. Hence the name '**Random Flux**'. For example lets generate a time sequence of 12 images... for i in `seq 0 30 359`; do magick random.png -channel G -function Sinusoid 1,${i} \ -virtual-pixel tile -blur 0x8 -auto-level \ -separate flux_${i}.png done | | | | | --- | --- | --- | | [![[IM Output]](flux_0.png)](flux_0.png) | ![=>](../img_www/right.gif) [![[IM Output]](flux_30.png)](flux_30.png)
[![[IM Output]](flux_60.png)](flux_60.png)
[![[IM Output]](flux_90.png)](flux_90.png)
[![[IM Output]](flux_120.png)](flux_120.png) | [![[IM Output]](flux_150.png)](flux_150.png) | | ![=>](../img_www/up.gif) | | ![=>](../img_www/down.gif) | | [![[IM Output]](flux_330.png)](flux_330.png) | [![[IM Output]](flux_300.png)](flux_300.png)
[![[IM Output]](flux_270.png)](flux_270.png)
[![[IM Output]](flux_240.png)](flux_240.png)
[![[IM Output]](flux_210.png)](flux_210.png)
![=>](../img_www/left.gif) | [![[IM Output]](flux_180.png)](flux_180.png) | And your one random image can now generates a whole sequence images forming a cycle. Note that the 'time' extraction has to happen before any other processing such as blurring, which is probably the slowest part of the whole generation process. The other thing to notice is that at phase '`180`' (bottom right), you actually get the exact negative of the first image (top-left). That is 'white' granules has become 'black' granules, and visa-versa. In fact the whole second half of the animation is actually the negative of the first half. This can be used to cut down the generation time of a simple 'Random Flux' animation. Because the image is a negative at a 180 degree phase, you will find that each 'white' granule slowly moves so as to swap places with a neighbouring 'black' granule. But as the whole second half is a negative of the first the it can't just simply shuffle back-and-forth, but must continue move forward to return to the original image, or circle around in a loop, or simply fade and appear appropriatally. In other words the white and black granules move in far more complex cycle. [![[IM Output]](flux_anim.gif)](flux_anim.gif) To the right is an animation of the above frames... The fluctuating pattern is completely random, but smoothly changing from frame to frame, and when the animation loops. You can see no beginning or end to the result. Sometimes you will get a swirling of movement, other times it looks like all the 'gas' like blobs are being sucked into a dark zone, or just appearing and fading away again. You also get periods of very fast movements, as well as very slow movements. It is totally random. **In summary**: The same properties present in [Blurred Random Images](#random) are also present in this animation. The image remains a roughly equal division between white and black segments, and it forms blobs of about _three times_ the size of the blur or [Granularity](#granularity) of the image. But on top of this you are guarantied that all parts of the image will form some cycle between both lighter and darker colors, as half the cycle is the negative of the other half. One thing you may not have noticed is that due to the conversion of a random linear value into a sinusoid waveform, you will get a sharper white and black separation of colors (contrast). As such you may like to use the de-contrasting aspect of [Sigmoidal Contrast](../color_mods/#sigmoidal) operator to make the resulting image less 'blob' like, and enhance the gradient between the granules, rather than the granules themselves. Now this is only a starting point for what you can do with a cyclic random animation. Everything that you can do with a [Random Image](#random) , such as described in [Generating Backgrounds](../backgrounds/) , can also be applied to '_Random Flux Animation_'For example, lets just show the movement of just the 'white' granules... magick flux_anim.gif -threshold 70% flux_thres_anim.gif [![[IM Output]](flux_thres_anim.gif)](flux_thres_anim.gif) Or generate changing electrical filaments that slowly flow over the image. magick flux_anim.gif \ -sigmoidal-contrast 30x50% -solarize 50% -auto-level \ -set delay 20 filaments_anim.gif [![[IM Output]](filaments_anim.gif)](filaments_anim.gif) Note that due to fact that half the cycle is a negation of the first half and we use a [Solarize](../color_mods/#solarize) to fold the white and black colors in half, the cycle is actually repeating twice over one animation cycle. It really needs a lot more frames to remove some of very fast changes that is taking place. To make the motion less predictable for a longer cyclic sequence, you can also use some [Gradient Math](../transform/#gradient_math) to combine multiple Sinusoidal Cycles, from multiple random images, or even just using the other color channels of the same random image. FUTURE: Create even less predictable, long time 'harmonic' cycles. ### Random Ripples By adding another variation to a [Blurred Random Image](#random_blur) we can add another level of complexity that makes these images far more useful, and gives use another control variable beyond its [Granularity](#granularity) . But first you need to remember that the random image does not consist of just bright and dark areas, but also contains a slope between those areas. Using that slope as into to the [Sinusoid Function](../transform/#function_sinusoid) , you can generate ripples between the spots in the image. Note that key difference to this use of the [Sinusoid Function](../transform/#function_sinusoid) to the previous [Random Flux](#random_flux) examples was that this time the function is being applied to the image AFTER it was smoothed using blur, instead of before. Also in this case it is the '_Frequency_' value, and not the second '_Phase_' value that is more important. For example... magick random\_10\_gray.png -function Sinusoid 1,90 ripples\_1.png magick random\_10\_gray.png -function Sinusoid 2,90 ripples\_2.png magick random\_10\_gray.png -function Sinusoid 3,90 ripples\_3.png magick random\_10\_gray.png -function Sinusoid 4,90 ripples\_4.png [![[IM Output]](random_10_gray.png)](random_10_gray.png) ![=>](../img_www/right.gif) [![[IM Output]](ripples_1.png)](ripples_1.png) [![[IM Output]](ripples_2.png)](ripples_2.png) [![[IM Output]](ripples_3.png)](ripples_3.png) [![[IM Output]](ripples_4.png)](ripples_4.png) As you can see the larger the '_Frequency_' of the [Sinusoid Function](../transform/#function_sinusoid) , the more ripples are being added into the gradient between the 'granules'. A '_Frequency_' of '`1`' will basically magick both the Light and Dark 'blobs' in the source image to white, and leave a dark gap between them. A '_Frequency_' of '`2`' squeezes an extra 'ridge' or 'ripple' in that dark gap. As the frequency increases you get more and more 'ripples' between the lightest and darkest areas of the original image, making it more an more complex. As the number of ridges increases, you can lose sight of the original 'blobs' or 'granules' in the image. You can fix this by modifying the gradient before adding the ripples, either by 'clipping' the gradient using a [Level Adjustment](../color_mods/#level) , or compress the midtones using [Sigmoidal Contrast](../color_mods/#sigmoidal-contrast) . This will give the 'granules' some mass or area, providing areas of 'calm' between the ripples. magick random\_10\_gray.png -level 25% random\_enhanced.png magick random\_enhanced.png -function Sinusoid 4,90 ripples\_4e.png magick random\_10\_gray.png -sigmoidal-contrast 10,50% random\_sigmoidal.png magick random\_sigmoidal.png -function Sinusoid 4,90 ripples\_4s.png | | | | --- | --- | | [![[IM Output]](random_10_gray.png)](random_10_gray.png)
![=>](../img_www/right.gif) | [![[IM Output]](random_enhanced.png)](random_enhanced.png)
![=>](../img_www/right.gif) [![[IM Output]](ripples_4e.png)](ripples_4e.png) | | [![[IM Output]](random_sigmoidal.png)](random_sigmoidal.png)
![=>](../img_www/right.gif) [![[IM Output]](ripples_4s.png)](ripples_4s.png) | Both methods have advantages and disadvantages, but in essence they will enlarge granules, though not the distance between the white and black sets of granules. The side effect of this is of course a compression the ripples between the two sets of granules. The second value '`90`' used above examples is the '_Phase_' of the [Sinusoid Function](../transform/#function_sinusoid) . It will determine the color that the 'black' granule in the source image will become in the 'rippled' image. magick random\_enhanced.png -function Sinusoid 3,0 ripples\_3e000.png magick random\_enhanced.png -function Sinusoid 3,90 ripples\_3e090.png magick random\_enhanced.png -function Sinusoid 3,180 ripples\_3e180.png magick random\_enhanced.png -function Sinusoid 3,270 ripples\_3e270.png [![[IM Output]](random_enhanced.png)](random_enhanced.png) ![=>](../img_www/right.gif) [![[IM Output]](ripples_3e000.png)](ripples_3e000.png) [![[IM Output]](ripples_3e090.png)](ripples_3e090.png) [![[IM Output]](ripples_3e180.png)](ripples_3e180.png) [![[IM Output]](ripples_3e270.png)](ripples_3e270.png) The color of the 'white' granule, will depend on both the '_Phase_', and the fraction of the '_Frequency_' that use applied. An integer '_Frequency_' value will cause both white and black granules to vary in color together (according to the '_Phase_'). as such with a pahse of '`90`' both will be white.However if you apply a fractional '_Frequency_' value of say '`0.5`', the 'white source' granule, will be the negative of the 'black source' granule (as determined by the '_Phase_'). magick random\_enhanced.png -function Sinusoid 3.5,90 ripples\_3.5e.png [![[IM Output]](ripples_3.5e.png)](ripples_3.5e.png) Note for the 'gray' '_Phase_ angles, one of granules is surrounded by a white ring, while the other is surrounded by a black ring. If a '_Frequency_' value with a '`0.5`' fraction is used, the first ripple around each spot will be all white or all black, depending on the '_Phase_' used. | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Other 'Frequencies' other than integers, or '`0.5`' are not recommended as the two sets of granules will not be synchronized in some way.

Similarly Phases other multiple of 90 degrees are not recommended unless generating a 'ripple animation' (see below).

A Phase value of '`0`' is recommended when generating a 'Dispersion Maps' (see below) as this will cause minimal distortions within the enhanced 'granule' areas._ | As previously in [Random Flux](#random_flux) , you can modify the '_Phase_' with time so as to generate an animation of the ripples moving from one set of granules to the other. This works particularly well without any contrast enhancement. for i in `seq 0 30 359`; do magick random_10_gray.png -function Sinusoid 3.5,${i} miff:- done | magick miff:- -set delay 15 -loop 0 ripples_anim.gif [![[IM Output]](ripples_anim.gif)](ripples_anim.gif) ASIDE: the technique used in the above is known as a "Pipelined [MIFF:](../files/#miff) " and is possible as the [MIFF:](../files/#miff) " file format can simply 'concatenate' images to generate a multiple image file. One point is that the animation seem to change much much slower than a [Flux Animation](#random_flux) we created above. That is, because over the one animation cycle a ripple will only travel a short distance, where in a 'flux' animation thge change will travel from the large scale white to black granules in just half the cycle and back again. Now you can combine the above ripple animation with an underlying 'flux' animation from the same random image source to generate a much more dynamic and flowing form, but be warned of that animation speed difference.For example, here I just take the previous [Flux Animation](#random_flux) created above, and add ripples to it. The ripples will in this case move only because the gradient in the flux animation moves. magick flux_anim.gif -function Sinusoid 3.5,0 flux_rippled_anim.gif [![[IM Output]](flux_rippled_anim.gif)](flux_rippled_anim.gif) You can also animate the ripples within the animation. Though you may need to use a much larger 'phase cycle rate' (the 'j = 5 \* i' expression) for the ripples themselves. Also as you are generating a cycle within a cycle, you will need to generate a much longer animation 60 frames in this case. However that has the benefit of slowing the larger 'flux' movements down too. for i in `seq 0 10 359`; do j=`expr $i \* 5` magick random.png -channel G \ -function Sinusoid 1,${i} \ -virtual-pixel tile -blur 0x8 -auto-level \ -function Sinusoid 2.5,${j} \ -separate +channel miff:- done | magick miff:- -set delay 15 -loop 0 ripples_flux_anim.gif [![[IM Output]](ripples_flux_anim.gif)](ripples_flux_anim.gif) Note in the second image how ripples seem to first come out from one point, then later they start back going into the same point, though they never just simply reverse direction. A better multi-cycled flux cycle generator should remove this slight weirdness by removing the 'negative' effect in the flux underlying flux animation. _FUTURE: Use of Rippled Random Images for Dispersion Mapped Distortions_. * * * Tiled Canvases -------------- Tile images can be very large or very small, are designed to fit together side-by-side and vertically to cover large areas of space. Thanks to the World Wide Web, there as been an explosion of tile images available for use (finding what you want is another matter). Below are a set of tiled images which I copied from [Anthony's Icon Library](http://www.ict.griffith.edu.au/anthony/icons/) for use through out these example pages. | | | | | | | | --- | --- | --- | --- | --- | --- | | [![[IM Output]](../images/bg.gif)](../images/bg.gif)

bg.gif | [![[IM Output]](../images/tile_aqua.jpg)](../images/tile_aqua.jpg)

tile\_aqua.jpg | [![[IM Output]](../images/tile_water.jpg)](../images/tile_water.jpg)

tile\_water.jpg | [![[IM Output]](rings.jpg)](rings.jpg)

rings.jpg | [![[IM Output]](../images/tile_disks.jpg)](../images/tile_disks.jpg)

tile\_disks.jpg | [![[IM Output]](../images/tile_weave.gif)](../images/tile_weave.gif)

tile\_weave.gif | Currently there are quite a number of way in which you can tile an image, over a large area. You can "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" any image so as to completely replace the original background image (using the "`Copy`" compose operator). (For more details see [Tile Compositing](../compose/#tile) ). magick composite -tile tile\_weave.gif -size 60x60 xc:none tile\_copy.gif [![[IM Output]](tile_copy.gif)](tile_copy.gif) Another way is to read in the tile image using the "`tile:`" coder, and tile it to a specific size. magick -size 60x60 tile:bg.gif tile\_size.gif [![[IM Output]](tile_size.gif)](tile_size.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Note that the "`tile:`" coder will replace any transparency in the image with the current background color. That is, because internally it generates a canvas of the size requested and 'overlays' the tiling image onto that canvas.

If you want to preserve transparency either set "`-background none`" or "`-compose SRC`" (see [Src Compose Method](../compose/#src)
for details)._ | You can use this to generate a tiled image much larger than you need, then use "`[-composite](https://imagemagick.org/script/command-line-options.php?#composite) `" to overlay it over the original image. If the tile image is partially transparent then a '`[Over](../compose/#over) `' "`[-compose](https://imagemagick.org/script/command-line-options.php?#compose) `" method will need to be specified. It is a very slow method of tiling, particularly for large images, and you have the problem of determining just how big an image you need to create for the overlay. magick test.png -size 200x200 tile:tile\_disks.jpg \\ -composite tile\_over.gif [![[IM Output]](tile_over.gif)](tile_over.gif) By specify a tile as 'tile fill pattern' for the "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" operator, you can draw the tile image over another image, to create any shape or figure you like. This is because the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting will override any of the "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color setting used by draw. See [MVG Drawing Settings](../draw/#settings) . magick -size 60x60 xc: -tile tile\_aqua.jpg \\ -draw "circle 30,30 2,30" tile\_draw.gif [![[IM Output]](tile_draw.gif)](tile_draw.gif) This only works for "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" and operators like "`[-annotate](https://imagemagick.org/script/command-line-options.php?#annotate) `" that also make use of "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to perform their function. It will not work for image operators that use "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color directly, like "`[label:](../text/#label) `", "`[caption:](../text/#caption) `", and "`[text:](../text/#text) `".However "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" has built in to it some special [color primitives](../draw/#color) , such as completely resetting all the pixels in the image to the fill color or tile pattern (if set). magick test.png -tile tile\_water.jpg -draw "color 0,0 reset" \\ tile\_reset.gif [![[IM Output]](tile_reset.gif)](tile_reset.gif) This is actually exactly the same method as used by some [Solid Color Canvases](#solid) methods using a [Specific Color](#specific) . Only here we used "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" instead of a "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" color. A more advanced method is to use a [Distort Operator](../distorts/#distort) with a special [Distort Viewport](../distorts/#distort_viewport) setting, that was set to the size of the original image (using a [Defined Global Artifact](../basics/#define) and [Percent Escapes](../basics/#arg_percent) ). This basically maps the smaller tiles [Virtual Pixels](../misc/#virtual) , that surrounds the small tile image, to generate the larger tiled canvas. magick rose: -set option:distort:viewport '%g' +delete \\ tree.gif -virtual-pixel tile -filter point -distort SRT 0 \\ tile\_distort\_sized.gif [![[IM Output]](tile_distort_sized.gif)](tile_distort_sized.gif) See [Tiling via Distort](#tile_distort) (below) where we will look at this same technique to tile an image that is already in memory. ### Offset Tiling Canvases Sometimes you need a little more control over the exact positioning of a background texture, either for aligning a tile pattern with some other image, or to avoid a bad correlation with some other part of the final image. For many of the standard tiling methods this can be achieved using the "`[-tile-offset](https://imagemagick.org/script/command-line-options.php?#tile-offset) `" setting. For example, here I roll the tile image being used to directly create a tiled canvas image using "`tile:`" or "`pattern:`". magick -size 80x80 -tile-offset +30+30 tile:rose: offset\_tile.gif magick -size 80x80 -tile-offset +20+20 \\ pattern:checkerboard offset\_pattern.gif [![[IM Output]](offset_tile.gif)](offset_tile.gif) [![[IM Output]](offset_pattern.gif)](offset_pattern.gif) | | | | --- | --- | | ![](../img_www/warning.gif)![](../img_www/space.gif) | _[Tile Offset](../crop/#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 while the above examples would have worked (both X and Y offsets are the same) you may not get the expected results when the two values differ._ | This also works for the "`magick montage`" background "`[-texture](https://imagemagick.org/script/command-line-options.php?#texture) `" setting. montage tree.gif -geometry +24+24 \\ -tile-offset +30+30 -texture rose: offset\_texture.gif [![[IM Output]](offset_texture.gif)](offset_texture.gif) You can also use the setting by defining it before the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" or "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" setting. For example... magick -tile-offset +30+30 -tile rose: \\ -size 80x80 xc: -draw 'color 30,20 reset' offset\_tile\_fill.gif [![[IM Output]](offset_tile_fill.gif)](offset_tile_fill.gif) Make sure that the "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `" setting is reset before defining the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" image, but after any other image has been read in. magick -size 80x80 xc: \\ -tile-offset +20+20 +size -tile pattern:checkerboard \\ -draw 'color 30,20 reset' offset\_pattern\_good.gif [![[IM Output]](offset_pattern_good.gif)](offset_pattern_good.gif) In any case it is probably best to define the tile offset and tile image just before its first use, which has the same result as the above solution. ### Tiling with an Image already In Memory Tiling an image you have in memory (created or modified) is not straight forward, and only a few indirect methods are available. #### Clone and Append the Tile Image If you are not worried about the exact size of the tiled image, you can just append the image together multiple times. For example, here we tile the image in a 3x3 array. magick tree.gif \\ \\( +clone +clone \\) +append \\ \\( +clone +clone \\) -append \\ tile\_clone.gif [![[IM Output]](tile_clone.gif)](tile_clone.gif) This method of tiling has the advantage of allowing you to flip-tile (mirror tile) the image. magick tree.gif \\ \\( +clone -flop +clone \\) +append \\ \\( +clone -flip +clone \\) -append \\ tile\_clone\_flip.gif [![[IM Output]](tile_clone_flip.gif)](tile_clone_flip.gif) In general this method is only practical when you have some idea of how big the image being tiled is. Also as clones are actually very fast and efficient it is a fairly simple and fast tiling method, especially if you use the results to further tile the larger image. #### Tile using MPR: (Memory Program Register) A better method is to save the image into a special 'In Memory' file format "`[mpr:](../files/#mpr) `", or named 'memory program register'. From this register you can then either use a "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" setting, or use the special "`tile:`" image file reader, both of which can only be set from a 'saved' image file format.For example using "`tile:`" to create a tiled image of a specific size... magick tree.gif -write mpr:tile +delete \\ -size 100x100 tile:mpr:tile tile\_mpr.gif [![[IM Output]](tile_mpr.gif)](tile_mpr.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _Remember that the "`tile:`" coder will replace any transparency in the image with the current background color. (see above)_ | Or tile over an existing image, by setting the "`[-tile](https://imagemagick.org/script/command-line-options.php?#tile) `" or "`[-fill](https://imagemagick.org/script/command-line-options.php?#fill) `" fill pattern, and using "`[-draw](https://imagemagick.org/script/command-line-options.php?#draw) `" to do a color reset (see [Color Fill Primitives](../draw/#color) )... magick tree.gif -write mpr:tile +delete \\ granite: -fill mpr:tile -draw 'color 0,0 reset' \\ tile\_mpr\_reset.gif [![[IM Output]](tile_mpr_reset.gif)](tile_mpr_reset.gif) | | | | --- | --- | | ![](../img_www/reminder.gif)![](../img_www/space.gif) | _If tiling with an image containing transparency, ensure the destination image also has transparency by using "`-alpha set`". If you do not the resulting image will show the tiles 'hidden' transparency color._ | Or draw using some other [Draw Primitive](../draw/#primitives) , such as a circle, using the fill pattern. magick tree.gif -write mpr:tile +delete \\ granite: -tile mpr:tile -draw 'circle 64,64 10,50' \\ tile\_mpr\_fill.gif [![[IM Output]](tile_mpr_fill.gif)](tile_mpr_fill.gif) The name given after "`[mpr:](../files/#mpr) `" can be anything you like, it is only a label on 'mpr' register name used to store the image, (in memory). It can even be a label, number, color, or even a filename. #### Tiling using Virtual Pixels via Distort In this method we use the [Virtual Pixel Setting](../misc/#virtual-pixel) to generate a large tiled canvas. This setting defines how the area surronding the actual image (outside the normal image bounds) should look. The easiest way to extract virtual pixels is to use the [Distort Operator](../distorts/#distort) with a special [Distort Viewport](../distorts/#distort_viewport) setting. magick tree.gif -set option:distort:viewport 100x100+0+0 \\ -virtual-pixel tile -filter point -distort SRT 0 \\ tile\_distort.gif  [![[IM Output]](tile_distort.gif)](tile_distort.gif) You also have access to other styles of virtual pixel tiling settings, such as '`[Mirror](../misc/#mirror) `', or even '`[CheckerTile](../misc/#checker_tile) `', and even good offset tiling control using the viewport setting. magick tree.gif -set option:distort:viewport 100x100-10-10 \\ -background firebrick -virtual-pixel CheckerTile \\ -distort SRT 0 +repage tile\_distort\_checks.gif [![[IM Output]](tile_distort_checks.gif)](tile_distort_checks.gif) By using the [General Distortion Operator](../distorts/#distort) in this way, you also have the added bonus of distorting the tiled image in some very complex ways. You can see examples of this in [Distort Affine Tiling](../distorts/#affine_tile) . As a more complex example, here I use an [Arc Distortion](../distorts/#arc) to tile the tree around the origin which is centered in the viewport. The '`45`' specifies the angle the width of the tree covers, while the '`50`' defines the radius for the top edge of the tree tile. The rest just follows from this. magick tree.gif -set option:distort:viewport 100x100-50-50 \\ -virtual-pixel tile -distort Arc '45 0 50' +repage \\ tile\_distort\_polar.gif [![[IM Output]](tile_distort_polar.gif)](tile_distort_polar.gif) ### Modifying Built-in IM Patterns/Tiles See the full list of [ImageMagick Built In Images and Patterns](https://imagemagick.org/script/formats.php#builtin-images) . There are a lot of such patterns, but I'll only look at one or two here. Now the built-in patterns are generally very very small images, which can tile to cover large areas. However, on their own they are very plain looking and rather useless. For example, here is one of the larger more interesting patterns that is provided... magick pattern:checkerboard pattern\_default.gif [![[IM Output]](pattern_default.gif)](pattern_default.gif) Pattern images are usually tiled over an larger areas, either as part of canvas creation, by setting a "`[-size](https://imagemagick.org/script/command-line-options.php?#size) `", or as a fill tile (see [Tiled Canvases](#tile) above). Without a size setting the default tile size of the pattern will be used, `30x30` pixels in this case. Now you will probably notice that all the patterns currently provided by IM are all pure black and white, with the single exception of the '`checkerboard`' pattern I used in the last example.Here is one pattern I particularly like to use as a tile pattern... magick -size 60x60 pattern:hexagons pattern\_hexagons.gif [![[IM Output]](pattern_hexagons.gif)](pattern_hexagons.gif) If you are not happy with these colors you can replace them using the "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" image operator. magick -size 60x60 pattern:hexagons \\ -fill blue -opaque black -fill skyblue -opaque white \\ pattern\_colored.gif [![[IM Output]](pattern_colored.gif)](pattern_colored.gif) If you want to color the "`checkerboard`" pattern, then that is best done by first using "`[-auto-level](https://imagemagick.org/script/command-line-options.php?#auto-level) `" to map the two greys to black and white before substituting those two colors. Here instead of using "`[-opaque](https://imagemagick.org/script/command-line-options.php?#opaque) `" to replace the colors, I use a "`[+level-colors](https://imagemagick.org/script/command-line-options.php?#level-colors) `" operator (add IM v6.2.4-1), which is a bit simpler to use. magick -size 60x60 pattern:checkerboard -auto-level \\ +level-colors red,blue pattern\_color\_checks.gif [![[IM Output]](pattern_color_checks.gif)](pattern_color_checks.gif) You can also use "`[-floodfill](https://imagemagick.org/script/command-line-options.php?#floodfill) `" operator to color the pattern. However for this to work properly you need to do this, _before_ you tile the modified pattern. In this case I also need to expand the tile three times to color it with the regular pattern of colors I wanted. magick -size 30x54 pattern:hexagons \\ -fill tomato -opaque white \\ -fill dodgerblue -draw 'color 10,10 floodfill' \\ -fill limegreen -draw 'color 10,25 floodfill' \\ -roll +15+27 \\ -fill dodgerblue -draw 'color 10,10 floodfill' \\ -fill limegreen -draw 'color 10,25 floodfill' miff:- |\\ magick -size 100x100 tile:- pattern\_color\_hexagons.gif [![[IM Output]](pattern_color_hexagons.gif)](pattern_color_hexagons.gif) I used a pipeline of two commands in the above to separate the colored pattern creation, from its actual usage. If you like to do this with a single command see [Tiling an Image In Memory](#tile_memory) above.You can also warp and distort a simple tiling pattern to produce an interesting variations. For example a 'wrinkling' effect (technique courtesy of the wrinkle IM effect from [Font Image Generator](http://interactimage.com/) ) on a hexagon pattern I found particularly interesting magick -size 160x100 pattern:hexagons \\ -wave 3x100 -background white -rotate 90 -wave 4x66 -rotate -87 \\ -gravity center -crop 120x90+0+0 +repage pattern\_distorted.gif [![[IM Output]](pattern_distorted.gif)](pattern_distorted.gif) ### Modifying Tile Images The biggest problem people face with modifying tiles, whether it's an existing tile, or one of the built in patterns, is that many image operations destroy the 'tilability' of the image. For example, here I have taken the built-in '`hexagon`' pattern, and tried to modify it to produce a shaded gray-scale pattern of wide hexagonal lines. magick pattern:hexagons -rotate 90 \\ -blur 0x1 -edge 1 -negate -shade 120x45 \\ miff:- |\\ magick -size 100x100 tile:- tile\_mod\_failure.jpg [![[IM Output]](tile_mod_failure.jpg)](tile_mod_failure.jpg) The first command generates the 'tile image' while the second actually tiles the image, so we can see how they all fit together. As you can see the resulting tile image does NOT tile properly, with artificial edge distortions clearly visible in the tiled image. Basically we lost the uniformity of the original tile, along the edges of the image. One solution is to use a special [Virtual Pixels](../misc/#virtual-pixel) setting, which is used to make operators think the image wraps around the edges, when looking up colors that are beyond the bounds of the actual image proper. magick pattern:hexagons -rotate 90 -virtual-pixel tile \\ -blur 0x1 -edge 1 -negate -shade 120x45 \\ miff:- |\\ magick -size 100x100 tile:- tile\_mod\_vpixels.jpg [![[IM Output]](tile_mod_vpixels.jpg)](tile_mod_vpixels.jpg) Here is another example where I join two related tile patterns together, and use various effects to create unusual brick wall tile. magick pattern:leftshingle pattern:rightshingle +append \\ -virtual-pixel tile -blur 0x0.75 -resize 150% -shade 100x45 \\ -fill Peru -tint 100% miff:- |\\ magick -size 100x100 tile:- tile\_slanted\_bricks.jpg [![[IM Output]](tile_slanted_bricks.jpg)](tile_slanted_bricks.jpg) #### Alternative There is an alternative to relying on [Virtual Pixels](../misc/#virtual-pixel) . Basically we provide the 'virtual edge pixels' ourselves before operating on the image, so as to avoid any edge effects that may be present. And that is done by tiling the image over a slightly larger area first. After modifying the image, we can re-extract the tile, avoiding the edge distortions that were introduced. It does not have to be lot bigger, depending on the extent of the image operations being performed. I have found 15 to 40 pixels should stop all edge effects in the final result. To re-extract the image we can either "`[-shave](https://imagemagick.org/script/command-line-options.php?#shave) `" off the extra pixels, or "`[-crop](https://imagemagick.org/script/command-line-options.php?#crop) `" the original tile size from the middle of the processed image. For example, here I create a 3d "`[-shade](https://imagemagick.org/script/command-line-options.php?#shade) `" effect using the built-in '`hexagons`' pattern. magick -size 60x60 tile:pattern:hexagons -rotate 90 \\ -blur 0x1 -edge 1 -negate -shade 120x45 \\ -gravity center -crop 18x30+0+0 +repage miff:- |\\ magick -size 100x100 tile:- tile\_mod\_success.jpg [![[IM Output]](tile_mod_success.jpg)](tile_mod_success.jpg) Note the exact position of the extracted tile does not matter. A tilable image can be cut anywhere from the tiled image, as long as it is away from the distorted edges, and you use the same original size of the tile. Here instead of tiling the image over a larger area, we use a 'double clone' technique to double the area the tile covers. When finished we then just center crop 50% of the image to recover our modified tile. This means we have no need to know the exact size of the tile you are processing. magick pattern:circles \\( +clone \\) +append \\( +clone \\) -append \\ -fill grey -opaque black -blur 0x0.5 -shade 120x45 \\ -gravity center -crop 50% +repage miff:- |\\ magick -size 100x100 tile:- tile\_circles.jpg [![[IM Output]](tile_circles.jpg)](tile_circles.jpg) ### Generating Tile Images The biggest problem you face when generating images that can tile together is trying to match the edges and corners of the image so that they can fit together seamlessly. If this is not done then all you get is a set of square boxes each with a repeated copy of the image. This is not an easy matter and can be a very frustrating and hair pulling experience. An object appearing in the tile on one edge must re-appear on the other side of the image in order to re-form the whole when the image is tiled. While you can do this fairly easily with computer generated images, it is next to impossible to produce a good tiling image featuring real-world photographs. The other major problem is trying to make the tile not look like it is repeating. The only true solution to this is to make your tile images large enough to contain enough very similar, but still different elements that it becomes difficult to see a repeated pattern. For this reason, generating small tiles that do not seem to repeat is especially difficult. FUTURE: Ideas and suggestions for generating tile patterns? Anyone? Or roll, add element, roll, add element, etc... Any and all suggestions and examples accepted. Suggestions for generating tile from real photos of repeating patterns, such as water, fallen leaves, clouds, stucco, brickwork, etc... Generating Escher-like tile patterns. ### Random Noise Tile Because a raw random noise canvas has no edges characteristics to begin with (every pixel color is completely independent of any of its neighbours), you can tile it without worry about edge distortions. Basically it is so extremely random at the pixel level, no edges match to begin with, so we don't lose anything, by tiling. Unfortunately very few situations would use a raw random noise image, as is, for any real purpose. It is just so horribly random that it is useless. However by modifying the image while preserving its inherent tilability, we can make just about any randomized tile pattern we want.For example lets look at the a basic "`[-blur](https://imagemagick.org/script/command-line-options.php?#blur) `" of the original tile, using the same 'modifying a tile' technique we used in the last example. magick -size 64x64 xc: +noise Random \\ -virtual-pixel tile -blur 0x6 -auto-level tile\_random.jpg magick -size 128x128 tile:tile\_random.jpg tiled\_random.jpg [![[IM Output]](tile_random.jpg)](tile_random.jpg) [![[IM Output]](tiled_random.jpg)](tiled_random.jpg) Using this technique you can apply just about any transformation to a raw random noise image image. For example... magick -size 64x64 xc: +noise Random \\ -virtual-pixel tile -blur 0x6 -edge 1 -fx G \\ -shade 280x45 -auto-level tile\_random\_pits.jpg magick -size 128x128 tile:tile\_random\_pits.jpg tiled\_random\_pits.jpg [![[IM Output]](tile_random_pits.jpg)](tile_random_pits.jpg) [![[IM Output]](tiled_random_pits.jpg)](tiled_random_pits.jpg) As you can see it is a lot simpler to create randomized tiles using the raw random noise image, and you will not have any edge distortions in the results. This particular image transformation is listed on the [Background Images](../backgrounds/) page and is titled "pits". See that page for lots of other image random image transformations, and examples of what they look like. ### Hexagonal Tiling Rather than tile in a square fashion, the 'random noise' image allows use to generate a very different sort of tile. By doubling the image dimensions and re-laying the tile in the extra space, but offset by half, we can generate a basic random noise hexagonal tile pattern.This is the same sort of tiling effect we get when we tile the special "`pattern:hexagons`" built-in of ImageMagick. magick pattern:hexagons tile\_hexagons.gif magick -size 64x64 pattern:hexagons tiled\_hexagons.gif [![[IM Output]](tile_hexagons.gif)](tile_hexagons.gif) [![[IM Output]](tiled_hexagons.gif)](tiled_hexagons.gif) Note however that for this tile to look 'hexagonal' the tile cannot be a normal square, or even a doubled square. The final tile size needs to be a rectangle. The exact ratio for this rectangle actually involves irrational numbers, which is not very good for image work with a pixel array. However a good working ratio is 4:3, which is used by most computer and digital camera images.Here we overlay the same 'random noise' image (a rectangle with a 2:3 ratio) two extra times to generate the basic hexagon pattern (in a 4:3 rectangle). The hex-tiled random noise tile is then transformed using the "paint\_3s" transformation from the [Background Images](../backgrounds/) page, to generate a rather nice looking hexagonal tile pattern. magick -size 48x64 xc: +noise Random -write mpr:rand \\ -extent 96x64 -page +48-32 mpr:rand -page +48+32 mpr:rand \\ -flatten tile\_hex\_random.jpg magick tile\_hex\_random.jpg -virtual-pixel tile -blur 0x10 -paint 3 \\ -shade 280x45 -auto-level tile\_hex\_layered.jpg magick -size 160x160 tile:tile\_hex\_layered.jpg tiled\_hex\_layered.jpg [![[IM Output]](tile_hex_layered.jpg)](tile_hex_layered.jpg) [![[IM Output]](tiled_hex_layered.jpg)](tiled_hex_layered.jpg) If you look at the pattern the tile produces you will see that any specific feature, will have 6 copies of that same feature surrounding it in a circle. This is the 'hexagonal' pattern the tile produces, even though it is still tiled in the same 'square' pattern as all other tiling images. One variant of the above 'hextile' pattern is to double up the tile image vertically, rather than horizontally as we have done above. The result is that the hexagonal pattern will be rotated ninety degrees. It is however still the same type of pattern. | | | | --- | --- | | ![](../img_www/expert.gif)![](../img_www/space.gif) | _Mathematically the above is not generating a new [Wallpaper Group](http://en.wikipedia.org/wiki/Wallpaper_group)
form an existing tile. Both the original 'non-hexagonal' image and the final verson belong to the same '**p1**' tiling group.

What we are actually doing in the above is converting a rhombus 'prototile' tiling pattern into a larger rectangular orthogonally aligned 'fundamental domain' of the same tiling pattern. In this way you can then tile the image using a standard tiling method._ | _Future: Flip the extra image over to generate a larger tiling pattern (**pmg** tiling group)._ _Future: how to cut out (mask) a hexagon from an image so it will tile perfectly, without gaps or overlaps._ ### Triple Hex Tiling Like we did when coloring the the "`hexagons`" built-in pattern (See [Modifying Built-in IM Patterns/Tiles](#pattern) above), you can make three different variants of the initial tile, (with rotations for example) before re-mapping them to form the larger tile. Of course, just as I did when coloring the "`hexagons`" pattern, the final tile image will need to be enlarged three times larger, so as to generate a repeating rectangular tile pattern. The variations between the three tiles generated must not be too different, and should survive any post-processing, otherwise you will not get the benefits of the technique. This means the initial tile must be reasonably large as well, so any distinct features present will be preserved. For example, here we take a very simple line drawing, and rotate it to produce 3 similar variations. These rotated images are then tiled seven times onto a larger canvas (6 times larger) to produce the triple image hex pattern. magick -size 24x24 xc: -draw "rectangle 3,11 20,12" tile\_line.gif magick tile\_line.gif -gravity center\\ \\( +clone -rotate 0 -crop 24x18+0+0 -write mpr:r1 +delete \\) \\ \\( +clone -rotate 120 -crop 24x18+0+0 -write mpr:r2 +delete \\) \\ -rotate -120 -crop 24x18+0+0 -write mpr:r3 +repage \\ -extent 72x36 -page +0+0 mpr:r3 \\ -page +24+0 mpr:r1 -page +48+0 mpr:r2 \\ -page -12+18 mpr:r1 -page +12+18 mpr:r2 \\ -page +36+18 mpr:r3 -page +60+18 mpr:r1 \\ -flatten tile\_hex\_lines.jpg magick -size 120x120 tile:tile\_hex\_lines.jpg tiled\_hex\_lines.jpg [![[IM Output]](tile_line.gif)](tile_line.gif) [![[IM Output]](tile_hex_lines.jpg)](tile_hex_lines.jpg) [![[IM Output]](tiled_hex_lines.jpg)](tiled_hex_lines.jpg) The above however only works for tiling a small shape in the middle of the original image. It does not work well for a general image. For a general image hex tiling we also need to mask out an equilateral triangles. The pieces are then rotated so the equilateral trianlge edges are mirrored. This is not an easy task. ### Diagonal Mirror Tiling Here is one way to take any square image and magick it into 8 mirrored images around a central point. Specifically we are generating a complex '**p4m**' tiling pattern. I first generate [Random Hue Image](#random_hue) , and using the bottom-left half of the source image I mirror it diagonally, then horizontally and vertically. magick -size 50x50 xc: +noise Random -virtual-pixel Tile -blur 0x5 \ -auto-level -separate -background white \ -compose ModulusAdd -flatten -channel R -combine +channel \ -set colorspace HSB -colorspace RGB tile_diag_source.jpg magick tile_diag_source.jpg \( +clone -transpose \) \ \( +clone -sparse-color voronoi '%w,0 white 0,%h black' \) \ -composite \ \( +clone -flop -chop 1x0 \) +append \ \( +clone -flip -chop 0x1 \) -append \ tile_diag_mirror.jpg [![[IM Output]](tile_diag_source.jpg)](tile_diag_source.jpg) [![[IM Output]](tile_diag_mirror.jpg)](tile_diag_mirror.jpg) The diagonal mirror is generated by doing a [Transpose](../warping/#transpose) and then using a mask generated using a [Voronoi, Sparse Color](#voronoi) . Note that this diagonal mirror automatically shares one line of pixels across the mirror in the same way, due to the pixel geometry of the square. I also remove one set of pixels along the edge before creating vertical and horizontal [Flips and Flops](../warping/#flip) . I also recommend the removal another row and column of pixels along the top and left edge, before using this image as a 'tile'. You don't need to do this, but I think it looks better. Without removing one row and column of edge pixels, you get ugly 'seams' of doubled pixels, where the images join together. An alternative is to tile the raw random image first, then do the [Background Pattern](../backgrounds/) conversion, you are less likely to get a 'clipped look' along the mirror lines, but a smoother transition. magick -size 51x51 xc: +noise Random \( +clone -transpose \) \ \( +clone -sparse-color voronoi '%w,0 white 0,%h black' \) \ -composite \ \( +clone -flop -chop 1x0 \) +append \ \( +clone -flip -chop 0x1 \) -append \ -chop 1x1 \ \ -virtual-pixel Tile -blur 0x5 -auto-level \ -separate -background white \ -compose ModulusAdd -flatten -channel R -combine +channel \ -set colorspace HSB -colorspace RGB tile_p4m.jpg [![[IM Output]](tile_p4m.jpg)](tile_p4m.jpg) The first part is the generation of the 'tiling of the random data' the second half I magick the random data into a 'hues' mapping. I also added the extra pixel to the initial image which will be later choped as appropiate to generate a tiling image. For a more complete introduction into tiling images and the mathematics behind them, see [Wikipedia: Wallpaper Group](http://en.wikipedia.org/wiki/Wallpaper_group) . What we have explored above is only a few of the many tiling patterns you can create. The '**p4g**' is almost exactly the same as the '**p4m**' tiling above, but uses a 180 degree rotations of the mirrored squares, rather than using flips, to generate the full tiling image. However as the images are not joined by mirrors you can not use an existing image as the tile source as the edges will become disjoint and discontinuous. However you can tile the raw random data then process the resulting tile image, to produce a smooth result. magick -size 50x50 xc: +noise Random \( +clone -transpose \) \ \( +clone -sparse-color voronoi '%w,0 white 0,%h black' \) \ -composite \ \( +clone -rotate -90 \) +append \ \( +clone -rotate 180 \) -append \ \ -virtual-pixel Tile -blur 0x5 -auto-level \ -separate -background white \ -compose ModulusAdd -flatten -channel R -combine +channel \ -set colorspace HSB -colorspace RGB tile_p4g.jpg [![[IM Output]](tile_p4g.jpg)](tile_p4g.jpg) Note that due to the non-mirroring nature of the tiling, you do not need need to remove the duplicated row or column of pixels from the edges before you append. Though it does not hurt to do so, if you want to follow the same type of process for both cases. * * * ---