如何将 GDI+ 位图放置到剪贴板上?
How to place GDI+ Bitmap onto the clipboard?
我想将 GDI+ Bitmap
放到剪贴板上。显而易见的方法是:
- 使用
Bitmap.GetHBITMAP
创建一个HBITMAP
- 使用
SetClipboardData
将 HBITMAP
作为 CF_BITMAP
放入剪贴板
所以我尝试伪代码:
void PlaceBitmapOnClipboard(Bitmap image)
{
//Convert GDI+ Bitmap to GDI Bitmap
HBITMAP bmp;
image.GetHBITMAP(0, @bmp);
OpenClipboard(this.Handle);
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();
}
出于说明目的省略了错误检查;但两个函数都失败了:
- 不是
GetHBITMAP
及其HRESULT
风格错误
SetClipboardData
return也不null
但是当我尝试使用剪贴板上的CF_BITMAP
时,它无法粘贴到画图中:
那么,填写函数的正确代码是什么:
void PlaceBitmapOnClipboard(Bitmap image)
{
//TODO: Ask Whosebug to figure this out
}
我们需要打电话给:
SetClipboardData(CF_BITMAP, hbitmap_ddb)
其中 hbitmap_ddb
必须是兼容位图 (DDB),而不是我们从 Gdiplus::GetHBitmap
获得的 DIB
或者我们调用:
SetClipboardData(CF_DIB, hmemory)
其中 hmemory
不是 HBITMAP
。 hmemory
在 documentation 中被描述为:
A memory object containing a BITMAPINFO
structure followed by the
bitmap bits.
示例使用 CF_BITMAP
使用CreateDIBitmap
根据我们的DIB 位图创建兼容的位图。然后用新的 DDB 位图调用 SetClipboardData
。
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(0, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
DIBSECTION ds;
if(sizeof ds == GetObject(hbitmap, sizeof ds, &ds))
{
HDC hdc = GetDC(NULL);
HBITMAP hbitmap_ddb = CreateDIBitmap(hdc, &ds.dsBmih, CBM_INIT,
ds.dsBm.bmBits, (BITMAPINFO*)&ds.dsBmih, DIB_RGB_COLORS);
ReleaseDC(NULL, hdc);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbitmap_ddb);
CloseClipboard();
}
DeleteObject(hbitmap_ddb);
}
DeleteObject(hbitmap);
示例使用 CF_DIB
使用GlobalAlloc
分配内存,然后将BITMAPINFOHEADER
复制到那块内存,然后是位。无需担心颜色 table,因为 Gdiplus::HBitmap
returns 32 位位图(至少据我所知在现代显示器上是这样)
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(NULL, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
BITMAPINFOHEADER bi =
{ sizeof bi, bm.bmWidth, bm.bmHeight, 1, bm.bmBitsPixel, BI_RGB };
std::vector<BYTE> vec(bm.bmWidthBytes * bm.bmHeight);
auto hdc = GetDC(NULL);
GetDIBits(hdc, hbitmap, 0, bi.biHeight, vec.data(), (BITMAPINFO*)&bi, 0);
ReleaseDC(NULL, hdc);
auto hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof bi + vec.size());
auto buffer = (BYTE*)GlobalLock(hmem);
memcpy(buffer, &bi, sizeof bi);
memcpy(buffer + sizeof bi, vec.data(), vec.size());
GlobalUnlock(hmem);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_DIB, hmem);
CloseClipboard();
}
DeleteObject(hbitmap);
我想将 GDI+ Bitmap
放到剪贴板上。显而易见的方法是:
- 使用
Bitmap.GetHBITMAP
创建一个HBITMAP
- 使用
SetClipboardData
将HBITMAP
作为CF_BITMAP
放入剪贴板
所以我尝试伪代码:
void PlaceBitmapOnClipboard(Bitmap image)
{
//Convert GDI+ Bitmap to GDI Bitmap
HBITMAP bmp;
image.GetHBITMAP(0, @bmp);
OpenClipboard(this.Handle);
EmptyClipboard();
SetClipboardData(CF_BITMAP, bmp);
CloseClipboard();
}
出于说明目的省略了错误检查;但两个函数都失败了:
- 不是
GetHBITMAP
及其HRESULT
风格错误 SetClipboardData
return也不null
但是当我尝试使用剪贴板上的CF_BITMAP
时,它无法粘贴到画图中:
那么,填写函数的正确代码是什么:
void PlaceBitmapOnClipboard(Bitmap image)
{
//TODO: Ask Whosebug to figure this out
}
我们需要打电话给:
SetClipboardData(CF_BITMAP, hbitmap_ddb)
其中 hbitmap_ddb
必须是兼容位图 (DDB),而不是我们从 Gdiplus::GetHBitmap
或者我们调用:
SetClipboardData(CF_DIB, hmemory)
其中 hmemory
不是 HBITMAP
。 hmemory
在 documentation 中被描述为:
A memory object containing a
BITMAPINFO
structure followed by the bitmap bits.
示例使用 CF_BITMAP
使用CreateDIBitmap
根据我们的DIB 位图创建兼容的位图。然后用新的 DDB 位图调用 SetClipboardData
。
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(0, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
DIBSECTION ds;
if(sizeof ds == GetObject(hbitmap, sizeof ds, &ds))
{
HDC hdc = GetDC(NULL);
HBITMAP hbitmap_ddb = CreateDIBitmap(hdc, &ds.dsBmih, CBM_INIT,
ds.dsBm.bmBits, (BITMAPINFO*)&ds.dsBmih, DIB_RGB_COLORS);
ReleaseDC(NULL, hdc);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbitmap_ddb);
CloseClipboard();
}
DeleteObject(hbitmap_ddb);
}
DeleteObject(hbitmap);
示例使用 CF_DIB
使用GlobalAlloc
分配内存,然后将BITMAPINFOHEADER
复制到那块内存,然后是位。无需担心颜色 table,因为 Gdiplus::HBitmap
returns 32 位位图(至少据我所知在现代显示器上是这样)
Gdiplus::Bitmap gdibmp(L"file.bmp");
if(gdibmp.GetLastStatus() != Gdiplus::Ok)
return;
HBITMAP hbitmap;
auto status = gdibmp.GetHBITMAP(NULL, &hbitmap);
if(status != Gdiplus::Ok)
return;
BITMAP bm;
GetObject(hbitmap, sizeof bm, &bm);
BITMAPINFOHEADER bi =
{ sizeof bi, bm.bmWidth, bm.bmHeight, 1, bm.bmBitsPixel, BI_RGB };
std::vector<BYTE> vec(bm.bmWidthBytes * bm.bmHeight);
auto hdc = GetDC(NULL);
GetDIBits(hdc, hbitmap, 0, bi.biHeight, vec.data(), (BITMAPINFO*)&bi, 0);
ReleaseDC(NULL, hdc);
auto hmem = GlobalAlloc(GMEM_MOVEABLE, sizeof bi + vec.size());
auto buffer = (BYTE*)GlobalLock(hmem);
memcpy(buffer, &bi, sizeof bi);
memcpy(buffer + sizeof bi, vec.data(), vec.size());
GlobalUnlock(hmem);
if(OpenClipboard(hwnd))
{
EmptyClipboard();
SetClipboardData(CF_DIB, hmem);
CloseClipboard();
}
DeleteObject(hbitmap);