Returning image created by Image.FromStream(Stream

2019-06-15 14:09发布

问题:

I have this function which returns an Image within the function the image is created using the Image.FromStream method According to MSDN:

You must keep the stream open for the lifetime of the Image

So I'm not closing the stream(if I do close the steam a GDI+ exception is thrown from the returned image object). My question is whether the stream will be closed/disposed when Image.Dispose() is called somewhere else on the returned Image

public static Image GetImage(byte[] buffer, int offset, int count)
{
    var memoryStream = new MemoryStream(buffer, offset, count);
    return Image.FromStream(memoryStream);
}

As suggested in one of the answers, using is not the way to go, since it throws an exception:

public static Image GetImage(byte[] buffer, int offset, int count)
{
    using(var memoryStream = new MemoryStream(buffer, offset, count))
    {
         return Image.FromStream(memoryStream);
    }
}

public static void Main()
{
   var image = GetImage(args);
   image.Save(path); <-- Throws exception
}
  1. According to some people explicitly disposing/closing a MemoryStream is not necessary as it doesn't use any unmanaged resources others say the opposite thing so its kind of a dilemma.
  2. Image.Dispose method doesn't dispose the stream ftom which the Image was created
  3. The Image class doesn't hold any reference to the Stream passed to Image.FromStream method so the stream will eventually be collected by the GC...? Hence the exception in Image.Save method
  4. Return a wrapper class which contains a reference to the stream and the Image created by it hence enabling us to dispose both of them...? or simply use the Tag property to keep a reference to the parent stream...?
  5. This problem only seems to happen when using the MemoryStream. If the image is created from ConnectStream nothing bad happens even if the parent stream is disposed.

回答1:

Despite what others advice to do, you should not close or dispose the stream until the image is disposed.

MSDN states:

You must keep the stream open for the lifetime of the Image.

For some streams, like MemoryStream, disposing doesn't have much use since it doesn't allocate unmanaged resources. File streams on the other hand do, so unless you are very sure the stream is safe, you should always dispose the stream when you are done with the image.



回答2:

Since you are only constructing an Image and then saving it consider this implementation instead:

  public static void GetAndSaveImage(byte[] buffer, int offset, int count,string path)
  {
      using(var memoryStream = new MemoryStream(buffer, offset, count))
      using(var img = Image.FromStream(memoryStream))
      {
          img.Save(path);
      }
  }


回答3:

Disposing the image will not affect the memorystream as the following example demonstrates :

static void Main(string[] args) {

        byte[] contents = File.ReadAllBytes(DESKTOP_PATH + "asample.tif");
        MemoryStream ms = new MemoryStream(contents);
        Image img = Image.FromStream(ms);
        img.Dispose();
        Image img2 = Image.FromStream(ms);
        Console.WriteLine(img2.PixelFormat);
        Console.ReadKey();


    }

This will output "Format32bppPargb". I suggest wrapping it into a using statement like so :

using (MemoryStream ms = new MemoryStream(contents){
            // code here
        }