1

I am using the following code to compress an image and it does a nice job but I want to use the compressed image not save it. So right now I have to save the image then read it in again which is slow. Is there a way of compressing it with out saving it.

    private void compress(System.Drawing.Image img, long quality, ImageCodecInfo codec)
    {
        EncoderParameters parameters = new EncoderParameters(1);
        parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
        img.Save("check1.jpg", codec, parameters);
    }

    private static ImageCodecInfo GetCodecInfo(string mimeType)
    {
        foreach (ImageCodecInfo encoder in ImageCodecInfo.GetImageEncoders())
            if (encoder.MimeType == mimeType)
                return encoder;
        throw new ArgumentOutOfRangeException(
            string.Format("'{0}' not supported", mimeType));
    }
kgsw
  • 95
  • 1
  • 10

1 Answers1

4

There is an overload that takes a Stream so you can save it straight to a MemoryStream and won't need to save to disk/reload.

EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);

var ms = new MemoryStream();
img.Save(ms, codec, parameters);

//Do whatever you need to do with the image
//e.g.
img = Image.FromStream(ms);

The reason you're getting the "Parameter not valid" exception you mention in the comments is because the image isn't being disposed of before you try to call FromStream, so you'll need to dispose it. Also, I don't know how you're calling this method, but you should probably update it to return the MemoryStream.

private MemoryStream compress(System.Drawing.Image img, long quality, ImageCodecInfo codec)
{
    EncoderParameters parameters = new EncoderParameters(1);
    parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);

    var ms = new MemoryStream();
    img.Save(ms, codec, parameters);
    return ms;
}

public void MyMethod()
{
    MemoryStream ms;
    using(var img = Image.FromFile("myfilepath.img"))
    {
        ms = compress(img, /*quality*/, /*codec*/);
    }

    using(var compressedImage = Image.FromStream(ms))
    {
        //Use compressedImage
    }
}

Notice how I return ms from compress and capture it. Also, more importantly, how we wrap the initial img in a using statement which will dispose the file handle correctly, and after that gets disposed create the second compressedImage which is also in a using so it will also get disposed of properly when you're done.

J.C
  • 633
  • 1
  • 13
  • 27
Dave Zych
  • 21,581
  • 7
  • 51
  • 66
  • When it does the save I now get this: An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll Additional information: Parameter is not valid. – kgsw Oct 28 '15 at 15:03
  • If you look at the link I provided, this overload doesn't throw an `ArgumentException`, only `ArgumentNullException` and `ExternalException`. Are you sure you're receiving an `ArgumentException`? Are you sure it's on the `img.Save` line? – Dave Zych Oct 28 '15 at 15:43
  • It is the definitely the save line and this is copied from the screen \An unhandled exception of type 'System.ArgumentException' occurred in System.Drawing.dll Additional information: Parameter is not valid. – kgsw Oct 28 '15 at 16:38
  • Oh, it's because the original `img` isn't getting disposed. I updated my answer with a more complete example, including `using` statements for proper disposal. – Dave Zych Oct 28 '15 at 16:52