views:

97

answers:

3

I've seen a lot of people try to code their own image conversion techniques. It often seems to be very complicated, and ends up using GDI+ function calls, and manipulating bits of the image. This has got me wondering if I am missing something in the simplicity of .NET's image conversion call when saving an image. Here's the code I have:

Bitmap tempBmp = new Bitmap("c:\temp\img.jpg");
Bitmap bmp = new Bitmap(tempBmp, 800, 600);
bmp.Save(c:\temp\img.bmp, //extension depends on format
    ImageFormat.Bmp) //These are all the ImageFormats I allow conversion to within the program.  Ignore the syntax for a second ;) 
    ImageFormat.Gif) //or 
    ImageFormat.Jpeg) //or
    ImageFormat.Png) //or
    ImageFormat.Tiff) //or
    ImageFormat.Wmf) //or
    ImageFormat.Bmp)//or
    );

This is all I'm doing in my image conversion. Just setting the location of where the image should be saved, and passing it an ImageFormat type. I've tested it the best I can, but I'm wondering if I am missing anything in this simple format conversion, or if this is sufficient?

A: 

I think by passing the imageformat .NET does the compression associated with the ImageFormat for you.

But when it comes to Graphic-Compression there can be much more than that (See the Photoshop or a Graphic-Programms Save-As Dialog as an example).

JPEG for example is just a Standard... and for alot of web-graphics you can still reduze the size by blurrying or taking away more colors without a noticable quality loss.

Will be up to you which techniques you're gonna use or if you're fine with a Standard.

Steav
A: 

What you are doing will work but is by far not the most efficient nor produces the most econonomical file sizes.

The reason you see complex GDI code when dealing with imaging is that there is no reasonable middle ground between using the default one-size-fits-all methods and even the most modest degree of fine tuning.

The .net<->gdi interop borders on black magic where obscure bugs abound. Luckily teh google has all you need to navigate this minefield.

(did i paint a dire enough picture? ;-))

Seriously though, you can do fairly well with gdi interop but it is by no means an obvious task. If you are willing to do the research and take the time to work out the kinks you can end up with some good code.

Otherwise find an imaging library that does most of this for you.

Sky Sanders
+3  A: 

System.Drawing.Imaging does give you additional control over the image compression if you pass in the JPEG codec and set the encoder parameter for Quality, which is essentially percent retention.

Here's a function I use with the parameter "image/jpeg" to get the JPEG codec. (This isn't related to compression per se, but the Image.Save overloads that accept EncoderParameters require ImageCodecInfo instead of ImageFormat.)

//  assumes an encoder for "image/jpeg" will be available.
public static ImageCodecInfo GetCodec( string mimeType )
{ 
    ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders(); 

    for( int i = 0;  i < encoders.Length;  i++ )
        if( encoders[i].MimeType == mimeType )
            return encoders[i];

    return null; 
}

Then you can set the encoder parameters before saving the image.

EncoderParameters ep = new EncoderParameters(2);
ep.Param[0] = new EncoderParameter( Encoder.Quality,    percentRetention ); // 1-100
ep.Param[1] = new EncoderParameter( Encoder.ColorDepth, colorDepth ); // e.g. 24L

(There are other encoder parameters — see the documentation.

So, put it all together, and you can say

image.Save( outFile, GetCodec("image/jpeg"), ep );

(I store the codec and parameters in static values, as they are used over and over again, but I wanted to simplify the example here.)

Hope this helps!

EDIT: If you are scaling images, you also have some control over the quality. Yes it is very "black box", but I find that it works well. Here are the "good & slow" settings (which you need to set before you call DrawImage, but you can look up the "quick & dirty" versions.

// good & slow
graphics.SmoothingMode      = SmoothingMode.HighQuality;
graphics.InterpolationMode  = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode    = PixelOffsetMode.HighQuality;
graphics.CompositingQuality = CompositingQuality.HighQuality;
harpo
+1 answer. Just wanted to point out that SmoothingMode does not affect image scaling, it affects draiwng primitives as lines, ellipses and such.
danbystrom