You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#单窗体双打印机打印Bitmap异常问题求助

问题描述

我在窗体上设置了两个按钮,分别用于向PDF打印机和普通打印机打印Bitmap图像,但程序运行行为异常:

  • 有时两个按钮均正常工作;
  • 有时普通打印机打印空白,PDF打印正常;
  • 有时普通打印机无输出,PDF打印机却打印出乱码;
  • 有时PDF文件中还会出现异常artifacts。

以下是我的代码片段:

private void printBtn_Click(object sender, EventArgs e) { 
    ... 
    BmpToPrint = new Bitmap(tmp_bmp); 
    tmp_bmp.Dispose(); 
    string file = "sometext"; 
    pdoc.PrinterSettings.PrinterName = System.Configuration.ConfigurationManager.AppSettings["Printer"]; 
    pdoc.DocumentName = file; 
    pdoc.DefaultPageSettings.Landscape = false; 
    ppv.Document = pdoc; //printpreviewdialog ppv, printdocument pdoc
    printDialog1.Document = pdoc; 
    if (printDialog1.PrinterSettings.IsValid) { 
        pdoc.Print(); 
    } 
}

private void printPdfBtn_Click(object sender, EventArgs e) {
    ... 
    BmpToPrint = new Bitmap(tmp_bmp); 
    tmp_bmp.Dispose(); 
    string file = "sometext" + ".pdf"; 
    if (!Directory.Exists(directory)) { 
        directory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 
    } 
    pdoc.PrinterSettings.PrinterName = System.Configuration.ConfigurationManager.AppSettings["PdfPrinter"]; 
    pdoc.PrinterSettings.PrintToFile = true; 
    pdoc.DocumentName = file; 
    pdoc.PrinterSettings.PrintFileName = Path.Combine(directory, file); 
    pdoc.DefaultPageSettings.Landscape = false; 
    ppv.Document = pdoc; 
    printDialog1.Document = pdoc; 
    if (printDialog1.PrinterSettings.IsValid) { 
        pdoc.Print(); 
    } 
}

private void pdoc_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e) { 
    e.Graphics.Clear(Color.White); 
    Point PktWst = new Point(5, 0); 
    e.Graphics.DrawImage(BmpToPrint, PktWst); 
    e.HasMorePages = false; 
}

请问切换打印机时是否需要重置某些设置或清理相关数据?


问题分析与解决方案

你的问题核心在于重复使用同一个PrintDocument实例切换打印机时,没有彻底重置打印机相关的状态和资源,导致不同打印任务的设置相互干扰,加上Bitmap资源管理的潜在问题,引发了各种异常。下面是具体的修复步骤:

1. 每次打印任务使用独立的PrintDocument实例

不要复用同一个pdoc对象,因为PrinterSettings和DefaultPageSettings会保留上一次打印的状态,尤其是PrintToFile这类属性,在切换到普通打印机时如果没有重置,会导致打印行为异常。

修改思路:在每个按钮点击事件中创建新的PrintDocument实例,而不是复用全局的pdoc。示例代码:

private void printBtn_Click(object sender, EventArgs e) { 
    // 创建新的PrintDocument实例,using自动释放资源
    using (PrintDocument pdoc = new PrintDocument())
    {
        // 用using包裹Bitmap,确保资源正确释放
        using (Bitmap BmpToPrint = new Bitmap(tmp_bmp))
        {
            string file = "sometext"; 
            pdoc.PrinterSettings.PrinterName = System.Configuration.ConfigurationManager.AppSettings["Printer"]; 
            // 显式关闭PrintToFile,避免PDF打印的设置残留
            pdoc.PrinterSettings.PrintToFile = false;
            pdoc.DocumentName = file; 
            pdoc.DefaultPageSettings.Landscape = false; 

            // 绑定PrintPage事件,捕获当前的Bitmap实例
            pdoc.PrintPage += (s, eArgs) => {
                eArgs.Graphics.Clear(Color.White); 
                Point PktWst = new Point(5, 0); 
                eArgs.Graphics.DrawImage(BmpToPrint, PktWst); 
                eArgs.HasMorePages = false; 
            };

            printDialog1.Document = pdoc; 
            if (printDialog1.PrinterSettings.IsValid) { 
                pdoc.Print(); 
            }
        }
    }
}

private void printPdfBtn_Click(object sender, EventArgs e) {
    using (PrintDocument pdoc = new PrintDocument())
    {
        using (Bitmap BmpToPrint = new Bitmap(tmp_bmp))
        {
            string file = "sometext" + ".pdf"; 
            string directory = /* 你的目录变量 */;
            if (!Directory.Exists(directory)) { 
                directory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); 
            } 
            pdoc.PrinterSettings.PrinterName = System.Configuration.ConfigurationManager.AppSettings["PdfPrinter"]; 
            pdoc.PrinterSettings.PrintToFile = true; 
            pdoc.PrinterSettings.PrintFileName = Path.Combine(directory, file); 
            pdoc.DocumentName = file; 
            pdoc.DefaultPageSettings.Landscape = false; 

            pdoc.PrintPage += (s, eArgs) => {
                eArgs.Graphics.Clear(Color.White); 
                Point PktWst = new Point(5, 0); 
                eArgs.Graphics.DrawImage(BmpToPrint, PktWst); 
                eArgs.HasMorePages = false; 
            };

            printDialog1.Document = pdoc; 
            if (printDialog1.PrinterSettings.IsValid) { 
                pdoc.Print(); 
            }
        }
    }
}

2. 修复Bitmap资源的生命周期问题

你当前的代码中tmp_bmp.Dispose()在创建BmpToPrint后立即执行,虽然new Bitmap(tmp_bmp)会复制像素数据,但如果tmp_bmp依赖外部资源(比如从文件或GDI+对象创建),提前释放可能导致BmpToPrint异常。使用using语句包裹BmpToPrint可以确保资源被正确释放,同时避免全局变量BmpToPrint被不同打印任务覆盖。

3. 若坚持复用PrintDocument,需显式重置关键设置

如果一定要复用全局的pdoc实例,必须在每次打印前彻底重置所有可能影响打印的设置:

  • 重置PrinterSettings.PrintToFile:PDF打印设为true,普通打印设为false
  • 清空PrinterSettings.PrintFileName:避免残留的PDF路径干扰普通打印
  • 重置DefaultPageSettings:通过pdoc.DefaultPageSettings = new PageSettings();恢复默认值
  • 重新验证PrinterSettings.IsValid:设置打印机名称后再次确认有效性

4. 解决PDF打印的Artifacts问题

PDF打印机的Artifacts通常是GDI+绘图上下文状态未正确重置,或Bitmap分辨率与打印机不匹配导致的:

  • 在PrintPage事件中保存并恢复绘图上下文状态,避免后续操作影响当前打印:
private void pdoc_PrintPage(object sender, PrintPageEventArgs e) {
    // 保存当前Graphics状态,using自动恢复
    using (var state = e.Graphics.Save())
    {
        e.Graphics.Clear(Color.White);
        // 设置高质量插值模式,避免缩放失真
        e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        Point PktWst = new Point(5, 0);
        e.Graphics.DrawImage(BmpToPrint, PktWst);
        e.HasMorePages = false;
    }
}
  • 确保Bitmap的DPI与打印机DPI匹配,或绘制时指定目标尺寸而非直接使用原始Bitmap大小。

总结

最可靠的方案是每次打印任务使用独立的PrintDocument和Bitmap实例,彻底避免不同打印任务的状态干扰,同时通过using语句确保资源被正确释放。

内容的提问来源于stack exchange,提问作者Mmaa Bbaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:12:39