Transferring properties to a thumbnail image
A while back, I created a simple console app for thumbnailing photos for posting on my family Web site. The application simply asks for a directory and a reduction percentage, then looks for any images in the directory provided and reduces them by the requested percentage.
This was fine as far as it went, but I realized after a colleague, Ryan Trudelle-Schwarz, requested copies of some of the photos I'd thumbnailed with this app, that I had neglected to correctly transfer the properties from the old image to the newly-created thumbnail. Given that digital cameras like mine (a Nikon CoolPix 4500) provide a lot of information in the properties, from photo info like focal length, exposure time, and ISO speed to important stuff like the date the photo was taken (as opposed to the date the file was last copied/altered), this is stuff you don't want to lose.
Since the app did mostly what I wanted, I didn't tackle the property transfer until recently. I was pleased to find that as with most stuff in .NET, it was pretty easy, once I stopped trying to fight the platform (I initially tried doing a For loop with a counter variable, but wasn't getting the PropertyItems populated that way). My initial successful code took advantage of a neat feature of arrays (the properties of an image are stored in an array called PropertyItems) called Enumerators. Enumerators, which implement the IEnumerator interface, allow you to easily traverse the members of an array or collection much the same way as you would a recordset or a DataReader. The code below gets an enumerator for the PropertyItems array of an instance of System.Drawing.Image that is created from the image being thumbnailed, and then calls the SetPropertyItem method of a new instance of System.Drawing.Bitmap that will contain the thumbnail version of the image:
Dim imgPropEnum As System.Collections.IEnumerator = _
img.PropertyItems.GetEnumerator
While imgPropEnum.MoveNext()
bmp.SetPropertyItem(imgPropEnum.Current)
End While
In a subsequent email, Ryan suggested the following code, which is a little cleaner, and perhaps more like what a VB programmer would expect to use:
Dim PropItm As PropertyItem
For Each PropItm In img.PropertyItems
bmp.SetPropertyItem(PropItm)
Next
Either will work, and both are examples of how simple tasks graphics-related tasks are in the .NET Framework. The trick, as I discovered, is to work with the framework, rather than against it.
As an aside, while I was playing with the code above, I also took a look at the GetThumbnailImage method of the Image class, but found that the method appears to both reduce the size of the image and compress it, such that the resulting image quality is fairly poor. In all fairness, the MSDN docs for the GetThumbnailImage method does warn that
GetThumbnailImage works well when the requested thumbnail image has a size of about 120 x 120. If you request a large thumbnail image (say 300 x 300) from an Image object that has an embedded thumbnail, there could be a noticeable loss of quality in the thumbnail image. It might be better to scale the main image (instead of scaling the embedded thumbnail) by calling DrawImage.
but I was hoping that the code for creating a decent thumbnail would've been as simple as a single method call, perhaps one overloaded to allow both compressed and non-compressed thumbnails. Not that it's all that difficult to scale an image in .NET, of course. I guess I've just gotten spoiled by how much the framework classes do for the developer that now I expect them to do everything. Perhaps in version 2.0.