Delay's Blog is the blog of David Anson, a Microsoft developer who works with C#, XAML, HTML, and Azure.
I've been doing some work with Windows Presentation Foundation lately and came across a scenario where an application needed to load a user-specified image and display it at a fairly small size for the entire life of the application. Now, WPF makes working with images easy and I could have simply used the Image class's automatic image scaling and moved on. But it seemed wasteful for the application to keep the entire (arbitrarily large!) image in memory forever when it was only ever going to be displayed at a significantly reduced size...
What I really wanted was a way to shrink the source image down to the intended display size so the application wouldn't consume a lot of memory storing pixels that would never be seen. The WPF documentation notes that the most efficient way to load an image at reduced size is to set Image's DecodePixelWidth/DecodePixelHeight properties prior to loading it so WPF can decode the original image to the desired dimensions as part of the load process. However, the comments in one of the overview's samples explain why this isn't suitable for the aforementioned scenario:
// To save significant application memory, set the DecodePixelWidth or// DecodePixelHeight of the BitmapImage value of the image source to the desired// height or width of the rendered image. If you don't do this, the application will// cache the image as though it were rendered as its normal size rather then just// the size that is displayed.// Note: In order to preserve aspect ratio, set DecodePixelWidth or// DecodePixelHeight but not both.
Basically, the problem with this approach occurs when an application doesn't know the aspect ratio of the image before loading it: the application doesn't know whether to set DecodePixelWidth or DecodePixelHeight to constrain the larger dimension. If the application picks the right one (width vs. height), then the image will be properly resized to fit within the bounds of the application - but if it picks the wrong one, then the image will be resized some but will still be unnecessarily large (though less unnecessarily large than before!). While the application could arbitrarily pick one dimension to constrain, load the image, check if it guessed correctly, and reload the image with the other constraint when necessary, I was looking for something a little more deterministic. After all, sometimes you get only one chance to load an image - or someone else loads it for you - or the cost of loading it a second time is prohibitive, so it's nice to have a way to dynamically resize an already-loaded image.
After a search of the documentation didn't turn up anything promising, I wrote a small helper function using the handy RenderTargetBitmap class to generate a new, properly sized image based on the original. The code for that method ended up being fairly simple:
[Note: If you want to see this code in action, you can download the complete source code for a sample application (including Visual Studio 2008 solution/project files) that's attached to this post (click the WpfResizeImageSample.zip link below).]
Basically, the CreateResizedImage method works by creating a new image of exactly the size specified and then drawing the original image onto the new, blank "canvas". WPF automatically scales the original image during the drawing operation, so the resulting image ends up being exactly the right (smaller) size. All that remains is for the calling application to do a bit of math on the original image's dimensions to determine how to scale it, pass that information along to CreateResizedImage to get back a properly sized image, and then discard the large original image. It's that easy.
WPF and XAML make it easy to author compelling user interfaces. But sometimes it's worth a little extra effort to optimize some aspect of the user experience. So if you're looking to trim the fat from some of your in-memory images, consider something like CreateResizedImage to help you out!
Since last week's release of the 11119 version of the AJAX Control Toolkit, some people have reported problems using the .NET 3.5 flavor of the Toolkit with the Visual Studio 2008 web designer. Our team has just updated the 3.5 ZIPs (AjaxControlToolkit-Framework3.5.zip and AjaxControlToolkit-Framework3.5-NoSource.zip) available from the 11119 release page to address the issue. Whereas the old assembly had version number 3.5.11119.*, the new assembly has version number 3.0.11119.*. This is the only change to the Toolkit and only the 3.5 version has been updated.
If you have already downloaded the 3.5 flavor of the Toolkit, please remove the Toolkit from your Toolbox (if present), download the new 3.5 ZIPs, extract the new files over top of the existing ones, and designer support should work as expected. We apologize for any inconvenience this may have caused.
A short while ago we published the 11119 release of the AJAX Control Toolkit to coincide with today's release of .NET 3.5 and Visual Studio 2008! As usual, we have published "source" and "no-source" versions for .NET 2.0/Visual Studio 2005 and .NET 3.5/Visual Studio 2008.
The content of the 11119 release is largely the same as our previous 10920 release, with most changes being minor tweaks to the .NET 3.5 flavor of the Toolkit:
As always, it's easy to sample any of the controls (no install required). You can also browse the project web site, download the latest Toolkit, and start creating your own controls and/or contributing to the project!
If you have any feedback, please share it with us on the support forum!