What InterpolationMode and CompositingQuality to use when generating thumbnails via System.Drawing

For some reason I keep writing photo thumbnail generators lately. The last time was this week for an internal app building contest. One thing that I never seriously investigated before was how to optimize the quality of the generated thumbnails. So today I wrote a small benchmark that compares all combinations of InterpolationMode and CompositingQuality values and that measures the time each takes when generating small thumbnail versions of different images.

The benchmark project contains a few of my photos but the one where the differences are the  most obvious was the following:

Copenhagen

It is a contrasted image with sharp edges and a high potential for scaling artifacts. This is made clear by the thumbnail that gets rendered with the default settings:

CopenhagenDefault

There's plenty of artifacts here and pixels are very visible on edges. The scaling needs to be done with more subtlety. When comparing all combinations of mode and quality, it is very clear that CompositingQuality has very little effect if any on a thumbnail of this size. Even the differences between HighQuality and HighSpeed are not immediately obvious. The HighSpeed mode is not significantly faster. The documentation is not very explicit on what this is doing but I think it only really has an effect when composing different graphical elements on a same rendering surface, especially when transparency is involved, which is not the case here but could have an impact on my PhotoHandler folder thumbnails that combine different images.

The differences between InterpolationMode values, on the other hand, are pretty obvious. Here are the results for the main values:

CopenhagenNearestNeighbor CopenhagenBicubic CopenhagenBilinear
Nearest Neighbor
3.44 ms
Bicubic
6.41 ms
Bilinear
3.59 ms
CopenhagenHigh CopenhagenHighQualityBicubic CopenhagenHighQualityBilinear
High
10.78 ms
HQ Bicubic
10.62 ms
HQ Bilinear
12.50 ms

High Quality Bilinear is clearly too fuzzy: most of the details are gone. High and High Quality Bicubic are both of acceptable quality, the details are still there, no pixels are visible on the edges and there are no artifacts. Based only on quality, I'd choose High Quality Bicubic. Of course, it takes three times as long as Nearest Neighbor, which is the fastest but looks plain ugly.

Of course, you'd get a much better result by using Photoshop, but the point here is to have something fully automated. For the sake of comparison, here are thumbnails generated from Photoshop using the different available algorithms for image resizing:

CopenhagenNearest CopenhagenBicubic CopenhagenBilinear
Nearest neighbor Bicubic Bilinear
  CopenhagenBicubicSharper CopenhagenBicubicSmoother
  Bicubic sharper Bicubic smoother

The difference in quality is quite dramatic. The bicubic sharper version in particular looks very nice. I really wish we could have those great algorithms or something close to them packaged in a nice .NET assembly that scales in a server environment.

But wait, maybe that exists... If you heard of one, please comment here. Cheers!

UPDATE: Kjell-Åke Andersson suggested in the comments that I check out Paint.NET. So I did and I have to say I'm quite impressed by how far the project has gone since the last time I checked it out. It really is a nice package, much more accessible than Photoshop (although of course nowhere near as powerful and complete). Anyway, here's how the resizing went with Paint.NET with the different available options:

Paint.NET nearest neighbor Paint.NET bicubic Paint.NET bilinear Paint.NET best quality
Nearest neighbor Bicubic Bilinear Best quality

This is clearly not quite as nice as Photoshop's bicubic sharper (there are some remaining artifacts and it's not as sharp) and I actually think the automatic thumbnails in high quality bicubic look better. I'm not sure if Paint.NET rolls out its own algorithms here or uses System.Drawing but whatever they use is not on par with Photoshop and definitely plays in the same league as System.Drawing.

Download the benchmarking code here:
ScalingExperiment.zip

9 Comments

  • Have you checked if Paint.Net generates thumbnails with similar quality as Photoshop? If it does, then you you probably could get the algotrithm from there since the code for it is open source. Otherwise you probably could get it from Gimp.

  • Nice article. Definately clears some things. I'll use High(or photoshop) for my thumbnails.

  • "Another thing I want to test is how much jpeg compression levels affected my automatic thumbnails"

    For these sort of tests, you shouldn't be doing any kind of lossy compression. That will just give you too many variables.

  • My point exactly, Morten, although the differences between the compressed versions are still very visible. But there are only 24 hours a day and those will have to wait a bit.

  • Lionel, that is very good info. Thanks a lot.

  • Rick: thanks for the info! Cheers!

  • You might be interested in this image resizing module, then.

    It integrates with the pipeline, so you can just slap a query string onto any image URL to get it resized or converted:

    image.jpg?thumbnail=jpg&maxwidth=30

    It also permanently caches resized versions to disk... otherwise you run into serious scalability issues. With disk caching it's practical to use this on high-load production servers.

    Take a look:
    http://nathanaeljones.com/products/asp-net-image-resizer/

  • @Nathanael: well, yes, I also wrote this, which explains how to do the same thing:
    http://weblogs.asp.net/bleroy/archive/2008/06/20/generating-thumbnails-in-asp-net-dotnetslackers.aspx

  • Cool! I recently read the article, but hadn't realized you wrote it.

    I usually have my photos in the same directory with the .aspx file that contain them, so putting everything in a photos folder would be a severe disadvantage... I like relative paths :).

    MapPath completely ignores the security and access settings in the URL authorization portion of web.config. Since that's the easiest way to protect static files, it's nice to support it. Integrating as HttpHandler makes that compatibility automatic.

    I also use a *wide* variety of thumbnail sizes, so having them all the same wouldn't benefit me much. I often need several versions of the same file, so the caching system needs to be that flexible also.

    I also implemented automatic cache management to prevent denial of service attacks... you can read my comment at http://nathanaeljones.com/products/asp-net-image-resizer/

Comments have been disabled for this content.