I'm working on application that builds FlowDocuments and exports them to various formats. We can export to XPS easily enough and PDF is possible using the Microsoft Print to PDF driver, but the latter has limitations that provide a poor user experience. Namely, it provides its own 'Save As' dialog and doesn't provide any notification upon completion when printing large documents. Therefore, I'm looking at alternatives to either convert FlowDocuments or XPS documents to PDF.
Most sources (a selection linked below) suggest using PDFSharp
library using the PdfSharp.Xps.XpsConverter.Convert
method to convert an XPS to PDF, with code samples similar to the following:
public void SaveAsPdf(FlowDocument flowDoc, string path)
{
using var stream = new MemoryStream();
using var package = Package.Open(stream, FileMode.Create);
using var xpsDoc = new XpsDocument(package);
var xpsDocWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
xpsDocWriter.Write(((IDocumentPaginatorSource)flowDoc).DocumentPaginator);
using var pdfXpsDoc = PdfSharp.Xps.XpsModel.XpsDocument.Open(stream);
PdfSharp.Xps.XpsConverter.Convert(pdfXpsDoc, path, 0);
}
However, whatever NuGet package I try to install I am unable to resolve the PdfSharp.Xps
namespace. I've tried searching various code repositories on Github for the XpsConverter
class but I can't seem to find any. From what I can gather the XPS features were a beta in version 1.31 of PDF Sharp but were included in version 1.32 and haven't been today. I'd rather not use beta code in our solution if we can avoid it. Many of these articles 10 years old and I suspect that the information may be out of date.
Therefore, I'm asking, as of 2023, how can I convert a FlowDocument or an XPS document to PDF without the usability limitations of Microsoft Print to PDF driver mentioned above. Acceptable answers including the use of third party libraries, but ideally they are open source, stable and easily accessible via NuGet. Example code would also be welcome.
Sources
I think I've figured out. There's a couple of things that confused me:
I've found the following NuGet package that provides the XpsConverter
class: XpsToPdf. This packages wasn't mentioned in any of the sources above, probably because the package was first published in 2020. I'm grateful that it exists now.
Also there was a mistake in my sample code in the question. I was getting a System.IO.FileFormatException: 'Archive file cannot be size 0.'
exception from the PdfSharp.Xps.XpsModel.XpsDocument.Open
. Turns out I need to close the Package
and XpsDocument
objects before data is written to the stream. Therefore the correct code sample is:
public void SaveAsPdf(FlowDocument flowDoc, string path)
{
using var stream = new MemoryStream();
using (var package = Package.Open(stream, FileMode.Create))
using (var xpsDoc = new XpsDocument(package))
{
var xpsDocWriter = XpsDocument.CreateXpsDocumentWriter(xpsDoc);
xpsDocWriter.Write(((IDocumentPaginatorSource)flowDoc).DocumentPaginator);
}
using var pdfXpsDoc = PdfSharp.Xps.XpsModel.XpsDocument.Open(stream);
PdfSharp.Xps.XpsConverter.Convert(pdfXpsDoc, path, 0);
}
So in summary, to answer the original question: