1

I have been having a tough time creating a thumbnail that is not horrible quality. So far the best code i've come up with is:

Bitmap bmp = new Bitmap(width, height);
Graphics graphic = Graphics.FromImage(bmp);
graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphic.SmoothingMode = SmoothingMode.HighQuality;
graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphic.CompositingQuality = CompositingQuality.HighQuality;
graphic.DrawImage(photo, 0, 0, width, height);
return imageToByteArray(bmp);

Which produces this gem:

enter image description here

If I resize the same image in Paint.NET i get this:

enter image description here

Which is WAY better. Everything I've found on line points me to some variation of the code I have above. I know Paint.NET was open source at one point. Does anyone know what magic they were doing to create such nice resize functionality and if that functionality can be reproduced in C#?

UPDATE:

The original image from this example was a jpg

Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
  • Are you using a palette-based format? – Tim M. Sep 06 '12 at 04:20
  • I'm sorry but I don't know what that means. They are JPG, PNG or GIF typically – Abe Miessler Sep 06 '12 at 04:22
  • GIF has a limited palette...I think that's (at least part) of your problem. I'll post an answer. – Tim M. Sep 06 '12 at 04:23
  • Something like this never happened to me. Seems to be 256-color-bmp are you sure that this is the picture you return in this function or could it be that you saved it wrong ? – lorenz albert Sep 06 '12 at 04:24
  • @lorenze - That is entirely possible, I posted my code above, do you see something there that would cause this to happen? I should also mention that the poor quality image is actually pulled from a byte array that is stored in a database and then converted. The good quality one, is generated from the original image before it is uploaded to the DB. Not sure if that makes a difference. – Abe Miessler Sep 06 '12 at 04:27
  • take a look at imageresizing.net – Daniel Powell Sep 06 '12 at 04:30
  • Just saw the update that the original image was a JPEG. Try the code I posted if you can. It will struggle with GIFs but it should not pixelate a JPEG. – Tim M. Sep 06 '12 at 04:31
  • I think that it is not about the function you posted. Try this to be sure. Add the image by openeing it from your harddrive(the original one) then do this with your returned bitmap.`Clipboard.SetImage(bmp);` go into paint and paste. Then you can see if your function is the problem. – lorenz albert Sep 06 '12 at 04:32

2 Answers2

2

GIFs

I recalled reading that .NET has issues with palette-based formats, like GIF, so I dug up a few articles.

This article describes how to quantize (pick an optimum palette) to improve quality: http://msdn.microsoft.com/en-us/library/aa479306.aspx, as does this (badly formatted) article.

In brief, I believe GDI+ picks a non-optimum palette when performing the resize.

PNGs

PNGs are palette-based, so they may be prone to the same issues as GIFs. I'm not sure if it matters that the palette can be much larger.

JPEG-friendly example

This code should work fine on JPEGs (but does not render GIFs smoothly). If you try it and it pixelates a JPEG, then there is probably something else going on.

private static byte[] GetScaledImage( byte[] inputBytes, int width, int height ) {
    Image img = null;

    using( MemoryStream ms = new MemoryStream() ) {
        ms.Write( inputBytes, 0, inputBytes.Length );
        img = Image.FromStream( ms );
    }

    using( MemoryStream ms = new MemoryStream() ) {
        using( Image newImg = new Bitmap( width, height ) ) {
            using( Graphics g = Graphics.FromImage( newImg ) ) {
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage( img, 0, 0, width, height );

                newImg.Save( ms, img.RawFormat );
                return ms.GetBuffer();
            }
        }
    }
}
Tim M.
  • 53,671
  • 14
  • 120
  • 163
  • +1, Ok so I just tried this function and there is no noticeable quality loss, so apparently you are doing something here correctly that I was not. I'll have to dig in a bit and see if I can make sense of it. – Abe Miessler Sep 06 '12 at 04:32
  • Cool. I don't remember if I did anything special since it has been several years since I wrote it (maybe saving using the raw format?). If you care about GIF quality, you'll still have to optimize it further (not sure about PNGs). – Tim M. Sep 06 '12 at 04:34
0

since Bitmap(int,int) is effectively Bitmap(int,int,PixelFormat.Format32bppArgb) I think the problem is in source image. Try to create another intermediate copy of the image of the same size as source image if using palette, then use that 32bppArgb image source for your resize function.

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
aiodintsov
  • 2,545
  • 15
  • 17