| |
Adding image functionality to applications can greatly enrichen the user experience. Images, of course, come in all sorts of shapes and sizes, and this variance needs to be handled correctly in applications.
On the display of any device, screen real estate is limited, and it usually makes sense to confine an image to some pre-defined dimensions. The idea is, you want to display the image as large as possible within its container. However, to maintain the integrity of the image, the picture must of course be resized while maintaining the aspect ratio. Sounds simple? You would like to think so.
Unfortunately, this very useful resize functionality has been omitted in the Micrososft PictureBox control that ships with the .NET Vramework. It was also absent in the equivalent image controls that shipped with Visual Studio 6.0. Oddly enough, it is included in the image control that comes with Microsoft Access, with a resize mode called "Zoom." Depsite universal requests for its inclusion by developers, this feature remains awkwardly absent from today's imaging controls.
Instead of this simple resize mode, we instead get several similar, but wholly inadequate, options for manipulating our images. Examples include "Autosize," (enlarge the control to fit the image), "Stretch" (more appropriately named 'distort', which mangles you image in whatever way necessary to MAKE it fit the bounds of its containing control, and "Normal," which simply crops the image to the bottom and right as necessary.
Essentially, this results in ugly images, since most developers resort to some sort of "stretch" functionality. Case in point: Check out the little Dalmation, my DevHood image, that appears with this tutorial. No, he's not sick, and there's nothing wrong with the pup's body structure. Rather, he is subject to a SizeMode of "Stretch," ignoring the fact that this image isn't perfectly square. Not a good thing to have!
There is a solution. I have outlined one here for you. This code will look at a given image, look at where that image is being displayed, and then make it AS LARGE AS POSSIBLE to fit within its containing control. However, the aspect ratio will be maintained (that is, each dimension is multiplied by the same scaling factor), and the result is the image will not appear distorted.
Perhaps one day, we can have this functionality intrinsic to the imaging controls we use. For now, we can instead make do with code along the lines of that shown below. Feel free to use them in your own applications. They are self-contained, and the main code consists of two methods.
The first method is handleFitToWindow(bool). This references a PictureBox on the form (could be a passed in window handle). To be effective, there needs to be an image already loaded in the PictureBox control. Here is the code:
private void handleFitToWindow(bool doFit)
{
try
{
if (this.pboxMain.Tag != null)
{
if (doFit) /* We're fitting it to the window, and centering it. */
{
Image tempImage = (Image)this.pboxMain.Tag;
Size fitImageSize = this.getScaledImageDimensions(
tempImage.Width, tempImage.Height, this.pboxMain.Width, this.pboxMain.Height);
Bitmap imgOutput = new Bitmap(tempImage, fitImageSize.Width, fitImageSize.Height);
this.pboxMain.Image = null;
this.pboxMain.SizeMode = PictureBoxSizeMode.CenterImage;
this.pboxMain.Image = imgOutput;
}
else /* Restore the image to its original size */
{
this.pboxMain.Image = null;
this.pboxMain.SizeMode = PictureBoxSizeMode.Normal;
this.pboxMain.Image = (Image)this.pboxMain.Tag;
}
}
}
catch (System.Exception e)
{
Console.WriteLine(e);
}
}
|
The second method, getScaledImageDimensions(int, int, int, int), is called by the previous method shown above. It is responsible for determining the dimensions of the resized image. In all cases, the aspect ratio is mantained, since both dimensions get multiplied by the same scaling factor.
private Size getScaledImageDimensions(
int currentImageWidth,
int currentImageHeight,
int desiredImageWidth,
int desiredImageHeight)
{
double scaleImageMultiplier = 0;
if (currentImageHeight > currentImageWidth) /* Image is Portrait */
{
if (desiredImageHeight > desiredImageWidth)
{
scaleImageMultiplier = (double)desiredImageWidth / (double)currentImageWidth;
}
else
{
scaleImageMultiplier = (double)desiredImageHeight / (double)currentImageHeight;
}
}
else /* Image is Landscape */
{
if (desiredImageHeight > desiredImageWidth)
{
scaleImageMultiplier = (double)desiredImageWidth / (double)currentImageWidth;
}
else
{
scaleImageMultiplier = (double)desiredImageHeight / (double)currentImageHeight;
}
}
return new Size(
(int)(currentImageWidth * scaleImageMultiplier),
(int)(currentImageHeight * scaleImageMultiplier));
}
|
That's it! I've tried to be very thorough in commenting the code, so you should have some idea of what's going on. However, you don't really need to know how these work to make use of them.
As far as future work goes, using these methods, it would be straightforward to inherit from the existing PictureBox control and extend its functionality to include the ability to "Zoom" the image as described above.
Now, if we could only convince the DevHood guys to implement this code, so my poor dalmation pup would finally look normal!
Michael
|
|