views:

3415

answers:

3

Hi folks,

i've got some binary data which i want to save as an image. When i try to save the image, it throws an exception if the memory stream used to create the image, was closed before the save. The reason i do this is because i'm dynamically creating images and as such .. i need to use a memory stream.

this is the code:

[TestMethod]
public void TestMethod1()
{
    // Grab the binary data.
    byte[] data = File.ReadAllBytes("Chick.jpg");

    // Read in the data but do not close, before using the stream.
    Stream originalBinaryDataStream = new MemoryStream(data);
    Bitmap image = new Bitmap(originalBinaryDataStream);
    image.Save(@"c:\test.jpg");
    originalBinaryDataStream.Dispose();

    // Now lets use a nice dispose, etc...
    Bitmap2 image2;
    using (Stream originalBinaryDataStream2 = new MemoryStream(data))
    {
        image2 = new Bitmap(originalBinaryDataStream2);
    }

    image2.Save(@"C:\temp\pewpew.jpg"); // This throws the GDI+ exception.
}

Does anyone have any suggestions to how i could save an image with the stream closed? I cannot rely on the developers to remember to close the stream after the image is saved. In fact, the developer would have NO IDEA that the image was generated using a memory stream (because it happens in some other code, elsewhere).

I'm really confused :(

+9  A: 

As it's a MemoryStream, you really don't need to close the stream - nothing bad will happen if you don't, although obviously it's good practice to dispose anything that's disposable anyway. (See this question for more on this.)

However, you should be disposing the Bitmap - and that will close the stream for you. Basically once you give the Bitmap constructor a stream, it "owns" the stream and you shouldn't close it. As the docs for that constructor say:

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

I can't find any docs promising to close the stream when you dispose the bitmap, but you should be able to verify that fairly easily.

Jon Skeet
awesome! that's a great reply Jon. Makes perfect sence (and I missed the bit about the stream in the docs).Two Thumbs Up!I'll report back when i've given it a go :)
Pure.Krome
It doesn't appear to close the stream. This test fails:` [Test]`` public void ShouldCloseMemoryStreamAfterDisposingImage()`` {`` var stream = new MemoryStream(File.ReadAllBytes("bitmap.bmp"));`` var image = Image.FromStream(stream);`` `` image.Dispose();`` `` Assert.IsFalse(stream.CanRead);`` }`
Brian
@Brian: That's very strange. I seem to remember that Image has some special casing around memory streams though - I could be wrong, but that could explain it.
Jon Skeet
A: 

What Jon means is that after :

using(Stream.....){
}// here the stream is closed so when you try to save - you get an exception

Also it would be useful if you wouldn't put the code in an image and rather copy paste it here.

EDIT: I guess I didn't really understand what Jon was saying after all :). - was kinda close I think.

sirrocco
No, what I mean is that you shouldn't close the stream explicitly yourself at all if it's being passed to the Bitmap constructor. You should, however, have a using statement for the image instead.
Jon Skeet
A: 

Copy the Bitmap.

http://stackoverflow.com/questions/1772083/when-drawing-an-image-system-runtime-interopservices-externalexception-a-generi

    public static Image ToImage(this byte[] bytes)
    {
        using (var stream = new MemoryStream(bytes))
        using (var image = Image.FromStream(stream, false, true))
        {
            return new Bitmap(image);
        }
    }

    [Test]
    public void ShouldCreateImageThatCanBeSavedWithoutOpenStream()
    {
        var imageBytes = File.ReadAllBytes("bitmap.bmp");

        var image = imageBytes.ToImage();

        image.Save("output.bmp");
    }
Brian