我有一个包含BITMAP
结构的变量。该结构定义如下。
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct BITMAP
{
public Int32 Type;
public Int32 Width;
public Int32 Height;
public Int32 WidthBytes;
public UInt16 Planes;
public UInt16 BitsPixel;
public IntPtr Bits;
}
这种结构没有错。当我尝试使用GDI GetObject
API获取位图时,它会填充实际数据。
当我尝试将其转换为字节数组并再次返回时,会出现问题。
下面你看看我如何将结构转换为字节数组。再一次,这工作正常,我在数组中看到数据。
var bitmap = new BITMAP();
var bufferSize = Marshal.SizeOf(bitmap);
GetObject(bitmapHandle, bufferSize, out bitmap);
var bytes = new byte[bitmap.WidthBytes * bitmap.Height];
Marshal.Copy(bitmap.Bits, bytes, 0, bytes.Length);
DeleteObject(bitmapHandle);
//"bytes" now contains the byte array of pixels.
现在,这里一切都出了差错。当我尝试将此给定数组转换回BitmapImage
之后,我得到NotSupportedException
。
这是我的转换代码。
var image = new BitmapImage();
using (var stream = new MemoryStream(bytes))
{
stream.Position = 0;
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.None;
image.CacheOption = BitmapCacheOption.OnDemand;
image.UriSource = null;
image.StreamSource = stream;
image.EndInit(); //it throws the exception here
}
image.Freeze();
异常消息是No imaging component suitable to complete this operation was found
。
我曾尝试在线寻找解决方案,但没有运气。我似乎无法弄清楚我做错了什么。我假设它是在从BITMAP
到字节数组的转换过程中,但我不知道。
应该注意的是,BitmapSource也可以。
答案 0 :(得分:1)
如果您只需要一个BitmapSource(或一个ImageSource),您可以使用GDI的CreateBitmapIndirect function和WPF互操作Imaging.CreateBitmapSourceFromHBitmap Method,如下所示:
static BitmapSource FromBITMAP(ref BITMAP bmp)
{
Int32Rect rect = new Int32Rect(0, 0, bmp.Width, bmp.Height);
IntPtr hbitmap = CreateBitmapIndirect(ref bmp);
if (hbitmap == IntPtr.Zero)
return null;
try
{
return Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, rect, BitmapSizeOptions.FromEmptyOptions());
}
finally
{
DeleteObject(hbitmap);
}
}
[DllImport("gdi32.dll", SetLastError = true)]
public static extern IntPtr CreateBitmapIndirect(ref BITMAP lpbm);
[DllImport("gdi32.dll", SetLastError = true)]
public static extern bool DeleteObject(IntPtr hObject);
答案 1 :(得分:1)
创建位图数据数组时失败了。你正在计算数组大小只是乘以
bitmap.WidthBytes * bitmap.Height
这不是BitmapImage的预期来源,因为BitmapImage源需要是一个完整的位图文件结构,在像素数据之前包含54个字节。
有关位图结构的更多信息: https://www.daubnet.com/en/file-format-bmp
也许您需要知道像素数据区域的大小受“填充”的影响,位于每个Scanline末尾的一些额外字节添加到完整的Int32块以加速位图加载。
答案 2 :(得分:0)
这里出了点问题。根据GetObject API文档,BITMAP不是一个对象,声称获取带像素的字节数组的代码是不正确的:
如果hgdiobj是通过调用CreateDIBSection创建的位图的句柄,并且指定的缓冲区足够大,则GetObject函数返回DIBSECTION结构。此外,DIBSECTION中包含的BITMAP结构的bmBits成员将包含指向位图的位值的指针。如果hgdiobj是通过任何其他方式创建的位图的句柄,则GetObject仅返回位图的宽度,高度和颜色格式信息。您可以通过调用GetDIBits或GetBitmapBits函数来获取位图的位值。
所以让我们从头开始吧。从我看到的,你的代码开始于一个名为bitmapHandle的东西,我认为它来自某个地方的HBITMAP。如果是这种情况,我认为你真正需要的是一个函数,它接受一个HBITMAP并输出一个字节数组,另一个函数就像你描述的那样。像这样:
private static byte[] GetBitmapData(IntPtr hBitmap)
{
var source = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, null);
// You may use Bmp, Jpeg or other encoder of your choice
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(source));
var stream = new MemoryStream();
encoder.Save(stream);
return stream.ToArray();
}
private static BitmapSource GetBitmapSource(byte[] data)
{
return BitmapFrame.Create(new MemoryStream(data));
}