Point of Discussion
Magnolia does not always render images in sufficient quality. This problem occurs sometimes, when magnolia has to scale images to new sizes.
The STK, in conjuction with Magnolia's imaging module, supports image variations configured via the themes. By default, the variation is implemented by the class
info.magnolia.module.templatingkit.imaging.generation.SimpleResizeVariation, configured via component configuration in the STK module.
The standard variation class (as the name implies) has a standard image operation chain which loads the image and resizes it using either the
info.magnolia.imaging.operations.cropresize.AutoCropAndResize image operation classes, depending on whether crop=true is set in the variation.
The BoundedResize or AutoCropAndResize classes in turn make use of a
info.magnolia.imaging.operations.cropresize.Resizer class which does the actual resizing. The STK fixes this resizer class to use the implementation
Explanation of the Problem
Basically, scaling images is not as simple as it seems. When scaling an image to a new size, usually smaller than the original, each pixel in new image is a combination of several pixels in the original image. How to sample and combine these pixels to make a new pixel is a hard problem to solve, and turns out to be a kind of filtering of the original image.
Done right, the sampling produces a smaller version of the original image that looks, to our eyes, exactly like the original. Done wrong the sampling can introduce artifacts, drop details and otherwise change the resulting output image so that we visually see differences between the images that make us say "this is a bad copy", or "something went wrong shrinking this image".
Shrinking images costs performance, and isn't that easy to do right. For this reason the JDK has provided methods for developers with which they can resize images.
Traditionally this was done using Image.getScaledInstance(), which works very well, produces great quality with its "area averaging" algorithm, but is very slow.
In JDK 1.2 Sun added the Graphics2D API with drawImage() methods to draw scaled versions of images. Due to the poor performance of getScaledInstance() Sun recommended that developers use these new APIs. Unfortunately, although drawImage() can work with several different algorithms, none of them come close to the quality achieved with getScaledInstance().
A proposed solution to this quality problem is what is currently in use in magnolia: the MultiStepResizer attempts to achieve better quality by using the drawImage() method repeatedly to produce scaled images via a series of intermediate scaled resolutions. While this is a big improvement in quality for many cases, it is not a perfect solution:
- firstly, the multi-step resizing is slow due to the multiple intermediate scaled resolutions it has to compute before arriving at its final answer
- secondly, it does not cover all cases - for example any image less than twice the size of the desired thumbnail will be scaled in only one step, resulting in the same quality as a single application of drawImage()
More information on all this can be found at:
Solution to all this: Use the cool imgscalr library to get good quality and good performance, for all images.
Some snippets to show how:
The following is a Resizer implementation which uses the imgscalr library:
The following is a replacement variation class which allows you to configure the resizer to be used, either by setting a default resizer via component configuration, or by configuring it in the variation definition:
The component configuration in your module XML could look like this:
To motivate all this, here a quick comparison of image quality. In this comparison the same source image was scaled to the same size with a variety of different methods.
Note how the first three images are pretty bad quality. Multistep works ok too in this case.
Image is (c) Richard Unger 2014, all rights reserved worldwide.