代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

如何将GDI+位图放置到剪贴板上?

  •  2
  • Ian Boyd  · 技术社区  · 9 年前

    我想放置GDI+ 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 样式错误
    • 也没有 设置剪贴板数据 返回a null

    但当我尝试 使用 这个 CF_位图 在剪贴板上,它不能粘贴到Paint:

    enter image description here

    那么,填写函数的正确代码是什么

    void PlaceBitmapOnClipboard(Bitmap image)
    {
       //TODO: Ask Stackoverflow to figure this out
    
    }
    
    1 回复  |  直到 9 年前
        1
  •  2
  •   Barmak Shemirani    5 年前

    我们需要致电:
    SetClipboardData(CF_BITMAP, hbitmap_ddb)

    哪里 hbitmap_ddb 必须是兼容的位图(DDB),而不是我们从中获得的DIB Gdiplus::GetHBitmap


    或者我们打电话:
    SetClipboardData(CF_DIB, hmemory)

    哪里 hmemory 不是 HBITMAP . 数学记忆 如中所述 documentation 作为:

    包含 BITMAPINFO 结构后面是 位图位。


    示例使用 CF_BITMAP

    使用 CreateDIBitmap 基于我们的DIB位图创建兼容的位图。然后打电话 SetClipboardData 使用新的DDB位图。

    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 然后是位。不必担心颜色表,因为 Gdiplus::HBitmap 返回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);