我有一个将数据打印到打印机的应用程序。现在,我已经将字体大小硬编码为18点,计算了所有与打印相关的坐标和偏移量(对于某个18点字体),我只是打印。我这样做只是作为开发我的应用程序的基础。
现在,我希望能够根据字体大小和面部动态调整所有内容(应该是这样)。
我编写了以下测试代码,没有任何错误检查,(C)获取字体的逻辑大小:
void GetTextSize(char *input, size_t inputSize, char *fontName, size_t fontSize, SIZE *size)
{
if(input == NULL || size == NULL || fontName == NULL)
{
return;
}
else
{
HFONT hFont = NULL;
LOGFONT lf;
HDC hdc = NULL;
memset(&lf, 0, sizeof(lf));
// Get the device context of the entire screen
hdc = GetDC(NULL);
// Set the face-name
strcpy(lf.lfFaceName, fontName);
// Set the font height
lf.lfHeight = -MulDiv(fontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
// Set the font weight
lf.lfWeight = FW_NORMAL;
// Create the font
hFont = CreateFontIndirect(&lf);
// Re-associate the obtained device context with the font just created
SelectObject(hdc, hFont);
// Get the required dimensions for the text
GetTextExtentPoint32(hdc, input, inputSize, &size);
// Free resources
ReleaseDC(NULL, hdc);
DeleteObject(hFont);
hFont = NULL;
hdc = NULL;
}
}
基本上,
CreateFontIndirect
和LOGFONT
结构创建所需的字体。GetTextExtentPoint32
以逻辑单位计算字体宽度。上述代码会导致size
变量包含:cx = 241
,cy = 34
。 (我的显示器的DPI是96)
如何将这些值映射到实际打印尺寸?由于默认文本映射模式为MM_TEXT
,因此这些cx
和cy
值对应于像素。
我需要这样做有两个原因:
根据打印机的规格,每毫米的点数为8;即,DPI约为203.2。
答案 0 :(得分:1)
您的代码已经接近您需要的代码。您需要修复句柄泄漏,设备上下文在删除之前需要恢复:
HGDIOBJ hOldFont = SelectObject(hdc, hFont);
// Get the required dimensions for the text
GetTextExtentPoint32A(hdc, input, strlen(input), size);
// Free resources
SelectObject(hdc, hOldFont);
::ReleaseDC(NULL, hdc);
DeleteObject(hFont);
您接下来要做的事情很大程度上取决于您希望结果准确的方式。在屏幕上15点的字体也将在纸上15点。因此,如果您想找到适合纸张的最宽字符串,那么您将从以下网址获取:
int maxWidth = (int)(paperWidthInInches * GetDeviceCaps(hdc, LOGPIXELSX));
请注意DrawTextEx()函数如何处理在文档中拟合文本的大量繁琐工作。您需要将RECT设置为纸张大小,它会自动渲染文本以适合该矩形。您通常希望使用DT_WORDBREAK选项使其自动将文本包装在单词边界。使用DT_CALCRECT选项计算页面布局而不实际呈现文本。将更新DRAWTEXTPARAMS.uiLengthDrawn值,以告诉您在不适合页面时打印字符串的位置。
现在只需将打印机设备上下文传递给DrawTextEx(),您就可以将文本呈现给打印机了。传递从CreateDC()获得的设备上下文。 PrintDlg()函数可以让用户选择打印机。
这是个好消息。坏消息是GDI不提供真正的设备独立文本呈现。特别是对于监视器,渲染文本的宽度被巧妙地改变以固定像素网格。这提供了高度可读的文本,但在具有更高DPI的设备(例如打印机)上抛弃了布局。差异很小,只是文本行上的少数几个像素,字体越大,差异就越小。由于自动换行,这些小差异往往会在印刷文本上产生很大的差异。
为避免这种情况,您需要使用打印机设备上下文来计算页面布局。通过将RECT传递给只适合一行的DrawTextEx(),找出每一行结束的位置。你现在渲染到屏幕上的东西当然不是很完美,你需要一些肘部空间来渲染可能更宽的琴弦。 DirectWrite为真正与设备无关的文本呈现提供了一个api。