tags:

views:

182

answers:

1

This seems to be in infamous error. I remember getting it a while back for different code, but it's back, with a vengeance, but with some new code that I can't seem to figure out.
It's definitely generic, for sure!

The Goal

I'm trying to build a form that allows a user to:

  1. Select an image.
  2. Press save (which closes the form), and saves the image to a byte[] into a database.
  3. Open the form (which loads the image from the byte[]).
  4. Allow them to press save again.
  5. Allow them to open the form again, displaying the image (again).

A pretty standard load/save scenario.

The Problem

Everything works fine regarding loading and saving to the SQL Server. The problem I'm getting is to do with repeatedly loading and saving to and from a byte[] even though I'm using the same settings. Take a look at this code which I mocked up to demonstrate the problem:

static void Main(string[] args)
{
    // Load the image
    var initialImage = (Bitmap)Bitmap.FromFile(@"D:\picture.jpg");

    // Save to a memory stream and get the bytes
    var initialImageBytes = SaveImageToBytes(initialImage);

    // Load again from this saved image
    Bitmap byteLoadedImage = LoadImageFromBytes(initialImageBytes);

    // Save again to bytes, throws "A generic error occurred in GDI+."
    var secondaryImageBytes = SaveImageToBytes(byteLoadedImage);
}

private static byte[] SaveImageToBytes(Bitmap image)
{
    byte[] imageBytes;
    using (MemoryStream imageStream = new MemoryStream())
    {
        image.Save(imageStream, image.RawFormat);
        // "A generic error occurred in GDI+." thrown when saved second time
        imageBytes = imageStream.ToArray();
    }

    return imageBytes;
}

private static Bitmap LoadImageFromBytes(byte[] bytes)
{
    using (MemoryStream imageStream = new MemoryStream(bytes))
    {
        Bitmap image = (Bitmap)Bitmap.FromStream(imageStream);
        return image;
    }
}

The error A generic error occurred in GDI+. is thrown as the image is saved once more to the MemoryStream the second time round. I checked this wasn't to do with the RawFormat by inspecting the value before the first save, and before the second:

1st Save : {b96b3cae-0728-11d3-9d7b-0000f81ef32e}
2nd Save : {b96b3cae-0728-11d3-9d7b-0000f81ef32e}

The values are identical, so it can't be a problem with it losing the ImageFormat information.

Can anyone help debug this problem? The code sample I used is tested with a JPEG, and you can get it here.

+2  A: 

I had what I believe was the same problem recently. You need to skip the using statement around the creation of your MemoryStream. Creating a bitmap keeps a reference to the stream that created it. You can read about it on MSDN.

private static Bitmap LoadImageFromBytes(byte[] bytes)
{
    var imageStream = new MemoryStream(bytes))
    var image = (Bitmap)Bitmap.FromStream(imageStream);
    return image;
}
Jake Pearson
Oh my... thanks for that. I found the bit you refer to:You must not destroy the stream.When a stream is provided to the Bitmap or the Image class constructor, GDI+ may defer reading from the stream until later. This means that you must not destroy the stream until after you destroy the Bitmap or the Image object. If you try to use the Bitmap or the Image object after you destroy the stream, you may receive an error message. It is the responsibility of the application to make sure that the stream can be used during the life of the new image object.
Codesleuth
I'll need to build some clever stream-management, more than your example provides. Don't want to leave that stream floating around without being disposed!
Codesleuth