How can I send a file document to the printer and have it print?
Solution 1:
Adding a new answer to this as the question of printing PDF's in .net has been around for a long time and most of the answers pre-date the Google Pdfium library, which now has a .net wrapper. For me I was researching this problem myself and kept coming up blank, trying to do hacky solutions like spawning Acrobat or other PDF readers, or running into commercial libraries that are expensive and have not very compatible licensing terms. But the Google Pdfium library and the PdfiumViewer .net wrapper are Open Source so are a great solution for a lot of developers, myself included. PdfiumViewer is licensed under the Apache 2.0 license.
You can get the NuGet package here:
https://www.nuget.org/packages/PdfiumViewer/
and you can find the source code here:
https://github.com/pvginkel/PdfiumViewer
Here is some simple code that will silently print any number of copies of a PDF file from it's filename. You can load PDF's from a stream also (which is how we normally do it), and you can easily figure that out looking at the code or examples. There is also a WinForm PDF file view so you can also render the PDF files into a view or do print preview on them. For us I simply needed a way to silently print the PDF file to a specific printer on demand.
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;
}
}
Solution 2:
You can tell Acrobat Reader to print the file using (as someone's already mentioned here) the 'print' verb. You will need to close Acrobat Reader programmatically after that, too:
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();
}
This opens Acrobat Reader and tells it to send the PDF to the default printer, and then shuts down Acrobat after three seconds.
If you are willing to ship other products with your application then you could use GhostScript (free), or a command-line PDF printer such as http://www.commandlinepdf.com/ (commercial).
Note: the sample code opens the PDF in the application current registered to print PDFs, which is the Adobe Acrobat Reader on most people's machines. However, it is possible that they use a different PDF viewer such as Foxit (http://www.foxitsoftware.com/pdf/reader/). The sample code should still work, though.
Solution 3:
I know the tag says Windows Forms
... but, if anyone is interested in a WPF
application method, System.Printing
works like a charm.
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);
}
Just remember to include System.Printing
reference, if it's not already included.
Now, this method does not play well with ASP.NET
or Windows Service
. It should not be used with Windows Forms
, as it has System.Drawing.Printing
. I don't have a single issue with my PDF printing using the above code.
I should mention, however, that if your printer does not support Direct Print for PDF file format, you're out of luck with this method.
Solution 4:
The following code snippet is an adaptation of Kendall Bennett's code for printing pdf files using the PdfiumViewer library. The main difference is that a Stream is used rather than a file.
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;
}
}
In my case I am generating the PDF file using a library called PdfSharp and then saving the document to a Stream like so:
PdfDocument pdf = PdfGenerator.GeneratePdf(printRequest.html, PageSize.A4);
pdf.AddPage();
MemoryStream stream = new MemoryStream();
pdf.Save(stream);
MemoryStream stream2 = new MemoryStream(stream.ToArray());
One thing that I want to point out that might be helpful to other developers is that I had to install the 32 bit version of the pdfuim native dll in order for the printing to work even though I am running Windows 10 64 bit. I installed the following two NuGet packages using the NuGet package manager in Visual Studio:
- PdfiumViewer
- PdfiumViewer.Native.x86.v8-xfa