Here's the basic premise:
My user clicks some gizmos and a PDF file is spit out to his desktop. Is there some way for me to send this file to the printer queue and have it print to the locally connected printer?
string filePath = "filepathisalreadysethere";
SendToPrinter(filePath); //Something like this?
He will do this process many times. For each student in a classroom he has to print a small report card. So I generate a PDF for each student, and I'd like to automate the printing process instead of having the user generated pdf, print, generate pdf, print, generate pdf, print.
Any suggestions on how to approach this? I'm running on Windows XP with Windows Forms .NET 4.
I've found this StackOverflow question where the accepted answer suggests:
Once you have created your files, you
can print them via a command line (you
can using the Command class found in
the System.Diagnostics namespace for
that)
How would I accomplish this?
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;
}
}
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.
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.
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 Pdfium 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
The easy way:
var pi=new ProcessStartInfo("C:\file.docx");
pi.UseShellExecute = true;
pi.Verb = "print";
var process = System.Diagnostics.Process.Start(pi);
This is a slightly modified solution. The Process will be killed when it was idle for at least 1 second. Maybe you should add a timeof of X seconds and call the function from a separate thread.
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();
}
System.Diagnostics.Process.Start can be used to print a document. Set UseShellExecute to True and set the Verb to "print".
You can try with GhostScript like in this post:
How to print PDF on default network printer using GhostScript (gswin32c.exe) shell command
I know Edwin answered it above but his only prints one document. I use this code to print all files from a given directory.
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");
}
It essentually cycles through each file in the given directory variable Directory - > for me it was #"C:\Users\Owner\Documents\SalesVaultTesting\" and prints off those files to your default printer.
this is a late answer, but you could also use the File.Copy method of the System.IO namespace top send a file to the printer:
System.IO.File.Copy(filename, printerName);
This works fine
You can use the DevExpress PdfDocumentProcessor.Print(PdfPrinterSettings) Method.
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);
}
}
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;
}
}
I need to print Word document without installing MS Office.
I am using WordprocessingDocument to manipulate Word file.
Now I need to print it.
I have tried:
System.Diagnostics.Process printProcess = new System.Diagnostics.Process();
printProcess.StartInfo.FileName = "D:/testWordPad1.docx";
printProcess.StartInfo.Verb = "Print";
printProcess.StartInfo.CreateNoWindow = true;
printProcess.Start();
printProcess.WaitForExit();
It works in my local system which has MS Office installed. But it does not work at my server which does not have MS office installed.
It shows me:
No application is associated with the specified file for this operation - at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
Please give me your suggestions regarding this.
In order to print textual files [which is what it seems you try to do], you can use notepad's command line arguments [read more here]
The following will send the document to the default printer:
System.Diagnostics.Process printProcess = new System.Diagnostics.Process();
printProcess.StartInfo.FileName = "notepad.exe";
printProcess.StartInfo.Parameters = "/P D:\\testWordPad1.txt";
printProcess.StartInfo.CreateNoWindow = true;
printProcess.Start();
printProcess.WaitForExit();
If you want to define the printer to which the file will be sent, use the following parameter:
/PT [filename] [printername] [driverdll] [port]
The Error means, that the Verb is not available.
First you can check the available Verbs like this:
foreach (String verb in printProcess.StartInfo.Verbs)
{
System.Diagnostics.Debug.WriteLine(verb);
}
Are you sure that there any printing facilities available on your Server?
If you do a right click on that file on your server, does it show "Print" in the context menu?
To print .docx files on web server without MS Office installed, a third party library might be the best choice. I tried a free component (nuget package) with 100 passages and 5 tables limits for small project and it works.
using System;
using System.Collections.Generic;
using System.Text;
using Spire.Doc;
using System.Windows.Forms;
using System.Drawing.Printing;
namespace Doc_Print
{
class Program
{
static void Main(string[] args)
{
Document doc = new Document();
doc.LoadFromFile("sample.doc");
PrintDialog dialog = new PrintDialog();
dialog.AllowPrintToFile = true;
dialog.AllowCurrentPage = true;
dialog.AllowSomePages = true;
dialog.UseEXDialog = true;
doc.PrintDialog = dialog;
PrintDocument printDoc = doc.PrintDocument;
printDoc.Print();
if (dialog.ShowDialog() == DialogResult.OK)
{
printDoc.Print();
}
}
}
}
I can print a PDF with Acrobat (not the reader)
Here is the code:
var mApp = new AcroAppClass();
var avDoc = new AcroAVDocClass();
if (avDoc.Open(filename, ""))
{
var pdDoc = (CAcroPDDoc)avDoc.GetPDDoc();
avDoc.PrintPagesSilent(0, pdDoc.GetNumPages()-1, 2, 1, 1);
pdDoc.Close();
avDoc.Close(1);
}
if (mApp != null)
{
mApp.CloseAllDocs();
mApp.Exit();
}
This will print the PDF to the default windows printer.
Is there a way to choose the printer without changing the windows default printer?
Here is the documentation:
http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/iac_api_reference.pdf
It seems this is not possible:
PrintPages always uses the default printer setting.
I have the Graphics.DrawString method for Print Preview.
Now I would like to use the same code to save it as a PDF. I have a Form, I have created a printprewiew and I would like to save as it is in printPrview to pdf.
Is it posible to do this?
I have a solution this may help you, but it requires to download and install "CutePDF Writer". CutePDF Writer is free software. You can download it from there official website.
PrintDialog pDia = New PrintDialog()
PrinterSettings ps = New PrinterSettings()
pDia.Document = PrintDocument1
pDia.Document.DocumentName = "Your File Name"
ps.PrinterName = item.ToString()
ps.PrintToFile = False
//Create folder inside Bin folder to save PDFs
String strReportBackupPath = "C:\\"
String strFilePath = strReportBackupPath & "\\" & pDia.Document.DocumentName & ".pdf"
//To avoid the replace dialog of cutePDF - To save new file if have same name
ps.PrintFileName = strFilePath
PrintDocument1.PrinterSettings = ps
PrintDocument1.Print()
but it will show you save as dialog to save the file to pdf.
I have problem when i print html file, i have tried doc,xls, and txt files and they work perfectly, but when i give the html file it shows me the print dialog and i have to select the ghostscript printer in order to work.
My code is:
[DllImport("Winspool.drv")]
private static extern bool SetDefaultPrinter(string printerName);
[ValidateInput(false)]
public ActionResult CreatePdf(string file , string html)
{
SetDefaultPrinter("Ghostscript");
Process process1 = new Process();
if (html != null && html != "")
{ process1.StartInfo.FileName = "example.html"; }
else
{ process1.StartInfo.FileName = file; }
process1.EnableRaisingEvents = true;
process1.StartInfo.Verb = "print";
process1.StartInfo.Arguments = "\"Ghostscript PDF\"";
process1.StartInfo.WorkingDirectory = Server.MapPath("~" + "/Export");
process1.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process1.StartInfo.CreateNoWindow = true;
process1.Start();
try
{
process1.WaitForExit();
}
catch (InvalidOperationException) { }
process1.Dispose();
}
This should change my output.ps file,which then i use to make the pdf file,that works perfectly i just need to make this work for html file.
I followed this 2 examples:
Example 1
Example 2
Edit:
I needed this converstion in order to get pdf file from the html, and found that wkhtmltopdf suits me best.
Ghostscript does not convert (layout and render) HTML documents to PDF or PostScript, it is just a library for working with PostScript and PDF files, such as creating them from scratch and converting PostScript files to a raster format.
If you want to convert HTML to PDF your best bet is to use a commercial library like PrinceXML, or host WebKit.
When your code works, it works by getting Internet Explorer (or whatever your shell-default web-browser is) to do the rendering and printing itself. This technique will not reliably work in a server-side environment.