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.
Related
After struggling whole day, I identified the issue but this didn't solve my problem.
On short:
I need to open a PDF, convert to BW (grayscale), search some words and insert some notes nearby found words. At a first look it seems easy but I discovered how hard PDF files are processed (having no "words" concepts and so on).
Now the first task, converting to grayscale just drove me crazy. I didn't find a working solution either commercial or free. I came up with this solution:
open the PDF
print with windows drivers, some free PDF printers
This is quite ugly since I will force the C# users to install such 3'rd party SW but.. that is fpr the moment. I tested FreePDF, CutePDF and PDFCreator. All of them are working "stand alone" as expected.
Now when I tried to print from C#, obviously, I don't want the print dialog, just select BW option and print (aka. convert)
The following code just uses a PDF library, shown for clarity only.
Aspose.Pdf.Facades.PdfViewer viewer = new Aspose.Pdf.Facades.PdfViewer();
viewer.BindPdf(txtPDF.Text);
viewer.PrintAsGrayscale = true;
//viewer.RenderingOptions = new RenderingOptions { UseNewImagingEngine = true };
//Set attributes for printing
//viewer.AutoResize = true; //Print the file with adjusted size
//viewer.AutoRotate = true; //Print the file with adjusted rotation
viewer.PrintPageDialog = true; //Do not produce the page number dialog when printing
////PrinterJob printJob = PrinterJob.getPrinterJob();
//Create objects for printer and page settings and PrintDocument
System.Drawing.Printing.PrinterSettings ps = new System.Drawing.Printing.PrinterSettings();
System.Drawing.Printing.PageSettings pgs = new System.Drawing.Printing.PageSettings();
//System.Drawing.Printing.PrintDocument prtdoc = new System.Drawing.Printing.PrintDocument();
//prtdoc.PrinterSettings = ps;
//Set printer name
//ps.PrinterName = prtdoc.PrinterSettings.PrinterName;
ps.PrinterName = "CutePDF Writer";
ps.PrintToFile = true;
ps.PrintFileName = #"test.pdf";
//
//ps.
//Set PageSize (if required)
//pgs.PaperSize = new System.Drawing.Printing.PaperSize("A4", 827, 1169);
//Set PageMargins (if required)
//pgs.Margins = new System.Drawing.Printing.Margins(0, 0, 0, 0);
//Print document using printer and page settings
viewer.PrintDocumentWithSettings(ps);
//viewer.PrintDocument();
//Close the PDF file after priting
What I discovered and seems to be little explained, is that if you select
ps.PrintToFile = true;
no matter C# PDF library or PDF printer driver, Windows will just skip the PDF drivers and instead of PDF files will output PS (postscript) ones which obviously, will not be recognized by Adobe Reader.
Now the question (and I am positive that others who may want to print PDFs from C# may be encountered) is how to print to CutePDF for example and still suppress any filename dialog?
In other words, just print silently with programmatically selected filename from C# application. Or somehow convince "print to file" to go through PDF driver, not Windows default PS driver.
Thanks very much for any hints.
I solved conversion to grayscale with a commercial component with this post and I also posted there my complete solution, in care anyone will struggle like me.
Converting PDF to Grayscale pdf using ABC PDF
I try to extract the text of a pdf via
iTextSharp.text.pdf.parser.PdfTextExtractor.GetTextFromPage,
which does not work because of some bad formatting of the pdf file with respect to an inline picture.
I figured out that I can fix this problem, if I (A) open the pdf in Adobe Acrobat and save it as an optimized pdf. Then the parsing would work.
Or (B) I would open it in Adobe Acrobat and print it again via Adobe PDF as pdf.
Now I have 14.000 of these files and want to automate (A) or (B). But somehow I cannot succeed.
For (A) I included the Adobe library and do in short something like this
mApp = new AcroAppClass();
avDoc = new AcroAVDocClass();
avDoc.Open (strFilePath, "");
pdDoc = (CAcroPDDoc)avDoc.GetPDDoc ();
pdDoc.Save(1, strFilePath.Substring(0, strFilePath.Length - 4) + "_changed.pdf");
But Adobe SDK does not allow me to save as a different format.
For (B) it tried something like this:
Process pdfProcess = new Process();
pdfProcess.StartInfo.FileName = #"C:\Program Files (x86)\Adobe\Acrobat 11.0\Acrobat\AcroRd32.exe";
pdfProcess.StartInfo.Arguments = string.Format(#"/t", strFilePathSource, "Adobe PDF", "Adobe PDF", strFilePathTarget);
pdfProcess.Start();
This is not throwing any error, but there is also no file produced.
I am creating a HTML catalog of movies, and then converting it to PDF. I was using EO.Pdf, and it worked for my small test sample. However, when I run it against the entire list of movies, the resulting HTML file is nearly 8000 lines, and 7MB. EO.Pdf times out when attempting to convert it. I believe it is a limitation of the free version, as I can copy the entire HTML and paste it into their online demo and it works.
I am looking for an alternative to use. I am not good with command line, or running external programs, so I would prefer something I can add to the .NET library and use easily. I will admit that the use of EO.Pdf was easy, once I added the dll to the libarary and added the namespace, it took one line of code to convert either the HTML Code, or the HTML file into a PDF. The downsides I ran into were that they had a stamp on every page (in 16pt font) with their website on it. It also wouldn't pick up half of my images, not sure why. I used a relative URL in the HTML file to the images, and I created the PDF in the same dir as the HTML file.
I do not want to re-create the layout in a PDF, so I think something like iTextSharp is out. I've read a bit about something called like wkhtmltopdf or something strange like that. It sounded good, but needed a wrapper, and I have no clue how to accomplish that, or use it.
I would appreciate suggestions with basic instructions how to use them. Either a library and a couple lines on how to use it. Or if you can tell me how to setup/use the wkhtmltopdf I would be extremely greatful!
Thanks in advance!
I'm using wkhtmltopdf and I'm very happy with it. One way of using it:
Process p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "wkhtmltopdf.exe";
p.StartInfo.Arguments = "-O landscape <<URL>> -";
p.Start();
and then you can get a stream:
p.StandardOutput.BaseStream
I used this because I needed a stream, of course you can invoke it differently.
Here is also a discussion about invoking wkhtmltopdf
I just saw, that someone is implementing a c# wrapper for wkhtmltopdf. I haven't tested it, but may be worth a look.
After much searching I decided to use HiQPdf. It was simple to use, fast enough for my needs and the price point was acceptable to me.
var converter = new HiQPdf.HtmlToPdf();
converter.Document.PageSize = PdfPageSize.Letter;
converter.Document.PageOrientation = PdfPageOrientation.Portrait;
converter.Document.Margins = new PdfMargins(15); // Unit = Points
converter.ConvertHtmlToFile(htmlText, null, fileName);
It even includes a free version if you can keep it to 3 pages.
http://www.hiqpdf.com/free-html-to-pdf-converter.aspx
And no, I am in no way affiliated with them.
I recommend ExpertPdf.
ExpertPdf Html To Pdf Converter is very easy to use and it supports the latest html5/css3. You can either convert an entire url to pdf:
using ExpertPdf.HtmlToPdf;
byte[] pdfBytes = new PdfConverter().GetPdfBytesFromUrl(url);
or a html string:
using ExpertPdf.HtmlToPdf;
byte[] pdfBytes = new PdfConverter().GetPdfBytesFromHtmlString(html, baseUrl);
You also have the alternative to directly save the generated pdf document to a Stream of file on the disk.
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
What is the best way to print stuff from c#/.net?
The question is in regard to single pages as well as to reports containing lots of pages.
It would be great to get a list of the most common printing libs containing the main features and gotchas of each of them.
[Update] for standard windows clients (or servers), not for web apps, please.
For reports, I use the RDLC control.
For everything else, I use the inherent printing objects within .NET.
Edit
The inherent printing objects are all found in the System.Drawing.Printing namespace. When you use the PrintDialog or the PrintPreviewDialog in a WinForms (or WPF) application, it is to these objects that you're turning over control.
The fundamental concept is that you're drawing to the printer. The simplest form of this is:
Sub MyMethod()
Dim x as New PrintDocument
AddHandler x.PrintPage, AddressOf printDoc_PrintPage
x.Print
End Sub
Sub printDoc_PrintPage( sender as Object, e as PrintPageEventArgs)
Dim textToPrint as String= ".NET Printing is easy"
dim printFont as new Font("Courier New", 12)
dim leftMargin as int= e.MarginBounds.Left
dim topMargin as int = e.MarginBounds.Top
e.Graphics.DrawString(textToPrint, printFont, Brushes.Black, leftMargin, topMargin)
End Sub
What's happening here is that when my object (x) is sent the print command, it raises the "PRINT PAGE" event (which is designed to print 1 page at a time). This event then uses the Graphics attribute of the PrintPageEventArgs to draw the relevant string directly to the print spooler.
Here's one tutorial, and a quick Google search for ".NET printing tutorial" returns a bit over 200K results.
We used a set of third party DLLs from PDFSharp who in turn use DLLs from MigraDoc. I'm not privy to all the reasons that we went that direction (the decision was made by a senior developer), but I can tell you that:
It seems to be in active
development.
It had most of the
features we needed.
The source code
is available. Although it used some
patterns and conventions that I
hadn't seen before, once I got on to
them, it was fairly easy to make the
changes. I added support for using
the System.Drawing.Image directly
rather than as saving files.
It is
not documented well either
internally or externally.
» Sample Code to show basics of Printing in Windows Forms Applications:
using System.Drawing.Printing;
PrintDocument printDoc = new PrintDocument();
printDoc.DefaultPageSettings.Landscape = true;
printDoc.DefaultPageSettings.Margins.Left = 100; //100 = 1 inch = 2.54 cm
printDoc.DocumentName = "My Document Name"; //this can affect name of output PDF file if printer is a PDF printer
//printDoc.PrinterSettings.PrinterName = "CutePDF";
printDoc.PrintPage += new PrintPageEventHandler(printDoc_PrintPage);
PrintDialog printDialog = new PrintDialog();
printDialog.Document = printDoc; //Document property must be set before ShowDialog()
DialogResult dialogResult = printDialog.ShowDialog();
if (dialogResult == DialogResult.OK)
{
printDoc.Print(); //start the print
}
void printDoc_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
string textToPrint = ".NET Printing is easy";
Font font = new Font("Courier New", 12);
// e.PageBounds is total page size (does not consider margins)
// e.MarginBounds is the portion of page inside margins
int x1 = e.MarginBounds.Left;
int y1 = e.MarginBounds.Top;
int w = e.MarginBounds.Width;
int h = e.MarginBounds.Height;
g.DrawRectangle(Pens.Red, x1, y1, w, h); //draw a rectangle around the margins of the page, also we can use: g.DrawRectangle(Pens.Red, e.MarginBounds)
g.DrawString(textToPrint, font, Brushes.Black, x1, y1);
e.HasMorePages = false; //set to true to continue printing next page
}
Loads of stuff, you say. Hum, seems that you should use a solution with a designer, so you should look into Crystal Reports and RDLC.
There's also the Reporting Services solution, but in that case you would need a server with SQL Server.
Crystal Reports seems to give you more choices, but needs a little more learning than RDLC.
I wouldn't recommend you create those in HTML + CSS, because of the limitations and the extra work you would have to throw at it.
If you can build your output as a FlowDocument, you can turn it into XPS easily to get an "electronic" version, and the print the XPS.
It depends a lot on the requirements of your application.
Even though it isn't the perfect tool (really far from that), Crystal Reports tends to be a good choice.
It gives you the option of getting data directly from a Database or, if you already have a list of objects you want to print, you can pass them to the document and bind the object properties to the labels of the report.
But give us some more information of what you're trying to do, so you can receive better proposals.
Can Print via Adobe Acrobat
I use the standard libraries such as System.Diagnostics.ProcessStartInfo to use Adobe Acrobat to print a pdf. The end user will not have to interact with the Acrobat GUI, though, annoyingly, the following code still pulls it on-screen for a few seconds.
// Sample fileName = System.Environment.GetFolderPath(
// System.Environment.SpecialFolder.CommonApplicationData)
// + #"\MyCompany\MyProject\TestPrint.pdf"
private void SendPrintJob(string fileName)
{
try
{
// Start by finding Acrobat from the Registry.
// This supposedly gets whichever you have of free or paid
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = processFilename;
info.Arguments = String.Format("/p /h {0}", fileName);
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.UseShellExecute = false;
Process p = new Process();
p.StartInfo = info;
p.Start();
p.WaitForInputIdle();
// Recommended to add a time-out feature. Mine is coded here.
}
catch (Exception e)
{
Console.WriteLine("Error sending print job. " + e.Message);
}
Can Manipulate via PDFSharp/MigraDoc
I did not read document manipulation into the OP, but I see other answers commenting on the fact. A few StackOverflow Q&As from 2008-2012 (including #Robert Gowland from this question) say that PDFSharp / MigraDoc have poor documentation.
In 2018, I have found it to be an easy learning curve, with many samples at the homepage. I read this question this morning to figure out how to print a graph, and now have a button to screen-shot my application and print.
You will want to go to NuGet package manager for PDFsharp-MigraDocs (or PDFsharp-MigraDocs-WPF, or PDFsharp-MigraDocs-GDI). MigraDocs is the high-level component that can create documents from elements, without care of if they are pdf or image or what have you. PDFSharp is the component that helps to, i.e., rearrange documents, put multiple documents on a page, and break apart content from one to two pages.