Search code examples
c#pinvokegdi+clipboardgdi

Convert DIB to DDB?


I'm developing a clipboard manager (which can be seen here: http://flamefusion.net/software/shapeshifter).

However, I am currently having issues with a bitmap (bmp) that won't really insert itself into the clipboard properly. My first approach was the following, using SetClipboardData.

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

I am aware of the potential memory leaks in this, and it was made solely as a test. The test failed. The image put into the clipboard was not readable by Paint when pasting it in.

So after a lot of researching and failed attempts, I got a new theory. The bitmap I am using is created from a MemoryStream, which has been created through a previous call to the Bitmap.Save(Stream, ImageFormat) method. This leads me to believe that a System.Drawing.Bitmap's GetHBitmap is not the kind of HBITMAP the SetClipboardData function expects.

So I tried the following, with some kind of success.

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

Now the image is inserted with the right dimensions, but as a black image. And this is quite obvious, since nothing from bmp is actually used to create the "compatible" bitmap other than its width and height.

I assume I have to use BitBlt somehow to copy my original bitmap over to this now "compatible" bitmap, but I have no clue of where to begin.

Would any of you GDI wizards know? Magic is obviously needed here.

Edit 1 As dthorpe nicely pointed out, it seems that my problem is that the image I am trying to save is in fact a DIB. Now the question has changed. I need to figure out how to convert from a DIB to a DDB. I am aware of the alpha loss while doing this among other things, but it is nevertheless needed.

Edit 2 It is not acceptable to use Clipboard.SetImage. This won't work in my scenario. I need to use the APIs.


Solution

  • CF_BITMAP is probably the wrong format to use with your bitmap. The CF_BITMAP clipboard format specifies a device bitmap, but nearly all bitmaps today are DIBs - device independent bitmaps. Device bitmaps are relative to the system/hardware device palette (think EGA graphics) and must match the pixel format of the current display mode. DIBs carry their own color info and their pixel format is independent of the display mode.

    Docs say that the clipboard manager will convert a CF_BITMAP to a CF_DIB if an application asks for CF_DIB when reading from the clipboard, but that assumes that the original image is actually a device bitmap in the current display mode pixel format. If it is not, the conversion will produce garbage because the input is garbage.

    Try again using CF_DIB instead of CF_BITMAP.