Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
444 views
in Technique[技术] by (71.8m points)

.net - How can I write an extension method that converts a System.Drawing.Bitmap to a byte array?

How can I write an extension method that converts a System.Drawing.Bitmap to a byte array? Why not:

<Extension()> _
Public Function ToByteArray(ByVal image As System.Drawing.Bitmap) As Byte()
    Using ms = New MemoryStream()
        image.Save(ms, image.RawFormat)
        Return ms.ToArray()
    End Using
End Function

Yet when I use that, I get "System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+" thrown from the Save() operation. What am I doing wrong?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As someone else state, this is a known GDI+ bug.

However, it usually appear when you've closed the source stream of the image before reading it completely. Just loading a new Image object will only load metadata, like width, height, color depth, etc, not the actual pixels. They will be lazily loaded at a later time.

This can be avoided by copying your image (during loading) into a new Image created in memory. I presume that the input stream is still available at that time. Once you have the new memory-based Image class you can dispose of the source stream freely. (Another solution would be not to close/dispose the source stream).

Edit: Problem described in KB814675 Bitmap and Image constructor dependencies together with a workaround.

Create a Non-Indexed Image

This approach requires that the new image be in a non-indexed pixel format (more than 8 bits-per-pixel), even if the original image was in an indexed format. This workaround uses the Graphics.DrawImage() method to copy the image to a new Bitmap object:

  1. Construct the original Bitmap from the stream, from the memory, or from the file.
  2. Create a new Bitmap of the same size, with a pixel format of more than 8 bits-per-pixel (BPP).
  3. Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
  4. Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
  5. Use Graphics.Dispose() to dispose of the Graphics.
  6. Use Bitmap.Dispose() to dispose of the first Bitmap.

Create an Indexed Image

This workaround creates a Bitmap object in an indexed format:

  1. Construct the original Bitmap from the stream, from the memory, or from the file.
  2. Create a new Bitmap with the same size and pixel format as the first Bitmap.
  3. Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
  4. Use either the Marshal.Copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
  5. Use the Bitmap.UnlockBits() method to unlock both Bitmap objects.
  6. Use Bitmap.Dispose() to dispose of the first Bitmap.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...