C# 客户端PDF文件打印方法大全

前言

最近开发客户端的时候,用户提出了要增加打印PDF文件的需求,于是我各种翻官网和CSDN,然而好像还没有人总结得特别全,于是自己记录一下这几天的研究吧。

目前发现的有以下四种方式调用打印服务:

  1. 使用创建新进程的方式打印
  2. 使用WPF命名空间下的打印接口打印
  3. 使用WinForm命名空间下的打印接口打印
  4. 使用第三方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
{
    /// 
    /// 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

使用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;
            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

使用第三方PDF组件打印

参考代码(以使用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();
            }
    }
}

可以看出前面三种方法在真正的实际应用中都有点难受,所以我查资料的时候看到很多人都会使用第三方组件去实现打印,但是组件不开源(自己找破解版不算),需要收费且价格不算低,下面给出我找的几个组件信息。
C# 客户端PDF文件打印方法大全_第1张图片

你可能感兴趣的:(c#,pdf,wpf)