winapi - TextOutW 在屏幕和打印机上的显示不同
问题描述
我们有一个用于打印的 VB6 应用程序,目前无法在 .NET 中重写。:) 我们要解决的问题是打印的文本与 UI 预览不完全匹配。我们有一个自定义文本框控件,它分别使用 ExtTextOut 和 TextOut 来处理自己的绘画和打印。它们的输出应该是相同的,但是如果使用相同的字体,屏幕或打印机上的文本可能会更大。高度是完美的,只是间距和字符宽度不同。我还不相信这是一个字体字距调整问题,但差异确实取决于打印机 DPI 的间距和字符宽度。DPI越高,差异越大。4000 DPI 可产生更细的字符。但我可以确信我们在某个地方处理了错误的 DPI。
以下代码来自设置字体并打印一些文本的打印方面。
fntHeight = MulDiv(m_Font.SIZE, GetDeviceCaps(printerDC, LOGPIXELSY), 72)
fnt = CreateFont(-fntHeight, 0, escapement, escapement, FW_BOLD, Font.Italic, Font.Underline, _
Font.Strikethrough, Font.Charset, 0, CLIP_LH_ANGLES, FontQuality, 0, Font.Name)
SelectObject(printerDC, fnt)
TextOutW(printerDC, x, y, StrPtr(strOutputText), Len(strOutputText))
UI 的绘制代码非常相似。用户看到的问题:UI 不能很好地判断文本字段何时过小,因为如果打印机 DC 上的文本比屏幕 DC 稍宽,最后的字符(例如句点)会被截断。
这种差异随字体大小而变化,在 28 时差异为 0。它可以很容易地在 +14 和 -14 之间变化,打印或绘制的文本宽度更大。到目前为止,我一直无法找出导致 TextOut、ExtTextOut 和 GetTextExtentPoint32 给出不同结果的原因。
此代码计算差异并被绘制事件用于尝试调整间距以解决它,但如果我们能首先找出为什么存在差异会更好,因为它不能解释字符宽度差异。GetTextExtentPoints32 隐藏在对 TextWidthU 的调用之后。
' Call GetTextExtentPoint32W(hdc, StrPtr(strText), Len(strText), textSize)
printerTextWidth = TextWidthU(printerDC, strOutputText) * (screenXdpi / printerXdpi)
screenTextWidth = TextWidthU(UserControl.hdc, strOutputText)
totalDifference = printerTextWidth - screenTextWidth
解决方案
文本光栅器对齐像素边界上的所有字符。例如,字母“i”对于 96 DPI 可以有 3 个像素宽度,但对于 192 DPI,可以有 5、6 或 7 个像素宽度。如果要匹配屏幕宽度和打印机宽度,则应根据打印机分辨率计算宽度并适当调整屏幕位置。
您可以调整单个字母、整个单词的位置,或按原样保留屏幕布局,但根据打印机文本大小剪切或扩展右边距。
MS Word 调整字母位置(观察字母之间的空间):
有趣的起点: http ://www.antigrain.com/research/font_rasterization/index.html#FONT_RASTERIZATION
推荐阅读
- unity3d - ui.inputfield 可以将来自文本框和输入的数据相互重叠显示吗?
- google-app-engine - 在服务 3 个请求后,超过了 532 MB 的软内存限制 512 MB。考虑在 app.yaml 中设置更大的实例类
- flutter - 如何在单个页面上制作多个小部件并在它们之间转换
- python - 特定索引 Numpy 数组中的 Python Reapt 值
- c# - 如何使用反射为数组字段和字典设置值?
- android - React Native 错误:尝试通过调用 firebase.firestore() 使用未安装在您的 Android 项目上的 firebase 模块
- javascript - 促销代码激活表问题
- java - 我正在研究一个数组的基本排序算法,尽管解决方案有效,但我并不完全理解
- php - 在 WooCommerce 中提供免费送货时隐藏特定的送货方式
- javascript - Google Apps 脚本日历服务:仅获取所有重复(全天)事件的第一个事件