以比屏幕分辨率更高的dpi打印表单 [英] Print a Form at higher dpi than screen resolution

查看:113
本文介绍了以比屏幕分辨率更高的dpi打印表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:



我们需要有关如何使用WinForms自动缩放到不同DPI的功能的帮助,以便我们打印



对于600dpi,而不是屏幕DPI格式。



对于看到什么就是看到什么,我们只是简单地摆放好了外窗并打印(关闭滚动条和按钮等)。除了一件事,它的效果非常好:它的输出速度为96dpi或120dpi(无论屏幕分辨率是什么)……两者看上去都不真实且不专业(我们的客户在抱怨)。而且,尽管它与屏幕上的内容一样可读,但是您希望打印的文档比在屏幕上更具可读性……您希望能够看到更多详细信息,能够阅读更小的文本,等等。



已考虑的替代方案:



鉴于我们的自动缩放功能很好,因此我们的窗口在96dpi,120dpi,144 dpi等条件下看起来都不错,我们希望我们可以以600dpi的速度绘制窗口,然后进行打印。



或者,我们查看了绘图屏幕上的窗口比正常情况大5-6倍,因此我们拥有与600dpi相同的像素数,但是像素为96或120 dpi…但是随后以300或600 dpi的分辨率将巨大的窗口绘制到打印页面上(无论打印机是什么)。



如果您可以告诉我们如何执行这些替代方法,或者可以通过其他方式实现目标,那么我们将不胜感激。



当前代码:



如果重要的话,我们的表格包括FlowLayoutPanel将其他较小的FlowLayoutPanels放置到列中,那些较小的FlowLayoutPanels放置TextBoxes,RichTextBoxes,第三方RichTextEditor,PictureBoxes和DataGridViews的单个列。我们使用从PrintDocument派生的类来实现OnBeginPrint,OnPrintPage和OnEndPrint。在OnPrintPage中,它将操纵我们正常的屏幕外窗口(在实际屏幕的下方和右侧)以适合页面大小,然后要求主面板(顶部FlowLayoutPanel)使用DrawToBitmap,然后使用传递到PrintEventArgs中的Graphics对象到DrawImage该位图。我们还使用Graphics.DrawString将页脚应用于每个页面。主要代码:

 使用(位图bm =新位图(sz.Width,sz.Height))
{
Rectangle rect = new Rectangle(0,0,sz.Width,sz.Height);
mp.DrawToBitmap(bm,rect);
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; //因此页脚是抗锯齿的
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; //因此,当我们按比例放大时,我们会稍微消除锯齿
e.Graphics.DrawImage(bm,this.MarginBounds,rect,GraphicsUnit.Pixel);
if(this.Footer!= null)
e.Graphics.DrawImage(this.Footer,this.FooterLocation);
if(!string.IsNullOrEmpty(pageNumber))
{
e.Graphics.DrawString(pageNumber,KBStyle.Normal.Font,Brushes.Black,
this.MarginBounds.X ,this.FooterLocation.Y + FooterOffset);
}
}

我们应该怎么做才能获得600dpi的打印质量页? (甚至300 dpi都很棒!)



当我们打印时,用120dpi的机器打印比用96dpi的机器打印要好得多,所以为什么我们知道它以屏幕分辨率进行打印。但是,这也让我们怀疑是否有一种简单的方法可以告诉它该表格应该以600 dpi的速度绘制,然后上面的所有其余代码都可以正常工作。



注意:如果我们使用上述代码抓取EMF(增强型图元文件)并将其打印到打印机,则该EMF的输出速度为600dpi。不幸的是,我们没有找到可以在FlowLayoutPanel而不是DrawToBitmap上调用的DrawToEMF方法。将位图更改为600dpi无济于事……DrawToBitmap方法似乎仍然以屏幕分辨率绘制位图。



谢谢!

解决方案

好的,我已经弄清楚了...而且效果很好!



我仍然不知道不知道如何创建300dpi的格式并使用自动缩放功能。



但是...



我已经证明,如果您创建的窗口比96 dpi时所需的窗口大3.125倍,并且将字体放大至3.125倍,依此类推,那么即使您的屏幕是像素数,也需要300 dpi的速度为96dpi,则可以使用正常的Control.DrawToBitmap()功能将其转换为位图,然后可以使用GDI Graphics.DrawImage(thatGiantBitmap,giantSrcRect,pageSizeDestRect)到打印机Graphics对象,它将进行映射那些巨大的96dpi像素到页面大小的300dpi像素,可为您提供300dpi的打印效果。完美。



对于我们任何支持调整大小的窗口,让我们的用户任意缩放内容,然后打印所见即所得简单:



在您的PrintDocument的 OnBeginPrint 中,执行:



(1) (可选)将表单重复放置,以免弄乱用户的视线。



(2)将要打印的表单移出屏幕(在所有页面的下方和右侧)您的屏幕)



(3)设置窗体,使其可以大于屏幕尺寸(默认情况下,WinForms不会大于屏幕尺寸)



(4)用屏幕dpi除以300 dpi以获得增长因子



(5)扩大表格按增长因子



(6)按增长因子缩放其内容(如果它们不自动缩放/不随窗体的大小自动缩放)



在PrintDocument的 OnPrintPage 中,执行以下操作:



(7)在表单中的任何控件上,您想要打印,将DrawToBitmap()转换为该控件大小的位图



(8)在e.Graphics上执行DrawImage(thatGiantBitmap,giantSrcRect,pageSizeDestRect)



如果thatGiantBitmap中有许多像素,则DrawImage调用将以打印机的分辨率绘制。在这种情况下,我计算了位图以提供300 dpi所需的像素数,因此即使打印机为600 dpi,我也将获得300 dpi的打印输出。如果您需要600 dpi的全分辨率,只需在第4步的计算中使用600 dpi。


Problem:

We need help with how to use WinForms' ability to auto-scale to different DPI’s to allow us to print our Forms at 600dpi, rather than at the screen DPI.

For What-You-See-Is-What-You-Get printing, we have been simply taking our nicely laid out window and printing it (turning off scrollbars and buttons and such). That works great EXCEPT for one thing: it comes out at 96dpi or 120dpi (whatever is the screen resolution)… either of which look grainy and unprofessional (our customers are complaining). And although it is as readable as what would be on the screen, you expect printed documents to be MORE readable than on-screen… you expect to be able to see additional details, to be able to read smaller text, etc.

Alternatives considered:

Given we have auto-scaling working great, such that our window looks good in 96dpi, 120dpi, 144 dpi, etc., we were hoping we could just draw our window at 600dpi and then print that.

OR, we looked at drawing the window off-screen 5-6x larger than normal such that we have the same number of pixels as 600dpi, but at 96 or 120 dpi… but then drawing that giant window to the printed page at 300 or 600 dpi (whatever the printer is).

If you can tell us how to do either of those alternatives, OR if you can give us a different way to accomplish our goal, then we would greatly appreciate it.

Current code:

In case it matters, our Form consists of a FlowLayoutPanel laying other smaller FlowLayoutPanels into columns, those smaller FlowLayoutPanels laying out a single column of TextBoxes, RichTextBoxes, a third-party RichTextEditor, PictureBoxes, and DataGridViews. We use a class derived from PrintDocument implementing OnBeginPrint, OnPrintPage, and OnEndPrint. In OnPrintPage, it manipulates our normal window off-screen (below and right of the actual screens) to fit the page size, then asks our main panel (the top FlowLayoutPanel) to DrawToBitmap, then uses the Graphics object passed into the PrintEventArgs to DrawImage that Bitmap. We also use Graphics.DrawString to apply a footer to each page. The main code:

                    using (Bitmap bm = new Bitmap(sz.Width, sz.Height))
                    {
                        Rectangle rect = new Rectangle(0, 0, sz.Width, sz.Height);
                        mp.DrawToBitmap(bm, rect);
                        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; // so footer is anti-aliased
                        e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;  // so when we scale up, we smooth out the jaggies somewhat
                        e.Graphics.DrawImage(bm, this.MarginBounds, rect, GraphicsUnit.Pixel);
                        if (this.Footer != null)
                            e.Graphics.DrawImage(this.Footer, this.FooterLocation);
                        if (!string.IsNullOrEmpty(pageNumber))
                        {
                            e.Graphics.DrawString(pageNumber, KBStyle.Normal.Font, Brushes.Black,
                                                  this.MarginBounds.X, this.FooterLocation.Y + FooterOffset);
                        }
                    }

How should we do this to get 600dpi to the printed page? (Or even 300 dpi would be great!)

When we print this, it looks far better when printed from a 120dpi machine than when printed from a 96dpi machine, hence why we know it is printing at screen resolution. But also makes us wonder if there’s some simple way to tell it "this Form should draw at 600 dpi" and then all the rest of the code above just works.

Note: if we grab an EMF (Enhanced Metafile) and print it to the printer in the code above, that EMF comes out at 600dpi. Unfortunately, we haven’t found a DrawToEMF method that we can call on the FlowLayoutPanel instead of DrawToBitmap. Changing the Bitmap to be 600dpi doesn’t help… the DrawToBitmap method still seems to draw the bitmap at screen resolution.

Thanks!!

解决方案

Okay, I have figured this out... and it works great!

I still don’t know how to create a form at 300dpi and use the auto-scaling functionality.

BUT…

I have proven that if you create the window 3.125x larger than needed at 96 dpi, and scale the font up 3.125x, and so on, such that everything is the pixel count you’d need to be at 300dpi, even though your screen is at 96dpi, then you can use the normal Control.DrawToBitmap() functionality to turn that into a Bitmap, and then you can use the GDI Graphics.DrawImage(thatGiantBitmap, giantSrcRect, pageSizeDestRect) to the printer Graphics object, and it will map those giant 96dpi pixels to the page-size 300dpi pixels, giving you a 300dpi print. Perfect.

For any of our windows that support resizing AND let our users zoom the contents arbitrarily, then printing What-You-See-Is-What-You-Get is easy:

In OnBeginPrint of your PrintDocument, do:

(1) Optionally dup the Form so as to not mess with what the user is looking at

(2) Move the Form you want to print off-screen (below and right of all your screens)

(3) Set the Form so that it is allowed to grow bigger than the screen size (by default WinForms won’t grow larger than the screen)

(4) Divide 300 dpi by your screen dpi to get the growth factor

(5) Grow your Form by growth factor

(6) Zoom its contents by growth factor (if they don’t auto-scale / auto-zoom with the Form’s size)

In OnPrintPage of your PrintDocument, do:

(7) On whatever Control in your Form you want to print, do DrawToBitmap() to a Bitmap the size of that Control

(8) On the e.Graphics do DrawImage(thatGiantBitmap, giantSrcRect, pageSizeDestRect)

That DrawImage call will draw at the printer’s resolution, if you have that many pixels in your thatGiantBitmap. In this case, I computed the Bitmap to give the number of pixels needed for 300 dpi, so I will get 300 dpi print-outs even if the printer is 600 dpi. If you need full 600 dpi, just use 600 dpi in step 4's calculation.

这篇关于以比屏幕分辨率更高的dpi打印表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆