![]() |
Making Thumbnails with RMagick |
If you're using RMagick to make thumbnails of JPEG images and you're concerned about the amount of CPU time it takes, consider using the thumbnail method instead of resize. Thumbnail is faster than resize with all the default arguments but produces equally-attractive results. The difference is even more marked when the thumbnail image is much smaller (less than 10%) than the original image. If you're using RMagick with ImageMagick 6.2.6, there may even be a better option. Read on to see how I reached these conclusions.
RMagick binds Ruby programs to either the ImageMagick or the GraphicsMagick library. Both libraries provide the same set of resizing APIs. In RMagick these APIs are expressed as the resize, sample, scale, and thumbnail methods in the Magick::Image class. Christy (ImageMagick's chief architect) explains the difference between the 4 methods like this:
[Sample] does not introduce any new colors into the image by sampling at the exact center of each pixel so no partial pixels are considered. [Sample] is the equivalent of [resize] with a point filter. [Thethumbnailmethod] uses point sampling to 5 times its reduced size and then calls [resize] to reduce the 5x image to its reduced size. In addition, any profiles or comments are stripped from the thumbnail. [Scale] samples the image like [sample] but uses floating-point sampling and blends partial pixels. [Resize] permits one to resize using a filter of choice...and also permits a blur/smooth operation. By default, the Lanczos filter is used when reducing an image in size and the Mitchell when enlarging. [Resize] weights the pixel blending relative to the alpha transparency of the neighboring pixels. Opaque pixels are weighted higher than transparent pixels when determining the final pixel color.
I used Ruby's benchmark module to collect timing data for each of the methods. In addition to measuring sample, scale, and thumbnail, I measured resize 15 times with each of the 15 different filters it accepts. I made the measurements by resizing a 2272x1704 photograph in JPEG format down to 3 thumbnail sizes (200x150, 300x225, and 400x300). With this data I made two charts, one for ImageMagick and one for GraphicsMagick. In both charts the columns are sorted by decreasing CPU time for the smallest thumbnail size.
Looking at the benchmarks, it's clear that the resizing algorithms have diverged since GraphicsMagick forked from ImageMagick. The ImageMagick resizing algorithms seem to sacrifice performance with some filters in order to gain performance with others, while the GraphicsMagick algorithms demonstrate consistent performance regardless of the filter. With the exception of thumbnail, all methods take a bit more time as the size of the thumbnail increases. Look at thumbnail, though, which performs similarly in both libraries. The smaller the thumbnail compared to the original, the better it works. This is consistent with the algorithm described above. Even with the largest size (which admittedly is getting out of the typical range for "thumbnails") thumbnail still outperforms resize with the default Lanczos filter.
If you don't care how your thumbnails look, it's obvious you should always use sample since that method always runs in essentially no time. However, you probably won't like the noisy, pixelated thumbnails it produces. If, like most people, you want thumbnails that look good you can't choose a method on its execution speed alone. To evaluate the results of each of the methods, you need to look at the actual thumbnails. (Caveat: I made the thumbnail images with ImageMagick 6.2.6. If you're using GraphicsMagick or a different release of ImageMagick your results may be different.)
For simplicity and consistency you can't beat thumbnail. You don't have to choose a filter for it, it performs the same in both ImageMagick and GraphicsMagick, it runs fast, and it produces good thumbnails. Scale performs as nearly as well as thumbnail, or even better when the thumbnail is large, but the resulting thumbnail seems a touch less sharp, at least to my eye. With ImageMagick 6.2.6, resize with the Point filter always out-performs thumbnail yet produces a very similar-looking thumbnail. If you choose any method other than thumbnail, remember to use strip afterwards to remove any profiles or comments from the thumbnail image.
You can tell the JPEG library to reduce the amount of data read from very large images. When reading the original image, use the self.size Image::Info attribute to specify dimensions that are twice the dimensions of the desired thumbnail. The JPEG library will limit the amount of data it reads from the image file to an amount sufficient to satisfy the specified dimensions. (Thanks and a tip o' the hat to Anthony Thysson for this tip! In fact, visit Anthony's excellent site for more information about thumbnails.)
I ran all the benchmarks on a PC with a 933MHz Intel Pentium III CPU and 512MB RAM. I used Mandriva 2006, Ruby 1.8.4, RMagick 1.10.0, ImageMagick 6.2.6 and GraphicsMagick 1.1.7. Both ImageMagick and GraphicsMagick were compiled with full optimization (gcc's -O3 option). I used OpenOffice.org 1.1.5 to produce the charts.
Tim - Jan 21, 2006