Bmp to jpg/png in C#
Asked Answered
K

7

58

Is there any way to convert a bmp image to jpg/png without losing the quality in C#? Using Image class we can convert bmp to jpg but the quality of output image is very poor. Can we gain the quality level as good as an image converted to jpg using photoshop with highest quality?

Kamasutra answered 3/9, 2008 at 13:29 Comment(0)
D
58
var qualityEncoder = Encoder.Quality;
var quality = (long)<desired quality>;
var ratio = new EncoderParameter(qualityEncoder, quality );
var codecParams = new EncoderParameters(1);
codecParams.Param[0] = ratio;
var jpegCodecInfo = <one of the codec infos from ImageCodecInfo.GetImageEncoders() with mime type = "image/jpeg">;
bmp.Save(fileName, jpegCodecInfo, codecParams); // Save to JPG
Darbie answered 3/9, 2008 at 13:39 Comment(2)
Should there not be some using statements here? I notice that EncoderParameter is IDisposable, but I'm not master enough of the disposable pattern to say for certain that they are needed.Astronavigation
Yes, there should be some using statements. That code above is an example of what can be done, not what should be used.Catchfly
C
43
public static class BitmapExtensions
{
    public static void SaveJPG100(this Bitmap bmp, string filename)
    {            
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
        bmp.Save(filename, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static void SaveJPG100(this Bitmap bmp, Stream stream)
    {
        EncoderParameters encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
        bmp.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static ImageCodecInfo GetEncoder(ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();

        foreach (ImageCodecInfo codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                return codec;
            }
        }

        return null;
    }
}
Comehither answered 9/3, 2010 at 20:37 Comment(2)
Equivalent expression for GetEncoder in one line: return ImageCodecInfo.GetImageDecoders().Where(x => x.FormatID == format.Guid).FirstOrDefault();Strategist
Or even shorter return ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == ImageFormat.Jpeg.Guid);.Cameron
R
16

Provided BitmapExtensions by jestro are great, I used them. However would like to show the corrected version - works for Image parent class which is more convenient as I think and provides a way to supply quality:

public static class ImageExtensions
{
    public static void SaveJpeg(this Image img, string filePath, long quality)
    {
        var encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
        img.Save(filePath, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    public static void SaveJpeg(this Image img, Stream stream, long quality)
    {
        var encoderParameters = new EncoderParameters(1);
        encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
        img.Save(stream, GetEncoder(ImageFormat.Jpeg), encoderParameters);
    }

    static ImageCodecInfo GetEncoder(ImageFormat format)
    {
        ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
        return codecs.Single(codec => codec.FormatID == format.Guid);
    }
}
Rafaelof answered 2/1, 2012 at 17:34 Comment(1)
Is the ImageCodecInfo supposed to change anyhow? I store the GetEncoder result in a dedicated variable: private ImageCodecInfo _jpg = null; private ImageCodecInfo jpg => _jpg ?? (_jpg = GetEncoder(ImageFormat.Jpeg)); Thanks anyway for your code!Orsa
B
1

Fundamentally you won't be able to keep the same quality because jpg is (so far as I'm aware) always lossy even with the highest possible quality settings.

If bit-accurate quality is really important, consider using png, which has some modes which are lossless.

Boule answered 3/9, 2008 at 13:36 Comment(0)
H
1

Just want to say that JPEG is by nature a lossy format. So in thoery even at the highest settings you are going to have some information loss, but it depends a lot on the image.But png is lossless.

Hyperventilation answered 4/9, 2008 at 6:52 Comment(0)
B
0

You can try:

Bitmap.InterpolationMode = InterpolationMode.HighQualityBicubic;

and

Bitmap.CompositingQuality = CompositingQuality.HighQuality;

Which does keep the quality fairly high, but not the highest possible.

Brazilin answered 3/9, 2008 at 13:33 Comment(1)
Bitmap doesn't have such properties. They must be applied to Graphics and during the image modifications such as resizing.Rafaelof
R
0

I am working on an expense report app, and I am really pleased with the default quality settings for JPG (and PNG) when saving from a Bitmap object.

https://msdn.microsoft.com/en-us/library/9t4syfhh%28v=vs.110%29.aspx

Bitmap finalBitmap = ....; //from disk or whatever
finalBitmap.Save(xpsFileName + ".final.jpg", ImageFormat.Jpeg);
finalBitmap.Save(xpsFileName + ".final.png", ImageFormat.Png);

I'm on .NET 4.6...perhaps the quality has improved in subsequent framework releases.

Rotten answered 23/8, 2015 at 11:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.