如何将文件文档发送到打印机并进行打印?


72

这是基本前提:

我的用户单击一些小控件,然后将一个PDF文件吐出到他的桌面。我可以通过某种方式将此文件发送到打印机队列,并打印到本地连接的打印机吗?

string filePath = "filepathisalreadysethere";
SendToPrinter(filePath); //Something like this?

他将多次执行此过程。对于教室中的每个学生,他必须打印一张小报告卡。因此,我为每个学生生成一个PDF,并且我想使打印过程自动化,而不是让用户生成pdf,打印,生成pdf,打印,生成pdf,打印。

有关如何处理此问题的任何建议?我在运行Windows Forms .NET 4的Windows XP上运行。

我发现了这个StackOverflow问题,其中可接受的答案表明:

创建文件后,可以通过命令行打印它们(可以使用在System.Diagnostics命名空间中找到的Command类)。

我将如何完成?


为什么不合并PDF文档并让用户打印一个多页文档?似乎不那么容易出错,并且很难错过打印一份报告(例如,如果其中一个文件发生错误)。
德克·沃尔玛

@ 0xA3,我将对此进行调查,但现在我需要研究将文件发送到打印机。
只有玻利维亚人在这里

Answers:


70

您可以告诉Acrobat Reader使用“打印”动词来打印文件(正如此处已经提到的那样)。之后,您还需要以编程方式关闭Acrobat Reader:

private void SendToPrinter()
{
   ProcessStartInfo info = new ProcessStartInfo();
   info.Verb = "print";
   info.FileName = @"c:\output.pdf";
   info.CreateNoWindow = true;
   info.WindowStyle = ProcessWindowStyle.Hidden;

   Process p = new Process();
   p.StartInfo = info;
   p.Start();

   p.WaitForInputIdle();
   System.Threading.Thread.Sleep(3000);
   if (false == p.CloseMainWindow())
      p.Kill();
}

这将打开Acrobat Reader,并告诉它将PDF发送到默认打印机,然后在三秒钟后关闭Acrobat。

如果您愿意随应用程序一起提供其他产品,则可以使用GhostScript(免费)或命令行PDF打印机,例如http://www.commandlinepdf.com/(商业)。

注意:该示例代码在当前注册的可打印PDF的应用程序中打开PDF,这是大多数人的机器上的Adobe Acrobat Reader。但是,他们可能使用其他PDF查看器,例如Foxit(http://www.foxitsoftware.com/pdf/reader/)。但是,示例代码仍应正常工作。


1
@Mvcdev,代码依赖于:a)服务器上安装了Acrobat(或其他阅读器),以及b)调用交互式应用程序(例如Adobe Acrobat),如果您的代码在其下运行的用户帐户不是交互式的,则该程序可能不起作用。在这种情况下,最好的方法是使用命令行工具(如上所述,www.commandlinepdf.com)
Edwin Groenendaal,2012年

3
WaitForInputIdle()无效。似乎在Start()之后p处于空闲模式。只有3秒钟的睡眠时间,Adobe才能完成后台处理。这对于大型文档可能是个问题。
user1027167 2014年

2
@ user1027167,如果您需要打印多个文档,这尤其是一个问题。@EdwinGroenendaal如果要打印多个文档,您将如何处理?在命令外壳中,可以将它们全部写在打印机名称之后:print /D:printerName file1.pdf file2.pdf file3.pdf
Mong Zhu

1
我收到“此应用程序没有与指定文件关联的应用程序”即使连接了打印机也出错
Peck_conyon

1
@BK我通过用线程监听假脱机按文件名跟踪我的文件。我想提供该链接以跟踪作业状态表单假脱机(codeproject.com/Articles/74359/…)。
ceyun

71

由于在.net中打印PDF的问题已经存在很长时间了,因此对此添加了新的答案,并且大多数答案早于Google Pdfium库,该库现在具有.net包装器。对我来说,我自己一直在研究这个问题,并一无所获,试图做一些棘手的解决方案,例如生成Acrobat或其他PDF阅读器,或者运行到昂贵且没有非常兼容的许可条款的商业库中。但是Google Pdfium库和PdfiumViewer .net包装器是开源的,因此对于包括我在内的许多开发人员来说都是一个很好的解决方案。PdfiumViewer是根据Apache 2.0许可获得许可的。

您可以在此处获取NuGet软件包:

https://www.nuget.org/packages/PdfiumViewer/

您可以在此处找到源代码:

https://github.com/pvginkel/PdfiumViewer

这是一些简单的代码,它们将从文件名中静默打印出任意数量的PDF文件副本。您还可以从流中加载PDF(这是我们通常的方式),并且通过查看代码或示例可以很容易地发现这一点。还有一个WinForm PDF文件视图,因此您也可以将PDF文件渲染到视图中或对其进行打印预览。对于我们来说,我只需要一种方法即可按需将PDF文件静默打印到特定打印机。

public bool PrintPDF(
    string printer,
    string paperName,
    string filename,
    int copies)
{
    try {
        // Create the printer settings for our printer
        var printerSettings = new PrinterSettings {
            PrinterName = printer,
            Copies = (short)copies,
        };

        // Create our page settings for the paper size selected
        var pageSettings = new PageSettings(printerSettings) {
            Margins = new Margins(0, 0, 0, 0),
        };
        foreach (PaperSize paperSize in printerSettings.PaperSizes) {
            if (paperSize.PaperName == paperName) {
                pageSettings.PaperSize = paperSize;
                break;
            }
        }

        // Now print the PDF document
        using (var document = PdfDocument.Load(filename)) {
            using (var printDocument = document.CreatePrintDocument()) {
                printDocument.PrinterSettings = printerSettings;
                printDocument.DefaultPageSettings = pageSettings;
                printDocument.PrintController = new StandardPrintController();
                printDocument.Print();
            }
        }
        return true;
    } catch {
        return false;
    }
}

这使我启动并运行了大约10分钟。
菲利普·斯特拉特福德

好的解决方案,谢谢!还有一个非常漂亮的Google图书馆,它也是开源的,因此它可能存在更长时间。如果有人对双面打印感兴趣,您可以轻松地使用来完成此任务printerSettings.Duplex = Duplex.Vertical,对于我们来说,这就像是一种魅力。
Viorel

在IIS环境中也可以使用吗?我有通过IIS中托管的应用程序将pdf(从流生成)打印到网络打印机的方案。我尝试使用此代码,现在面临的问题是:1.文档正在排队到大小为0字节的打印作业队列中。2.文档正在以所有者名称为machine_name进入打印作业队列。
Binod Mahto

1
我安装了此库,并在大约3分钟内完成了打印。
TimS

1
您好,它对我不起作用,它给出了错误。无法加载DLL'pdfium.dll':找不到指定的模块。(来自HRESULT的异常:0x8007007E)ibb.co/dm4yYPH
Ali Jamal

30

我知道标签上写着Windows Forms...,但是,如果有人对一种WPF应用程序方法感兴趣,它的System.Printing作用就像是一种魅力。

var file = File.ReadAllBytes(pdfFilePath);
var printQueue = LocalPrintServer.GetDefaultPrintQueue();

using (var job = printQueue.AddJob())
using (var stream = job.JobStream)
{
    stream.Write(file, 0, file.Length);
}

请记住要包括System.Printing参考(如果尚未包含)。现在,此方法不能与ASP.NET或配合使用Windows Service。它不应该被使用Windows Forms,因为它有System.Drawing.Printing。使用上述代码的PDF打印没有任何问题。

但是,我要指出的是,如果您的打印机不支持PDF文件格式的直接打印,那么您将无法使用这种方法。


1
我正在尝试使用HP LaserJet CP1025nw进行打印,但是无法正常工作。有一会儿,它在状态为假脱机的打印队列中显示了该打印作业,然后它从那里消失了,没有任何打印发生
sohaiby

1
@sohaiby您必须查看打印机的规格,以查看是否允许直接打印PDF文件格式。我还要确保您拥有适用于您的操作系统的最新驱动程序。
BK

没有为兄弟MFC-7860DW打印机工作从LINQPad 5
造口

1
@stomy可能没有Direct-PDF / Direct Print来支持PDF。另外,如果您尝试打印任何其他文件格式,则打印机必须支持直接打印。这是一种简单的打印方法,但肯定不是灵丹妙药。当我几年前使用它时,它仅适用于某些正在工作的打印机。
BK

14

以下代码段是Kendall Bennett的代码的改编版,该代码使用PdfiumViewer库打印pdf文件。主要区别在于使用的是Stream而不是文件。

public bool PrintPDF(
    string printer,
    string paperName,
    int copies, Stream stream)
        {
            try
            {
                // Create the printer settings for our printer
                var printerSettings = new PrinterSettings
                {
                    PrinterName = printer,
                    Copies = (short)copies,
                };

            // Create our page settings for the paper size selected
            var pageSettings = new PageSettings(printerSettings)
            {
                Margins = new Margins(0, 0, 0, 0),
            };
            foreach (PaperSize paperSize in printerSettings.PaperSizes)
            {
                if (paperSize.PaperName == paperName)
                {
                    pageSettings.PaperSize = paperSize;
                    break;
                }
            }

            // Now print the PDF document
            using (var document = PdfiumViewer.PdfDocument.Load(stream))
            {
                using (var printDocument = document.CreatePrintDocument())
                {
                    printDocument.PrinterSettings = printerSettings;
                    printDocument.DefaultPageSettings = pageSettings;
                    printDocument.PrintController = new StandardPrintController();
                    printDocument.Print();
                }
            }
            return true;
        }
        catch (System.Exception e)
        {
            return false;
        }
    }

就我而言,我正在使用称为PdfSharp的库生成PDF文件,然后将文档保存到Stream中,如下所示:

        PdfDocument pdf = PdfGenerator.GeneratePdf(printRequest.html, PageSize.A4);
        pdf.AddPage();

        MemoryStream stream = new MemoryStream();
        pdf.Save(stream);
        MemoryStream stream2 = new MemoryStream(stream.ToArray());

我想指出的一件事可能对其他开发人员有所帮助,就是即使我运行的是Windows 10 64位版本,我也必须安装32位版本的pdfuim本机dll才能使打印正常。我在Visual Studio中使用NuGet软件包管理器安装了以下两个NuGet软件包:

  • PdfiumViewer
  • PdfiumViewer.Native.x86.v8-xfa

这是一个可靠的答案。它解决了我们遇到的一个问题。
bdwakefield '18

8

这是经过稍微修改的解决方案。进程空闲至少1秒钟后将被杀死。也许您应该添加X的时间,然后从单独的线程中调用该函数。

private void SendToPrinter()
{
  ProcessStartInfo info = new ProcessStartInfo();
  info.Verb = "print";
  info.FileName = @"c:\output.pdf";
  info.CreateNoWindow = true;
  info.WindowStyle = ProcessWindowStyle.Hidden;

  Process p = new Process();
  p.StartInfo = info;
  p.Start();

  long ticks = -1;
  while (ticks != p.TotalProcessorTime.Ticks)
  {
    ticks = p.TotalProcessorTime.Ticks;
    Thread.Sleep(1000);
  }

  if (false == p.CloseMainWindow())
    p.Kill();
}

5

简单的方法:

var pi=new ProcessStartInfo("C:\file.docx");
pi.UseShellExecute = true;
pi.Verb = "print";
var process =  System.Diagnostics.Process.Start(pi);

2
为了定位特定的打印机,请添加:pi.Arguments = "PATH_TO_PRINTER"并使用pi.Verb = "PrintTo"代替pi.Verb = "print"
Andi

4

System.Diagnostics.Process.Start可用于打印文档。将UseShellExecute设置为True并将动词设置为“ print”。


你能详细说明吗?我不明白应该将UseShellExecute设置为true。
只有玻利维亚人在这里

Process.Start方法可以将ProcessStartInfo具有这些属性的对象作为参数。
蒂姆·斯坦

@Tim Destan:我不知所措我真的在这里,这是VerbUseShellExecute中的ProcessStartInfo类的实际性能?你有一些示例代码吗?
只有玻利维亚人在这里


2

我知道爱德温在上面回答过,但他只打印一份文件。我使用此代码打印给定目录中的所有文件。

public void PrintAllFiles()
{
    System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo();
    info.Verb = "print";
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    //Load Files in Selected Folder
    string[] allFiles = System.IO.Directory.GetFiles(Directory);
    foreach (string file in allFiles)
    {
        info.FileName = @file;
        info.CreateNoWindow = true;
        info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
         p.StartInfo = info;
        p.Start();
    }
    //p.Kill(); Can Create A Kill Statement Here... but I found I don't need one
    MessageBox.Show("Print Complete");
}

它基本上遍历给定目录变量Directory中的每个文件->对我而言,它是@“ C:\ Users \ Owner \ Documents \ SalesVaultTesting \”,然后将这些文件打印到默认打印机中


1

这是一个较晚的答案,但是您也可以使用System.IO命名空间的File.Copy方法将文件发送到打印机:

System.IO.File.Copy(filename, printerName);

这很好


4
您能详细说明一下吗?我唯一得到的是一个名为printerName...的文件写入硬盘
Mong Zhu

3
例如:File.Copy(“ myFileToPrint.pdf”,“ \\ myPrintServerName \ myPrinterName”);
Doug Clutter

我尝试了该代码,并创建了文件副本,其名称输入了我的桌面应用程序的exe文件夹
AttaH。18年

0

您可以使用DevExpress PdfDocumentProcessor.Print(PdfPrinterSettings)方法。

public void Print(string pdfFilePath)
{
      if (!File.Exists(pdfFilePath))
          throw new FileNotFoundException("No such file exists!", pdfFilePath);

      // Create a Pdf Document Processor instance and load a PDF into it.
      PdfDocumentProcessor documentProcessor = new PdfDocumentProcessor();
      documentProcessor.LoadDocument(pdfFilePath);

      if (documentProcessor != null)
      {
          PrinterSettings settings = new PrinterSettings();

          //var paperSizes = settings.PaperSizes.Cast<PaperSize>().ToList();
          //PaperSize sizeCustom = paperSizes.FirstOrDefault<PaperSize>(size => size.Kind == PaperKind.Custom); // finding paper size

          settings.DefaultPageSettings.PaperSize = new PaperSize("Label", 400, 600);

          // Print pdf
          documentProcessor.Print(settings);
      }
}

0
    public static void PrintFileToDefaultPrinter(string FilePath)
    {
        try
        {
            var file = File.ReadAllBytes(FilePath);
            var printQueue = LocalPrintServer.GetDefaultPrintQueue();

            using (var job = printQueue.AddJob())
            using (var stream = job.JobStream)
            {
                stream.Write(file, 0, file.Length);
            }
        }
        catch (Exception)
        {

            throw;
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.