menu E4b9a6's blog
rss_feed
E4b9a6's blog
有善始者实繁,能克终者盖寡。

使用C#自动打印PDF文件的方案(多种方案)

作者:E4b9a6, 创建:2022-08-28, 字数:4143, 已阅:141, 最后更新:2022-08-28

这篇文章更新于 818 天前,文中部分信息可能失效,请自行甄别无效内容。

接到这个需求的时候感觉非常简单,在公司开发的浏览器中识别特定的url然后自动输出到用户一早默认设置好的打印机中,核心点在于PDF如何直接输出到打印机,以为很简单..

1. 要求

对打印的要求就是最简单的傻瓜化打印,不要预览,直接后台输出到对应打印机

2. 方案

2.1. RawPrint

安装RawPrint,在控制台输入

TEXT
Install-Package RawPrint

调用RawPrint的代码如下

C#
IPrinter printer = new Printer();
    FileStream file = File.Open(fileFullPath, FileMode.Open);
    byte[] array = new byte[file.Length];
    file.Read(array, 0, array.Length);
    printer.PrintRawStream(printerName, file, fileName);
    file.Close();
    printer.PrintRawFile(printerName, fileFullPath, fileName);

测试结果:输出到虚拟打印机也正常,但是输出到公司的真实打印机总是大小不正常,问题可能是文件没有包含打印参数,因为部分PDF又打印正常

2.2. Spire

Spire.Pdf是用C# 写的PDF组件,他并不是一个专门用来打印PDF的软件,但也包含了这个功能

Spire不是免费的,他是一个企业级产品,测试了打印功能没有任何问题,也可以做到“静默打印”,但单单为了这个功能付费..emmm

在引入Spire.License.dll和 Spire.Pdf.dll之后,可以使用下列代码进行打印测试,这两个文件并不免费,这里也不赞同使用破解版本(仅用于测试用途的破解表示理解)

C#
PdfDocument pdf = new PdfDocument(filePath);
//Set the printer
pdf.PrintSettings.PrinterName = "Microsoft Print to PDF";
pdf.Print();

2.3. PrintDocument

Windows本身也是提供API进行打印的,也可以做到静默打印

但考虑到公司Windows版本复杂,要应用在多个客户端上成功性难以保证以及调试的复杂性,选择放弃

下列代码也可以用于测试打印效果,使用Process来启动打印进程

C#
PrintDocument pd = new PrintDocument();
Process p = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
pd.PrinterSettings.PrinterName = "Microsoft Print to PDF";
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.UseShellExecute = true;
startInfo.FileName = filePath;
startInfo.Verb = "print";
startInfo.Arguments = @"/p /h \" + filePath + "\"\"" + pd.PrinterSettings.PrinterName + "\"";
p.StartInfo = startInfo;
p.Start();
p.WaitForExit();

上面的Process启动打印进程是可以使用的,但相对不是太友好

PrintDocument本身也提供打印方法的,直接调用的代码如下

C#
PrintDocument doc = new PrintDocument() {
    PrinterSettings = new PrinterSettings() {
        // set the printer to 'Microsoft Print to PDF'
        PrinterName = "Microsoft Print to PDF",
        // tell the object this document will print to file
        PrintToFile = false,
        // set the filename to whatever you like (full path)
        PrintFileName = filePath,
    }
};
doc.PrintController = new PrintControllerWithStatusDialog(new StandardPrintController());
doc.Print();

2.4. 系统打印队列

该方法一直输出空白pdf..此处仅提供方法,如有兴趣可深入研究下

TEXT
var file = File.ReadAllBytes(fileFullPath);
var printQueue = LocalPrintServer.GetDefaultPrintQueue();
using (var job = printQueue.AddJob())
using (var stream = job.JobStream) {
    stream.Write(file, 0, file.Length);
}

2.5. PdfiumViewer

PdfiumViewer是在Github上找到的项目,项目地址PdfiumViewer - github

这个项目已经停止维护了,但测试之后发现是满足“静默打印“的需求,上述其他解决方案并不是不行,多多少少要么有小毛病要么收费

最终采用PdfiumViewer这个方案,经过一段时间的测试在多个Windows版本上的适应性也非常好,没有其他问题

接下来说说安装,打开项目,转到程序包控制台,并安装如下版本(注意,指定版本是必要的)

TEXT
Install-Package PdfiumViewer -Version 2.10.0

安装完成之后,现在在你的项目中会多出一个x86和x64文件夹,里面会有pdfium.dll文件,右键该文件,选择属性,在属性栏中的复制到输出目录选择为较新则复制或者始终复制

下面是完整的示例代码,该代码在.Net Framework4.5以上版本测试没有问题

C#
public static void PrintPDF(){
    var path = @"path\file.pdf";
    using (var document = PdfDocument.Load(path))
    {
        using (var printDocument = document.CreatePrintDocument())
        {
            printDocument.PrinterSettings.PrintFileName = "pdf路径";
            printDocument.PrinterSettings.PrinterName = @"打印机名称";
            printDocument.DocumentName = "文档名称";
            printDocument.PrinterSettings.PrintFileName = "在队列中显示的文件名称";
            printDocument.PrintController = new StandardPrintController();
            printDocument.Print();
        }   
    }
}

3. 引用资料

C# - How to programmatically print an existing PDF file using PrintDocument?

How to print a PDF from your Winforms application in C#?

PrintDocument - MSDN文档


[[replyMessage== null?"发表评论":"发表评论 @ " + replyMessage.m_author]]

account_circle
email
web_asset
textsms

评论列表([[messageResponse.total]])

还没有可以显示的留言...
gravatar
[[messageItem.m_author]] [[messageItem.m_author]]
[[messageItem.create_time]]
[[getEnviron(messageItem.m_environ)]]
[[subMessage.m_author]] [[subMessage.m_author]] @ [[subMessage.parent_message.m_author]] [[subMessage.parent_message.m_author]]
[[subMessage.create_time]]
[[getEnviron(messageItem.m_environ)]]