Menu Search
Jump to the content X X
Smashing Conf Barcelona

You know, we use ad-blockers as well. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. our upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Efficient Image Resizing With ImageMagick

Responsive1 images2 have been keeping us on our toes for quite some time, and now that they are getting traction in browsers, they come with a scary problem: the need to efficiently resize all our image assets. The way responsive images work is that an appropriately sized image is sent to each user — small versions for users on small screens, big versions for users on big screens.

It’s fantastic for web performance, but we have to face the grim reality that serving different sizes of images to different users means that we first need to create all of those different files, and that can be a huge pain3.

Further Reading on SmashingMag: Link

Many tools out there automate image resizing, but too often they create large files that cancel out the performance benefits that responsive images are supposed to deliver. In this article, we’ll see how we can use ImageMagick178 — an open-source command-line graphics editor — to quickly resize your images, while maintaining great visual quality and really tiny file sizes.

Big Images == Big Problem Link

The average web page is about 2 MB9 in size, and about two thirds of that weight is from images. At the same time, millions of people are accessing the Internet on 3G-or-worse connections that make a 2 MB website a horror show to use. Even on a fast connection, a 2 MB website can wreak havoc on your users’ data plans and cost them real money10. Improving web performance and giving a better experience to our users is our job as developers and designers.

imagemagick resize 11

The average web page is 2,099 KB, 1,310 KB of which comes from images. (Image: HTTP Archive12) (View large version13)

Responsive images14 to the rescue! Right? Well, yes, but first we have to generate our responsive image assets, and we have to make sure those assets look good and have a small enough footprint to improve the website’s performance.

For a very small website, saving a few different sizes of each image directly in our image editor is trivial — Photoshop even provides a handy “Save for Web” option that keeps file sizes low. But what about a large website with a lot of images? An online store, for example, might have hundreds or thousands of image assets, and having to create different sizes of each of these is an enormous task.

ImageMagick Link

This is where automated image resizing comes in handy. A bunch of tools out there do this, including GD15 and GraphicsMagick16, but ImageMagick178 strikes a good balance between power and availability in hosting environments. ImageMagick has been around for almost 25 years and is a full-fledged command-line image editor. It is widely supported by content management systems (CMS) such as WordPress7418 and Drupal7919, integrated with task runners such as Grunt8620, and used on its own to automate image editing — including resizing.

It’s also available on desktop systems (Mac, Windows and Linux). If you use Homebrew21 on a Mac, you can install it like this:

brew install imagemagick

Otherwise, look for it in your favorite package manager, or download it directly from the ImageMagick website22.

ImageMagick provides a fast, simple way to automate image resizing. Unfortunately, with the default settings, the resized files it outputs are often really big — sometimes bigger than the inputted image, even though the output has fewer pixels. These big files completely negate the performance gains you’d expect to get from responsive images and, in fact, can make things worse for your users than if you’d simply loaded the huge unshrunk assets.

Below, I’ll describe why this problem exists and show you how to change ImageMagick’s default settings to solve this problem and get small, great-looking images.

How Image Resizing Works Link

The best way to solve the problem is to understand why it’s happening, and that means understanding the basics of how image resizing works.

By definition, when a computer resizes an image, the number of pixels in that image will change. If the image is being enlarged, the output will have more pixels than the input; if the image is being shrunk, the output will have fewer pixels than the input. The challenge is in figuring out the best way to store the original image’s content in this different number of pixels. In other words, we need to figure out the best way to add or remove pixels without changing what the image looks like.

Although not as common a use case, image upsampling (i.e. making images larger) can be a little easier to visualize, so let’s start with that. Consider an image of a blue 4 × 4 pixel square that we want to double in size to 8 × 8 pixels. What we’re doing is taking the same image and applying it to a new pixel grid; this is called resampling and is usually what we mean when we talk about resizing images. To resample our 4 × 4 blue square to 8 × 8 pixels, we need to add 48 extra pixels somewhere. Those pixels will need some color value, and the process of determining that color value is called interpolation. When you’re resampling, the algorithm for determining how the interpolation works is called a resampling filter.

Two blue squares, one 4 by 4 pixels, the other 8 by 823

How do we resample a 4 × 4 pixel square to an 8 × 8 pixel grid? (View large version24)

We could use all sorts of resampling filters and interpolation methods to figure out those 48 extra pixels. The absolute simplest thing we could do is to add four more rows and four more columns of pixels in some arbitrary color — say, red. This is called background interpolation, because the empty pixels are simply exposing a background color (red). This is what you’re doing in Photoshop when you resize using “Image” → “Canvas Size,” instead of “Image” → “Image Size.”

This, of course, is a terrible outcome when we want to resize an image: we don’t perceive the new outputted image to really look like the original inputted image at all; the original square is blue, the new one is blue and red. Background interpolation is only possible when adding pixels (i.e. when making the image bigger or when upsampling), and even then it is essentially useless for resizing, except as a means to show where the new pixels are.

A pink and blue square25

Background interpolation. (View large version26)

Another very simple interpolation method is to make our new pixels the same color as their neighboring pixels; this is called nearest-neighbor interpolation. This produces a much better result than background interpolation, especially for a simple square like this.

A blue square27

Nearest-neighbor interpolation: upsampling a square. (View large version28)

Downsampling (i.e. making the image smaller) with nearest-neighbor interpolation is not as intuitive as upsampling, but it helps to remember that the math involved is OK with fractional pixels. First, the new pixel grid gets applied to the orignal image. Because there are fewer pixels to store the image information, some of the pixels in this new grid will contain multiple colors; in the example below, some pixels contain both blue and white.

Outputting the image in this way to the physical pixels in the real world isn’t possible, though — each pixel can be only one color. The final color of each pixel in the new grid is determined by the color at its center point. In other words, that center point is sampled to determine the final color, which is why nearest-neighbor interpolation is sometimes called point sampling.

Four images: a circle; an 8×8 pixel grid; the grid overlayed on top of the circle with the center marked; and the resized circle, which is blocky and not very circular29

Nearest-neighbor interpolation: downsampling a circle. (View large version30)

For anything more complicated than a line or square, nearest-neighbor interpolation produces very jagged, blocky images. It’s fast and creates small files but doesn’t look very good.

Most resampling filters use some sort of variation on nearest-neighbor interpolation — they sample multiple points to determine the color of a pixel and use math to try to come up with a smart compromise for those values. Bilinear interpolation, for example, creates a weighted average of colors. It produces much nicer results than nearest-neighbor interpolation.

Two circles31

Bilinear interpolation. (View large version32)

One way that resampling — and the specific resampling filter used — can affect file size is by affecting the colors in the image. Bilinear interpolation gives the circle smooth edges, but that means giving the image more colors. The original blue circle has two colors, blue and white. The resized circle has more — some pixels are a pale bluey-white. All else being equal, more colors in an image will make the file size bigger. This is one reason why resizing an image to have fewer pixels sometimes gives it more bytes.

What All This Means for Us Link

In order to make our outputted images smaller, we’ll want to look at ways to reduce the number of colors without sacrificing quality. Choosing an appropriate resampling filter has one of the biggest effects, but other settings can affect the number of colors in the output as well. I’ll also discuss settings that control file compression and quality and that eliminate extraneous data.

Optimal Settings For ImageMagick Link

ImageMagick Basics Link

ImageMagick has a ton of options and functions33, and finding a good combination of these can be tricky.

Two main ImageMagick settings are of interest to us, convert and mogrify. Both of these perform similar operations, but mogrify is intended to be used with multiple files at once, while convert handles only one image at a time.

A simple ImageMagick operation might look like this:

convert input.jpg -resize 300 output.jpg

This says that we want ImageMagick’s convert function to take input.jpg and resize it to 300 pixels wide, and then save that to output.jpg. The -resize 300 part is an example of one of ImageMagick’s many built-in functions. Each function uses the same format: -functionName option.

Using mogrify is similar, but with the syntax reordered a bit:

mogrify -path output/ -resize 300 *.jpg

This says that we want ImageMagick’s mogrify function to take all JPEG files in the current directory (*.jpg), resize them to 300 pixels wide and then save them in the output directory.

Functions can be combined for more complex results:

convert input.jpg -resize 300 -quality 75 output.jpg

As before, this resizes input.jpg to 300 pixels wide, but this time it also sets the JPEG quality to 75 before saving it to output.jpg.

I’ve performed hundreds of tests34 to see which combinations of functions and options produce the smallest results at an acceptable quality.

Testing and Results Link

I wanted to keep the file size as low as possible but keep the quality high — indistinguishable from Photoshop’s “Save for Web.” To do this, I used both a subjective quality measure — my own opinion on whether the output looks good — and an objective quality measure — structural dissimilarity35 (DSSIM). DSSIM compares two images — in this case, my test image and a control generated by Photoshop’s “Save for Web” — and generates a score. The lower the score, the more the images resemble each other; a score of zero means they are identical. To make sure test images look the same as Photoshop’s output, I wanted a mean DSSIM score of 0.0075 or lower. In research released last year36, RadWare37 found that image pairs with a DSSIM score of 0.015 were indistinguishable to their test users.

To make sure the results weren’t biased by outliers, I tested on 40 images that are a mixture of JPEGs and PNGs; photos, drawings and line art; color and monochrome; transparent and opaque. I also tested at three output sizes (300, 600 and 1200 pixels wide) from a variety of input sizes. Finally, I tested both with and without image optimization.

From my tests, running ImageMagick with the following settings produced the smallest results, while generally being visually indistinguishable from Photoshop’s output:

mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.25+8+0.065 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB -strip INPUT_PATH

That’s a lot to take in, so let’s go through each bit and see what it means.

Mogrify vs. Convert Link

As mentioned, ImageMagick provides two similar tools for manipulating images: convert is the basic image editor and works on one image at a time; mogrify is mostly used for batch image manipulation. In an ideal world, these two tools would produce identical results; unfortunately, that’s not the case — convert has a bug38 that makes it ignore one of the settings I recommend using (the -define jpeg:fancy-upsampling=off setting, discussed below), so using mogrify is better.

Resampling Link

Choosing a resampling filter in ImageMagick is surprisingly complicated. There are three ways you can do this:

  • with the resizing function you choose,
  • with the -filter setting,
  • or with the -interpolate setting.
Example output from twelve different resizing functions39

One of these things just doesn’t belong here, but the rest look pretty much the same, which is why I used an objective quality measure. (Image: Richard Fisher6552494640) (View large version41)

The most obvious resizing function to use is -resize, but it creates files that are too large. I looked at 11 different functions and found that -thumbnail does the best job of optimizing quality and file size. In most cases, the -thumbnail function uses a three-step process to resize images:

  1. It resizes the image to five times the output size using the -sample function, which has its own built-in resampling filter that’s similar to the nearest-neighbor approach discussed above.
  2. It resizes the image to its final output size using the basic -resize filter.
  3. It strips meta data from the image.

This means that if we were resizing an image to be 500 pixels wide, -thumbnail would first resize it to 2,500 pixels wide using -sample; the result might be blocky and pixelated, as we saw in the examples above, but the operation would be fast and would produce a result with a small file size. Then, ImageMagick would resize this image from 2,500 pixels wide to 500 pixels wide using -resize. This smooths out the blockiness, but the file size stays pretty low. Finally, ImageMagick would remove meta data to get an even smaller file.

The second way to choose a resampling filter in ImageMagick is with the -filter setting. Some resizing functions (such as -sample) have a built-in resampling function that’s always used, but others (such as -resize) have defaults that can be overridden with -filter. The -filter setting gets used in -thumbnail’s second step, because that step uses -resize.

I tested 31 different settings for -filter and got the best results with Triangle. The Triangle resampling filter is also known as bilinear interpolation, which I discussed above. It determines pixel color by looking at a support area of neighboring pixels and produces a weighted average of their colors. I found it best to specify this support area at two pixels using the -define filter:support=2 setting.

The third way to choose a resampling filter, the -interpolate setting, is ignored by -thumbnail, so it’s not needed here.

In addition to the settings above, by default ImageMagick also uses something called JPEG fancy upsampling42, an algorithm that tries to produce better-looking JPEGs. I’ve found that it produces larger files and that the quality difference is negligible, so I recommend turning it off with -define jpeg:fancy-upsampling=off.

Sharpening Link

Images pretty often get a little blurry when resized, so programs such as Photoshop will often apply some sharpening afterwards to make the images a little crisper. I recommend using an unsharp filter — which, despite its name, actually does sharpen the image — with the setting -unsharp 0.25x0.25+8+0.065.

Unsharp filters work by first applying a Gaussian blur43 to the image. The first two values for the unsharp filter are the radius and sigma, respectively — in this case, both have a value of 0.25 pixels. These values are often the same and, combined, tell ImageMagick how much to blur the image. After the blur is applied, the filter compares the blurred version to the original, and in any areas where their brightness differs by more than a given threshold (the last value, 0.065), a certain amount of sharpening is applied (the third value, 8). The exact meanings of the threshold and numerical amounts aren’t very important; just remember that a higher threshold value means that sharpening will be applied less often, and a higher numerical amount means that the sharpening will be more intense wherever it is applied.

Color Reduction Link

I mentioned that one of the biggest reasons why resized images get bloated is because of all the extra colors in them. So, try to reduce the number of colors — but not so much that the quality suffers.

One way to reduce colors is with posterization, a process in which gradients are reduced to bands of solid color. Posterization reduces colors to a certain number of color levels — that is, the number of colors available in each of the red, green and blue color channels that images use. The total number of colors in the final image will be a combination of the colors in these three channels.

Posterization can drastically reduce file size, but can also drastically change how an image looks. With only a few color levels, it creates an effect like what you might see in 1970s rock posters44, with a few discrete bands of color. With many color levels — for example, 136, as I’m suggesting — you get a smaller file without losing much image quality.

Close up of an owl with reduced colors45

Original image. (Image: Richard Fisher6552494640) (View large version47)
Close up of an owl with reduced colors48

Posterization reduces the colors in the image. (Image: Richard Fisher6552494640) (View large version50)

Dithering is a process that is intended to mitigate color banding by adding noise into the color bands to create the illusion that the image has more colors. In theory, dithering seems like a good idea when you posterize; it helps the viewer perceive the result as looking more like the original.

Two images of an old woman, the second full of image rendering artifacts51

Dithering. (Image: Richard Fisher6552494640) (View large version53)

Unfortunately, ImageMagick has a bug that ruins images with transparency when dithering is used like this. So, it’s best to turn dithering off with -dither None. Luckily, even without dithering, the posterized images still look good.

Two images of an old woman, the second full of image rendering artifacts54

ImageMagick dithering bug. (Image: Nemo55) (View large version5956)

Color Space Link

While not strictly a matter of color reduction, setting an image’s color space is a related concept. The color space defines what colors are available for an image. The image below shows that the ProPhoto RGB color space contains more colors than the Adobe RGB color space, which in turn contains more colors than the sRGB color space. All of these contain fewer colors than are visible to the human eye.

Map that compares how much of the color spectrum is covered by different color spaces; sRGB covers the least57

Color spaces. (Image: Cpesacreta58) (View large version5956)

sRGB was created to be the one true king of color spaces on the Internet. It has been endorsed by the W3C and other standards bodies; it is the required color space in the CSS Color Module Level 360 and the SVG specification61 and is the assumed color space of the WebP62 specification; and it is explicitly referenced in the PNG specification63. It’s also the default color space in Photoshop. In short, sRGB is the color space of choice for the web platform, and, assuming you want your images to render predictably, using it is probably a good idea.

Quality and Compression Link

With lossy image formats such as JPEG, quality and compression go hand in hand: the higher the compression, the lower the quality and the lower the file size. We could drastically reduce file size by setting a high JPEG compression factor, but this would also drastically reduce quality. A balance is needed.

When I was doing my tests, the control images I created with Photoshop had a JPEG quality setting of high, or 60. I’ve found that this setting works well for me and strikes the right balance between quality and file size. However, in my ImageMagick settings, I’m recommending -quality 82. Why?

It turns out that JPEG quality scales are not defined in a specification or standard, and they are not uniform across encoders. A quality of 60 in Photoshop might be the same as a quality of 40 in one program, quality B+ in another and quality fantastico in a third. In my tests, I found that Photoshop’s 60 is closest to -quality 82 in ImageMagick.

For non-lossy image formats, such as PNG, quality and compression are not related at all. High compression doesn’t change how an image looks at all and only comes at the expense of processing load (in terms of CPU usage, memory usage and processing time). Assuming that our computers can handle this load, there’s no reason not to max out PNG compression.

PNG compression in ImageMagick can be configured with three settings, -define png:compression-filter, -define png:compression-level and -define png:compression-strategy. Compression filtering64 is a pre-compression step that reorganizes the image’s data so that the actual compression is more efficient; I got the best results using adaptive filtering (-define png:compression-filter=5). Compression level is the amount of compression that gets applied; I recommend maxing this out to 9 (-define png:compression-level=9). Finally, the compression strategy setting determines the actual algorithm that’s used to compress the files; I got the best result with the default compression strategy (-define png:compression-strategy=1).

Meta Data Link

In addition to the actual image data, image files can contain meta data: information about the image, such as when it was created and the device that created it. This extra information could take up space without providing any benefit to our users and should usually be removed. Above, when describing the -thumbnail function that handles the actual resizing of the image, I mentioned that its third step involves stripping meta data. Even though that’s true, -thumbnail doesn’t remove all of the meta data, and there are gains to be had by using -strip and -define png:exclude-chunk=all as well. Neither of these should affect quality at all.

Progressive Rendering Link

JPEGs and PNGs can be saved to use either progressive or sequential rendering. Sequential rendering is usually the default: The image will load pixels row by row from top to bottom. Progressive rendering means the image is delivered and rendered in stages.

For JPEGs, progressive rendering can happen in any number of stages, as determined when the file is saved. The first stage will be a very low-resolution version of the full image; at each subsequent stage, a higher-resolution version is delivered until, in the last stage, the full-quality version is rendered.

An owl, rendering at progressively higher quality

Progressive JPEG simulation. (Image: Richard Fisher6552494640)

PNGs use a type of progressive rendering called Adam7 interlacing66, in which the pixels of the image are delivered in seven stages based on an 8 × 8 pixel grid.

Pixels being rendered in seven passes

Adam7 interlacing. (Image: CountingPine67)

Both types of progressive rendering can be controlled in ImageMagick using the -interlace setting. But should progressive rendering be turned on or not?

For both JPEGs and PNGs, progressive rendering increases the file size, but for a long time conventional wisdom held that it was worth turning on68 because it delivered a better experience to the user. The idea is that even if the full, perfect image doesn’t load quite as quickly, users would be able to see something earlier, and that something is probably better than nothing.

Last year, though, Radware69 released research on progressive JPEGs70 that shows users actually tend to prefer sequential image rendering. This is just one study (and one that hasn’t gone through a formal peer review process), but the results are interesting. Radware’s results, combined with the fact that sequential images have smaller file sizes, lead me to recommend the -interlace none setting in ImageMagick.

Image Optimization Link

I mentioned above that I ran tests both with and without image optimization. All of the settings I’ve described so far are what I’d recommend if you’re not optimizing your images. If you can optimize them, though, my recommendations would change slightly: I found that slightly different -unsharp settings work better (-unsharp 0.25x0.08+8.3+0.045 versus -unsharp 0.25x0.25+8+0.065 without optimization) and that there’s no need to use -strip.

mogrify -path OUTPUT_PATH -filter Triangle -define filter:support=2 -thumbnail OUTPUT_WIDTH -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB INPUT_PATH

A lot of different image optimizers are out there. I tested image_optim71, picopt72 and ImageOptim73, all of which run images through a battery of different optimization steps. I tested these tools both individually and in combination, and I found that the best results come from running files through all three, in the order listed above. That said, there are diminishing returns: After the first round of optimization with image_optim, the extra compression that picopt and ImageOptim achieve is quite small. Unless you have a lot of time and processing power, using multiple image optimizers is probably overkill.

The Results (Or, Is This Even Worth It?) Link

The settings I’m recommending are, admittedly, complicated, but they are absolutely worthwhile for your users. When I set out to do these tests, I did so hoping that I’d be able to drastically reduce file size without sacrificing image quality. I’m happy to report that, using the settings described above, I was successful.

On average, my recommended settings and optimizations reduced file sizes by 35% compared to Photoshop’s “Save for Web”:

Savings compared to Photoshop Creative Cloud
Condition File size: mean File size: % difference
My settings, with optimization 218,274 bytes
My settings, without optimization 259,852 bytes 19.05%
Photoshop CC, with optimization 260,305 bytes 19.28%
Photoshop CC, without optimization 299,710 bytes 35.26%

My settings without optimization even beat Photoshop’s output with optimization!

Compared to ImageMagick’s default image resizing, my recommendations resulted in file sizes that were 82% smaller on average:

Savings compared to ImageMagick defaults
Condition File size: mean File size: % difference
My settings, with optimization 218,274 bytes
My settings, without optimization 259,852 bytes 19.05%
-resize 397,588 bytes 82.15%

Compared to WordPress’s default image resizing (which uses ImageMagick under the hood), my recommendations resulted in file sizes that were 77% smaller on average:

Savings compared to WordPress
Condition File size: mean File size: % difference
My settings, with optimization 218,274 bytes
My settings, without optimization 259,852 bytes 19.05%
WordPress7418* 385,795 bytes 76.75%
* Simulation using ImageMagick with the settings that these CMS’ use by default. The specific settings used can be found in the GitHub repository for these tests8375.

Compared to other CMS’ and tools that use ImageMagick, my recommendations resulted in file sizes that were up to 144% smaller:

Savings compared to other tools
Condition File size: mean File size: % difference
My settings, with optimization 218,274 bytes
My settings, without optimization 259,852 bytes 19.05%
CodeIgniter76/ExpressionEngine77* 340,461 bytes 55.98%
TYPO3.CMS78* 359,112 bytes 64.52%
Drupal7919* 397,588 bytes 82.15%
Perch80* 416,790 bytes 90.95%
Craft CMS81* 425,259 bytes 94.83%
grunt-responsive-images82 533,030 bytes 144.20%
* Simulation using ImageMagick with the settings that these CMS’ use by default. The specific settings used can be found in the GitHub repository for these tests8375.

And remember, this is all with the images being visually indistinguishable from the Photoshop output, on average.

Using the settings I described above can get you huge file size savings without hurting quality. This can be a huge boon to your website’s performance!

How To Implement This In Your Projects Link

I hope the benefits of using this technique are obvious. Luckily for you, the hard part — figuring all of this out — is all done. Despite the apparent complexity of the recommended settings, implementing this in your own projects can be fairly quick and easy. Although running this whopper of a command from the terminal every time you want to resize an image may be inconvenient, there are simpler options that require very little muss or fuss.

bash shell Link

Most command-line shells allow you to setup aliases and functions for complicated commands. If you use a bash shell, you can add a function to your .bash_aliases (or .bashrc) file that acts as an alias for my recommended command:

smartresize() {
   mogrify -path $3 -filter Triangle -define filter:support=2 -thumbnail $2 -unsharp 0.25x0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB $1

Then, you can call it like this:

smartresize inputfile.png 300 outputdir/

Node.js Link

An npm package called, unsurprisingly, imagemagick84 allows you to use ImageMagick via Node.js85. If you’re using this module, you can add resizing using my recommended settings like this:

var im = require('imagemagick');

var inputPath = 'path/to/input';
var outputPath = 'path/to/output';
var width = 300; // output width in pixels

var args = [
   '-unsharp 0.25x0.25+8+0.065',
   '-dither None',
   '-posterize 136',
   '-quality 82',
   '-define jpeg:fancy-upsampling=off',
   '-define png:compression-filter=5',
   '-define png:compression-level=9',
   '-define png:compression-strategy=1',
   '-define png:exclude-chunk=all',
   '-interlace none',
   '-colorspace sRGB',

im.convert(args, function(err, stdout, stderr) {
   // do stuff

Grunt Link

If you use Grunt8620 as a task runner, good news: I’ve built a Grunt task named grunt-respimg9687 (npm88) that handles everything I’ve described above. You can include it in your projects by running:

npm install grunt-respimg --save-dev

Then, you can run it in your Grunt file like this:

  respimg: {
    default: {
      options: {
        widths: [200, 400]
      files: [{
        expand: true,
        cwd: 'src/img/',
        src: ['**.{gif,jpg,png,svg}'],
        dest: 'build/img/'

PHP Link

PHP89 has ImageMagick integration called Imagick90 that makes it relatively easy to run ImageMagick operations from within your PHP scripts. Unfortunately, Imagick is a bit limited and doesn’t let you do some things that I recommend, like setting a resampling filter to be used with the thumbnail function.

But, again, you’re in luck: I’ve created a composer package called php-respimg9791 (packagist92) that handles everything described above. You can include it in your projects with Composer93 by running:

composer require nwtn/php-respimg

Then, you can resize your images like this:

use nwtn\Respimg as Respimg;
$image = new Respimg($input_filename);
$image->smartResize($output_width, 0, false);

Content Management Systems Link

If you use a CMS, you might want to take advantage of these savings for the thumbnails and other resized images that get generated when users upload images. A few options are available to you.

If your CMS is built on PHP, you could bake the PHP stuff above into a theme or plugin. However, if your PHP-based CMS happens to be WordPress, then there’s no need for you to do that work: This is now integrated into the Responsive Issues Community Group’s plugin RICG Responsive Images9894 as an experimental feature. After you install the plugin, all you’ll need to do to activate these ImageMagick settings is add the following lines to your functions.php file:

function custom_theme_setup() {
   add_theme_support( 'advanced-image-compression' );
add_action( 'after_setup_theme', 'custom_theme_setup' );

If you don’t use WordPress and don’t want to try to hack this into your CMS, most CMS’ include some way to modify image defaults (especially for quality). You might be able to get a lot of these benefits with a few simple changes to your CMS’ configuration. Check out the documentation and see what options are available to you.

Performance Link

The settings I’m recommending are obviously far more complex than simply using -resize, and this complexity brings a performance hit with it. Using my recommendations will take longer and use more resources on your computer or server. In my tests, I found that memory and CPU usage peaks were comparable but that my settings took an average of 2.25 times longer to render an image than from just using -resize alone.

Conclusion Link

As designers and developers, we have an enormous amount of power to shape how — and how well — the web works. One of the biggest impacts we can have is to make our websites more performant, which will improve our users’ experiences and even make our content available to whole new markets95. Cutting image weight is a relatively simple and hugely impactful way to increase performance, and I hope the information outlined above helps you make a difference to your users.

Thank you to Mat Marquis for reviewing a draft of this article.

(da, ml, al)

Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98

↑ Back to top Tweet itShare on Facebook

Dave Newton is a web developer in Toronto, Canada, and will soon be starting a new role as a front-end deveveloper at Shopify. He strongly believes in making web content accessible and usable, and this goal has made him passionate about web standards, responsive design, progressive enhancement, accessibility, and web performance. He is an active member of the W3C’s Responsive Issues Community Group.

  1. 1

    Nice article!

    I also use IM to resize and sharpen images, but mostly for the better quality output compared to Photoshop

    Here is my script:

    for file in *.jpg; do convert $file -resize 1012x -unsharp 0x0.55+0.55+0.008 -quality 90% small-$file; done

  2. 2

    Mathieu Lajeunesse

    June 25, 2015 3:00 pm

    Good article. While this article talks about stripping the meta data make the files thinner, I would like to give a different perspective on the same feature.

    I recently built a WordPress website for a photographer. One of the client’s requirements was that the EXIF/IPTC meta data, including the copyright notice and color profile which are very important to preserve the work integrity of the photos, were kept when the photos were resized automatically by WordPress. The default solution on most servers, GD, does not support that at all and just strips everything. I went with ImageMagick because it allowed the possibility to keep the data instead of erasing it. So in that sense ImageMagick just offers more possibilities than GD which I have seen as the default on 99% of the servers I have worked with in my life. The quality of the resampling is very good too.

    Just so you know I also wrote some PHP to make sure the files were renamed when resized so visitors couldn’t access every size of every photo just by changing the URL (removing the -300×300.jpg part for example) on a file. That was an other requirement of the client, and a good idea for anyone building a website for a professional photographer.

    Just thought I’d mention it in case you guys have to deal with a similar project.

    • 3

      Good point about the metadata, @Mathieu. For some edge cases, such as the one you raised, these settings may not be appropriate. You’ll need to assess what’s best for your clients and users when choosing which settings to use. I think the settings I’m suggesting hit a good balance for *most* use cases, though.

  3. 4

    I still don’t understand the point of responsive images (unless a very different image/ratio for different layouts). On one hand you’d want the lower res image for mobile because not everyone is on a fast connection, but on the other hand you’d want the higher res image for mobile due to its higher pixel density.

    • 5

      That’s true, @Mark. The way I think about it is that responsive images are concerned with delivering the most appropriate image for a user’s context. Determining what’s appropriate might depend on a number of factors, including ones you mentioned — screen resolution, pixel density, connection speed, etc. At the moment, browsers aren’t taking connection speed into account, but the responsive image spec gives browsers the ability to do this in the future if they determine it’s important. The `srcset` attribute is a hint, or recommendation to the browser, but it’s ultimately the browser that makes the final decision about which resource to download. That means that it might choose to download a low res images on a high res screen based on user settings, connection speed, etc.

  4. 6
  5. 7

    @Mark: there´s a trick to get high dpi images also with low filesizes.
    Double image size (e.g. 800×400) with extreme compression and display half size (400×200) to get more detail on retina displays.

    BTW some essential Drupal-Modules for this:

    • 8

      I am somewhat unsure about the merits of the “double image dimensions at low quality, and display at half the size” approach. I think that might put more of a strain on the other two precious mobile resources besides network bandwidth – namely processing power and RAM consumption.

      Before the browser can render the image, it has to unpack it in its full dimensions in memory (and at that point the fact that it is “low quality” doesn’t matter, the browser has to calculate a value for each pixel) – and with your suggested approach, the memory consumption for that will be *four* times that of an image that wasn’t double in size in each dimension. And I am not sure if memory usage will go down after the browser has rendered the image down to its “target” display size, or if it will maybe keep the larger original in memory.

      And while computing power might not be your mayor concern in the newest iPhone, other devices with double-density displays, but less CPU power are out there.

      So you might be trading of bandwith/traffic for overall handling (low memory might cause the whole browser/UI/device to become “laggy”) and maybe even battery lifetime here …

      • 9

        (Spelling correction: That part about computing power was supposed to be a *major* concern, not one of the head honcho of your city …)

  6. 10
  7. 11

    Maybe someone could also add an “How to get imagemagick running with MAMP” on OS X?
    I never managed that without support and it´s not that easy for “non-coders”.

    • 12

      MAMP Pro comes with built in Image Magick by default since version 3, you only have to find out how to enable it (since its not documented properly) and in which path you have to search:

      Hope this helps.

      I use Imagemagick with TYPO3 (the latter supports/requires Imagemagick for image resizing for years).

  8. 13

    Takis Bouyouris

    June 25, 2015 5:56 pm

    @Mark has indeed a point when saying that it is a controversy to try to reduce image sizes for mobile devices while the trend is that mobile devices have higher pixel density (retina, HiDPI) displays.

    @Mathieu also has a point about PHP GD and image metadata, still it is a great solution!

    @Dave (the author) I would love to see some comparison between PHP GD and ImageMagick!

    WordPress-wise we have a developed a quite transparent solution (Adaptive Images for WordPress, which uses PHP GD for image resizing. Its main goal is to work as a transparent filter between the server and the device. Transparent means that one should not have to change anything in their development process! Maybe you’d like to check it out.

    • 14

      I’d love to see a comparison with GD too, @Takis! Collecting the ImageMagick data took a *long* time, and collecting similar data for GD (and GraphicsMagick and vips, etc.) would also be fairly intensive. I’d be very happy if somebody took this on, but if nobody does I may eventually look into it down the road.

  9. 15

    Well if you can have a high res image with low file size, then why do responsive images? Just serve all screen sizes that image.

    • 16

      Chris Koerner

      June 25, 2015 9:33 pm

      @Mark Let’s say I’m targeting just two viewports. Most projects target many more. One is a viewport for 375px wide. The width of an iPhone 6 viewport in portrait. I want my image to go ‘edge to edge’ in that screen and be retina sharp. Lets say the same project has me targeting a 960px target for desktop (non-retina).

      An iPhone 6 has a natural* width of 750px. A non-retina desktop is, well 960px. That’s still 90px more to deal with, just in the width. Let’s say my image is a ratio 3.2:1. A nice banner image. The desktop image will be 960px by 300px. My iPhone6 image will be 750px by 234px.

      960 – 288,000 pixels
      750 – 175,266 pixels

      Save For Web in Photoshop gives me two files:

      960px is 516kb
      750px is 305kb

      My 960px image – which looks great on my desktop is 40.7% larger than my 750px image- before any optimization! I don’t want to serve that up to a mobile user.

      After running them through ImageOptim I can save an additional 9.3% for each image.

      Here’s my files so you can compare yourself.

      *The 6 Plus is a little trickier –

  10. 17

    One of the best articles I’ve read on Smashing in awhile, thanks for everything you put into it. I will definitely be adding your grunt task to my build.

  11. 18

    The venerable SLIR (Smart Lencioni Image Resizer) is an extremely flexible and performance-friendly PHP solution (using the GD Graphics library) which copes well with whatever you throw at it:

  12. 19

    Burak Çalık

    June 26, 2015 2:42 am

    I have done a lot of testing with large image files (over 1 gb) using Vips and Imagemagick.
    Vips has always took about half time than Imagemagick for every operation. Creating thumbnail, resizing, converting etc. All operations take the half amount of time than Imagemagick. So Vips is clear winner.

  13. 23

    Keep your loving brother smiling and happy on this Raksha Bandhan by delivering attractive presents best available in online shopping store. Send Rakhi Gifts to UK and express your best love and affection towards your dear brothers. Send Rakhi to United Kingdom and make the event for your brothers more special from miles away.

  14. 24


    June 26, 2015 1:09 pm

    Great tips!
    Very nice and informative Presentation.. Thanks for taking the time to deliver such a nice information to your readers…

  15. 25

    Excellent article. Thanks a lot for the very detailed explanation, appreciated.

  16. 26

    Thanks for sharing this article it is indeed one of the best articles on your website. I use imagemagick for giving my images a professional look, as compaerd to Photoshop.

  17. 27

    Ahn, Hyeong-woo

    June 27, 2015 2:04 pm

    Thank you. I used your script, immediately.
    And, improved a little(help message, whitespace in path problem).

    smartresize() {
    if [ “$3” == “” ] ; then
    echo “smartresize inputfile.png 300 outputdir/”
    mogrify -path “$3” -filter Triangle -define filter:support=2 -thumbnail “$2” -unsharp 0.25×0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB “$1”

  18. 28

    Ahn, Hyeong-woo

    June 27, 2015 2:05 pm

    Thank you. I used your script, immediately.
    And, improved a little(help message, whitespace in path problem).

    smartresize() {
    if [ “$3” == “” ] ; then
    echo “smartresize inputfile.png 300 outputdir/”
    mogrify -path “$3” -filter Triangle -define filter:support=2 -thumbnail “$2” -unsharp 0.25×0.08+8.3+0.045 -dither None -posterize 136 -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -colorspace sRGB “$1”

  19. 29

    Ahn, Hyeong-woo

    June 27, 2015 2:08 pm

    Thank you. I used your script, immediately.
    And, improved a little(help message, whitespace in path problem).

  20. 30

    So, what you’re saying is basically that ImageMagick is broken. Instead of doing perhaps -resize 300 -optimize, you have to do a command line with about 15 arguments. Really?
    ImageMagick seems to be designed by the same people who built PHP (or at least in the same spirit), as it lacks any logic. 8 different ways to resize images and no, you don’t want the one called “resize” because, you know, that would be too logical. You want to use the option called “thumbnail” instead. Makes so much more sense. And of course you have to use the multi-file feature, even though you’re only using one file. Because they are somehow implemented differently…
    I just don’t get why anyone would consider this mess a good solution.

    The article itself was very interesting, though, especially the detail about how image resizing works. Very well explained!

    • 31

      It’s a command line tool. Not a Photoshop. That’s how you use a command line tools – by adding parameters. And if you need a shortcut you write a bash script. Actually, the automation done in that way is more convenient than in Photoshop.

  21. 32

    Christopher Anderton

    June 27, 2015 8:59 pm

    If you can run other tools like PNGOUT, PNGCrush, OptiPNG, JpegOptim, Jpegrescan, jpegtean, Gifsicle (about every library used in the ImageOptim app) in your enviroment, you can save even more space. I set up a batch script on a local server with ImageMagick, and compared with another batch script using specific libraries (such as the ones mentioned above) the result was a lot better (the batches was cutting down filesize with no loss of quality) than ImageMagick.

    I ended up using ImageMagick (or GraphicMagick) for things like thumbnail generation, cropping and so on, and the others for optimization.

    However, this article is maybe the best one out there regarding optimization using just ImageMagick. Lot’s of good information. Keep up the great work!

  22. 33

    “Consider an image of a blue 4 × 4 pixel square that we want to double in size to 8 × 8 pixels.”
    16, 64.
    Double in size?

  23. 34

    Jan Klosowski

    June 28, 2015 7:28 am

    Great solid article. An important topic which is not covered here is adding a specific postfix to the output filename. Is that possible? Example (the WordPress way):

    filename.jpg —> filename-320×200.jpg

    The ultimate bash script should create a batch of images for different resolutions with different names. Is that possible with ImageMagick itself?

    • 35

      With `convert` you can definitely specify an output name, but I don’t think you can with `mogrify`. You’d have to build the renaming logic into your script.

  24. 36

    I personnaly rely a lot on mozjpeg. It just makes miracles on all my pictures; easily cutting down the size to half what it was.

  25. 37

    On this site you can change size of pictures online (powered by Imagemagick) :

  26. 38

    Thank you for sharing this! Will definitely start experimenting. However, online services still seem like a compelling alternative: Just letting the cloud fix everything… Have you experience with services like the WIT-service here:
    I find it very reliable and convenient.

    • 39

      No, I don’t have any experience with services like this, but I do think for a lot of situations these make a lot of sense.

  27. 40

    Angie Winterbottom

    June 29, 2015 9:02 pm

    To add it to a .NET project, there’s a nice nuget package called “Magick.NET”:

    It’s super awesome. :)

  28. 41

    Thank you for this great article, did you try to use Mozjpeg?
    In our company we got a great result using it with ImageMagick:
    ImageMagick for resizing and Mozjpeg for compression and the result is very good.

    • 42

      I did look at mozjpeg and found it really impressive. I didn’t include it as part of my first round of tests, but I hope to do some more formal testing on it (and cjpeg-dssim []) in the future.

  29. 43

    I’m a huge proponent of IM, but I prefer to use the imagick PHP extension, and I encourage everyone to give it a try for dynamically altering/generating web images. Fantastic tool.

  30. 44

    A useful option for speeding up resize time (although I don’t know how it works with mogrify) is -size HEIGHTxWIDTH that tells to the jpeg loader to load a smaller version of the image so that will use less ram and resize will be faster.

    If resizing all the images takes too much I’d suggest to use a server that does the resize on the fly, like or a paid service, like

    (disclaimer: I was a collaborator on the first and working at the second)

  31. 45

    How can I use the bash script on a whole directory of images?

    • 46

      At the moment the script is a bit limited, and there’s no *great* way to do this. However, you could try running it in a loop on the command line, like this:

      for f in inputdir/* ; do smartresize "$f" 300 outputdir/; done

      It will produce errors for any non-image files in the directory, but otherwise it should work.

  32. 47

    A great article that explained why I’ve so often run into the issue of WordPress creating smaller images (by pixel size) with larger file sizes than their original. I’m very curious to see how much improvement I see with the RICG plugin and the function referenced.

    I’m also curious if using the RICG plugin + function will have any compatibility issues with the EWWW Image Optimizer plugin for WordPress or if it would be overkill to use EWWW to try to losslessly compress these files further. I’m about to test it myself but would love any other input from folks more knowledgeable on the subject than myself.

    • 48

      A little after the fact, but I just ran a test optimization with a handful of JPG images after RICG for WordPress had processed them, and still saw about a 5% savings on every image with EWWW Image Optimizer.

  33. 49

    Collin Anderson

    August 26, 2015 3:16 am

    This may sound counter-intuitive, but in my experience progressive JPEGs actually have a _smaller_ file size, if they’re at least 10kb. Did you test the file size difference between progressive and not for JPEGs?

    • 50

      In my testing, this is generally the case as well. As the author of EWWW Image Optimizer, this is why the plugin tries both progressive AND non-progressive optimization, then moves forward with the best option for every individual image.

  34. 51

    Fantastic walkthrough. I’ve been starting to prefer GraphicsMagick over ImageMagick lately, as I find it faster and more accurate. Anyways, I ported your one-liner to GraphicsMagick:

    gmsmartresize() {
    gm mogrify -filter Triangle -define filter:support=2 -thumbnail $2 -unsharp 0.25x0.08+8.3+0.045 -dither -quality 82 -define jpeg:fancy-upsampling=off -define png:compression-filter=5 -define png:compression-level=9 -define png:compression-strategy=1 -define png:exclude-chunk=all -interlace none -strip -output-directory $3 $1

    It works the same way as yours, but RGB is the default colorspace for gm, and I added -strip to remove the metadata.

  35. 52

    Hello and thanks for that fantastic tome of knowledge in one article. I request guidance with regard to converting text to responsive and clean images. I have user inputted data that I am currently outputting with css on my wordpress site. I want to output that data as responsive png images.

    I will appreciate it greatly if you could guide me or point me in the right direction.

    Thank You

  36. 53

    congrats for the insightful article you wrote.
    Allow me to suggest a correction: though it isn’t very intuitive, using
    interlaced=line (instead of your suggested interlaced=none) will generally lead to _smaller_ files.
    When I say “generally” I actually mean all the files smaller than approx 9K.
    We tested this extensively on and from our empirical evidence this leads generally to the smallest possible files.

    Just to give you an idea, I made a quick test using 2045 randomly chosen files of over 9KB with a total size of 169MB.
    Using your suggested command (except for posterize option) the interlaced version of the files totalled 133MB vs 137MB with the other option.
    That means files were reduced by 21.3% vs 18.9%
    While this is not a huge difference it clearly shows it is better to use interlaced. And in my opinion it is better for UX also.

    If you’re interested I could send you an archive with the original and optimized files so you can verify :-)

  37. 54

    Hello great article!

    One question: Have you tested the node version of your code you posted in the artlcle?

    I used your given args:

    var args = [
    ‘-unsharp 0.25×0.25+8+0.065’,
    ‘-dither None’,
    ‘-posterize 136’,
    ‘-quality 82’,
    ‘-define jpeg:fancy-upsampling=off’,
    ‘-define png:compression-filter=5’,
    ‘-define png:compression-level=9’,
    ‘-define png:compression-strategy=1’,
    ‘-define png:exclude-chunk=all’,
    ‘-interlace none’,
    ‘-colorspace sRGB’,

    I am using the npm module imagemagick and used your code but getting the error:

    { [Error: Command failed: convert: unrecognized option `-unsharp 0.25×0.25+8+0.065′ @ error/convert.c/ConvertImageCommand/3112.

    Commenting out the unsharp argument then gives me the error for dither:
    { [Error: Command failed: convert: unrecognized option `-dither None’ @ error/convert.c/ConvertImageCommand/1400.
    ] timedOut: false, killed: false, code: 1, signal: null }

    ..and so on for each argument after that. I am using the latest versions for imagemagick and the node module.

    Any help is appreciated!

    • 55

      For anybody else running into above problem, just put the paramaters for each -command in the next element in the array instead of in the same string: e.g. ‘-unsharp’, ‘0.25×0.08+8.3+0.045’ instead of ‘-unsharp 0.25×0.08+8.3+0.045’.

  38. 56

    Antonio Belloso

    October 5, 2015 4:15 pm

    Node.js lib works fine with this arguments

    function imgConvert(inputPath, outputPath, width) {
    var args = [
    im.convert(args, function (err, stdout) {
    if (err) throw err;
    console.log(‘stdout:’, stdout);


↑ Back to top