State of .NET Image Resizing: how does imageresizer do?
I've written several times before about image resizing in .NET and how the various built-in solutions (GDI, WPF and WIC) compare in terms of quality, speed and size. I'll put the links to my previous articles at the end of this post for reference.
Several readers have since pointed me to the imageresizer library, which is pure .NET and thus has no problems running in medium trust. Medium trust is an issue that has plagued existing options, preventing many people from using the best available approach. I was doubtful though that a purely managed library could come anywhere near the native Windows libraries in terms of performance. The best way to find out, of course, is to run a benchmark. Fortunately, I still had the code for my previous benchmarks so I just had to add imageresizer code to it.
I excluded IO from this test by measuring the processing time for each library working on binary streams. This also levels the playing field as some of them start processing while they are reading a file, making it harder to separate file reading overhead from image processing. By working with streams, the comparison is more meaningful. The timing code is wrapped around only the meaningful code.
The first problem that I hit with imageresizer is that it has a strong dependency on System.Web. This is really unfortunate and very probably unjustified. The library should be split between the pure image processing bits, which should have no System.Web dependency, and the request handling and caching bits, which can depend on System.Web all they want.
Since I'm mostly interested in web applications, I changed my command-line code into an ASP.NET Pages application, which probably saved me some configuration headache. The code is linked to at the end of this post. One thing I have to say is that the API feels good, natural and reasonably concise, a nice change when compared with the noisy Interop-like code we had to write before. It's nice to have something that is native .NET rather than a thin layer on top of Windows APIs that stink of C.
var settings = new ResizeSettings { MaxWidth = thumbnailSize, MaxHeight = thumbnailSize, Format = "jpg" }; settings.Add("quality", quality.ToString()); ImageBuilder.Current.Build(inStream, outStream, settings); resized = outStream.ToArray();
I really liked that I don't have to do size calculations myself, and I can just give it a square or rectangle inside of which it has to fit. You have many options to customize that. It's unfortunate that the quality setting has to be set this way instead of being promoted to a 1st class property like other settings but I can live with it. Notice how the library can work with streams, which is very important for web apps. One thing I really didn't like though was that some APIs, such as Build, take untyped object parameters and then decide internally at runtime what to do with them. Why the author didn't use strongly-typed overloads here is a mystery to me.
So how does imageresizer do then? Well, mostly as expected. In terms of size, I found it to be a little greedier than its peers, but really nothing dramatic:
The quality of the images is where imageresizer shines. See for yourself (quality 85% for those images):
imageresizer |
WIC |
The images look sharper (in particular the hummingbird one), and a little bit more saturated. Because of that, some moiré effects seem more visible (the shot before last makes that the most obvious. Still, the resizing is overall the best I've seen so far.
Now of course, while managed code is usually quite fast, image processing is heavy in the sort of operation where native code has a definitive advantage. That is reflected in the results I got in terms of processing speed:
Imageresizer is clearly the slowest. That was expected, but now we know by how much. It is 31% slower than GDI (I excluded the 50 quality point here), and almost 4 times slower than WIC.
Of course, unless your application is doing lots and lots of resizing operations, speed may not be that important, in particular if you are doing appropriate disk caching. Imageresizer shines in that department by making disk caching super-easy. The library, after all, is very web centric and tries hard to do everything right for the web scenarios. We should not underestimate how hard it is to get web image resizing right.
That leaves us with the unfortunate conclusion that we still don't have an image resizing silver bullet. I'll try to summarize all that we know in a table that will hopefully help you make a decision in the context of your specific application:
Imageresizer | WIC | WPF | GDI | |
Speed | * | **** | **** | ** |
Quality | ***** | **** | **** | *** |
Medium trust | Yes | No | No | Yes |
Supported | By author | By MS | No | No |
.NET friendly | **** | * | **** | *** |
Web centric | Yes | No | No | No |
Benchmark code:
http://weblogs.asp.net/blogs/bleroy/ImageResizeBenchmark.zip
Results:
http://weblogs.asp.net/blogs/bleroy/ImageResizerBenchResults.zip
Previous articles:
- The fastest way to resize images from ASP.NET. And it’s (more) supported-ish
- Server-side resizing with WPF: now with JPG
- Resizing images from the server using WPF/WIC instead of GDI+
- What InterpolationMode and CompositingQuality to use when generating thumbnails via System.Drawing
- Generating image thumbnails in ASP.NET
The imageresizer library:
http://imageresizing.net/