最近开发客户端的时候,用户提出了要增加打印PDF文件的需求,于是我各种翻官网和CSDN,然而好像还没有人总结得特别全,于是自己记录一下这几天的研究吧。
目前发现的有以下四种方式调用打印服务:
参考代码
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
参考代码
<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
{
///
/// MainWindow.xaml 的交互逻辑
///
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 options
PrintDialog 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
参考代码:
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;
else
ev.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
参考代码(以使用spire.pdf为例)
using Spire.Pdf;
using System.Drawing.Printing;
namespace 引入其他组件的打印
{
class Program
{
static void Main(string[] args)
{
//pdftron.PDFNet.Initialize();
//测试spire.pdf
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile(@"d:\测试.pdf");
pdf.PrintSettings.PrinterName = "Microsoft XPS Document Writer";
pdf.PrintSettings.PrintToFile(@"d:\测试.xps");
pdf.Print();
}
}
}
可以看出前面三种方法在真正的实际应用中都有点难受,所以我查资料的时候看到很多人都会使用第三方组件去实现打印,但是组件不开源(自己找破解版不算),需要收费且价格不算低,下面给出我找的几个组件信息。