Direct2D 和 GDI 互通性概觀
本主題描述如何同時使用 Direct2D 和 GDI 。 有兩種方式可將 Direct2D 與 GDI 結合:您可以將 GDI 內容寫入 Direct2D GDI 相容的轉譯目標,也可以將 Direct2D 內容寫入 GDI 裝置內容 (DC) 。
本主題包含下列各節。
- 先決條件
- 將 Direct2D 內容繪製至 GDI 裝置內容
- ID2D1DCRenderTargets、GDI 轉換和 Windows 的由右至左語言組建
- 將 GDI 內容繪製至 Direct2D GDI-Compatible轉譯目標
- 相關主題
必要條件
此概觀假設您已熟悉基本的 Direct2D 繪圖作業。 如需教學課程,請參閱 建立簡單的 Direct2D 應用程式。 它也假設您已熟悉 GDI 繪圖作業。
將 Direct2D 內容繪製至 GDI 裝置內容
若要將 Direct2D 內容繪製至 GDI DC,請使用 ID2D1DCRenderTarget。 若要建立 DC 轉譯目標,請使用 ID2D1Factory::CreateDCRenderTarget 方法。 這個方法會採用兩個參數。
第一個參數 D2D1_RENDER_TARGET_PROPERTIES 結構,指定轉譯、遠端、DPI、像素格式及使用方式資訊。 若要讓 DC 轉譯目標能夠使用 GDI,請將 DXGI 格式設定為 DXGI_FORMAT_B8G8R8A8_UNORM ,並將 Alpha 模式設定為 D2D1_ALPHA_MODE_PREMULTIPLIED 或 D2D1_ALPHA_MODE_IGNORE。
第二個參數是接收 DC 轉譯目標參考的指標位址。
下列程式碼會建立 DC 轉譯目標。
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pDCRT);
在上述程式碼中, m_pD2DFactory 是 ID2D1Factory的指標, m_pDCRT 是 ID2D1DCRenderTarget的指標。
您必須先使用其 BindDC 方法將它與 GDI DC 產生關聯,才能使用 DC 轉譯目標進行轉譯。 每次使用不同的 DC,或您想要繪製到變更的區域大小時,都會執行這項操作。
BindDC方法會採用兩個參數hDC和pSubRect。 hDC參數會提供接收轉譯目標輸出之裝置內容的控制碼。 pSubRect參數是一個矩形,描述轉譯內容的裝置內容部分。 DC 轉譯目標會更新其大小,以符合 pSubRect所描述的裝置內容區域,其應該變更大小。
下列程式碼會將 DC 系結至 DC 轉譯目標。
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
C++ |
---|
|
將 DC 轉譯目標與 DC 產生關聯之後,您可以使用它來繪製。 下列程式碼會使用 DC 繪製 Direct2D 和 GDI 內容。
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
HRESULT hr;
RECT rc;
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
//
// Draw the pie chart with Direct2D.
//
// Create the DC render target.
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);
m_pDCRT->BeginDraw();
m_pDCRT->SetTransform(D2D1::Matrix3x2F::Identity());
m_pDCRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
m_pDCRT->DrawEllipse(
D2D1::Ellipse(
D2D1::Point2F(150.0f, 150.0f),
100.0f,
100.0f),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.15425f),
(150.0f - 100.0f * 0.988f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.525f),
(150.0f + 100.0f * 0.8509f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f - 100.0f * 0.988f),
(150.0f - 100.0f * 0.15425f)),
m_pBlackBrush,
3.0
);
hr = m_pDCRT->EndDraw();
if (SUCCEEDED(hr))
{
//
// Draw the pie chart with GDI.
//
// Save the original object.
HGDIOBJ original = NULL;
original = SelectObject(
ps.hdc,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(ps.hdc, blackPen);
Ellipse(ps.hdc, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(ps.hdc, pntArray1, 2);
Polyline(ps.hdc, pntArray2, 2);
Polyline(ps.hdc, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(ps.hdc, original);
}
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
此程式碼會產生輸出,如下圖所示 (圖說文字已新增,以醒目提示 Direct2D 與 GDI 轉譯之間的差異。)
ID2D1DCRenderTargets、GDI 轉換和 Windows 的由右至左語言組建
當您使用 ID2D1DCRenderTarget時,它會將 Direct2D 內容轉譯為內部點陣圖,然後使用 GDI 將點陣圖轉譯至 DC。
GDI 可以透過 SetWorldTransform 方法套用 GDI 轉換 (,) 或其他效果套用至轉譯目標所使用的相同 DC,在此情況下,GDI 會轉換 Direct2D 所產生的點陣圖。 使用 GDI 轉換來轉換 Direct2D 內容可能會降低輸出的視覺品質,因為您正在轉換已計算反鋸齒和子圖元位置的點陣圖。
例如,假設您使用轉譯目標來繪製包含反鋸齒幾何和文字的場景。 如果您使用 GDI 轉換將縮放轉換套用至 DC 並調整場景,使其大於 10 倍,您會看到像素化和不規則邊緣。 (如果您使用 Direct2D 套用類似的轉換,場景的視覺品質將不會降級。)
在某些情況下,GDI 執行可能會降低 Direct2D 內容品質的額外處理可能並不明顯。 例如,在由右至左 (RTL) Windows 組建上,當 GDI 將它複製到目的地時, ID2D1DCRenderTarget 所轉譯的內容可能會水準反轉。 內容是否實際反轉取決於 DC 目前的設定。
視要呈現的內容類型而定,您可能會想要防止反轉。 如果 Direct2D 內容包含 ClearType 文字,此反轉會降低文字的品質。
您可以使用 SetLayout GDI 函式來控制 RTL 轉譯行為。 若要防止鏡像,請呼叫 SetLayout GDI 函式,並指定 LAYOUT_BITMAPORIENTATIONPRESERVED 做為第二個參數的唯一值, (不要將其與 LAYOUT_RTL) 結合,如下列範例所示:
SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);
將 GDI 內容繪製至 Direct2D GDI-Compatible轉譯目標
上一節說明如何將 Direct2D 內容寫入 GDI DC。 您也可以將 GDI 內容寫入 Direct2D GDI 相容的轉譯目標。 這個方法適用于主要使用 Direct2D 轉譯但具有擴充性模型或其他需要使用 GDI 轉譯之舊版內容的應用程式。
若要將 GDI 內容轉譯為 Direct2D GDI 相容的轉譯目標,請使用 ID2D1GdiInteropRenderTarget,其可讓您存取可接受 GDI 繪製呼叫的裝置內容。 不同于其他介面,不會直接建立 ID2D1GdiInteropRenderTarget 物件。 請改用現有轉譯目標實例的 QueryInterface 方法。 下列程式碼示範如何執行這項作業:
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
// Create a GDI compatible Hwnd render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&m_pGDIRT);
}
在上述程式碼中, m_pD2DFactory 是 ID2D1Factory的指標, m_pGDIRT 是 ID2D1GdiInteropRenderTarget的指標。
請注意,建立 Hwnd GDI 相容的轉譯目標時,會指定D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE 旗標。 如果需要像素格式,請使用 DXGI_FORMAT_B8G8R8A8_UNORM。 如果需要 Alpha 模式,請使用 D2D1_ALPHA_MODE_PREMULTIPLIED 或 D2D1_ALPHA_MODE_IGNORE。
請注意 ,QueryInterface 方法一律會成功。 若要測試 ID2D1GdiInteropRenderTarget 介面的方法是否適用于指定的轉譯目標,請建立指定 GDI 相容性和適當像素格式的 D2D1_RENDER_TARGET_PROPERTIES ,然後呼叫轉譯目標的 IsSupported 方法,以查看轉譯目標是否與 GDI 相容。
下列範例示範如何將圓形圖繪製 (GDI 內容) 到 Hwnd GDI 相容的轉譯目標。
HDC hDC = NULL;
hr = m_pGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &hDC);
if (SUCCEEDED(hr))
{
// Draw the pie chart to the GDI render target associated with the Hwnd render target.
HGDIOBJ original = NULL;
original = SelectObject(
hDC,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(hDC, blackPen);
Ellipse(hDC, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(hDC, pntArray1, 2);
Polyline(hDC, pntArray2, 2);
Polyline(hDC, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(hDC, original);
m_pGDIRT->ReleaseDC(NULL);
}
程式碼會輸出圖表,如下圖所示,圖說文字以醒目提示轉譯品質差異。 右圓形圖 (GDI 內容) 轉譯品質低於左圓形圖 (Direct2D 內容) 。 這是因為 Direct2D 能夠使用反鋸齒進行轉譯
相關主題