Windows - GDI - 将屏幕DC缩放到打印机DC而不修改绘制功能

时间:2017-12-04 22:21:25

标签: windows printing scale viewport gdi

我正在编写一个向用户显示文档的Windows应用程序。内容使用GDI函数绘制,并且所有内容都在屏幕上显示为预期。

现在我要打印这份文件。我得到一个打印机设备上下文,我做的与我在屏幕上完全相同。当然,打印内容在打印页面的顶部看起来很小。这种行为的原因对我来说很清楚,这里有充分说明:

https://www.codeproject.com/Articles/764057/GDI-Drawing-and-Printing

所以我需要在我的打印机DC上添加一个缩放视口,并且有几个功能可以在GDI中实现。但是我对如何配置这些功能感到有点困惑。我尝试了在互联网上找到的各种例子,但没有一个能为我工作。

我的屏幕分辨率为1920x1080像素,我正在尝试在A4纵向页面上打印。我测试了各种配置,我发现适合打印页面的最佳近似值如下:

::SetMapMode(hDC, MM_ISOTROPIC);
::SetWindowExtEx(hDC, 1, 1, NULL);
::SetViewportExtEx(hDC, 5, 5, NULL);
::SetViewportOrgEx(hDC, -10200, 0, NULL);

由于屏幕和打印配置当然可以在其他PC上更改,我需要知道如何计算上述值,但我找不到适用于我的情况的公式。特别是我不知道为什么我需要使用SetViewportOrgEx()函数来缩放我的画布原点,没有人在我阅读的文档中提到过。

考虑到:

,计算我的打印DC视口的正确方法是什么?
  • 完全相同的绘画功能将用于屏幕和打印机绘图,我将永远不会编写不同的功能来在屏幕和打印机上打印
  • 屏幕和打印机设备可能完全由用户配置,但打印结果应始终适合屏幕和打印机上的文档

另外一个问题是,使用图元文件做这种工作会更好吗?

1 个答案:

答案 0 :(得分:1)

为了将屏幕坐标映射到纸张坐标,我们需要纸张的宽度和长度。此信息位于GetDeviceCaps(hdc, PHYSICALWIDTH)GetDeviceCaps(hdc, PHYSICALHEIGHT),其中hdc是打印机的设备上下文。我们已经在某个地方设置了屏幕坐标。

打印机无法在纸张边缘打印。我们可以从PHYSICALOFFSETXPHYSICALOFFSETY获取该信息。

以下示例使用一个共同的函数paint来完成所有绘画。 print不做任何绘画,而是调用paint

这假设屏幕坐标中rc.leftrc.right(0,0)

void paint(HDC hdc, RECT rc)
{
    HBRUSH brush = GetSysColorBrush(COLOR_WINDOWTEXT);
    InflateRect(&rc, -10, -10);
    FrameRect(hdc, &rc, brush);
    DrawText(hdc, L"hello world", -1, &rc, 0);
}

void print(HWND hWnd, RECT rc)
{
    PRINTDLG pd = { sizeof(pd) };
    pd.hwndOwner = hWnd;
    pd.Flags = PD_RETURNDC;
    if(!PrintDlg(&pd))
        return;

    HDC hdc = pd.hDC;
    DOCINFO doc = { sizeof(doc) };
    StartDoc(hdc, &doc);
    StartPage(hdc);
    SetMapMode(hdc, MM_ISOTROPIC);
    SetWindowExtEx(hdc, rc.right, rc.bottom, NULL);
    SetViewportExtEx(hdc, 
      GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT), NULL);
    SetViewportOrgEx(hdc,
      -GetDeviceCaps(hdc, PHYSICALOFFSETX), -GetDeviceCaps(hdc, PHYSICALOFFSETY), NULL);

    paint(hdc, rc);

    EndPage(hdc);
    EndDoc(hdc);
    DeleteObject(hdc);
}

测试:

case WM_PAINT:
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    RECT rc;
    GetClientRect(hwnd, &rc);
    paint(hdc, rc);
    EndPaint(hwnd, &ps);
    break;
}

case WM_LBUTTONDOWN:
{
    RECT rc;
    GetClientRect(hwnd, &rc);
    print(hwnd, rc);
    break;
}