思路:把HDC里的內容保存到Direct2D格式的位圖里,后續直接調用 renderTarget->DrawBitmap即可。本例中,位圖將保存為類的字段。
本例中 COM 接口指針皆使用
com_ptr
,這是 WinRT 的 COM 智能指針類,com_ptr<I>::get()
返回的是實際接口指針,put()
返回實際接口指針的指針。可以用 ATL 的ComPtr
類代替,功能相同,但用法稍有不同。
緩存
假設已有 RichEdit Control 句柄 m_editBox
,欲將其圖像緩存到一個D2D位圖里,后續要把位圖繪制到 Render target 或 ID2D1DeviceContext 對象 m_ctx
上。字段 m_bitmap
作為位圖緩存,字段 m_bmpRT
作為位圖緩存的呈現目標(不會在繪制位圖時真的用到,但要存)。
則可用如下代碼把該編輯框的 DC 的內容復制到 m_bitmap
里:
float dpiX, dpiY;
m_ctx->GetDpi(&dpiX, &dpiY);
auto dpiFactor = dpiX / 96.0f;RECT rect;
GetClientRect(m_editBox, &rect);// 先創建內存render target(BitmapRenderTarget),類似于創建內存DC,
// 不同之處在于不用手動創建、選擇bitmap,D2D會自動完成該操作。
auto bmpRtPixelSize = D2D1::SizeU(rect.right, rect.bottom);
auto bmpRtSize = D2D1::SizeF(bmpRtPixelSize.width / dpiFactor, bmpRtPixelSize.height / dpiFactor);
auto bmpRtPixelFmt = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
HRESULT hr = m_ctx->CreateCompatibleRenderTarget(bmpRtSize, bmpRtPixelSize, bmpRtPixelFmt,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_GDI_COMPATIBLE,m_bmpRT.put());// 獲取與 GDI 兼容的 render target 接口指針。
// 該接口仍然屬于上面創建的 BitmapRenderTarget 對象(對 QueryInterface
// 的理解),所以盡管 gdiRT 本身沒有 BeginDraw 方法,仍可調用
// m_bmpRT->BeginDraw() 來使該對象處于正確狀態。EndDraw() 同理。
com_ptr<ID2D1GdiInteropRenderTarget> gdiRT;
m_bmpRT->QueryInterface(gdiRT.put());
m_bmpRT->BeginDraw();
HDC rtDC{};
hr = gdiRT->GetDC(D2D1_DC_INITIALIZE_MODE_CLEAR, &rtDC);// 把編輯框 DC 內容復制到 render target 的 DC 上
HDC hdc = GetDC(m_editBox);
BitBlt(rtDC, 0, 0, rect.right, rect.bottom, hdc, 0, 0,SRCCOPY);
ReleaseDC(m_editBox, hdc);gdiRT->ReleaseDC(nullptr);
hr = m_bmpRT->EndDraw();
if (FAILED(hr)) {// 處理異常
}m_bmpRT->GetBitmap(m_bitmap.put());
繪制到任意 ID2D1RenderTarget 或 ID2D1DeviceContext 上
直接調用 DrawBitmap
即可:
m_ctx->DrawBitmap(m_bitmap.get());