I want to save an IDocumentPaginatorSource, e.g. FixedDocument or XpsDocument, as a PDF by using the virtual printer "Microsoft Print to PDF":
var printServer = new System.Printing.PrintServer();
var queue = printServer.GetPrintQueue("Microsoft Print to PDF");
var writer = System.Printing.PrintQueue.CreateXpsDocumentWriter(queue);
writer.Write(Document.DocumentPaginator); // Document = IDocumentPaginatorSource
This works, but makes the printer open a file save dialog. I would like to set the file name programmatically and either suppress this dialog completely or at least set the initial file name in the dialog. Is this possible?
I know, that this can be done when using System.Drawing.Printing.PrintDocument by setting PrinterSettings.PrintFileName and PrinterSettings.PrintToFile (see 1, 2), but this is the old printing framework that does not support IDocumentPaginatorSource.
I checked all classes in the System.Printing namespace but did not find any way to set these two settings. Maybe it's possible to retrofit these seetings into the PrintTicket by extending the print schema? If so, how exactly would you do that?
I don't have a solution using the "Microsoft Print to PDF printer", but if you switched to using the Win2PDF printer driver you can set the file name programatically through the registry. To do this, see the documentation for the "PDFFileName" or "PDFDefaultFileName" registry settings.
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 am using PrintTicket object (printTicket.Stapling = Stapling.StapleTopLeft;) and using PrintQueue.Addjob method in System.printing to enable stapling option. Stapling is working fine with XPS document, but not working with PDF documents. Here is my code:
PrintTicket printTicket = printQueue.DefaultPrintTicket;
printTicket.Stapling = Stapling.StapleTopLeft;
printQueue.CurrentJobSettings.CurrentPrintTicket = printTicket;
printQueue.AddJob("TEST", "C:\\TEST.XPS", false, printTicket);
TEST.XPS is printing and stapling, but changing the file to PDF is not working.
If you look at the MDSN for that AddJob method it specifically says it for XPS documents only.
https://msdn.microsoft.com/en-us/library/jj205516%28v=vs.110%29.aspx
Inserts a new print job for an XML Paper Specification (XPS) Document
into the queue, gives it the specified name and settings, and
specifies whether or not it should be validated.
I have a PDF template with a form with the Extended features enabled. After filling in the fields of this form using iTextSharp, a user with acrobat reader gets the error message:
This document enabled extended features in Adobe Reader. The document has
been changed since it was created and use of extended features is no longer
available. Please contact the author for the original version of this
document.
I googled a bit but all the posts talk about "enabling" extended features, however, I want the form fields to remain disabled and extended features turned off
Here a sample code which I am using:
using (var existingFileStream = new FileStream(fileNameExisting, FileMode.Open))
using (var newFileStream = new FileStream(fileNameNew, FileMode.Create))
{
// Open existing PDF
var pdfReader = new PdfReader(existingFileStream);
// PdfStamper, which will create
var stamper = new PdfStamper(pdfReader, newFileStream);
var form = stamper.AcroFields;
var fieldKeys = form.Fields.Keys;
foreach (string fieldKey in fieldKeys)
{
if (fieldKey.Equals("Retailer Name"))
form.SetField(fieldKey, retailerName);
}
// “Flatten” the form so it wont be editable/usable anymore
stamper.FormFlattening = true;
stamper.Close();
pdfReader.Close();
}
The links here are dead as the iTextPdf web site has been completely revamped. But the answer can be understood without those links, too.
The iText Keyword: Reader enabled PDFs points to the following information:
Submitted by Bruno Lowagie on Fri, 12/31/2010 - 16:37
After filling out my form, my PDF shows the following message: This document enabled extended features in Adobe Reader. The document has been changed since it was created and use of extended features is no longer available. Please contact the author for the original version of this document. How do I avoid this message?
The creator of the form made the document Reader enabled. Reader enabling can only be done using Adobe software. You can avoid this message in two ways:
Remove the usage rights. This will result in a form that is no longer Reader enabled. For instance: if the creator of the document allowed that the filled out form could be saved locally, this will no longer be possible after removing the usage rights.
Fill out the form in append mode. This will result in a bigger file size, but Reader enabling will be preserved.
It also points to the sample ReaderEnabledForm.java (the C#/iTextSharp equivalent of which is ReaderEnabledForm.cs) which shows how to do either.
In your case this amounts to calling
pdfReader.RemoveUsageRights();
right after creating the PdfReader and before creating the PdfStamper.
/**
* Removes any usage rights that this PDF may have. Only Adobe can grant usage rights
* and any PDF modification with iText will invalidate them. Invalidated usage rights may
* confuse Acrobat and it's advisabe to remove them altogether.
*/
public void RemoveUsageRights()
Fill out the form in append mode by using the PdfStamper constractor overload
// PdfStamper, which will create
var stamper = new PdfStamper(pdfReader, fileStream, '\0', true);
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.