Gunnar Peipman's ASP.NET blog

ASP.NET, C#, SharePoint, SQL Server and general software development topics.

Sponsors

News

 
 
 
 
 
Programming Blogs - Blog Catalog Blog Directory
 
 
 

Links

Social

Resizing images without loss of quality

ASP.NET provides us with System.Drawing namespace where we can find classes we can use to manipulate with images. There are many people out there who mistakenly think that Image.GetThumbnailImage is best choice for image resizing. You can easily create crappy images if you follow the code examples in previously pointed article. In this post I will show you how to resize images without negative side effects.

Some words about images and thumbnails

Cameras today are powerful tools. They can do many tricks we cannot even imagine if we are dumb users. One those functionalities is generating thumbnails of images. These thumbnails are embedded in original image and are usually small by their dimensions.

If you take image with high resolution and resize it to 50% then using Image.GetThumbnailImage method may produce the result we expect. It takes small thumbnail image and resizes it larger. This causes hard loss of quality and resized image look awful.

Our original image here is taken during Wacken Open Air 2005. I am on this photo too (guess which one). Original image has dimensions 2048x1536. Be aware – size this file is about 1.6MB.

Original metalheads
Click on the image to see it in original size.  

This file contains thumbnail image and let’s see how previously pointed example fails.

Image.GetThumbnailImage

As a first thing let’s use Image.GetThumbnailImage to get new version of original image that is four times smaller (512x384). Here is the code.


public void ResizeImage(double scaleFactor, Stream fromStream, Stream toStream)

{

    var image = Image.FromStream(fromStream);

    var newWidth = (int)(image.Width * scaleFactor);

    var newHeight = (int)(image.Height * scaleFactor);

 

    var abort = new Image.GetThumbnailImageAbort(ThumbnailCallback);

    var thumbnail = image.GetThumbnailImage(newWidth, newHeight, abort, IntPtr.Zero);

    thumbnail.Save(toStream, image.RawFormat);

 

    thumbnail.Dispose();

    image.Dispose();

}

 

public bool ThumbnailCallback()

{

    return false;

}


And here is the result…

Messy metalheads

Awful, isn’t it? Now I tell you a little secret. It is directly copy-pasted from MSDN library:

If the Image contains an embedded thumbnail image, this method retrieves the embedded thumbnail and scales it to the requested size. If the Image does not contain an embedded thumbnail image, this method creates a thumbnail image by scaling the main image.

The GetThumbnailImage method works well when the requested thumbnail image has a size of about 120 x 120 pixels. If you request a large thumbnail image (for example, 300 x 300) from an Image 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 the DrawImage method.

I have on advice too: don’t trust everything you find in web, even if it has very high position in search engine results (Google: asp.net resize image).

Metalheads as thumbnailLet’s follow now MSDN Library suggestion and make thumbnail that is 7% of original image. To get image with this size you should use 0.07 as scaling factor.

Use GetThumbnailImage to create small thumbnails. It has less impact on your system and it wants less resources than resizing full size image down to thumbnail size.

Custom resizing

Now let’s see the code that makes clean resizing. This code doesn’t use GetThumbnailImage method and operates therefore on full size image. Also you can see that this code tries to save as much quality as possible.


public void ResizeImage(double scaleFactor, Stream fromStream, Stream toStream)

{

    var image = Image.FromStream(fromStream);

    var newWidth = (int)(image.Width * scaleFactor);

    var newHeight = (int)(image.Height * scaleFactor);

    var thumbnailBitmap = new Bitmap(newWidth, newHeight);

 

    var thumbnailGraph = Graphics.FromImage(thumbnailBitmap);

    thumbnailGraph.CompositingQuality = CompositingQuality.HighQuality;

    thumbnailGraph.SmoothingMode = SmoothingMode.HighQuality;

    thumbnailGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;

 

    var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);

    thumbnailGraph.DrawImage(image, imageRectangle);

 

    thumbnailBitmap.Save(toStream, image.RawFormat);

 

    thumbnailGraph.Dispose();

    thumbnailBitmap.Dispose();

    image.Dispose();

}


And the resulting picture is here.

Metalheads resized

This image is larger than thumbnail, but still looks nice.

kick it on DotNetKicks.com vote it on WebDevVote.com pimp it Progg it Shout it

Comments

DotNetKicks.com said:

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# April 2, 2009 5:57 AM

Resizing images without loss of quality - Gunnar Peipman's ASP.NET blog - DotNetBurner said:

DotNetBurner.com - news and articles about .net DotNetBurner

# April 2, 2009 5:58 AM

Justin Chase said:

You should also be able to do this quite easily (probably easier) with the BitmapSource class found in .NET 3.5. There is a TransformedBitmap that you can add a ScaleTransform to. There is no reason why this wouldn't work in asp.net as well as WPF.

# April 2, 2009 5:07 PM

DigiMortal said:

Thank you for your comment, Justin. :)

I will investigate BitmapSource class as soon as I find time for it. If it makes life easier then I will blog it about for sure.

# April 2, 2009 5:19 PM

Web Development Community said:

You are voted (great) - Trackback from Web Development Community

# April 2, 2009 9:44 PM

KiggFish said:

HI,Thank you for submitting this story - Trackback from KiggFish

# April 2, 2009 9:47 PM

pashakasim said:

Sorry for newbie question. How would you call this class to resize to thumbnail? Thank you.

# April 2, 2009 10:10 PM

flalar said:

Keep getting

System.ArgumentNullException: Value cannot be null. Parameter name: encoder

from the  thumbnailBitmap.Save(toStream, Image.RawFormat);  statement...  Any suggestions

# April 14, 2009 8:55 AM

DigiMortal said:

What kind of file you were resizing (bmp/gif/jpg)?

# April 14, 2009 9:29 AM

M said:

Can you show the toStream - I get a null exception and wonder how to pass this infomation back out and post it to the page for display.

# April 21, 2009 4:53 PM

DigiMortal said:

# April 21, 2009 5:10 PM

Cyp said:

everything seems nice, but draw image sometimes doesn't resize as it should and instead of having a width of 300 for instance, you might end up with a width of 295... drawimage has some major bugs!

# June 30, 2009 7:39 AM

DigiMortal said:

Thanks for feedback, Cyp. Can you provide us with original image size and format?

# July 3, 2009 4:29 AM

PimpThisBlog.com said:

Thank you for submitting this cool story - Trackback from PimpThisBlog.com

# July 3, 2009 4:48 AM

progg.ru said:

Thank you for submitting this cool story - Trackback from progg.ru

# July 3, 2009 5:02 AM

nathanaeljones said:

Thanks. I've been trying to educate people about that mistake for years...

I wrote an article on this and other image resizing mistakes a while back....

nathanaeljones.com/11191_20_Image_Resizing_Pitfalls

I discovered a lot of them during development of my commercial image resizing module.

nathanaeljones.com/.../asp-net-image-resizer

# August 4, 2009 5:18 PM

DigiMortal said:

Thanks for feedback, Nathanael!

I suggest also other readers take a look at links Nathanael provided here. First one is really *GOOD* reading. :)

# August 4, 2009 6:13 PM

Supratim said:

22222222222 good thanks a ton

# September 11, 2009 8:56 AM

Steve said:

Hey, there

This is pretty cool. As for Mac users, i wanna introduce a simple image resizing tool called <a href="www.mediasoftmac.com/.../>PhotoMagic </a>, which is useful for my resizing photos, pictures etc.  It is powerful and useful and can be used to resize photos to upload, attach to emails,make wallpaper etc.

# September 20, 2009 10:40 PM

Jason said:

Thank you! This is exactly what I needed.

# October 22, 2009 5:52 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)