This days I've been developing a service that sends a PDF file to a network printer and effectively print it using C# and the GhostscriptProcessor library.
But now I'm really stuck with the next (and last) step I want to make. I need to know wether or not the file was really printed. I tried everything I could (for instance I tried implementing this powershell script but I'm not familiar at all with powershell and I got depressed since I got too many errors I can't solve) but I can't find the answer.
Is there ANY way using C# (any library) to retrieve if a document has been printed. Or retrieve the whole log of documents printed? Any script I can call through C# (or not, I am able to circumvent that) that tells me the information I need?
I'd like to add that I have access to the printer using the System.Drawing.Printing library as follows:
var printServer = new PrintServer();
var myPrintQueues = printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections });
foreach (PrintQueue pq in myPrintQueues)
{
pq.Refresh();
string printerName = "ES7470 MFP(PCL)";
if (!pq.Name.ToUpper().Contains(printerName.ToUpper())) break;
PrintJobInfoCollection jobs = pq.GetPrintJobInfoCollection();
//And here I can use pq or jobs but I can't retrieve the log at all.
}
I think the problem is the PrintServer, I'm not in your environment so I cant tell your setup but LocalPrintServer.GetPrintQueue should do the trick.
string printerName = "ES7470 MFP(PCL)";
LocalPrintServer localPrintServer = new LocalPrintServer();
PrintQueueCollection printQueues = localPrintServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections });
if (printQueues == null) return false;
PrintQueue queue = printQueues.Where(x => x.Name.Equals(printerName)).FirstOrDefault();
I'm guessing your application will know if someone printed something, otherwise you'll have to poll the Printer Queue each second or two to find out if a job went to the printer...
I´ve trying to solve this problem for nearly 2 days. There are a lot of more or fewer good solutions on the net, but not a single one fits my task perfectly.
Task:
Print a PDF programmatically
Do it with a fixed printer
Don´t let the user do more than one Button_Click
Do it silent - the more, the better
Do it client side
First Solutions:
Do it with a Forms.WebBrowser
If we have Adobe Reader installed, there is a plugin to show PDF´s in the webbrowser. With this solution we have a nice preview and with webbrowserControlName.Print() we can trigger the control to print its content.
Problem - we still have a PrintDialog.
Start the AcroRd32.exe with start arguments
The following CMD command let us use Adobe Reader to print our PDF.
InsertPathTo..\AcroRd32.exe /t "C:\sample.pdf" "\printerNetwork\printerName"
Problems - we need the absolute path to AcroRd32.exe | there is an Adobe Reader Window opening and it has to be opened until the print task is ready.
Use windows presets
Process process = new Process();
process.StartInfo.FileName = pathToPdf;
process.StartInfo.Verb = "printto";
process.StartInfo.Arguments = "\"" + printerName + "\"";
process.Start();
process.WaitForInputIdle();
process.Kill();
Problem - there is still an Adobe Reader window popping up, but after the printing is done it closes itself usually.
Solution - convince the client to use Foxit Reader (don´t use last two lines of code).
Convert PDF pages to Drawing.Image
I´ve no idea how to do it with code, but when I get this to work the rest is just a piece of cake. Printing.PrintDocument can fulfill all demands.
Anyone an idea to get some Drawing.Image´s out of those PDF´s or another approach how to do it?
Best Regards,
Max
The most flexible, easiest and best performing method I could find was using GhostScript. It can print to windows printers directly by printer name.
"C:\Program Files\gs\gs9.07\bin\gswin64c.exe" -dPrinted -dBATCH -dNOPAUSE -sDEVICE=mswinpr2 -dNoCancel -sOutputFile="%printer%printer name" "pdfdocument.pdf"
Add these switches to shrink the document to an A4 page.
-sPAPERSIZE=a4 -dPDFFitPage
If a commercial library is an option, you can try with Amyuni PDF Creator. Net.
Printing directly with the library:
For opening a PDF file and send it to print directly you can use the method IacDocument.Print. The code in C# will look like this:
// Open PDF document from file<br>
FileStream file1 = new FileStream ("test.pdf", FileMode.Open, FileAccess.Read);
IacDocument doc1 = new IacDocument (null);
doc1.Open (file1, "" );
// print document to a specified printer with no prompt
doc1.Print ("My Laser Printer", false);
Exporting to images (then printing if needed):
Choice 1: You can use the method IacDocument.ExportToJPeg for converting all pages in a PDF to JPG images that you can print or display using Drawing.Image
Choice 2: You can draw each page into a bitmap using the method IacDocument.DrawCurrentPage with the method System.Drawing.Graphics.FromImage. The code in C# should look like this:
FileStream myFile = new FileStream ("test.pdf", FileMode.Open, FileAccess.Read);
IacDocument doc = new IacDocument(null);
doc.Open(myFile);
doc.CurrentPage = 1;
Image img = new Bitmap(100,100);
Graphics gph = Graphics.FromImage(img);
IntPtr hdc = gph.GetHDC();
doc.DrawCurrentPage(hdc, false);
gph.ReleaseHdc( hdc );
Disclaimer: I work for Amyuni Technologies
I tried many things and the one that worked best for me was launching a SumatraPDF from the command line:
// Launch SumatraPDF Reader to print
String arguments = "-print-to-default -silent \"" + fileName + "\"";
System.Diagnostics.Process.Start("SumatraPDF.exe", arguments);
There are so many advantages to this:
SumatraPDF is much much faster than Adobe Acrobat Reader.
The UI doesn't load. It just prints.
You can use SumatraPDF as a standalone application so you can include it with your application so you can use your own pa. Note that I did not read the license agreement; you should probably check it out yourself.
Another approach would to use spooler function in .NET to send the pre-formatted printer data to a printer. But unfortunately you need to work with win32 spooler API
you can look at How to send raw data to a printer by using Visual C# .NET
you only can use this approach when the printer support PDF document natively.
My company offers Docotic.Pdf library that can render and print PDF documents. The article behind the link contains detailed information about the following topics:
printing PDFs in Windows Forms or WPF application directly
printing PDFs via an intermediate image
rendering PDFs on a Graphics
There are links to sample code, too.
I work for the company, so please read the article and try suggested solutions yourselves.
Process proc = new Process();
proc.StartInfo.FileName = #"C:\Program Files\Adobe\Acrobat 7.0\Reader\AcroRd32.exe";
proc.StartInfo.Arguments = #"/p /h C:\Documents and Settings\brendal\Desktop\Test.pdf";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();
for (int i = 0; i < 5; i++)
{
if (!proc.HasExited)
{
proc.Refresh();
Thread.Sleep(2000);
}
else
break;
}
if (!proc.HasExited)
{
proc.CloseMainWindow();
}
You can use ghostscript to convert PDF into image formats.
The following example converts a single PDF into a sequence of PNG-Files:
private static void ExecuteGhostscript(string input, string tempDirectory)
{
// %d will be replaced by ghostscript with a number for each page
string filename = Path.GetFileNameWithoutExtension(input) + "-%d.png";
string output = Path.Combine(tempDirectory, filename);
Process ghostscript = new Process();
ghostscript.StartInfo.FileName = _pathToGhostscript;
ghostscript.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
ghostscript.StartInfo.Arguments = string.Format(
"-dSAFER -dBATCH -dNOPAUSE -sDEVICE=png16m -r300 -sOutputFile=\"{0}\" \"{1}\"", output, input);
ghostscript.Start();
ghostscript.WaitForExit();
}
If you prefer to use Adobe Reader instead you can hide its window:
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
I found a slightly different version of your code that uses the printto verb. I didn't try it, but maybe it helps you:
http://vbcity.com/forums/t/149141.aspx
If you're interested in commercial solutions which do exactly what you require then there are quite a few options. My company provides one of those options in a developer toolkit called Debenu Quick PDF Library.
Here is a code sample (key functions are PrintOptions and PrintDocument):
/* Print a document */
// Load a local sample file from the input folder
DPL.LoadFromFile("Test.pdf", "");
// Configure print options
iPrintOptions = DPL.PrintOptions(0, 0, "Printing Sample")
// Print the current document to the default
// printing using the options as configured above.
// You can also specify the specific printer.
DPL.PrintDocument(DPL.GetDefaultPrinterName(), 1, 1, iPrintOptions);
I know that the tag has Windows Forms; however, due to the general title, some people might be wondering if they may use that namespace with a WPF application -- they may.
Here's code:
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);
}
Now, this namespace must be used with a WPF application. It 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.
Note that if your printer does not support Direct Printing for PDF files, this won't work.
What about using the PrintDocument class?
http://msdn.microsoft.com/en-us/library/system.drawing.printing.printdocument.aspx
You just need to pass the filename of the file you want to print (based on the example).
HTH
As of July 2018, there is still no answer for the OP. There is no free way to 1) silently print your pdf for a 2) closed source project.
1) You can most certainly use a process i.e. Adobe Acrobat or Foxit Reader
2) Free solutions have a GPL (GNU's General Public License). This means you must open your source code if giving the software, even for free, to anyone outside your company.
As the OP says, if you can get a PDF to Drawing.Image, you can print it with .NET methods. Sadly, software to do this also requires payment or a GPL.
I have a MonoTouch application that generates some PDFs locally and then prints them to a network printer. To get this working I initially just added a PDF resource to the project that I could try and print but am having a heck of a time. When I print just HMTL or a string value everything is good but printing the PDF has me lost. When debugging it looks like the app is getting the proper URL.
Any help would be greatly appreciated and my sampled code is below:
public void PrintSomePDF ()
{
var printInfo = UIPrintInfo.PrintInfo;
printInfo.OutputType = UIPrintInfoOutputType.General;
printInfo.JobName = "Test: PDF Print";
string pdfFileName = "printthispdf_01.pdf";
NSUrl url = NSUrl.FromFilename(pdfFileName);
var printer = UIPrintInteractionController.SharedPrintController;
printer.PrintInfo = printInfo;
printer.PrintingItem = url.Path;
printer.ShowsPageRange = true;
printer.Present (true, (handler, completed, err) => {
if (!completed && err != null){
Console.WriteLine ("error");
}
});
}
I was able to resolve the problem with the way I passed in the NSUrl to the PrintingItem. Before I was passing in printer.PrintingItem = url.Path; which was basically just passing in a string of the path and not the actual shape of NSUrl.
printer.PrintingItem = url;
What I've always preferred to do (and this depends very much on the deployed device - in my case it was a server I controlled) was to just install a PDF printer and then it's as easy as printing any other kind of document.
Something like BullZip is free and allows you to write any settings for the print to a RunOnce.ini (xml) file to have a silent mode print with settings for the filename and so forth.
Obviously not a great solution if you don't have control of the system you're deploying to, but a solid and easy one if you do.
I have a C# application that When the user clicks Print the application creates a PDF in memorystream using ITextSharp. I need to print this PDF automatically to a specific printer and tray.
I have searched for this but all i can find is using javascript, but it doesn't print to a specific tray.
Does anyone have an examples of doing this?
Thank you.
You can change printer tray with this code.
string _paperSource = "TRAY 2"; // Printer Tray
string _paperName = "8x17"; // Printer paper name
//Tested code comment. The commented code was the one I tested, but when
//I was writing the post I realized that could be done with less code.
//PaperSize pSize = new PaperSize() //Tested code :)
//PaperSource pSource = new PaperSource(); //Tested code :)
/// Find selected paperSource and paperName.
foreach (PaperSource _pSource in printDoc.PrinterSettings.PaperSources)
if (_pSource.SourceName.ToUpper() == _paperSource.ToUpper())
{
printDoc.DefaultPageSettings.PaperSource = _pSource;
//pSource = _pSource; //Tested code :)
break;
}
foreach (PaperSize _pSize in printDoc.PrinterSettings.PaperSizes)
if (_pSize.PaperName.ToUpper() == _paperName.ToUpper())
{
printDoc.DefaultPageSettings.PaperSize = _pSize;
//pSize = _pSize; //Tested code :)
break;
}
//printDoc.DefaultPageSettings.PaperSize = pSize; //Tested code :)
//printDoc.DefaultPageSettings.PaperSource = pSource; //Tested code :)
in the past I spent a lot of time searching the web for solutions to print pdf files to specific printer trays.
My requirement was: collect several pdf files from server directory and send each file to a different printer tray in a loop.
So I have tested a lot of 3rd party tools (trials) and best practices found in web.
Generally all theese tools can be divide into two classifications: a) send pdf files to printer in a direct way (silent in UI) or b) open pdf files in UI using a built-in pdf previewer working with .Net-PrintDocument.
The only solution that fix my requirement was PDFPrint from veryPdf (drawback: it´s not priceless, but my company bought it). All the other tools and solutions didn´t work reliable, that means: calling their print-routines with parameter e.g. id = 258 (defines tray 2; getting from installed printer) but printing the pdf file in tray 3 or pdf was opened in print previewer (UI) with lost images or totally blank content and so on..
Hope that helps a little bit.
There is a tool called pdfprint:
http://www.verypdf.com/pdfprint/index.html
And here they discuss some solutions:
http://social.msdn.microsoft.com/forums/en-US/csharpgeneral/thread/da99765f-2706-4bb6-aa0e-b90730294cb4
I have a webpage that activates a print job on a printer. This works in the localhost environment but does not work when the application is deployed to the webserver. I'm using the PrintDocument class from the .net System.Drawing.Print namespace. I'm now assuming the printer has to be available to the application on the remote server? Any suggestions on how I would get this to work?
PrintDocument pd = new PrintDocument();
PaperSource ps = new PaperSource();
pd.DefaultPageSettings.PaperSize =
new System.Drawing.Printing.PaperSize("Custom", 1180, 850);
pd.PrintPage += new PrintPageEventHandler
(this.pd_PrintPage);
// Set your printer's name. Obtain from
// System's Printer Dialog Box.
pd.PrinterSettings.PrinterName =
"Okidata ML 321 Turbo/D (IBM)";
//PrintPreviewDialog dlgPrintPvw = new PrintPreviewDialog();
//dlgPrintPvw.Document = pd;
//dlgPrintPvw.Focus();
//dlgPrintPvw.ShowDialog();
pd.Print();
The printer is on a different computer. PrintDocument is for use in desktop applications, not web applications.
To print on the client, you would need to use JavaScript, and you would only be able to print documents already on the client machine. I don't know for sure that there is a way to print on the client. You may be able to display a "Print" dialog and have the user print the file himself.
I was having the same issues. I was told to put your code inside of this:
using (WindowsIdentity.GetCurrent().Impersonate())
{
// code here
}
It allows for specific user settings to be used instead of the ASP.NET settings for that particular printer.
This code got it to the printer, but now I'M having issues with multiple copies of one webform hitting the printer.