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 thatImage.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 2048×1536. Be aware – size this file is about 1.6MB.

Metalheads @ Wacken: Image at original size
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 (512×384). 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…

Metalheads @ Wacken: Thumbnail read from image is resized

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 @ Wacken: Thumbnail read from original photoLet’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 @ Wacken: Image is correctly resized

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

Liked this post? Empower your friends by sharing it!

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    50 thoughts on “Resizing images without loss of quality

    • April 2, 2009 at 9:19 pm
      Permalink

      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 3, 2009 at 2:10 am
      Permalink

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

    • April 14, 2009 at 1:29 pm
      Permalink

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

    • April 21, 2009 at 8:53 pm
      Permalink

      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.

    • June 30, 2009 at 11:39 am
      Permalink

      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!

    • July 3, 2009 at 8:29 am
      Permalink

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

    • August 4, 2009 at 10:13 pm
      Permalink

      Thanks for feedback, Nathanael!

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

    • September 11, 2009 at 12:56 pm
      Permalink

      22222222222 good thanks a ton

    • December 11, 2009 at 4:18 am
      Permalink

      I tried and running very well ….
      Thanks GUNNAR ….

    • December 23, 2009 at 9:33 am
      Permalink

      i have a photo that is uploading like ~/images/1.jpg. how can i send this photo to this void class? in the other hand , how can i use this class? how prepare inputs (Stream)?

    • January 4, 2010 at 5:07 am
      Permalink

      what are the namespace should be included for this method? i just convert it to the VB code. but it isshowing error on “Dim thumbnailBitmap = New Bitmap(newWidth, newHeight)”. what to do ?

    • January 6, 2010 at 12:26 am
      Permalink

      Great post! I want to know if you can post the source code (sorry if sounds like a crazy).

    • January 10, 2010 at 8:27 am
      Permalink

      Just what I was looking for… great post! Keep up the good work.

    • January 27, 2010 at 9:41 am
      Permalink

      Thanks man

      Great code

      have been searching for this since very long time

      but your blog has unique solution which was not present anywhere in the web.

      Thank you very much for such a great post

    • February 22, 2010 at 11:30 pm
      Permalink

      Thanks man!
      Helps me a lot!

    • May 30, 2010 at 7:45 pm
      Permalink

      This is really very nice. I really appreciate this post.

      How can I dynamically calculate the scaleFactor from the size of the original image?

      This is necessary because I want my thumbnails to have a max height/width, which this example does not give.

    • May 30, 2010 at 9:15 pm
      Permalink

      You can calculate it in caller method by example. The other option is to bring this calculation to resizing method. But I don’t think it is an good idea because calculating scale factor is not responsibility of resize image method.

    • May 31, 2010 at 6:46 am
      Permalink

      Thanks, I will give it a shot, I don’t want to calculate it within the resize method, my calling method will calculate and pass it to the resize method.

      My challenge however lies with the fomula to calculate the scale factor, given original image height, width and maximum width/height.

      eg. I want to create my thumbnails to have a maximum width/height of 100 irrespective of the different sizes of images my users may upload.

      I know this is not within the scope of this post, I need help on this and will really appreciate it.

    • May 31, 2010 at 7:01 am
      Permalink

      I’ve gotten my answer. To calculate the scale factor of an image, you divide the max width/height by the larger of the height and width. Example (VB.NET):

      Dim max As Integer = 100

      If (img.Width >= img.Height) Then
      scaleFactor = (100 / img.Width)
      Else
      scaleFactor = (100 / img.Height)
      End If

      newWidth = CInt(img.Width * scaleFactor)
      newHeight = CInt(img.Height * scaleFactor)

      I hope this is helpful to someone else out there

    • May 31, 2010 at 8:01 am
      Permalink

      wow, that example got a standing ovation!!!
      It gave me a square thumbnail, perfect for my project.

      Thanxxxx.

    • May 31, 2010 at 8:12 am
      Permalink

      Be aware that squared avatars are created by cropping image if it is not square.

    • September 26, 2010 at 4:36 pm
      Permalink

      very good thanks :))

    • September 30, 2010 at 2:12 pm
      Permalink

      Hey,

      I think your work is awesome, going by what i see as output and readers comments.

      I tried some other examples, and i am completely new to images part, i am just a DB guy.

      So can you help me in baby steps if you dont mind

      I have an image ~/images/dolphin.jpg (1024 x 800)

      I need to reduce this to 100 x 100

      How do i use what you have developed to do that.

      You help would be very useful.

      thanks a lot

      Deepesh

    • October 18, 2010 at 2:16 pm
      Permalink

      Excelent, after a long research, the exact thing I needed to present a small image when I have no photo to ilustrate my articles.

      Thank you

    • October 26, 2010 at 7:30 pm
      Permalink

      Have you checked out ImageSense for image resizing? It takes care of all the edge cases and you can easily convert formats (bmp to gif to jpg to png, etc) as part of your filter rules when doing a resize event. It also supports cropping, rotating, and color filters while preserving transparency.

    • October 27, 2010 at 12:39 pm
      Permalink

      Hi Michael! ImageSense is commercial solution but my solutions here are free :)

    • December 28, 2010 at 12:37 pm
      Permalink

      Really a very Good approach…

    • February 15, 2011 at 12:30 pm
      Permalink

      thanks,very helpful blog

    • April 3, 2011 at 10:44 pm
      Permalink

      Damn, thanks for the help, that was a simple solution that you explained clearly. Putting it to use now.

    • April 4, 2011 at 3:13 pm
      Permalink

      By the way… let me guess that in the picture you are the one who is wearing jean jacket !!!
      Thanks!

    • April 16, 2011 at 7:01 pm
      Permalink

      Tang Si Han, you won the prize! :)

    • June 18, 2011 at 7:40 am
      Permalink

      Isn’t there any easier method? Like isn’t there simple software that allows you to resize and not have resolution degradation? I am using an expensive service ShutterStock to buy my photos. I have been downloading them extra large thinking that when I “reduced” then they surely would not loose quailty. I did this size reduction in Microsoft Office Picture Manager and the result is unbelievably bad. What’s going on?

    • June 19, 2011 at 6:22 pm
      Permalink

      This is the method to use if you need image resizing functionality in your applications. Using command-line or COM-based external apps for this will be overkill in web context. In web systems with many users I am sure you don’t want to offer image resizing functionality to users the manual way :)

    • July 9, 2011 at 3:10 pm
      Permalink

      how to do it without fileupload control ? like i have the path of the file ( which is gonna be resize) so its not converting into stream but this function need stream how to resize in that case ?
      thanks

    • October 9, 2011 at 10:32 am
      Permalink

      Hi,
      it would be nice if you also show how to define quality of final picture (jpeg compression).

      Also you should use “using” or “try-finally>Dispose” approach instead of calling “Dispose” at the end of methods. It can cause memory leaks when more larger files are processed.

    • November 3, 2011 at 2:29 am
      Permalink

      You surely deserve a round of applause for your post and more particularly, your blog in common. Really top quality material

    • December 4, 2011 at 6:52 pm
      Permalink

      Awesome Work Done….

      Really Helped…

    • February 2, 2012 at 5:17 am
      Permalink

      Select * from Sys.Tables

      Select * from Sys.Procedures

      Select * from sys.functions

    • February 11, 2016 at 9:35 am
      Permalink

      This code was very use full but while using a image path which been already file upload and it’s in folder. while download only i need to resize in this at stream getting error

    • February 11, 2016 at 12:41 pm
      Permalink

      Seems like something is wrong with output stream. Can you show your code and exception you get?

    • February 15, 2016 at 7:07 am
      Permalink

      protected void btndwn_Click(object sender, EventArgs e)
      {
      string targetPath = Server.MapPath(“Images/”);

      //At this place getting error(
      Stream strm = targetPath.InputStream;
      )

      var targetFile = targetPath;

      GenerateThumbnails(0.5, strm, targetFile);
      }
      private void GenerateThumbnails(double scaleFactor, Stream sourcePath, string targetPath)
      {
      using (var image = Image.FromStream(sourcePath))
      {
      var newWidth = (int)(image.Width * scaleFactor);
      var newHeight = (int)(image.Height * scaleFactor);
      var thumbnailImg = new Bitmap(newWidth, newHeight);
      var thumbGraph = Graphics.FromImage(thumbnailImg);
      thumbGraph.CompositingQuality = CompositingQuality.HighQuality;
      thumbGraph.SmoothingMode = SmoothingMode.HighQuality;
      thumbGraph.InterpolationMode = InterpolationMode.HighQualityBicubic;
      var imageRectangle = new Rectangle(0, 0, newWidth, newHeight);
      thumbGraph.DrawImage(image, imageRectangle);
      thumbnailImg.Save(targetPath, image.RawFormat);
      }

    • February 15, 2016 at 9:40 am
      Permalink

      Exception is I’m not able get the Stream value while using path

    • February 15, 2016 at 10:43 am
      Permalink

      Stream fs = File.OpenRead(@”c:\testdocument.docx”);
      while using the path use like this it works.

    • April 20, 2018 at 11:02 pm
      Permalink

      Was using the GetThumbnailImage method for thumbnails on a website with poor results. This posting gave me exactly what I needed to decide how to improve it and get it done right.

    Leave a Reply

    Your email address will not be published. Required fields are marked *