我正在编写一个向用户显示文档的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视口的正确方法是什么?另外一个问题是,使用图元文件做这种工作会更好吗?
答案 0 :(得分:1)
为了将屏幕坐标映射到纸张坐标,我们需要纸张的宽度和长度。此信息位于GetDeviceCaps(hdc, PHYSICALWIDTH)
和GetDeviceCaps(hdc, PHYSICALHEIGHT)
,其中hdc
是打印机的设备上下文。我们已经在某个地方设置了屏幕坐标。
打印机无法在纸张边缘打印。我们可以从PHYSICALOFFSETX
和PHYSICALOFFSETY
获取该信息。
以下示例使用一个共同的函数paint
来完成所有绘画。 print
不做任何绘画,而是调用paint
。
这假设屏幕坐标中rc.left
和rc.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;
}