Monday, April 20, 2009

System.Drawing... just not good enough!

Some 9 months ago, a client approached me with an idea for a desktop application. The basic premise was that you could browse the local machine, much like Windows explorer. Upon selecting a directory, all the images in the directory were to be thumbnailed an displayed in a form control. Simple, right? Wrong!

I accepted the project without researching or even prototyping the problem beforehand and landed in a Hell which haunts me to this day.

Before I continue, let me point out that I am a firm supporter of the .NET Framework. I am constantly amazed by the wonderful technologies Microsoft which has given developers to tinker, and ultimately produce solutions to business problems with. That being said, here comes the criticism...

I proceeded to Google "C# thumbnail generation" and found a plethora of articles dealing with the topic, regurgitating the same code in an array of different ways. The code snippet in question looks something like this...

...
Bitmap imgTmp = new Bitmap("C:\test.jpg");
Image imgFinal = imgTmp.GetThumbnailImage(width, height,
new Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
...

My first attempt at thumbnailing a large number of images using this method was dreadfully, dreadfully slow. I didn't lose hope though, and with the help of my braniac friend, implemented a solid multi-threading solution using the BackgroundWorker. The program was now generating a large number of thumbnails quite efficiently, so I hastily completed the program, handed it over to the client, and carried on with my life.

3 Weeks ago, I received a call from the client. He was attempting to use the program to generate thumbnails for images well above 5 meg. in size, and found that it would simply get slower, and slower, until eventually an OutOfMemoryException occurred.

I hastily opened up the latest production version of the program, downloaded some large-ish images to test with, and found to my horror that this was no fluke...

I ran the program with Windows Task Manager open, and monitored my resource usage - every time the program started generating a new thumbnail the memory usage would spike, in a very Mortal Kombat, pit of doom kind of way.

So, I returned to the drawing board (pardon the pun) and looked for alternate methods of performing the task and found that I am not alone in my plight. Many developers out there have been looking for alternate ways to generate large amounts of thumbnails, all struggling to get out of the muck that is the System.Drawing namespace.

After a lot (and I do mean A LOT) of searching, I stumbled upon a tutorial written by none other than Steve McMahon of vbAccelerator entitled, "Thumbnail Extraction Using The Shell".

Steve - the genius that he is - saw fit to supply us poor lost souls with a class to use for this very purpose... extracting thumbnails using the shell.

Now, I know what you're thinking - "No Van! Say no to unmanaged code!". If that's what you're thinking, and you're unable to offer a viable alternative, please keep it locked up.

I hastily employed his class, and found to my greatest satisfaction that it worked like a friggin' charm! My program now runs faster than an impala on crack, and resource usage is rock-bottom!

This brings me to my point. I understand that .NET puts several layers between the machine and the developer and there are many, many good reasons why this is acceptable. As I mentioned previously, the .NET Framework is amazing and I absolutely adore it, but using the System.Drawing namespace is simply not feasible when one is dealing with a large number of images.

I find it shocking that image handling - which Windows does so well - is so bastardized in the .NET Framework, that it's capabilities in this respect are rendered completely useless. In short, it's just not good enough.