如何编写将System.Drawing.Bitmap转换为字节数组的扩展方法?为什么不:
<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
然而,当我使用它时,我从Save()操作中抛出“System.Runtime.InteropServices.ExternalException:GDI +中发生了一般错误”。我做错了什么?
答案 0 :(得分:4)
正如其他人所说,这是一个已知的GDI +错误。
但是,它通常会在您完全读取之前关闭图像的源流时出现。只是加载一个新的Image对象只会加载元数据,如宽度,高度,颜色深度等,而不是实际的像素。它们将在以后延迟装载。
可以通过将图像(在加载期间)复制到在内存中创建的新图像来避免这种情况。我认为输入流在那时仍然可用。一旦有了新的基于内存的Image类,就可以自由地处理源流。 (另一种解决方案是不关闭/处置源流)。
编辑: KB814675 Bitmap and Image constructor dependencies中描述的问题以及解决方法。
创建非索引图像
这种方法要求新图像采用非索引像素格式(每像素超过8位),即使原始图像采用索引格式。此解决方法使用Graphics.DrawImage()方法将图像复制到新的Bitmap对象:
- 从流,内存或文件构造原始位图。
- 创建一个相同大小的新位图,像素格式超过每像素8位(BPP)。
- 使用Graphics.FromImage()方法获取第二个Bitmap的Graphics对象。
- 使用Graphics.DrawImage()将第一个Bitmap绘制到第二个Bitmap上。
- 使用Graphics.Dispose()处理Graphics。
- 使用Bitmap.Dispose()处理第一个Bitmap。
醇>创建索引图像
此解决方法以索引格式创建Bitmap对象:
- 从流,内存或文件构造原始位图。
- 创建一个与第一个Bitmap具有相同大小和像素格式的新位图。
- 使用Bitmap.LockBits()方法以原生像素格式锁定两个Bitmap对象的整个图像。
- 使用Marshal.Copy函数或其他内存复制功能将图像位从第一个位图复制到第二个位图。
- 使用Bitmap.UnlockBits()方法解锁两个Bitmap对象。
- 使用Bitmap.Dispose()处理第一个Bitmap。
醇>
答案 1 :(得分:1)
已知的GDI +错误。
您无法立即关闭MemoryStream
。
将输出数组复制到另一个字节数组,然后关闭该流。
答案 2 :(得分:0)
尝试将image.RawFormat
更改为JPEG或PNG。某些图像可以通过位图打开但不可保存(至少以原始格式)。
答案 3 :(得分:0)
根据该线程,我使用以下代码,并且可以正常工作:
using (var ms = new MemoryStream(bytes))
{
using (var bitmap = new Bitmap(ms))
{
var bitmapCopy = new Bitmap(bitmap, bitmap.Width, bitmap.Height);
return bitmapCopy;
}
}