7

Overview of my application: On the client side, a series of snapshots are taken with a webcam. On submit, I want the images to be converted to a byte array, and have that byte array sent to a service I have written.

My problem: I'm trying to save a single image to a MemoryStream, but it continues to break, spitting out the message, "A generic error occured in GDI+." When I dig deeper, I see that the exception is thrown when the MemoryStream's buffer position is at 54. Unfortunately, it's a 1.2 mb photo. Here's the block of code:

// Create array of MemoryStreams
var imageStreams = new MemoryStream[SelectedImages.Count];
for (int i = 0; i < this.SelectedImages.Count; i++)
{   
    System.Drawing.Image image = BitmapFromSource(this.SelectedImages[i]);
    imageStreams[i] = new MemoryStream();
    image.Save(imageStreams[i], ImageFormat.Bmp); /* Error is thrown here! */
}

// Combine MemoryStreams into a single byte array (Threw this 
// in in case somebody has a better approach)
byte[] bytes = new byte[imageStreams.Sum(s => s.Length)];
for(int i = 0; i < imageStreams.Length; i++)
{
    bytes.Concat(imageStreams[i].ToArray());
}

And here is my BitmapFromSource method

// Converts a BitmapSource object to a Bitmap object
private System.Drawing.Image BitmapFromSource(BitmapSource source)
{
    System.Drawing.Image bitmap;

    using (MemoryStream ms = new MemoryStream())
    {
        BitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(source));
        encoder.Save(ms);
        bitmap = new System.Drawing.Bitmap(ms);
    }
    return bitmap;
}

A lot of what I have read about the Generic GDI+ Error points to a permissions issue, but I don't see how that would apply here, considering I'm not saving to the file system. Also, I've seen that this error can arise due to the MemoryStream closing before the image is being saved, but I also don't see how this would apply considering I create the MemoryStream immediately before I save the image. Any insight would be greatly appreciated.

Alexander
  • 2,320
  • 2
  • 25
  • 33
Mr Jones
  • 1,188
  • 3
  • 17
  • 33
  • [SecurityException when calling Graphics.DrawImage](http://stackoverflow.com/questions/9185494/securityexception-when-calling-graphics-drawimage) Related maybe? Leads to this: [Common Problems with rendering Bitmaps into ASP.NET OutputStream](http://www.west-wind.com/weblog/posts/2006/Oct/19/Common-Problems-with-rendering-Bitmaps-into-ASPNET-OutputStream) – M. Mennan Kara Jul 31 '12 at 13:57
  • Also please have a look at this : **http://stackoverflow.com/questions/1044085/a-generic-error-occurred-in-gdi** – huMpty duMpty Jul 31 '12 at 14:00
  • @MennanKara Your link solved my problem. Turns out the bitmap needs to be copied to a new bitmap before it can be saved. Seems redundant, but it worked. Please post your link as an answer and I will approve. – Mr Jones Jul 31 '12 at 14:06

2 Answers2

12

I think your problem actually lies in your BitmapFromSource method.

You're creating a stream, then creating a bitmap from that stream, then throwing the stream away, then trying to save the bitmap to another stream. However, the documentation for the Bitmap class says:

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

By the time you come to save that bitmap, the bitmap is already corrupted because you've thrown the original stream away.

See: http://msdn.microsoft.com/en-us/library/z7ha67kw

To fix this (bearing in mind I've not written the code let alone tested it), create the MemoryStream inside the first for loop in your first block of code, and pass that memory stream to your BitmapFromSource method as a second parameter.

Chris
  • 4,661
  • 1
  • 23
  • 25
  • +1 for pointing out that the MemoryStream is being closed in the BitmapFromSource method. This explains why the bitmap needs to be copied before it can be saved. – Mr Jones Jul 31 '12 at 14:07
  • There is one other oddity in your code that worries me, in that it seems unnecessary. You appear to be opening a MemoryStream to create your bitmap, and then saving that bitmap to another MemoryStream. I may be missing something, but why not just hold on to the first MemoryStream and store it in your array, rather than copy the bitmap to a second stream? – Chris Jul 31 '12 at 14:12
  • Another point of interest - the reason your original code was failing when writing to buffer position 54 is that that's the size of the bitmap header. The code is able to write the file header, but then fails when writing the actual content because it could no longer read from the stream. – Chris Jul 31 '12 at 14:14
  • This is the most appropriate answer. There was no need to copy the bitmap. – Mr Jones Jul 31 '12 at 14:17
1

Please see SecurityException when calling Graphics.DrawImage which leads to Common Problems with rendering Bitmaps into ASP.NET OutputStream

Community
  • 1
  • 1
M. Mennan Kara
  • 10,072
  • 2
  • 35
  • 39