前言
最近开发客户端的时候,用户提出了要增加打印PDF文件的需求,于是我各种翻官网和CSDN,然而好像还没有人总结得特别全,于是自己记录一下这几天的研究吧。
目前发现的有以下四种方式调用打印服务:
- 使用创建新进程的方式打印
- 使用WPF命名空间下的打印接口打印
- 使用WinForm命名空间下的打印接口打印
- 使用第三方PDF组件打印
使用创建新进程的方式打印
参考代码
using System.Diagnostics;namespace Process打印
{class Program{static void Main(string[] args){Process process = new Process();bool canPrint = false;string[] verbs = null;process.StartInfo.FileName = @"D:\test1.pdf";verbs = process.StartInfo.Verbs;for (int i = 0; i < verbs.Length; i++){if (verbs[i] == "Print"){canPrint = true;}}if (canPrint){process.StartInfo.UseShellExecute = true;process.StartInfo.CreateNoWindow = true;process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;process.StartInfo.Verb = "Print";process.Start();}}}
}
缺点说明:除了使用"Printto"操作可以指定打印机外,不能指定其他参数*(实际上可以程序传入一些参数,但没有更多资料无法继续研究);不能弹出打印机设置界面;以PDF文件为例,需要设置“对”默认打开程序,如Adobe Acrobat 或者Adobe Reader 是可以调用打印服务的,但如果是其他阅读器或者浏览器则会报错没有对应进程与之关联。
StartInfo的类说明文档:https://learn.microsoft.com/zh-cn/dotnet/api/system.diagnostics.processstartinfo?view=net-7.0
使用WPF命名空间下的打印接口打印
参考代码
<Window x:Class="WPFPrintTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WPFPrintTest"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><Button Content="点击展示打印设置窗口" HorizontalAlignment="Left" Height="56" Margin="21,24,0,0" VerticalAlignment="Top" Width="145" Click="InvokePrint"/><ComboBox Name ="PrinterList" HorizontalAlignment="Left" Height="25" Margin="276,175,0,0" VerticalAlignment="Top" Width="158" SelectionChanged="PrinterList_SelectionChanged"/><Button Content="点击使用上方设置进行打印" HorizontalAlignment="Left" Margin="276,216,0,0" VerticalAlignment="Top" Width="158" Height="56" Click="Button_Click"/></Grid>
</Window>
using System;
using System.Collections;
using System.IO;
using System.Printing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Xps.Packaging;namespace WPFPrintTest
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{object selectedItem = null;static PrintServer printServer = new PrintServer();PrintQueueCollection printqueen = printServer.GetPrintQueues();public MainWindow(){InitializeComponent();ShowAllPrinter();}public void ShowAllPrinter(){ArrayList currentPrinterList = new ArrayList();foreach (PrintQueue pq in printqueen){currentPrinterList.Add(pq.Name);}PrinterList.ItemsSource = currentPrinterList;PrintQueue defaultPrinter = LocalPrintServer.GetDefaultPrintQueue();PrinterList.Text = defaultPrinter.Name;}private void InvokePrint(object sender, RoutedEventArgs e){// Create the print dialog object and set optionsPrintDialog pDialog = new PrintDialog();pDialog.PageRangeSelection = PageRangeSelection.AllPages;pDialog.UserPageRangeEnabled = true;// Display the dialog. This returns true if the user presses the Print button.Nullable<Boolean> print = pDialog.ShowDialog();if (print == true){XpsDocument xpsDocument = new XpsDocument(@"d:\测试XPS文档.xps", FileAccess.ReadWrite);FixedDocumentSequence fixedDocSeq = xpsDocument.GetFixedDocumentSequence();pDialog.PrintDocument(fixedDocSeq.DocumentPaginator, "Test print job");}}private void PrinterList_SelectionChanged(object sender, SelectionChangedEventArgs e){selectedItem = PrinterList.SelectedItem;}private void Button_Click(object sender, RoutedEventArgs e){PrintQueue printQueue = printServer.GetPrintQueue(selectedItem.ToString());PrintTicket printTicket = printQueue.UserPrintTicket;printTicket.CopyCount = 2;PrintCapabilities printCapabilities = printQueue.GetPrintCapabilities();System.Printing.ValidationResult result = printQueue.MergeAndValidatePrintTicket(printQueue.UserPrintTicket, printTicket);PrintSystemJobInfo Info = printQueue.AddJob("TestJob");var stream = Info.JobStream;var data = File.ReadAllBytes(@"d:\测试XPS文档.xps");stream.Write(data, 0, data.Length);stream.Close();}}
}
此名称空间下的打印自带打印设置界面
缺点说明:只接受XPS文件类型(或者文本文件流);
参考链接:https://learn.microsoft.com/zh-cn/dotnet/api/system.printing?view=windowsdesktop-7.0
使用WinForm命名空间下的打印接口打印
参考代码:
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;namespace WinForm的打印
{class Program{private Font printFont;private StreamReader streamToPrint;private PrintDocument pd = new PrintDocument();static private Image newImage ;// Create point for upper-left corner of image.static private PointF ulCorner ;static void Main(string[] args){Program pg = new Program();pg.printFont = new Font("Arial", 10);//完全的静默打印//支持设置参数的静默打印Console.WriteLine("输入1进入完全静默打印;输入2进入设置参数的静默打印");string inputCommand = Console.ReadLine();if (inputCommand == "1"){ PurePrintSilense(pg); }else if (inputCommand == "2"){ PrintSilenceWithCommandLine(pg); }else{ Console.WriteLine("输入错误!按任意键退出程序");Console.ReadLine(); }}private static void PrintSilenceWithCommandLine(Program pg){Console.WriteLine("请输入要打印的文件全路径");string printFilePath = Console.ReadLine();pg.streamToPrint = new StreamReader(printFilePath);Console.WriteLine("以下当前电脑所有打印机名称,请输入将要设置打印的机器序号:");ArrayList currentPrinterList = pg.PopulateInstalledPrintersCombo();for (int i = 0; i < currentPrinterList.Count; i++){int num = i + 1;Console.WriteLine("打印机序号是:"+ num +",打印机名称是:"+ currentPrinterList[i]);}int selecePrinter = Convert.ToInt32(Console.ReadLine());pg.comboInstalledPrinters_SelectionChanged(pg, currentPrinterList[selecePrinter-1].ToString(),pg.pd);Console.WriteLine("请输入要打印的份数");int printCopies = Convert.ToInt32(Console.ReadLine());pg.setprintCopies(pg, printCopies,pg.pd);pg.print(pg,pg.pd);}private void print(Program pg, PrintDocument pd){try{try{pd.PrintPage += new PrintPageEventHandler(pg.pd_PrintPage);//去掉正在打印第几页的页面pd.PrintController = new System.Drawing.Printing.StandardPrintController();pd.Print();}finally{pg.streamToPrint.Close();}}catch (Exception ex){Console.WriteLine(ex.Message);}}private void setprintCopies(Program pg, int printCopies ,PrintDocument pd){pd.PrinterSettings.Copies = (short)printCopies;//throw new NotImplementedException();}private ArrayList PopulateInstalledPrintersCombo(){// Add list of installed printers found to the combo box.// The pkInstalledPrinters string will be used to provide the display string.String pkInstalledPrinters;ArrayList currentPrinterList = new ArrayList();for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++){pkInstalledPrinters = PrinterSettings.InstalledPrinters[i];currentPrinterList.Add(PrinterSettings.InstalledPrinters[i]);}return currentPrinterList;}private void comboInstalledPrinters_SelectionChanged(Program pg ,string printerName, PrintDocument pd){pd.PrinterSettings.PrinterName = printerName;}private static void PurePrintSilense(Program pg){//throw new NotImplementedException();Console.WriteLine("请输入要打印的文件全路径");string printFilePath = Console.ReadLine();//newImage = Image.FromFile(printFilePath);// Create point for upper-left corner of image.//ulCorner = new PointF(100.0F, 100.0F);pg.streamToPrint = new StreamReader(printFilePath);using (FileStream stream = new FileStream(printFilePath, FileMode.Open))pg.streamToPrint = new StreamReader(stream);pg.print(pg,pg.pd);}private void pd_PrintPage(object sender, PrintPageEventArgs ev){float linesPerPage = 0;float yPos = 0;int count = 0;float leftMargin = ev.MarginBounds.Left;float topMargin = ev.MarginBounds.Top;string line = null;// Calculate the number of lines per page.linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics);// Print each line of the file.while (count < linesPerPage && ((line = streamToPrint.ReadLine()) != null)){yPos = topMargin + (count *printFont.GetHeight(ev.Graphics));ev.Graphics.DrawString(line, printFont, System.Drawing.Brushes.Black,leftMargin, yPos, new StringFormat());count++;}ev.Graphics.DrawImage(newImage, ulCorner);// If more lines exist, print another page.if (line != null)ev.HasMorePages = true;elseev.HasMorePages = false;}}
}
缺点说明:只能打印纯文本文件或者image文件;
参考链接:https://learn.microsoft.com/zh-cn/dotnet/api/system.drawing.printing?view=dotnet-plat-ext-7.0
撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G
使用第三方PDF组件打印
参考代码(以使用spire.pdf为例)
using Spire.Pdf;
using System.Drawing.Printing;namespace 引入其他组件的打印
{class Program{static void Main(string[] args){//pdftron.PDFNet.Initialize();//测试spire.pdfPdfDocument pdf = new PdfDocument();pdf.LoadFromFile(@"d:\测试.pdf");pdf.PrintSettings.PrinterName = "Microsoft XPS Document Writer";pdf.PrintSettings.PrintToFile(@"d:\测试.xps");pdf.Print();}}
}
可以看出前面三种方法在真正的实际应用中都有点难受,所以我查资料的时候看到很多人都会使用第三方组件去实现打印,但是组件不开源(自己找破解版不算),需要收费且价格不算低,下面给出我找的几个组件信息。