views:

1021

answers:

8

Hello. I'm resizing jpegs by using the Graphics.DrawImage method (see code fragment below). Can anyone confirm that this will not affect the compression of the new image? I have seen this thread, but I am talking specifically about compression of jpegs.

    private byte[] getResizedImage(String url, int newWidth)
    {
        Bitmap bmpOut = null;
        System.IO.MemoryStream outStream = new System.IO.MemoryStream();

        //input image is disposable
        using (Bitmap inputImage = LoadImageFromURL(url))
        {
            ImageFormat format = inputImage.RawFormat;
            decimal ratio;  //ratio old width:new width
            int newHeight = 0;

            //*** If the image is smaller than a thumbnail just return it
            if (inputImage.Width < newWidth)
                return null;

            ratio = (decimal)newWidth / inputImage.Width;
            decimal h = inputImage.Height * ratio;
            newHeight = (int)h;

            bmpOut = new Bitmap(newWidth, newHeight);
            Graphics g = Graphics.FromImage(bmpOut);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
            // try testing with following options:
            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            //g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            //g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

            g.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);
            g.DrawImage(inputImage, 0, 0, newWidth, newHeight);
            bmpOut.Save(outStream, getImageFormat(url));
        }

        return outStream.ToArray();

    }
+5  A: 

JPEGs have no "compression" value saved within them. When you resize and save them, they are compressed with whatever value you tell your save function to use. As you are not passing a value, it will just use whatever default for the library is.

MrZebra
Of course - I was blinded by the Graphics object, and managed to ignore the rather crutial Bitmap.Save! Thanks.
darasd
A: 

In your code "HighQualityBicubic" is the compression you are using. Resizing to a smaller size does remove detail, but that has nothing to do with compression, it just has to do with fewer pixels.

Diodeus
+3  A: 

When you call "bmpOut.Save" you have to pass in some EncoderParameters to tell the method what quality level you would like to save it with.

http://msdn.microsoft.com/en-us/library/system.drawing.imaging.encoderparameters(VS.80).aspx

Jon Tackabury
A: 

JPEG compression is lossy -- not all of the original data is actually stored exactly. If you compress an image as a JPEG and decompress it, you won't get back the exact original image. Every time you compress and decompress, you lose a bit of quality.

For some simple transformations, such as rotating a JPEG, you can do it losslessly with programs such as jpegtran.

However, for resizing images, you can't do it losslessly. You're definitely going to degrade the quality somewhat when you do this, although probably not by very much. If possible, try to use original lossless images as the source for the resize operation to get the highest possible quality, and if you concatenate multiple resize operations, instead just do a single resize from the original.

Adam Rosenfield
A: 

Do not confuse the storage format (JPEG) with the format you operate on using the Graphics object. The storage format is compressed, the Graphics object works with decompressed data.

The LoadImageFromURL method decompresses the information stored in the JPEG, you perform your resize operation on the decompressed data, and when you save it to a JPEG file, it gets compressed again.

Since JPEG compression is not lossless, the picture quality will be reduced every time you perform this process: Decompress, mutate, recompress.

If I missunderstood your question: The compression factor you use for saving the image inot set in your code, so it will be at some default value. If you want to reduce quality loss by saving with a small compression factor, you need to explicitly set it.

Treb
A: 

Thanks to MrZebra who gave me a nudge in the right direction. This article demonstrates quite nicely what to do.

darasd
A: 

Same as what you already found, but here is the VB.NET version from Circumventing GDI+ default image compression.

I personally recommend JPEG quality setting of 90L.

mangokun
+3  A: 
Ates Goral