C# 打印质量winform
我在尝试从WinForms应用程序打印时遇到2个问题。第一个是一个非常非常糟糕的质量,无论我尝试什么。第二个问题是,我在左上角有一个很大的页边距,winform正在剪切。有什么想法吗?这是我的代码:C# 打印质量winform,c#,winforms,printing,C#,Winforms,Printing,我在尝试从WinForms应用程序打印时遇到2个问题。第一个是一个非常非常糟糕的质量,无论我尝试什么。第二个问题是,我在左上角有一个很大的页边距,winform正在剪切。有什么想法吗?这是我的代码: Bitmap MemoryImage; public void GetPrintArea(Panel pnl) { MemoryImage = new Bitmap(pnl.Width, pnl.Height); Rectangle rect = ne
Bitmap MemoryImage;
public void GetPrintArea(Panel pnl)
{
MemoryImage = new Bitmap(pnl.Width, pnl.Height);
Rectangle rect = new Rectangle(0, 0, pnl.Width, pnl.Height);
pnl.DrawToBitmap(MemoryImage, new Rectangle(0, 0, pnl.Width, pnl.Height));
}
protected override void OnPaint(PaintEventArgs e)
{
if (MemoryImage != null)
{
e.Graphics.DrawImage(MemoryImage, 0, 0);
base.OnPaint(e);
}
}
void printdoc1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
Rectangle pagearea = e.PageBounds;
e.Graphics.DrawImage(MemoryImage, (pagearea.Width / 2) - (this.panel1.Width / 2), this.panel1.Location.Y);
}
public void Print(Panel pnl)
{
panel1 = pnl;
GetPrintArea(pnl);
printPreviewDialog1.Document = printdoc1;
printPreviewDialog1.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
Print(this.panel1);
}
这件事一再出现。虽然问题最终可能会消失,但没有神奇的解决办法。“视网膜”显示器的出现至关重要 核心问题是显示器的分辨率比打印机差得多。典型的打印机分辨率为每英寸600点。这使得它能够在一张纸上打印6600 x 5100个像素。全高清显示器的最高分辨率为1920 x 1080像素,远远超过了显示器的显示能力。大约是差5分的一个因素 当你将显示器上显示的内容打印在一张纸上,并试图保持其大小不变时,这种方法效果不佳。不可避免地,由于显示器上缺少像素,显示器上的每一个像素都以5x5像素打印在纸上。如果你试图保持像素一对一的映射,你会在纸上得到一个锋利的副本。但它已经变成了一张邮票 不可避免地,由于这些像素点,打印输出看起来非常粗糙。看起来特别糟糕的是文本。操作系统使用许多技巧使文本在分辨率较差的显示器上看起来很好。消除混叠是标准的,像ClearType这样的技巧是为了利用监视器的物理特性来提高分辨率。当打印文本时,这不再有效,这些抗锯齿像素变成斑点,变得非常可见,完全破坏了效果。对于彩色打印机上的ClearType文本尤其糟糕,红色和蓝色的条纹现在可以清晰地看到
唯一合适的方法是使用实际分辨率而不是监视器分辨率渲染到打印机。就像在.NET中使用PrintDocument类一样。使用报表生成器有助于避免为其编写代码。您应该在打印文档打印时获得的图形对象上绘制自己。这给了你所有你需要的控制。汉斯·帕桑特所说的一切在这里同样适用。。。 请记住,这是最简单的实现,只是演示所能实现的,我并不是说这是最简单/最好/最有效的方式。。。我的代码不包含多个页面、contaimers中包含的控件或不是Label和PictureBox类型的控件 我用抽签。。。方法来自 从上面的代码中略微调整以使其正常工作:
public void GetPrintArea(Panel pnl, Graphics gr)
{
// scale to fit on width of page...
if (pnl.Width > 0)
{
gr.PageScale = gr.VisibleClipBounds.Width/pnl.Width;
}
// this should recurse...
// just for demo so kept it simple
foreach (var ctl in pnl.Controls)
{
// for every control type
// come up with a way to Draw its
// contents
if (ctl is Label)
{
var lbl = (Label)ctl;
gr.DrawString(
lbl.Text,
lbl.Font,
new SolidBrush(lbl.ForeColor),
lbl.Location.X, // simple based on the position in the panel
lbl.Location.Y);
}
if (ctl is PictureBox)
{
var pic = (PictureBox)ctl;
gr.DrawImageUnscaledAndClipped(
pic.Image,
new Rectangle(
pic.Location.X,
pic.Location.Y,
pic.Width,
pic.Height));
}
}
}
void printdoc1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality;
e.Graphics.InterpolationMode =Drawing2D.InterpolationMode.HighQualityBilinear;
e.Graphics.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality;
GetPrintArea(panel1, e.Graphics);
}
实际上,通过在“矢量”级别而不是位图级别对控件应用缩放,可以打印更清晰的控件 此快照显示以下技术的结果(请不要介意我的Win2000 ish UI:-): 我们所做的是以与rene在回答中所示非常相似的方式迭代控件的
ControlCollection
但是-此外,在我们将其位图绘制为预设大小的位图之前,我们将缩放应用于控件本身的位置、大小和字体,在本例中,预设大小的位图要大5倍(4倍表示大约300 DPI,这是大多数打印机上的有效打印分辨率)
这样做的原因是为了在打印时保持控件上的细线清晰,或者我们可以缩放位图本身,这不会给我们带来任何分辨率方面的好处。通过缩放字体,我们减少了抗锯齿效果,可以提供更好的打印质量
为此,您可以首先在按钮的单击事件设置中执行以下操作:
//this will produce 5x "sharper" print
MemoryImage = new Bitmap((Panel1.Width * 5), (Panel1.Height * 5));
Using Graphics g = Graphics.FromImage(MemoryImage) {
ScaleControls(Panel1, g, 5);
};
PrintPreviewDialog1.Document = printdoc1;
PrintPreviewDialog1.ShowDialog();
现在,在递归的ScaleControls
函数中,我们缩放位置、大小和字体,以使每个控件在绘制到位图之前具有更高的分辨率:
private void ScaleControls(Control c, ref Graphics g, double s)
{
//To detach controls for panels, groupboxes etc.
List<Control> hold = null;
foreach (Control ctrl in c.Controls) {
if (ctrl is GroupBox || ctrl is Panel) {
//backup reference to controls
hold = new List<Control>();
foreach (Control gctrl in ctrl.Controls) {
hold.Add(gctrl);
}
ctrl.Controls.Clear();
}
//backup old location, size and font (see explanation)
Point oldLoc = ctrl.Location;
Size oldSize = ctrl.Size;
Font oldFont = ctrl.Font;
//calc scaled location, size and font
ctrl.Location = new Point(ctrl.Location.X * s, ctrl.Location.Y * s);
ctrl.Size = new Size(ctrl.Size.Width * s, ctrl.Height * s);
ctrl.Font = new Font(ctrl.Font.FontFamily, ctrl.Font.Size * 5,
ctrl.Font.Style, ctrl.Font.Unit);
//draw this scaled control to hi-res bitmap
using (Bitmap bmp = new Bitmap(ctrl.Size.Width, ctrl.Size.Height)) {
ctrl.DrawToBitmap(bmp, ctrl.ClientRectangle);
g.DrawImage(bmp, ctrl.Location);
}
//restore control's geo
ctrl.Location = oldLoc;
ctrl.Size = oldSize;
ctrl.Font = oldFont;
//recursive for panel, groupbox and other controls
if (ctrl is GroupBox || ctrl is Panel) {
foreach (Control gctrl in hold) {
ctrl.Controls.Add(gctrl);
}
ScaleControls(ctrl, g, s);
}
}
}
现在,在本例中,我们在适当的位置缩放控件。当然,这并不理想,因为当我们进行打印预览时,他们似乎过着自己的生活
理想情况下,我们会在迭代时克隆每个控件,并在绘制位图后丢弃它。这也将消除备份几何图形的需要。但作为原则的例子,我还是保持原样。我将把它留给你去克隆等等
分离控件的原因是,如果我们不(就像现在的代码一样-这肯定可以通过提供另一种迭代方法来改变,即预缩放克隆控件)f.ex中的非缩放控件<代码>组框控件将首先打印,然后在迭代时,缩放的控件将显示在这些控件的顶部。这是因为在缩放其控件之前,我们将DrawToBitmap
GroupBox。这件事我会留给你处理的
我们正在处理的位图不一定要适合用户在设置打印对话框时最终得到的打印分辨率,但我们可以获得更高的分辨率,这反过来会产生比我们最初的较差屏幕位图分辨率更好的结果
您当然需要添加对其他控件的特殊情况的支持,而不是
面板
和组框
,这些控件可以容纳其他控件、图像控件等。我花了几天时间寻找一种高质量打印面板及其内容的方法。这不起作用,我尝试了其他人的代码,它们要么都是错误的,要么就是质量不好,直到我发现:
只需将eventhandler放入print按钮click事件处理程序中,并在其中包含print方法,如下所示:
private void button3_Click(object sender, EventArgs e)
{
printdoc1.PrintPage += new PrintPageEventHandler(printdoc1_PrintPage);
Print(panel1);
}
protected override void OnPaint(PaintEventArgs e)
{
if (MemoryImage != null)
{
e.Graphics.DrawImage(MemoryImage, 0, 0);
base.OnPaint(e);
}
}
并在override OnPaint方法中放置一条if语句,如下所示:
private void button3_Click(object sender, EventArgs e)
{
printdoc1.PrintPage += new PrintPageEventHandler(printdoc1_PrintPage);
Print(panel1);
}
protected override void OnPaint(PaintEventArgs e)
{
if (MemoryImage != null)
{
e.Graphics.DrawImage(MemoryImage, 0, 0);
base.OnPaint(e);
}
}
其余的都很好,你最终会得到近乎完美的打印质量
只是想分享这颗宝石,欢迎你上网
谢谢你,拉凯什先生 你能从另一个应用程序打印出高质量的图片吗;记事本或写字板有什么方法可以用
PrintScreen
来实现吗?然后检测表单位置并执行以下操作: