将DIB转换为DDB?

时间:2012-08-28 15:32:37

标签: c# pinvoke gdi+ clipboard gdi

我正在开发一个剪贴板管理器(可以在这里看到:http://flamefusion.net/software/shapeshifter)。

但是,我目前遇到了一个位图(bmp)的问题,它不会真正将自己插入到剪贴板中。我的第一种方法是使用SetClipboardData

var hBitmap = bmp.GetHBitmap();
SetClipboardData(CF_BITMAP, hBitmap);

我知道这可能存在内存泄漏,而且它仅作为测试。测试失败了。粘贴时,Paint无法读取放入剪贴板的图像。

经过大量的研究和失败的尝试后,我得到了一个新的理论。我使用的位图是从MemoryStream创建的,Bitmap.Save(Stream, ImageFormat)是通过先前调用System.Drawing.Bitmap方法创建的。这让我相信GetHBitmap的{​​{1}}不是HBITMAP SetClipboardData函数所期望的那种。

所以我尝试了以下方法,取得了一些成功。

var memDC = CreateCompatibleDC(IntPtr.Zero);
var memBitmap = CreateCompatibleBitmap(memDC, bmp.Width, bmp.Height);
SetClipboardData(CF_BITMAP, memBitmap);

现在,图像以正确的尺寸插入,但作为黑色图像。这是非常明显的,因为bmp中没有任何内容实际上用于创建除了宽度和高度之外的“兼容”位图。

我假设我必须以某种方式使用BitBlt将原始位图复制到现在的“兼容”位图,但我不知道从哪里开始。

你们中的任何一位GDI巫师都知道吗?这里显然需要魔术。

修改1 正如dthorpe很好地指出的那样,我的问题似乎是我想要保存的图像实际上是一个DIB。现在问题已经改变了。我需要弄清楚如何从DIB转换为DDB。

,我知道在执行此操作时会造成alpha损失,但仍需要它。

编辑2 使用Clipboard.SetImage是不可接受的。这在我的方案中不起作用。我需要使用API​​。

2 个答案:

答案 0 :(得分:2)

CF_BITMAP可能是与您的位图一起使用的错误格式。 CF_BITMAP剪贴板格式指定了设备位图,但今天几乎所有的位图都是DIB - 与设备无关的位图。设备位图与系统/硬件设备调色板(想想EGA图形)相关,并且必须与当前显示模式的像素格式匹配。 DIB带有自己的颜色信息,其像素格式与显示模式无关。

Docs说,如果应用程序在从剪贴板读取时要求CF_DIB,剪贴板管理器会将CF_BITMAP转换为CF_DIB,但假设原始图像实际上是当前显示模式像素格式的设备位图。如果不是,转换将产生垃圾,因为输入是垃圾。

再次尝试使用CF_DIB而不是CF_BITMAP。

答案 1 :(得分:2)

我认为你过于复杂了。根本不需要p / invoke - 框架已经为你处理了这个问题。你可以做一个单行:

Clipboard.SetImage(bmp);