none
GDI+ error when saving an image RRS feed

  • Question

  • In http://social.msdn.microsoft.com/Forums/vstudio/en-US/b15357f1-ad9d-4c80-9ec1-92c786cca4e6/bitmapsave-a-generic-error-occurred-in-gdi?forum=netfxbcl, someone suggests a workaround through a memory stream to solve 'generic GDI+ error' exceptions when saving an image to a file.

    However, I have this problem when saving to a memory stream in the first place.

    This code throws a "Generic GDI error" exception on the 2nd save (Image2.save).

    In my actual application, the image (after the first save) makes a detour through a database (varbinary(max) column) and back to a memory buffer and an image before the second save is called, with  no difference: the error still occurs.

    For backward compatibility to some mighty old machines (stilll running Win2000!) it all has to happen in framework 2.0, but the error occurs on my development machine in 4.0 client profile just as well.

    Dim Image1 As Image = Image.FromFile("C:\Users\Public\Pictures\Sample Pictures\Desert.jpg")
    
    Dim Buffer1 As Byte()
    Using MemoryStream1 As New IO.MemoryStream
        Image1.Save(MemoryStream1, System.Drawing.Imaging.ImageFormat.Jpeg)
        Buffer1 = MemoryStream1.ToArray
    End Using
    
    Dim Image2 As Image
    Using MemoryStream2 As New IO.MemoryStream(Buffer1)
        Image2 = Image.FromStream(MemoryStream2)
    End Using
    
    Dim Buffer3 As Byte()
    Using MemoryStream3 As New IO.MemoryStream
        Image2.Save(MemoryStream3, System.Drawing.Imaging.ImageFormat.Jpeg)
        Buffer3 = MemoryStream3.ToArray
    End Using
    

    Tuesday, January 7, 2014 8:45 AM

Answers

  • "Replacing the final step in the code above by this works:"

    I'm not sure how that works, it's not supposed to work either.

    The main problem is that the image returned Image.FromStream maintains a reference to the stream and it expects the stream to be left open while the image is in use. Your original code works if you move a 'end using' at the end to keep MemoryStream2 open:

            Dim Image2 As Image
            Using MemoryStream2 As New IO.MemoryStream(Buffer1)
                Image2 = Image.FromStream(MemoryStream2)
    
                Dim Buffer3 As Byte()
                Using MemoryStream3 As New IO.MemoryStream
                    Image2.Save(MemoryStream3, System.Drawing.Imaging.ImageFormat.Jpeg)
                    Buffer3 = MemoryStream3.ToArray
                End Using
            End Using
    
    A side note: I'm not sure how you real code looks and how is the image saved to the database but this particular example contains a lot of redundancy. For example there's no need to convert the first stream to an array and then create a second memory stream from that array. You can simply set the Position of the first stream to 0 and then load the image from that stream.

    • Marked as answer by lucvdv Friday, January 10, 2014 7:00 AM
    Tuesday, January 7, 2014 10:27 AM
    Moderator

All replies

  • Update: creating an additional copy of the image as a Bitmap object in the Buffer3 step avoids the problem.

    What I would like to know is if there's a way I can avoid having to create that additional copy.

    Replacing the final step in the code above by this works:

    Dim Buffer3 As Byte()
    Using MemoryStream3 As New IO.MemoryStream,  bm As New Bitmap(Image2)
        bm.Save(MemoryStream3, System.Drawing.Imaging.ImageFormat.Jpeg)
        Buffer3 = MemoryStream3.ToArray
    End Using
    

    Tuesday, January 7, 2014 9:31 AM
  • "Replacing the final step in the code above by this works:"

    I'm not sure how that works, it's not supposed to work either.

    The main problem is that the image returned Image.FromStream maintains a reference to the stream and it expects the stream to be left open while the image is in use. Your original code works if you move a 'end using' at the end to keep MemoryStream2 open:

            Dim Image2 As Image
            Using MemoryStream2 As New IO.MemoryStream(Buffer1)
                Image2 = Image.FromStream(MemoryStream2)
    
                Dim Buffer3 As Byte()
                Using MemoryStream3 As New IO.MemoryStream
                    Image2.Save(MemoryStream3, System.Drawing.Imaging.ImageFormat.Jpeg)
                    Buffer3 = MemoryStream3.ToArray
                End Using
            End Using
    
    A side note: I'm not sure how you real code looks and how is the image saved to the database but this particular example contains a lot of redundancy. For example there's no need to convert the first stream to an array and then create a second memory stream from that array. You can simply set the Position of the first stream to 0 and then load the image from that stream.

    • Marked as answer by lucvdv Friday, January 10, 2014 7:00 AM
    Tuesday, January 7, 2014 10:27 AM
    Moderator
  • Thanks, Mike.

    You're right, I feel a bit embarrassed for overlooking that the MemoryStream has to remain available. I knew it's locking files you load images from for as long as the image exists in code, it's only logical that it sinks it hooks into memory streams as well.


    Tuesday, January 7, 2014 1:20 PM