-1

I use the following codes to compress an image file to jpg:

// _rawBitmap = a Bitmap object

ImageCodecInfo encoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;

ImageConverter imageConverter = new ImageConverter();
byte[] b = (byte[])imageConverter.ConvertTo(_rawBitmap, typeof(byte[]));

using (MemoryStream ms = new MemoryStream())
{
    ms.Write(b, 0, b.Length);
    ms.Seek(0, SeekOrigin.Begin);
    rawBitmap.Save(ms, encoder, myEncoderParameters);
    bmp = ToBitmap(ms.ToArray());
    return (Bitmap)bmp.Clone();
}

but when I try to compress a png file with same way but only change:

ImageCodecInfo encoder = GetEncoder(ImageFormat.Jpeg);

to

ImageCodecInfo encoder = GetEncoder(ImageFormat.Png);

my png file lost transparent data.

so how to compress a PNG file properly?

Oh My Dog
  • 781
  • 13
  • 32
  • Without a good [mcve] that reliably reproduces the problem, it's impractical to try to guess what all might be wrong in your scenario. The code you've posted above is woefully broken in several different ways, as described in the one answer posted below so far. But there's not enough information in your question for anyone to post a _good_ answer that is actually known to fix your problem. For all we know, you discarded the transparency information long before the code gets to this point, which would make it impossible for the saved PNG file to have any transparent pixels. – Peter Duniho Aug 16 '17 at 02:02

2 Answers2

1

There are a couple of problems here. First, you don't need to set those EncoderParams for quality for PNG.

Second, you don't need ImageConverter

Third, you are writing whatever ImageConverter produces to your memory stream, rewinding, and then writing the encoded PNG over the top of it-- it is likely that you have a PNG file with a bunch of garbage at the end of it as a result.

The simplified approach should be:

using (MemoryStream ms = new MemoryStream())
{
    rawBitmap.Save(ms, ImageFormat.Png);    
}

If you want to load your bitmap back, open it from the stream, but don't close the stream (the stream will be disposed when your returned Bitmap is disposed):

var ms = new MemoryStream();    
rawBitmap.Save(ms, ImageFormat.Png);    
ms.Seek(0, SeekOrigin.Begin);
return Bitmap.FromStream(ms);
Tim
  • 5,940
  • 1
  • 12
  • 18
  • one of my params is EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L); to compress image, if no need, how to compress my image? – Oh My Dog Aug 16 '17 at 01:55
  • 1
    @OhMyDog: the quality parameter applies only to JPEG compression. Not providing the parameter doesn't prevent compression from happening; even the JPEG encoder would still do _some_ compression without it. The PNG encoders available in .NET don't offer any control over the PNG encoding parameters (and PNG itself doesn't have a "quality" parameter, since PNG is always lossless). – Peter Duniho Aug 16 '17 at 02:00
  • @PeterDuniho thank you and forgive my ignorance. I've known nothing about images. – Oh My Dog Aug 16 '17 at 05:54
0

You can use nQuant (https://www.nuget.org/packages/nQuant/)

With it, you convert 32 bit PNGs to high quality 8 bit PNGs

    private static int alphaTransparency = 10;
private static int alphaFader = 70;
var quantizer = new WuQuantizer();
using(var bitmap = new Bitmap(sourcePath))
{

    using(var quantized = quantizer.QuantizeImage(bitmap, alphaTransparency, alphaFader))
    {
        quantized.Save(targetPath, ImageFormat.Png);
    }

}
Marc
  • 107
  • 8