Direct2D 和 GDI 互操作性概述


必备条件

此概述假设您熟悉基本的 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 的指针。

必须先使用 DC 呈现器目标的 BindDC 方法将该目标与 GDI DC 关联,然后才能使用该目标进行呈现。每次使用不同的 DC 时,或者所要绘制的区域大小发生变化时,都要执行此操作。

BindDC 方法使用两个参数:hDC 和 pSubRecthDC 参数提供一个设备上下文的句柄,该设备上下文用于接收呈现器目标的输出。pSubRect 参数是一个矩形,描述了用来呈现内容的设备上下文区域。如果 pSubRect 所描述的设备上下文区域改变了大小,DC 呈现器目标也将更新大小,以便与设备上下文区域相匹配。

下面的代码将 DC 绑定到 DC 呈现器目标。

HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);

将 DC 呈现器目标与 DC 关联后,就可以使用该 DC 进行绘制。下面的代码使用 DC 来绘制 Direct2D 和 GDI 内容。有关完整代码,请参见 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 呈现方式之间的差别。)

 

呈现到 GDI DC 的 Direct2D 和 GDI 内容

 

ID2D1DCRenderTargets、GDI 转换以及从右向左书写语言版本的 Windows

在使用 ID2D1DCRenderTarget 时,它会将把 Direct2D 内容呈现到一个内部位图,然后通过 GDI 将该位图呈现到 DC。

GDI 能够将 GDI 转换(通过 SetWorldTransform 方法)或其他效果应用于呈现器目标使用的同一 DC,在此情况下,GDI 将对 Direct2D 生成的位图进行转换。使用 GDI 转换来转换 Direct2D 内容可能会使输出的视觉质量下降,因为所转换的是已对抗锯齿和子像素定位进行计算的位图。

例如,假设您使用呈现器目标来绘制一个包含抗锯齿几何图形和文本的场景。如果使用 GDI 转换来向 DC 应用缩放转换,并对场景进行缩放以使其放大 10 倍,那么您将看到像素化和参差不齐的边缘。(但是,如果使用 Direct2D 应用类似的转换,则不会降低场景的视觉质量。)

在某些情况下,GDI 正在执行的其他处理可能会降低 Direct2D 内容的质量,但这种情况可能并不显而易见。例如,在从右向左书写语言 (RTL) 版本的 Windows 中,由ID2D1DCRenderTarget 呈现的内容可能会在 GDI 将其复制到目标时发生水平反转。内容实际上是否反转取决于 DC 的当前设置。

您可能需要防止发生这种反转,具体取决于正在呈现的内容的类型。如果 Direct2D 内容包含 ClearType 文本,则这种反转将会降低文本质量。

您可使用 SetLayout GDI 函数来控制 RTL 呈现行为。若要防止这种镜像,请调用 SetLayout GDI 函数,并将 LAYOUT_BITMAPORIENTATIONPRESERVED 指定为第二个参数的唯一值(请勿将其与 LAYOUT_RTL 组合),如以下示例所示:

SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);

将 GDI 内容绘制到与 Direct2D GDI 兼容的呈现器目标

上一部分说明如何将 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 使用 GPU,而 GDI 使用 CPU。

 

呈现到与 Direct2D GDI 兼容的呈现器目标中的 Direct2D 和 GDI 内容

 

另请参见

Direct2D/GDI 互操作示例 GDI 互操作呈现器目标示例 ID2D1Factory::CreateDCRenderTarget ID2D1DCRenderTarget ID2D1GdiInteropRenderTarget D2D1_RENDER_TARGET_PROPERTIES GDI 设备上下文 GDI SDK

 


https://msdn.microsoft.com/zh-cn/library/dd370971(v=VS.85).aspx

必备条件

此概述假设您熟悉基本的 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 的指针。

必须先使用 DC 呈现器目标的 BindDC 方法将该目标与 GDI DC 关联,然后才能使用该目标进行呈现。每次使用不同的 DC 时,或者所要绘制的区域大小发生变化时,都要执行此操作。

BindDC 方法使用两个参数:hDC 和 pSubRecthDC 参数提供一个设备上下文的句柄,该设备上下文用于接收呈现器目标的输出。pSubRect 参数是一个矩形,描述了用来呈现内容的设备上下文区域。如果 pSubRect 所描述的设备上下文区域改变了大小,DC 呈现器目标也将更新大小,以便与设备上下文区域相匹配。

下面的代码将 DC 绑定到 DC 呈现器目标。

HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);

将 DC 呈现器目标与 DC 关联后,就可以使用该 DC 进行绘制。下面的代码使用 DC 来绘制 Direct2D 和 GDI 内容。有关完整代码,请参见 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 呈现方式之间的差别。)

 

呈现到 GDI DC 的 Direct2D 和 GDI 内容

 

ID2D1DCRenderTargets、GDI 转换以及从右向左书写语言版本的 Windows

在使用 ID2D1DCRenderTarget 时,它会将把 Direct2D 内容呈现到一个内部位图,然后通过 GDI 将该位图呈现到 DC。

GDI 能够将 GDI 转换(通过 SetWorldTransform 方法)或其他效果应用于呈现器目标使用的同一 DC,在此情况下,GDI 将对 Direct2D 生成的位图进行转换。使用 GDI 转换来转换 Direct2D 内容可能会使输出的视觉质量下降,因为所转换的是已对抗锯齿和子像素定位进行计算的位图。

例如,假设您使用呈现器目标来绘制一个包含抗锯齿几何图形和文本的场景。如果使用 GDI 转换来向 DC 应用缩放转换,并对场景进行缩放以使其放大 10 倍,那么您将看到像素化和参差不齐的边缘。(但是,如果使用 Direct2D 应用类似的转换,则不会降低场景的视觉质量。)

在某些情况下,GDI 正在执行的其他处理可能会降低 Direct2D 内容的质量,但这种情况可能并不显而易见。例如,在从右向左书写语言 (RTL) 版本的 Windows 中,由ID2D1DCRenderTarget 呈现的内容可能会在 GDI 将其复制到目标时发生水平反转。内容实际上是否反转取决于 DC 的当前设置。

您可能需要防止发生这种反转,具体取决于正在呈现的内容的类型。如果 Direct2D 内容包含 ClearType 文本,则这种反转将会降低文本质量。

您可使用 SetLayout GDI 函数来控制 RTL 呈现行为。若要防止这种镜像,请调用 SetLayout GDI 函数,并将 LAYOUT_BITMAPORIENTATIONPRESERVED 指定为第二个参数的唯一值(请勿将其与 LAYOUT_RTL 组合),如以下示例所示:

SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);

将 GDI 内容绘制到与 Direct2D GDI 兼容的呈现器目标

上一部分说明如何将 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 使用 GPU,而 GDI 使用 CPU。

 

呈现到与 Direct2D GDI 兼容的呈现器目标中的 Direct2D 和 GDI 内容

 

另请参见

Direct2D/GDI 互操作示例 GDI 互操作呈现器目标示例 ID2D1Factory::CreateDCRenderTarget ID2D1DCRenderTarget ID2D1GdiInteropRenderTarget D2D1_RENDER_TARGET_PROPERTIES GDI 设备上下文 GDI SDK

 


https://msdn.microsoft.com/zh-cn/library/dd370971(v=VS.85).aspx

必备条件

此概述假设您熟悉基本的 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 的指针。

必须先使用 DC 呈现器目标的 BindDC 方法将该目标与 GDI DC 关联,然后才能使用该目标进行呈现。每次使用不同的 DC 时,或者所要绘制的区域大小发生变化时,都要执行此操作。

BindDC 方法使用两个参数:hDC 和 pSubRecthDC 参数提供一个设备上下文的句柄,该设备上下文用于接收呈现器目标的输出。pSubRect 参数是一个矩形,描述了用来呈现内容的设备上下文区域。如果 pSubRect 所描述的设备上下文区域改变了大小,DC 呈现器目标也将更新大小,以便与设备上下文区域相匹配。

下面的代码将 DC 绑定到 DC 呈现器目标。

HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);

将 DC 呈现器目标与 DC 关联后,就可以使用该 DC 进行绘制。下面的代码使用 DC 来绘制 Direct2D 和 GDI 内容。有关完整代码,请参见 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 呈现方式之间的差别。)

 

呈现到 GDI DC 的 Direct2D 和 GDI 内容

 

ID2D1DCRenderTargets、GDI 转换以及从右向左书写语言版本的 Windows

在使用 ID2D1DCRenderTarget 时,它会将把 Direct2D 内容呈现到一个内部位图,然后通过 GDI 将该位图呈现到 DC。

GDI 能够将 GDI 转换(通过 SetWorldTransform 方法)或其他效果应用于呈现器目标使用的同一 DC,在此情况下,GDI 将对 Direct2D 生成的位图进行转换。使用 GDI 转换来转换 Direct2D 内容可能会使输出的视觉质量下降,因为所转换的是已对抗锯齿和子像素定位进行计算的位图。

例如,假设您使用呈现器目标来绘制一个包含抗锯齿几何图形和文本的场景。如果使用 GDI 转换来向 DC 应用缩放转换,并对场景进行缩放以使其放大 10 倍,那么您将看到像素化和参差不齐的边缘。(但是,如果使用 Direct2D 应用类似的转换,则不会降低场景的视觉质量。)

在某些情况下,GDI 正在执行的其他处理可能会降低 Direct2D 内容的质量,但这种情况可能并不显而易见。例如,在从右向左书写语言 (RTL) 版本的 Windows 中,由ID2D1DCRenderTarget 呈现的内容可能会在 GDI 将其复制到目标时发生水平反转。内容实际上是否反转取决于 DC 的当前设置。

您可能需要防止发生这种反转,具体取决于正在呈现的内容的类型。如果 Direct2D 内容包含 ClearType 文本,则这种反转将会降低文本质量。

您可使用 SetLayout GDI 函数来控制 RTL 呈现行为。若要防止这种镜像,请调用 SetLayout GDI 函数,并将 LAYOUT_BITMAPORIENTATIONPRESERVED 指定为第二个参数的唯一值(请勿将其与 LAYOUT_RTL 组合),如以下示例所示:

SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);

将 GDI 内容绘制到与 Direct2D GDI 兼容的呈现器目标

上一部分说明如何将 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 使用 GPU,而 GDI 使用 CPU。

 

呈现到与 Direct2D GDI 兼容的呈现器目标中的 Direct2D 和 GDI 内容

 

另请参见

Direct2D/GDI 互操作示例 GDI 互操作呈现器目标示例 ID2D1Factory::CreateDCRenderTarget ID2D1DCRenderTarget ID2D1GdiInteropRenderTarget D2D1_RENDER_TARGET_PROPERTIES GDI 设备上下文 GDI SDK

 


必备条件

此概述假设您熟悉基本的 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 的指针。

必须先使用 DC 呈现器目标的 BindDC 方法将该目标与 GDI DC 关联,然后才能使用该目标进行呈现。每次使用不同的 DC 时,或者所要绘制的区域大小发生变化时,都要执行此操作。

BindDC 方法使用两个参数:hDC 和 pSubRecthDC 参数提供一个设备上下文的句柄,该设备上下文用于接收呈现器目标的输出。pSubRect 参数是一个矩形,描述了用来呈现内容的设备上下文区域。如果 pSubRect 所描述的设备上下文区域改变了大小,DC 呈现器目标也将更新大小,以便与设备上下文区域相匹配。

下面的代码将 DC 绑定到 DC 呈现器目标。

HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);

将 DC 呈现器目标与 DC 关联后,就可以使用该 DC 进行绘制。下面的代码使用 DC 来绘制 Direct2D 和 GDI 内容。有关完整代码,请参见 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 呈现方式之间的差别。)

 

呈现到 GDI DC 的 Direct2D 和 GDI 内容

 

ID2D1DCRenderTargets、GDI 转换以及从右向左书写语言版本的 Windows

在使用 ID2D1DCRenderTarget 时,它会将把 Direct2D 内容呈现到一个内部位图,然后通过 GDI 将该位图呈现到 DC。

GDI 能够将 GDI 转换(通过 SetWorldTransform 方法)或其他效果应用于呈现器目标使用的同一 DC,在此情况下,GDI 将对 Direct2D 生成的位图进行转换。使用 GDI 转换来转换 Direct2D 内容可能会使输出的视觉质量下降,因为所转换的是已对抗锯齿和子像素定位进行计算的位图。

例如,假设您使用呈现器目标来绘制一个包含抗锯齿几何图形和文本的场景。如果使用 GDI 转换来向 DC 应用缩放转换,并对场景进行缩放以使其放大 10 倍,那么您将看到像素化和参差不齐的边缘。(但是,如果使用 Direct2D 应用类似的转换,则不会降低场景的视觉质量。)

在某些情况下,GDI 正在执行的其他处理可能会降低 Direct2D 内容的质量,但这种情况可能并不显而易见。例如,在从右向左书写语言 (RTL) 版本的 Windows 中,由ID2D1DCRenderTarget 呈现的内容可能会在 GDI 将其复制到目标时发生水平反转。内容实际上是否反转取决于 DC 的当前设置。

您可能需要防止发生这种反转,具体取决于正在呈现的内容的类型。如果 Direct2D 内容包含 ClearType 文本,则这种反转将会降低文本质量。

您可使用 SetLayout GDI 函数来控制 RTL 呈现行为。若要防止这种镜像,请调用 SetLayout GDI 函数,并将 LAYOUT_BITMAPORIENTATIONPRESERVED 指定为第二个参数的唯一值(请勿将其与 LAYOUT_RTL 组合),如以下示例所示:

SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);

将 GDI 内容绘制到与 Direct2D GDI 兼容的呈现器目标

上一部分说明如何将 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 使用 GPU,而 GDI 使用 CPU。

 

呈现到与 Direct2D GDI 兼容的呈现器目标中的 Direct2D 和 GDI 内容

 

另请参见

Direct2D/GDI 互操作示例 GDI 互操作呈现器目标示例 ID2D1Factory::CreateDCRenderTarget ID2D1DCRenderTarget ID2D1GdiInteropRenderTarget D2D1_RENDER_TARGET_PROPERTIES GDI 设备上下文 GDI SDK

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值