根据您想要的准确程度,这可能会变得很困难。
有很多方法。听起来您正在尝试绘制到打印机大小的位图,然后将其缩小。这样做的步骤是:
- 为打印机创建一个 DC(或者更好的是,一个 IC--信息上下文)。
- 查询打印机 DC 以了解分辨率、页面大小、物理偏移量等。
- 为窗口/屏幕创建一个 DC。
- 创建一个兼容的 DC(内存 DC)。
- 为窗口/屏幕创建兼容的位图,但大小应为打印机页面的像素大小。(这种方法的问题是这是一个巨大的位图,它可能会失败。)
- 选择兼容的位图到内存 DC。
- 绘制到内存 DC,使用与绘制到实际打印机相同的坐标。(当您选择字体时,请确保将它们缩放到打印机的逻辑英寸,而不是屏幕的逻辑英寸。)
StretchBlt
内存 DC 到窗口,这将缩小整个图像。您可能想尝试使用拉伸模式,看看哪种方式最适合您要显示的图像类型。
- 释放所有资源。
但在你朝那个方向前进之前,请考虑替代方案。这种方法涉及分配一个巨大的离屏位图。这在资源匮乏的计算机上可能会失败。即使没有,您也可能会饿死其他应用程序。
另一个答案中给出的元文件方法是许多应用程序的不错选择。我会从这个开始。
另一种方法是找出一些虚构的高分辨率单元中的所有尺寸。例如,假设一切都在千分之一英寸。然后,您的绘图例程会将这个假想单位缩放到目标设备使用的实际 dpi。
最后一种方法(也可能是图元文件)的问题在于 GDI 字体不能完美地线性缩放。根据目标分辨率调整单个字符的宽度。在高分辨率设备(如 300+ dpi 激光打印机)上,这种调整很少。但是在 96 dpi 的屏幕上,这些调整可能会在一行的长度上增加一个显着的错误。因此,预览窗口中的文本可能与打印页面上的文本不成比例(通常更宽)。
因此,核心方法是在打印机上下文中测量文本,然后在屏幕上下文中再次测量,并针对差异进行调整。例如(使用编造的数字),您可能会测量打印机上下文中某些文本的宽度,结果是 900 打印机像素。假设打印机像素与屏幕像素的比率为 3:1。您希望屏幕上的相同文本为 300 屏幕像素宽。但是您在屏幕上下文中进行测量,您会得到一个类似于 325 屏幕像素的值。当您绘制到屏幕上时,您必须以某种方式使文本变窄 25 像素。您可以将字符拉得更近,或者选择稍小的字体,然后将它们拉长。
硬核方法涉及更多复杂性。例如,您可能会尝试检测打印机驱动程序所做的字体替换,并尽可能将它们与可用的屏幕字体匹配。
大位图和硬核方法的混合体让我很幸运。我没有为整个页面制作一个巨大的位图,而是制作了一个足够大以容纳一行文本的位图。然后我以打印机大小绘制到屏幕外位图,StretchBlt
然后缩小到屏幕大小。这消除了在字体质量略有下降的情况下处理大小差异的问题。它适用于实际的打印预览,但您不会想要构建这样的 WYSIWYG 编辑器。单行位图足够小以使其实用。
好消息是只有文字很难。所有其他绘图都是坐标和大小的简单缩放。
我没有过多地使用 GDI+,但我认为它消除了非线性字体缩放。所以如果你使用 GDI+,你应该只需要缩放你的坐标。缺点是我不认为 GDI+ 上的字体质量那么好。
最后,如果您是 Vista 或更高版本的本机应用程序,请确保您已将您的进程标记为“ DPI-aware ”。否则,如果用户在高 DPI 屏幕上,Windows 会欺骗您并声称分辨率仅为 96 dpi,然后对您绘制的任何内容进行模糊放大。这会降低视觉质量,并使调试打印预览变得更加复杂。由于很多程序不能很好地适应更高 DPI 的屏幕,微软从 Vista 开始默认添加了“高 DPI 缩放”。
编辑添加
另一个警告:如果您使用打印机大小的位图将 HFONT 选择到内存 DC 中,则您可能会获得与在实际打印机 DC 中选择相同 HFONT 时所获得的字体不同的字体。那是因为一些打印机驱动程序会用内存中的字体替换常见的字体。例如,某些 PostScript 打印机会用内部 PostScript 字体替换某些常见的 TrueType 字体。
您可以先将 HFONT 选择到打印机 IC 中,然后使用 GDI 功能,如GetTextFace
、GetTextMetrics
,也许GetOutlineTextMetrics
可以找出实际选择的字体。然后,您可以创建一个新的 LOGFONT 以尝试更接近地匹配打印机将使用的内容,将其转换为 HFONT,然后将其选择到您的内存 DC 中。这是一个非常好的实现的标志。