+6  A: 

I cannot peek into the .NET source at the moment, but most likely the problem is in the Image.GetThumbnailImage method. Even MSDN says that "it works well when the requested thumbnail image has a size of about 120 x 120 pixels, but it 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". For true resizing (i.e. not thumbnailing), you should use the Graphics.DrawImage method. You may also need to play with the Graphics.InterpolationMode to get a better quality if needed.

Jan Zich
+2  A: 

As indicated on MSDN, GetThumbnailImage() is not designed to do arbitrary image scaling. Anything over 120x120 should be scaled manually. Try this instead:

using(var newImg = new Bitmap(origImg, newWidth, newHeight))
{
    newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
}

Edit

As a point of clarification, this overload of the Bitmap constructor calls Graphics.DrawImage, though you do not have any control over the interpolation.

Adam Robinson
A: 

For examples, the original image is JPG and the resized image is PNG. Are you converting between formats on purpose? Switching between different lossey compression schemes can cause quality loss.

James McMahon
I want to use the picture as wallpaper, and for that purpose I have to convert it to BMP because Win XP does not accept any other formats for wallpapers.
eWolf
+3  A: 

If you're not creating a thumbnail, using a method called GetThumbnailImage probably isn't a good idea...

For other options, have a look at this CodeProject article. In particular, it creates a new image, creates a Graphics for it and sets the interpolation mode to HighQualityBicubic and draws the original image onto the graphics. Worth a try, at least.

Jon Skeet
Downvoters: please give reasons...
Jon Skeet
they are just jealous of your epic knowledge jon ignore them
Neil Hickman
A: 

This is going to vary widely based on the following factors:

  1. How closely the destination resolution matches a "natural" scale of the original resolution
  2. The source image color depth
  3. The image type(s) - some are more lossy than others
GalacticCowboy
+6  A: 

Change the last two lines of your method to this:

var newImg = new Bitmap(newWidth, newHeight);
Graphics g = Graphics.FromImage(newImg);
g.DrawImage(origImg, new Rectangle(0,0,newWidth,newHeight));
newImg.Save(this.GetBitmapPath(filename), System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();
BFree
You need to set the quality settings also - they default to low.See http://nathanaeljones.com/163/20-image-resizing-pitfalls/
Computer Linguist
Cheers to both Bfree and Computer Linguist, now solved my issues...
Christopher Edwards
A: 

Are you increasing or decreasing the size of the image when you resize it? If you are creating a larger image from a smaller one, this sort of degradation is to be expected.

TwentyMiles
His two images seem to indicate that the original is larger.
Adam Robinson
A: 

Images will definitely be degraded if you enlarge them.

A: 

Some camera's put a resized thumbnail into the file itself presumably for preview purposes on the device itself.

The GetThumbnail method actually gets this Thumbnail image which is embedded within the image file instead of getting the higher res method.

The easy solution is to trick .Net into throwing away that thumbnail information before doing your resize or other operation. like so....

img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
//removes thumbnails from digital camera shots
img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);

If you are attempting to resize constraining proportions I wrote an extension method on System.Drawing.Image that you might find handy.

/// <summary>
/// 
/// </summary>
/// <param name="img"></param>
/// <param name="size">Size of the constraining proportion</param>
/// <param name="constrainOnWidth"></param>
/// <returns></returns>
public static System.Drawing.Image ResizeConstrainProportions(this System.Drawing.Image img,
    int size, bool constrainOnWidth, bool dontResizeIfSmaller)
{
    if (dontResizeIfSmaller && (img.Width < size))
        return img;
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX); 
    img.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipX);
    float ratio = 0;
    ratio = (float)img.Width / (float)img.Height;

    int height, width = 0;
    if (constrainOnWidth)
    {
        height = (int)(size / ratio);
        width = size;
    }
    else
    {
        width = (int)(size * ratio);
        height = size;
    }
    return img.GetThumbnailImage(width, height, null, (new System.IntPtr(0)));
}
Martin Murphy