DIY optimize

How do I... Resize images using GDI+ while preserving their aspect ratio?


This blog post is also available as a TechRepublic download, which includes a sample Visual Studio project with all the code shown and examples on how to call the methods described.

There are many projects that require the automatic resizing of an image. A good example of this is a Web site such as Flickr that allows users to upload images. The user-supplied images are resized, and a thumbnail version of the image is generated. In this How do I... blog post, Zach Smith explains how to use C# and the .NET Framework to implement this resizing and manipulation functionality.

The .NET Framework makes it easy to modify an image via the System.Drawing namespace. Within this namespace, you will find many different sets of objects that provide the developer with almost any image manipulation functionality that would be needed. The objects in this namespace allow you to resize an image and save a copy to the hard disk.

Resizing an image

To resize an image, we will go through five basic steps using objects in the System.Drawing namespace:

  1. Create an Image object using the Image.FromFile method
  2. Create a Bitmap object using our Image object's data as the source
  3. Create a Graphics object that will allow us to manipulate the Bitmap
  4. Use the Graphics object to draw the image to the bitmap with a different width/height
  5. Use the Bitmap object to save the image to disk

This may seem like a lot to go through just to resize an image, but the code is actually very simple. The code shown in Listing A will resize an image to any given width/height and save it to the C drive.

Listing A

    private void ResizeImage(string fileName, string outputFileName,

int width, int height)

{

//Open the original image

Image original = Image.FromFile(fileName);

//Create a bitmap of the correct size.

Bitmap temp = new Bitmap(width, height, original.PixelFormat);

//Get a Graphics object from the bitmap.

Graphics newImage = Graphics.FromImage(temp);

//Set the quality of the output image.

newImage.SmoothingMode = SmoothingMode.Default;

newImage.InterpolationMode = InterpolationMode.Bicubic;

//Draw the image with the new width/height

newImage.DrawImage(original, 0, 0, width, height);

//Save the bitmap

temp.Save(@"c:\" + outputFileName);

//Dispose of our objects.

original.Dispose();

temp.Dispose();

newImage.Dispose();

}

This method accepts an input filename, the name of the file you want it to generate, a set width, and a set height. It will then write out a resized version of the original file to the output file you specified.

While the function above is certainly useful and performs its task quite well, it is lacking something. It doesn't have the ability to resize an image and maintain the image's original aspect ratio.

Keeping the correct aspect ratio

The key to keeping the correct aspect ratio while resizing an image is the algorithm used to calculate the ratio. An example of this is shown in Listing B.

Listing B

NewHeight = GivenWidth * (OriginalHeight / OriginalWidth)

This calculation assumes that the "GivenWidth" is the width the image should be resized to. Once we know this, we can multiply it by the original image's aspect, and that will give us the height we need. Below is another example of this -- assuming the original image has a width of 1000 and a height of 1600 and we want it to be resized to a width of 500:

  • First find the aspect: (1600 / 1000) = aspect of 1.6
  • Now multiply the aspect by the desired new width: 1.6 * 500
  • The result of that multiplication is 800, which is what our height should be
  • In other words: 800 = 500 * (1600 / 1000)
So the resulting image would have a height of 800 and a width of 500. Listing C shows how to implement this functionality in C#:

Listing C

    private void ResizeImageWithAspect(string fileName, string outputFileName,

int newWidth)

{

Image original = Image.FromFile(fileName);

//Find the aspect ratio between the height and width.

float aspect = (float)original.Height / (float)original.Width;

//Calculate the new height using the aspect ratio

// and the desired new width.

int newHeight = (int)(newWidth * aspect);

//Create a bitmap of the correct size.

Bitmap temp = new Bitmap(newWidth, newHeight, original.PixelFormat);

//Get a Graphics object from the bitmap.

Graphics newImage = Graphics.FromImage(temp);

//Draw the image with the new width/height

newImage.DrawImage(original, 0, 0, newWidth, newHeight);

//Save the bitmap

temp.Save(@"c:\" + outputFileName);

//Dispose of our objects.

original.Dispose();

temp.Dispose();

newImage.Dispose();

}

As you can see, this code is similar to the code in Listing A, with the main difference being that this method dynamically calculates what the new image's height should be based on the desired width and the original image's aspect ratio.

An example project for this technique is available in the download version of this document. It contains all the code shown and examples on how to call the methods described.

7 comments
adrian0605
adrian0605

Hi there, I have an image uploaded on the website, and I want to generate width and height automatically from a given values(original image values in cm, in decreasing). Ex: ' Image values in cm Dim strInal as string = 140 Dim strLati as string = 90 Dim strRatio As String Dim cnstInaltime As Integer Dim cnstLatime As Integer ' checking to see the image format If strInal.ToString > strLati.ToString Then strRatio = Math.Round(strInal / strLati) cnstInaltime = 15 cnstLatime = 10 * strRatio End If If strInal.ToString = strLati.ToString Then strRatio = 1 cnstInaltime = 5 cnstLatime = 5 End If If strLati.ToString > strInal.ToString Then strRatio = Math.Round(strLati / strInal) cnstInaltime = 10 * strRatio cnstLatime = 15 End If Dim intA As Integer = strInal Dim intB As Integer = strLati ' generating the values in decreasing way While (intA > 15 Or intB > 15) intA -= cnstInaltime intB -= cnstLatime End While The code above cannot keep aspect ratio. Any advice would be appreciated. Thanks

ernesto
ernesto

where can I find the sample visual studio download?

Justin James
Justin James

I would imagine that the algorithm is not too hard to put together, either! J.Ja

zs_box
zs_box

Yeah it's probably pretty simple. It's one of those ideas that makes you go "Why didn't I think of that??".