简体   繁体   English

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

[英]GDI - Clipping is not working when used on a printer device context

I'm using the Embarcadero RAD Studio C++ builder XE7 compiler. 我正在使用Embarcadero RAD Studio C ++构建器XE7编译器。 In an application project, I'm using the both Windows GDI and GDI+ to draw on several device contexts. 在一个应用程序项目中,我同时使用Windows GDI和GDI +来绘制多个设备上下文。

My drawing content is something like that: 我的绘图内容是这样的:

在此处输入图片说明

On the above sample the text background and the user picture are drawn with GDI+. 在上面的示例中,使用GDI +绘制了文本背景和用户图片。 The user picture is also clipped with a rounded path. 用户图片也用圆角路径裁剪。 All the other items (the text and the emojis) are drawn with the GDI. 所有其他项目(文本和表情符号)均使用GDI绘制。

When I draw to the screen DC, all works fine. 当我绘制到屏幕DC时,一切正常。

Now I want to draw on a printer device context. 现在,我想在打印机设备上下文中进行绘制。 Whichever I use for my tests is the new "Export to PDF" printer device available in Windows 10. I prepare my device context to draw on an A4 viewport this way: 我测试使用的是Windows 10中可用的新“导出为PDF”打印机设备。我准备设备上下文以这种方式在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);
    }
}

The draw function executed between the StartDoc() and EndDoc() functions is exactly the same as whichever I use to draw on the screen. 在StartDoc()和EndDoc()函数之间执行的绘制函数与我在屏幕上绘制所使用的函数完全相同。 The only difference is that I added a global clipping rect on my whole page, to avoid the drawing to overlaps on the page margins when the size is too big, eg when I repeat the above drawing several times under the first one. 唯一的不同是,我在整个页面上添加了一个全局剪切矩形,以避免在尺寸过大时(例如,在第一个图形下重复上述图形几次时)在页边距上重叠图形。 (This is experimental, later I will add a page cutting process, but this is not the question for now) (这是实验性的,稍后我将添加页面剪切过程,但这不是现在的问题)

Here are my clipping functions: 这是我的剪辑功能:

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);
}

As mentioned above, I expected a clipping around my page. 如前所述,我希望页面周围有剪裁。 However the result is just a blank page. 但是结果只是空白页。 If I bypass the clipping functions, all is printed correctly, except that the draw may overlap on the page margins. 如果我跳过了剪切功能,则所有打印都将正确打印,但绘图可能会在页边距上重叠。 On the other hands, if I apply the clipping on an arbitrary rect on my screen, all works fine. 另一方面,如果将剪辑应用于屏幕上的任意矩形,则一切正常。

What I'm doing wrong with my clipping? 我的剪辑做错了什么? Why the page is completely broken when I enables it? 为什么启用该页面后,页面会完全损坏?

So I found what was the issue. 所以我发现了问题所在。 Niki was close to the solution. Niki接近解决方案。 The clipping functions seem always applied to the page in pixels, ignoring the coordinate system and the units defined by the viewport. 裁剪功能似乎总是以像素为单位应用于页面,而忽略了坐标系统和视口定义的单位。

In my case, the values passed to the CreateRectRgn() function were wrong, because they remained untransformed by the viewport, although the clipping was applied after the viewport was set in the device context. 在我的案例中,传递给CreateRectRgn()函数的值是错误的,因为尽管在设备上下文中设置了视口之后才应用了裁剪,但视口仍未对其进行转换。

This turned the identification of the issue difficult, because the clipping appeared as transformed while the code was read, as it was applied after the viewport, just before the drawing was processed. 这就使问题的识别变得困难,因为在处理代码之前,在视口之后,即在处理图形之前,应用了剪裁,因此在读取代码时剪裁显示为已转换。

I don't know if this is a GDI bug or a wished behavior, but unfortunately I never seen this detail mentioned in all the documents I read about the clipping. 我不知道这是GDI错误还是期望的行为,但是不幸的是,在我阅读的所有有关剪裁的文档中,我从未看到过此细节。 Although it seems to me important to know that the clipping isn't affected by the viewport. 尽管在我看来重要的是要知道裁剪不受视口的影响。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM