简体   繁体   English

如何在win32 c ++中打印预览?

[英]how do I do print preview in win32 c++?

I have a drawing function that just takes an HDC. 我有一个绘图功能,只需要一个HDC。 But I need to show an EXACT scaled version of what will print. 但是我需要展示一个精确版本的打印版本。

So currently, I use CreateCompatibleDC() with a printer HDC and CreateCompatibleBitmap() with the printer's HDC. 所以目前,我使用带有打印机HDC的CreateCompatibleDC()和带有打印机HDC的CreateCompatibleBitmap()。

I figure this way the DC will have the printer's exact width and height. 我这样想DC会有打印机的确切宽度和高度。 And when I select fonts into this HDC, the text will be scaled exactly as the printer would. 当我在这个HDC中选择字体时,文本将与打印机完全一样。

Unfortunately, I can't to a StretchBlt() to copy this HDC's pixels to the control's HDC since they're of different HDC types I guess. 不幸的是,我不能让StretchBlt()将这个HDC的像素复制到控件的HDC中,因为我猜它们是不同的HDC类型。

If I create the "memory canvas" from a window HDC with same w,h as the printer's page, the fonts come out WAY teeny since they're scaled for the screen, not page... 如果我从具有相同w,h和打印机页面的HDC窗口创建“内存画布”,那么这些字体会因为缩放屏幕而不是页面而显示出来。

Should I CreateCompatibleDC() from the window's DC and CreateCompatibleBitmap() from the printer's DC or something?? 我应该从窗口的DC和CreateCompatibleBitmap()创建CompatibleDC()来自打印机的DC还是什么?

If somebody could explain the RIGHT way to do this. 如果有人可以解释这样做的正确方法。 (And still have something that looks EXACTLY as it would on printer)... (并且仍然有像打印机那样看起来很完美的东西)......

Well, I'd appreciate it !! 好吧,我很感激!!

...Steve ...史蒂夫

Depending on how accurate you want to be, this can get difficult. 根据您想要的准确程度,这可能会变得困难。

There are many approaches. 有很多方法。 It sounds like you're trying to draw to a printer-sized bitmap and then shrink it down. 听起来你正试图绘制一个打印机大小的位图,然后缩小它。 The steps to do that are: 这样做的步骤是:

  1. Create a DC (or better yet, an IC--Information Context) for the printer. 为打印机创建DC(或更好的IC,信息上下文)。
  2. Query the printer DC to find out the resolution, page size, physical offsets, etc. 查询打印机DC以查找分辨率,页面大小,物理偏移等。
  3. Create a DC for the window/screen. 为窗口/屏幕创建DC。
  4. Create a compatible DC (the memory DC). 创建兼容的DC(内存DC)。
  5. Create a compatible bitmap for the window/screen, but the size should be the pixel size of the printer page. 为窗口/屏幕创建兼容的位图,但大小应该是打印机页面的像素大小。 (The problem with this approach is that this is a HUGE bitmap and it can fail.) (这种方法的问题是这是一个巨大的位图,它可能会失败。)
  6. Select the compatible bitmap into the memory DC. 在存储器DC中选择兼容的位图。
  7. Draw to the memory DC, using the same coordinates you would use if drawing to the actual printer. 绘制到内存DC,使用与绘制到实际打印机时相同的坐标。 (When you select fonts, make sure you scale them to the printer's logical inch, not the screen's logical inch.) (当您选择字体时,请确保将它们缩放到打印机的逻辑英寸,而不是屏幕的逻辑英寸。)
  8. StretchBlt the memory DC to the window, which will scale down the entire image. StretchBlt内存DC到窗口,这将缩小整个图像。 You might want to experiment with the stretch mode to see what works best for the kind of image you're going to display. 您可能希望尝试拉伸模式,以查看哪种图像最适合您要显示的图像。
  9. Release all the resources. 释放所有资源。

But before you head in that direction, consider the alternatives. 但在你走向这个方向之前,请考虑其他选择。 This approach involves allocating a HUGE off-screen bitmap. 这种方法涉及分配一个巨大的屏幕外位图。 This can fail on resource-poor computers. 这可能会在资源匮乏的计算机上失败。 Even if it doesn't, you might be starving other apps. 即使它没有,你可能会饿死其他应用程序。

The metafile approach given in another answer is a good choice for many applications. 另一个答案中给出的元文件方法对于许多应用程序来说是一个很好的选择 I'd start with this. 我从这开始。

Another approach is to figure out all the sizes in some fictional high-resolution unit. 另一种方法是在一些虚构的高分辨率单元中找出所有尺寸。 For example, assume everything is in 1000ths of an inch. 例如,假设一切都在千分之一英寸。 Then your drawing routines would scale this imaginary unit to the actual dpi used by the target device. 然后,您的绘图例程会将此虚构单位缩放到目标设备使用的实际dpi。

The problem with this last approach (and possibly the metafile one) is that GDI fonts don't scale perfectly linearly. 最后一种方法(可能还有元文件)的问题在于GDI字体不能完全线性扩展。 The widths of individual characters are tweaked depending on the target resolution. 根据目标分辨率调整各个字符的宽度。 On a high-resolution device (like a 300+ dpi laser printer), this tweaking is minimal. 在高分辨率设备(如300+ dpi激光打印机)上,这种调整很少。 But on a 96-dpi screen, the tweaks can add up to a significant error over the length of a line. 但是在96-dpi的屏幕上,调整可能会在一条线的长度上产生明显的误差。 So text in your preview window might appear out-of-proportion (typically wider) than it does on the printed page. 因此,预览窗口中的文本可能与打印页面上的文本不成比例(通常更宽)。

Thus the hardcore approach is to measure text in the printer context, and measure again in the screen context, and adjust for the discrepancy. 因此,硬核方法是在打印机上下文中测量文本,并在屏幕上下文中再次测量,并调整差异。 For example (using made-up numbers), you might measure the width of some text in the printer context, and it comes out to 900 printer pixels. 例如(使用虚拟数字),您可以测量打印机上下文中某些文本的宽度,它可以达到900个打印机像素。 Suppose the ratio of printer pixels to screen pixels is 3:1. 假设打印机像素与屏幕像素的比率为3:1。 You'd expect the same text on the screen to be 300 screen pixels wide. 您希望屏幕上的相同文本宽度为300像素。 But you measure in the screen context and you get a value like 325 screen pixels. 但是你在屏幕上下文中测量,你得到一个像325屏幕像素的值。 When you draw to the screen, you'll have to somehow make the text 25 pixels narrower. 当您绘制到屏幕时,您必须以某种方式使文本缩小25像素。 You can ram the characters closer together, or choose a slightly smaller font and then stretch them out. 您可以将字符拉近,或选择稍小的字体,然后将其拉伸。

The hardcore approach involves more complexity. 硬核方法涉及更多复杂性。 You might, for example, try to detect font substitutions made by the printer driver and match them as closely as you can with the available screen fonts. 例如,您可能会尝试检测打印机驱动程序所做的字体替换,并尽可能与可用的屏幕字体进行匹配。

I've had good luck with a hybrid of the big-bitmap and the hardcore approaches. 我很喜欢大位图和硬核方法的混合体。 Instead of making a giant bitmap for the whole page, I make one large enough for a line of text. 我没有为整个页面创建一个巨大的位图,而是为一行文本创建了一个足够大的位图。 Then I draw at printer size to the offscreen bitmap and StretchBlt it down to screen size. 然后,我在画打印机尺寸屏幕外的位图和StretchBlt下来到屏幕大小。 This eliminates dealing with the size discrepancy at a slight degradation of font quality. 这消除了在略微降低字体质量时处理尺寸差异。 It's suitable for actual print preview, but you wouldn't want to build a WYSIWYG editor like that. 它适用于实际的打印预览,但您不希望像这样构建WYSIWYG编辑器。 The one-line bitmap is small enough to make this practical. 单行位图足够小,可以实现这一点。

The good news is only text is hard. 好消息是文字很难。 All other drawing is a simple scaling of coordinates and sizes. 所有其他绘图都是坐标和大小的简单缩放。

I've not used GDI+ much, but I think it did away with non-linear font scaling. 我没有太多使用GDI +,但我认为它取消了非线性字体缩放。 So if you're using GDI+, you should just have to scale your coordinates. 因此,如果您使用的是GDI +,则只需缩放坐标即可。 The drawback is that I don't think the font quality on GDI+ is as good. 缺点是我不认为GDI +上的字体质量一样好。

And finally, if you're a native app on Vista or later, make sure you've marked your process as " DPI-aware " . 最后,如果您是Vista或更高版本的本机应用程序,请确保您已将您的流程标记为“支持DPI ”。 Otherwise, if the user is on a high-DPI screen, Windows will lie to you and claim that the resolution is only 96 dpi and then do a fuzzy up-scaling of whatever you draw. 否则,如果用户处于高DPI屏幕上,Windows将对您撒谎并声称分辨率仅为96 dpi,然后对您绘制的任何内容进行模糊放大。 This degrades the visual quality and can make debugging your print preview even more complicated. 这会降低视觉质量,并使调试打印预览变得更加复杂。 Since so many programs don't adapt well to higher DPI screens, Microsoft added "high DPI scaling" by default starting in Vista. 由于许多程序无法很好地适应更高的DPI屏幕,因此微软默认在Vista中添加了“高DPI缩放”。

Edited to Add 编辑添加

Another caveat: If you select an HFONT into the memory DC with the printer-sized bitmap, it's possible that you get a different font than what would get when selecting that same HFONT into the actual printer DC. 另一个警告:如果您使用打印机大小的位图选择HFONT到内存DC中,则可能会获得与在实际打印机DC中选择相同的HFONT时所获得的字体不同的字体。 That's because some printer drivers will substitute common fonts with in memory ones. 这是因为某些打印机驱动程序会将常用字体替换为内存字体。 For example, some PostScript printers will substitute an internal PostScript font for certain common TrueType fonts. 例如,某些PostScript打印机会将内部PostScript字体替换为某些常见的TrueType字体。

You can first select the HFONT into the printer IC, then use GDI functions like GetTextFace , GetTextMetrics , and maybe GetOutlineTextMetrics to find out about the actual font selected. 您可以先将HFONT选择到打印机IC中,然后使用GDI函数(如GetTextFaceGetTextMetricsGetOutlineTextMetrics来查找所选的实际字体。 Then you can create a new LOGFONT to try to more closely match what the printer would use, turn that into an HFONT, and select that into your memory DC. 然后,您可以创建一个新的LOGFONT,以尝试更紧密地匹配打印机将使用的内容,将其转换为HFONT,并将其选择到您的内存DC中。 This is the mark of a really good implementation. 这是一个非常好的实现的标志。

One thing that might be worth trying is to create an enhanced metafile DC, draw to it as normal and then scale this metafile using printer metrics. 可能值得尝试的一件事是创建增强的图元文件DC,正常绘制它,然后使用打印机指标缩放此图元文件。 This is the approach used by the WTL BmpView sample - I don't know how accurate this will be but it might be worth looking at (it should be easy to port the relevant classes to Win32 but WTL is a great replacement for Win32 programming so might be worth utilizing.) 这是WTL BmpView示例使用的方法 - 我不知道这将是多么准确,但它可能值得一看(将相关类移植到Win32应该很容易,但WTL是Win32编程的一个很好的替代品,所以可能值得利用。)

Well it won't look the same because you have a higher resolution in the printer DC, so you'll have to write a conversion function of sorts. 好吧它看起来不一样,因为你在打印机DC中有更高的分辨率,所以你必须编写各种转换函数。 I'd go with the method that you got to work but the text was too small and just multiply every position/font size by the printer window width and divide by the source window width. 我会使用你必须工作的方法,但文本太小,只是将每个位置/字体大小乘以打印机窗口宽度并除以源窗口宽度。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM