9

我有一个只需要 HDC 的绘图功能。但我需要显示将要打印的内容的精确缩放版本。

所以目前,我将 CreateCompatibleDC() 与打印机 HDC 一起使用,并将 CreateCompatibleBitmap() 与打印机的 HDC 一起使用。

我认为这样 DC 将具有打印机的确切宽度和高度。当我在这个 HDC 中选择字体时,文本将完全按照打印机的方式缩放。

不幸的是,我无法使用 StretchBlt() 将此 HDC 的像素复制到控件的 HDC,因为我猜它们属于不同的 HDC 类型。

如果我从具有与打印机页面相同的 w,h 的窗口 HDC 创建“内存画布”,则字体会变得很小,因为它们是针对屏幕而不是页面缩放的...

我应该从窗口的 DC 中 CreateCompatibleDC() 和从打印机的 DC 中的 CreateCompatibleBitmap() 还是什么?

如果有人可以解释这样做的正确方法。(并且仍然有一些看起来与打印机上完全相同的东西)......

好吧,我会很感激的!

...史蒂夫

4

3 回答 3

10

根据您想要的准确程度,这可能会变得很困难。

有很多方法。听起来您正在尝试绘制到打印机大小的位图,然后将其缩小。这样做的步骤是:

  1. 为打印机创建一个 DC(或者更好的是,一个 IC--信息上下文)。
  2. 查询打印机 DC 以了解分辨率、页面大小、物理偏移量等。
  3. 为窗口/屏幕创建一个 DC。
  4. 创建一个兼容的 DC(内存 DC)。
  5. 为窗口/屏幕创建兼容的位图,但大小应为打印机页面的像素大小。(这种方法的问题是这是一个巨大的位图,它可能会失败。)
  6. 选择兼容的位图到内存 DC。
  7. 绘制到内存 DC,使用与绘制到实际打印机相同的坐标。(当您选择字体时,请确保将它们缩放到打印机的逻辑英寸,而不是屏幕的逻辑英寸。)
  8. StretchBlt内存 DC 到窗口,这将缩小整个图像。您可能想尝试使用拉伸模式,看看哪种方式最适合您要显示的图像类型。
  9. 释放所有资源。

但在你朝那个方向前进之前,请考虑替代方案。这种方法涉及分配一个巨大的离屏位图。这在资源匮乏的计算机上可能会失败。即使没有,您也可能会饿死其他应用程序。

另一个答案中给出的元文件方法是许多应用程序的不错选择。我会从这个开始。

另一种方法是找出一些虚构的高分辨率单元中的所有尺寸。例如,假设一切都在千分之一英寸。然后,您的绘图例程会将这个假想单位缩放到目标设备使用的实际 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 功能,如GetTextFaceGetTextMetrics,也许GetOutlineTextMetrics可以找出实际选择的字体。然后,您可以创建一个新的 LOGFONT 以尝试更接近地匹配打印机将使用的内容,将其转换为 HFONT,然后将其选择到您的内存 DC 中。这是一个非常好的实现的标志。

于 2010-02-11T00:25:50.453 回答
3

可能值得尝试的一件事是创建一个增强的元文件 DC,正常绘制它,然后使用打印机指标缩放这个元文件。这是WTL BmpView 示例使用的方法 - 我不知道这将有多准确,但它可能值得一看(将相关类移植到 Win32 应该很容易,但 WTL 是 Win32 编程的一个很好的替代品,所以可能值得使用。)

于 2010-02-10T22:15:23.587 回答
2

好吧,它看起来不一样,因为您在打印机 DC 中具有更高的分辨率,因此您必须编写某种转换函数。我会采用您必须工作的方法,但文本太小,只需将每个位置/字体大小乘以打印机窗口宽度并除以源窗口宽度即可。

于 2010-02-10T21:00:40.087 回答