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