Print PDF with Acrobat Pro: select printer - c#

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.

Related

Is it possible to print pdf files without Adobe installed

I am trying to send pdf files to printer
Process p = new Process( );
p.StartInfo = new ProcessStartInfo( )
{
CreateNoWindow = true,
Verb = "Print",
FileName = pdfFilePath
WindowStyle := ProcessWindowsStyle.Hidden;
UseShellExecute := true;
};
p.Start( );
but i am constantly getting "No application is associated with the specified file for this operation".
I am using Edge to open pdf files (i tried also to set IE and Chrome as default .pdf apps) and i have no pdf reader installed. My question is it possible to send pdf files to the printer directly only with the default windows tools - without installing Acrobat reader etc. ?
Check this library Spire.PDF
https://www.nuget.org/packages/Spire.PDF/
PdfDocument pdf = new PdfDocument();
pdf.LoadFromFile("Sample.pdf");
//Set the printer
pdf.PrintSettings.PrinterName = "HP LasterJet P1007";
//Only print the second and fourth page
pdf.PrintSettings.SelectSomePages(new int[] { 2,4 });
//Print the pages from 1 to 15
pdf.PrintSettings.SelectPageRange(1,15);
pdf.Print();
Here is an alternative approach that uses GemBox.Pdf, which also doesn't require having Adobe Acrobat installed:
using (PdfDocument document = PdfDocument.Load(pdfFilePath))
document.Print();
The above will print your PDF using default printer and print options.
But if needed, you can specify the targeted printer and options like this:
using (var document = PdfDocument.Load(pdfFilePath))
{
var printer = "your printer's name";
var printOptions = new PrintOptions()
{
FromPage = 2,
ToPage = 4
};
document.Print(printer, printOptions);
}
You can find more Print example's here.
You can Ghostscript which is open source there is a NuGet to use this library in with this program
This NuGet is just a library that interfaces with the Ghostscript library, you need to have Ghostscript installed on the client or add the libraries to the project for it to work
https://www.nuget.org/packages/Ghostscript.NET
Example:
using (GhostscriptProcessor processor = new
GhostscriptProcessor())
{
List<string> arg = new List<string>() {
"-empty",
"-dPrinted",
"-dBATCH",
"-dNOPAUSE",
"-dNOSAFER",
"-dNumCopies=1",
"-sDEVICE=mswinpr2",
"-sOutputFile=%printer%" + printerName,
"-f",
inputFile};
processor.StartProcessing(arg.ToArray(), null);
}

How to print PDF documents or other printable files in UWP? [duplicate]

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;
}
}

Fill pdf template fields with cyrillic values (itextsharp)

I have PDF template file with fields.
Template created by customer. It has some text, field labels and fields itself. Text and labels uses some font which is embedded within the template.
Problems occur when I try to fill fields with cyrillic values - there is no cyrillic symbols in result document.
I saw a lot of similar problems which were solved by using substitution font for AcroFields. But here I can't use one specific font for substitution, because I can't define field font in template.
I tried to set different fonts for fields in Acrobat Editor - Times New Roman, Arial and other well known Windows fonts, but there is no effect in resulting pdf.
Code sample:
FontFactory.RegisterDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Fonts));
using (var dest = File.Create(#"result.pdf"))
{
using (var stamper = new PdfStamper(reader, dest))
{
var fields = stamper.AcroFields;
fields.SetField("ClientName", "Имя клиента");
stamper.FormFlattening = true;
stamper.Close();
}
}
I even registered all available fonts in FontFactory, but there was no effect.
So the questions are:
1. If I can embed font in Adobe Acrobat used for fields only, then how to do it?
2. If I can define font family for existing field with iTextSharp, then how to do it?
Well, I wrote solution suitable for me.
Register all existing system fonts in FontFactory.
Read document metadata to extract all used fonts in documents.
Read fields metadata and try to create BaseFont suitable to field font. If there is no suitable font - use fallback font (arial with encoding IDENTITY_H).
So full code looks like:
static IEnumerable<PdfFontInfo> ReadDocumentFonts(PdfReader reader)
{
if (reader.AcroForm == null)
yield break;
var dr = reader.AcroForm.GetAsDict(PdfName.DR);
// Read font information from resources
var fontDict = dr.GetAsDict(PdfName.FONT);
foreach (var fontKey in fontDict.Keys)
{
var data = fontDict.GetAsDict(fontKey);
// Read font descriptor if it possible
var descriptor = data.GetAsDict(PdfName.FONTDESCRIPTOR);
if (descriptor != null)
{
// Read font name and family
var family = descriptor.GetAsString(PdfName.FONTFAMILY);
yield return new PdfFontInfo(fontKey, family.ToUnicodeString());
}
}
}
static IReadOnlyList<BaseFont> CreateSubstitutionFontsForFields(PdfReader reader)
{
if (reader.AcroForm.Fields == null)
return new List<BaseFont>(0);
var documentFontMap = ReadDocumentFonts(reader).ToDictionary(f => f.Name, StringComparer.InvariantCultureIgnoreCase);
var substFonts = new Dictionary<string, BaseFont>();
var fallbackRequired = false;
// Read font information of each field
foreach (var field in reader.AcroForm.Fields)
{
var fieldFontDa = field.Info.GetAsString(PdfName.DA);
if (fieldFontDa == null)
continue;
var parts = AcroFields.SplitDAelements(fieldFontDa.ToUnicodeString());
if (parts.Length == 0)
continue;
var fontName = (string) parts[0];
PdfFontInfo inf;
if (documentFontMap.TryGetValue(fontName, out inf))
{
if (!substFonts.ContainsKey(fontName))
{
var font = FontFactory.GetFont(fontName, BaseFont.IDENTITY_H, true).BaseFont;
substFonts.Add(fontName, font);
}
}
else
fallbackRequired = true;
}
var allFonts = new List<BaseFont>(substFonts.Values);
if (fallbackRequired)
allFonts.Add(FALLBACK_FONT);
return allFonts;
}
If you can find any errors, you are welcome to comment.

C# PrintDocument creates invalid xps file depending on default printer?

My C# application prints some pages to a xps file, however i have discovered that if the default printer is a networked printer then the created xps file is invalid "The XPS viewer cannot open this document".
This confuses me since i'm not even writing to a networked printer.. but to a file.
If i don't have the default printer set to a networked printer (default printer is "send to OneNote" or "Microsoft XPS Document Writer"), then the bellow code correctly creates a XPS file with 2 pages when executed:
pageCounter = 0;
PrintDocument p = new PrintDocument();
p.PrintPage += delegate(object sender1, PrintPageEventArgs e1)
{
// 8.5 x 11 paper:
float x0 = 25;
float xEnd = 850 - x0;
float y0 = 25;
float yEnd = 1100 * 2 - y0; // bottom of 2ed page
Font TitleFont = new Font("Times New Roman", 30);
if (pageCounter == 0) // for the first page
{
e1.Graphics.DrawString("My Title", TitleFont, new SolidBrush(Color.Black), new RectangleF(300, 15, xEnd, yEnd));
e1.HasMorePages = true; // more pages
pageCounter++;// next page counter
}
else // the second page
{
e1.Graphics.DrawString("Page 2", TitleFont, new SolidBrush(Color.Black), new RectangleF(300, 15, xEnd, yEnd));
}
};
// now try to print
try
{
p.PrinterSettings.PrintFileName = fileName; // the file name set earlier
p.PrinterSettings.PrintToFile = true; // print to a file (i thought this would ignore the default printer)
p.Print();
}
catch (Exception ex)
{
// for the Bug I have described, this Exception doesn't happen.
// it creates an XPS file, but the file is invalid in the cases mentioned
MessageBox.Show("Error", "Printing Error", MessageBoxButton.OK);
}
so my question is... why does this happen, what am i doing wrong?
Well, there's no specific question here, but I'll tell you what I know. You are using the default printer's driver to generate the output document that is being saved to a file. Some drivers output xps content that is then consumed by the printer to put ink/toner on the page. Other drivers output postscript, PCL, PDF, or some other data format. So, depending on the default printer, you could be saving data in any one of these formats.
To ensure that you actually produce XPS content, you would need to specify the "Microsoft XPS Document Writer" as the printer to use in p.PrinterSettings.PrinterName. Of course, this could fail if that print queue has been renamed or removed. You could jump through some hoops with PrinterSettings.InstalledPrinters to try and determine which queue is the XPS Document Writer, but again, this will fail if the printer has been removed. A more robust solution would be to generate the XPS content directly with an XpsDocumentWriter, however that would require some substantial changes.

Excel, Word, PDFs AND PowerPoint print dialogues

Anybody know how to get all of these in a C# app that leads the user to a print dialogue screen?
What I mean is this:
In the gui the user selects a document, right clicks on the doc, chooses Print. Instead of immediately printing out the doc, the print dialogue comes up.
Anybody know the syntax for all of this? I tried using all of the interops for the MS Office apps and trying the printdialogue method...but no such luck.
Can anybody provide me with some code? I've seriously been at this for HOURS and can't come up with a thing.
Maybe see this previous Q&A:
send-document-to-printer-with-c#
Or, for a WPF app that prints a FlowDocument :
private void DoThePrint(System.Windows.Documents.FlowDocument document)
{
// Clone the source document's content into a new FlowDocument.
// This is because the pagination for the printer needs to be
// done differently than the pagination for the displayed page.
// We print the copy, rather that the original FlowDocument.
System.IO.MemoryStream s = new System.IO.MemoryStream();
TextRange source = new TextRange(document.ContentStart, document.ContentEnd);
source.Save(s, DataFormats.Xaml);
FlowDocument copy = new FlowDocument();
TextRange dest = new TextRange(copy.ContentStart, copy.ContentEnd);
dest.Load(s, DataFormats.Xaml);
// Create a XpsDocumentWriter object, implicitly opening a Windows common print dialog,
// and allowing the user to select a printer.
// get information about the dimensions of the seleted printer+media.
System.Printing.PrintDocumentImageableArea ia = null;
System.Windows.Xps.XpsDocumentWriter docWriter = System.Printing.PrintQueue.CreateXpsDocumentWriter(ref ia);
if (docWriter != null && ia != null)
{
DocumentPaginator paginator = ((IDocumentPaginatorSource)copy).DocumentPaginator;
// Change the PageSize and PagePadding for the document to match the CanvasSize for the printer device.
paginator.PageSize = new Size(ia.MediaSizeWidth, ia.MediaSizeHeight);
Thickness t = new Thickness(72); // copy.PagePadding;
copy.PagePadding = new Thickness(
Math.Max(ia.OriginWidth, t.Left),
Math.Max(ia.OriginHeight, t.Top),
Math.Max(ia.MediaSizeWidth - (ia.OriginWidth + ia.ExtentWidth), t.Right),
Math.Max(ia.MediaSizeHeight - (ia.OriginHeight + ia.ExtentHeight), t.Bottom));
copy.ColumnWidth = double.PositiveInfinity;
//copy.PageWidth = 528; // allow the page to be the natural with of the output device
// Send content to the printer.
docWriter.Write(paginator);
}
}

Categories

Resources