I have a FixedDocument
that I allow the user to preview in a WPF GUI and then print to paper without showing any Windows printing dialogue, like so:
private void Print()
{
PrintQueueCollection printQueues;
using (var printServer = new PrintServer())
{
var flags = new[] { EnumeratedPrintQueueTypes.Local };
printQueues = printServer.GetPrintQueues(flags);
}
//SelectedPrinter.FullName can be something like "Microsoft Print to PDF"
var selectedQueue = printQueues.SingleOrDefault(pq => pq.FullName == SelectedPrinter.FullName);
if (selectedQueue != null)
{
var myTicket = new PrintTicket
{
CopyCount = 1,
PageOrientation = PageOrientation.Portrait,
OutputColor = OutputColor.Color,
PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4)
};
var mergeTicketResult = selectedQueue.MergeAndValidatePrintTicket(selectedQueue.DefaultPrintTicket, myTicket);
var printTicket = mergeTicketResult.ValidatedPrintTicket;
// TODO: Make sure merge was OK
// Calling GetPrintCapabilities with our ticket allows us to use
// the OrientedPageMediaHeight/OrientedPageMediaWidth properties
// and the PageImageableArea property to calculate the minimum
// document margins supported by the printer. Very important!
var printCapabilities = queue.GetPrintCapabilities(myTicket);
var fixedDocument = GenerateFixedDocument(printCapabilities);
var dlg = new PrintDialog
{
PrintTicket = printTicket,
PrintQueue = selectedQueue
};
dlg.PrintDocument(fixedDocument.DocumentPaginator, "test document");
}
}
The problem is that I want to also support virtual/file printers, namely PDF printing, by giving the file destination path and not showing any Windows dialogues, but that doesn't seem to work with the PrintDialog
.
I would really like to avoid 3rd party libraries as much as possible, so at least for now, using something like PdfSharp
to convert an XPS to PDF is not something I want to do. Correction: It seems like XPS conversion support was removed from the latest version of PdfSharp.
After doing some research, it seems the only way to print straight to a file is to use a PrintDocument
where it's possible to set PrintFileName
and PrintToFile
in the PrinterSettings
object, but there is no way to give the actual document contents, rather we need to subscribe to the PrintPage
event and do some System.Drawing.Graphics
manipulation where the document is created.
Here's the code I tried:
var printDoc = new PrintDocument
{
PrinterSettings =
{
PrinterName = SelectedPrinter.FullName,
PrintFileName = destinationFilePath,
PrintToFile = true
},
PrintController = new StandardPrintController()
};
printDoc.PrintPage += OnPrintPage; // Without this line, we get a blank PDF
printDoc.Print();
Then the handler for PrintPage
where we need to build the document:
private void OnPrintPage(object sender, PrintPageEventArgs e)
{
// What to do here?
}
Other things that I thought could work are using the System.Windows.Forms.PrintDialog
class instead, but that also expects a PrintDocument
. I was able to create an XPS file easily like so:
var pkg = Package.Open(destinationFilePath, FileMode.Create);
var doc = new XpsDocument(pkg);
var writer = XpsDocument.CreateXpsDocumentWriter(doc);
writer.Write(PreviewDocument.DocumentPaginator);
pkg.Flush();
pkg.Close();
But it's not a PDF, and there seems to be no way to convert it to PDF without a 3rd party library.
Is it possible to maybe do a hack that automatically fills the filename then clicks save on the PrintDialog
?
Thank you!
EDIT: It's possible to print directly to PDF from Word documents using Microsoft.Office.Interop.Word
, but there seems to be no easy way of converting from XPS/FixedDocument to Word.
EDIT: It seems so far the best way is to grab the old XPS to PDF conversion code that was present in PdfSharp 1.31. I grabbed the source code and built it, imported the DLL's, and it works. Credit goes to Nathan Jones, check out his blog post about this here.