Image.FromStream : "Cannot access a closed Stream" exception

 

The problem with underlying managed APIs is that you never really know how they behave. Documentation is the key of using this kind of API accurately. Unfortunately, writing documentation is very tedious, and implementation details are so easy to forget…

This is what happens with Image.FromStream. Yesterday, I was talking about the ‘move to stream start’ issue, and today I’ll take about the issue described in the KB814675 article.

As you can read, Gdi+ can access Image raw data at any time. Thus data must be available at any time. If this raw data is a file, this file remains locked, if this data is an in memory stream, you must not dispose for the image lifetime. If you’re a modern style coder, you’re used to the using statement, keeping in mind: ‘close your resource as soon as possible’. Not compatible with this Gdi+ Image class design… You have to manage your memory stream lifetime with your image.

There are to main solutions to the problem. The first one is to create a class that can manage both Image and stream lifetime :

using System;

using System.Drawing;

using System.IO;

public class StreamedImage : IDisposable

{

privateImage image;

private Stream stream;

 

public StreamedImage(Stream stream, bool useEmbeddedColorManagement)

{

this.stream = stream;

this.image = System.Drawing.Image.FromStream(stream, useEmbeddedColorManagement);

}

 

public StreamedImage(Stream stream) : this(stream, false)

{}

 

public Image Image

{

get { return image; }

}

 

public Stream Stream

{

get { return stream; }

}

 

public void Dispose()

{

if (image != null)

{

image.Dispose();

image = null;

}

if (stream != null)

{

stream.Close();

stream = null;

}

}

}

You have now a simple way to manage your stream lifetime. But since you must keep you stream open, with all its data in memory, it would be better to get rid of it.

The second solution is quite direct, I just wrote it in the case of a Bitmap :

public Bitmap LoadBitmap(Stream stream, bool useEmbeddedColorManagement)

{

using (Image image = Image.FromStream(stream, useEmbeddedColorManagement))

return new Bitmap(image); // (1)

}

 

public void FunctionUsingTheImage()

{

Bitmap bitmap;

using (Stream stream = CreateStream())

bitmap = LoadBitmap(stream, true);

// now you can use the image

// without keeping the stream open

// ...

bitmap.Dispose();

}

This solution works because the line one performs a copy of the image. There is no underlying raw data anymore for this bitmap and the stream can be freed. There’s still a problem though, the bitmap constructor make only a copy of the image pixels, and not other data is copied, especially EXIF properties of JPEG files !

 

I’m sure Buz will be pleased to tell you more about EXIF in Gdi+ soon. This is once again a really tricky story since Gdi+ EXIF support is really light.

Skup

posted on Wednesday, March 09, 2005 8:00 PM

Feedback

# Streams and Bitmaps in .Net 6/19/2005 3:30 AM Mark M Mullin's Professional Blog

Title
 
Name
 
Url
Comments   
Protected by Clearscreen.SharpHIPEnter the code you see: