Sunday, August 2, 2009

Scalling dynamic images for display in browsers

Recently I found myself looking into improving the image quality of dynamically created images in a web project that I've been working on. Some of the factors involved in the issues, and the eventual way they were addressed, are specific to the project. However, I wanted to share the way we addressed them in case others found themselves with a similar situation.

One of the pieces of functionality that the project incorporates is the ability for users to create customized displays and save them for later viewing. The displays are made up of background images, multiple foreground graphics, as well as, HTML elements. One of the requirements of the project is that the displays must be saved off as static images and be previewed at different sizes, a thumbnail and a display size.

The problem that we encountered was that we had no control over the screen resolution that the users would save their display using. During the save process we would consolidate all of the elements into a single image using the dimensions from the user's browser. This was required to make sure that all of the elements lined up properly. After the single image was created it was saved and the thumbnail image was created using the Java2D API.

Users of the application primarily use IE6 & 7. We started noticing that when the displays were captured at the full-size preview resolution everything looked good, but if a higher resolution was used for creating the displays the images when shown at the full-size preview dimensions would look distorted. In addition, we noticed that regardless of the screen resolution used for saving the displays, the thumbnail images appeared jagged.

The first problem we were able to address was the thumbnail image quality. After reading Chris Campbell's excellent Java.net article "The Perils of Image.getScaledInstance()" we realized that we were using the default interpolation method of Nearest Neighbor which while fast was producing images of quality less than what we desired. Changing the interpolation method to Bilinear increased the image quality and solved the thumbnail image issue.

An interesting thing we noticed was that in Firefox the saved images appeared a lot clearer than when rendered in IE. As it turns out after a few Google searches apparently Firefox (and the majority of other browsers) use bicubic interpolation for image resizing by default, but IE defaults to nearest-neighbor. Bicubic interpolation produces better results than nearest neighbor, but takes longer to render.

Microsoft added a vendor specific CSS property "-ms-interpolation-mode" that can be used to specify which interpolation method is used as described in this MSDN Library entry. The CSS example below sets the interpolation method to bicubic for smoother image scaling.
img {
-ms-interpolation-mode:bicubic;
}

Unfortunately, the ms-interpolation-mode property was introduced in IE 7 and our project is still required to support IE 6. As a result, in addition to adding the CSS property we now create a scaled image on the server using bicubic interpolation in the dimensions appropriate for the preview. If the user is viewing the application with IE7, we let IE handle the interpolation but when IE6 is used the pre-scaled image is sent to the browser.

In the end we were able to achieve better image quality for the displayed images through the combination of specifying rendering hints to the Java2D API and the IE specific CSS property. When support for IE 6 is no longer a requirement, we will be able to remove the generation of the pre-scaled display image on the server which will increase performance.

No comments: