GDI - 在打印机设备上下文中使用时,剪辑不起作用

时间:2018-01-29 22:26:56

标签: printing gdi+ gdi clipping device-context

我正在使用Embarcadero RAD Studio C ++构建器XE7编译器。在应用程序项目中,我使用Windows GDI和GDI +来绘制多个设备上下文。

我的绘图内容是这样的:

enter image description here

在上面的示例中,文本背景和用户图片是用GDI +绘制的。用户图片也被剪切为圆形路径。所有其他项目(文本和表情符号)都是使用GDI绘制的。

当我画到屏幕DC时,一切正常。

现在我想在打印机设备上下文中绘图。无论我用于我的测试的是新的"导出到PDF" Windows 10中提供的打印机设备。我准备设备上下文以这种方式在A4视口上绘图:

HDC GetPrinterDC(HWND hWnd) const
{
    // initialize the print dialog structure, set PD_RETURNDC to return a printer device context
    ::PRINTDLG pd  = {0};
    pd.lStructSize = sizeof(pd);
    pd.hwndOwner   = hWnd;
    pd.Flags       = PD_RETURNDC;

    // get the printer DC to use
    ::PrintDlg(&pd);

    return pd.hDC;
}

...

void Print()
{
    HDC hDC = NULL;

    try
    {
        hDC = GetPrinterDC(Application->Handle);

        const TSize srcPage(793, 1123);
        const TSize dstPage(::GetDeviceCaps(hDC, PHYSICALWIDTH), ::GetDeviceCaps(hDC, PHYSICALHEIGHT));
        const TSize pageMargins(::GetDeviceCaps(hDC, PHYSICALOFFSETX), ::GetDeviceCaps(hDC, PHYSICALOFFSETY));

        ::SetMapMode(hDC, MM_ISOTROPIC);
        ::SetWindowExtEx(hDC, srcPage.Width, srcPage.Height, NULL);
        ::SetViewportExtEx(hDC, dstPage.Width, dstPage.Height,  NULL);
        ::SetViewportOrgEx(hDC, -pageMargins.Width, -pageMargins.Height, NULL);

        ::DOCINFO di = {sizeof(::DOCINFO), config.m_FormattedTitle.c_str()};

        ::StartDoc (hDC, &di);

        // ... the draw function is executed here ...

        ::EndDoc(hDC);
        return true;
    }
    __finally
    {
        if (hDC)
            ::DeleteDC(hDC);
    }
}

在StartDoc()和EndDoc()函数之间执行的绘制函数与我在屏幕上绘制的绘图函数完全相同。唯一的区别是我在整个页面上添加了一个全局剪切矩形,以避免当尺寸太大时绘图重叠在页边距上,例如当我在第一张图片下重复几次上面的图画时。 (这是实验性的,稍后我会添加一个页面切割过程,但这不是现在的问题)

以下是剪辑功能:

int Clip(const TRect& rect, HDC hDC)
{
    // save current device context state
    int savedDC = ::SaveDC(hDC);

    HRGN pClipRegion = NULL;

    try
    {
        // reset any previous clip region
        ::SelectClipRgn(hDC, NULL);

        // create clip region
        pClipRegion = ::CreateRectRgn(rect.Left, rect.Top, rect.Right, rect.Bottom);

        // select new canvas clip region
        if (::SelectClipRgn(hDC, pClipRegion) == ERROR)
        {
            DWORD error = ::GetLastError();
            ::OutputDebugString(L"Unable to select clip region - error - " << ::IntToStr(error));
        }
    }
    __finally
    {
        // delete clip region (it was copied internally by the SelectClipRgn())
        if (pClipRegion)
            ::DeleteObject(pClipRegion);
    }

    return savedDC;
}

void ReleaseClip(int savedDC, HDC hDC)
{
    if (!savedDC)
        return;

    if (!hDC)
        return;

    // restore previously saved device context
    ::RestoreDC(hDC, savedDC);
}

如上所述,我期望在我的页面周围剪辑。但结果只是一个空白页面。如果我绕过裁剪功能,则所有内容都会正确打印,但绘图可能会在页边距上重叠。另一方面,如果我在屏幕上的任意矩形上应用剪辑,一切正常。

我的剪辑错误了什么?我启用它时为什么页面完全被破坏了?

1 个答案:

答案 0 :(得分:0)

所以我发现了什么问题。尼基接近解决方案。剪切函数似乎始终以像素为单位应用于页面,忽略坐标系和视口定义的单位。

在我的情况下,传递给CreateRectRgn()函数的值是错误的,因为它们保持未被视口转换,尽管在设备上下文中设置视口后应用了剪辑。

这使问题的识别变得困难,因为剪辑在读取代码时显示为已转换,因为它在视口之后应用,就在处理图形之前。

我不知道这是一个GDI错误还是一个希望的行为,但不幸的是我从来没有看到我读到的有关剪辑的所有文档中提到的这个细节。虽然我觉得裁剪不受视口的影响似乎很重要。