Question: I've been attempting to find an easy solution to exporting a Canvas in my WPF Application to a PDF Document.

So far, the best solution has been to use the PrintDialog and set it up to automatically use the Microsoft Print the PDF 'printer'. The only problem I have had with this is that although the PrintDialog is skipped, there is a FileDialog to choose where the file should be saved.

Sadly, this is a deal-breaker because I would like to run this over a large number of canvases with automatically generated PDF names (well, programitically provided anyway).

Other solutions I have looked at include:
Using PrintDocument, but from my experimentation I would have to manually iterate through all my Canveses children and manually invoke the correct Draw method (of which a lot of my custom elements with transformation would be rather time consuming to do)

Exporting as a PNG image and then embedding that in a PDF. Although this works, TextBlocks within my canvas are no longer text. So this isn't an ideal situation.

Using the 3rd party library PDFSharp has the same downfall as the PrintDocument. A lot of custom logic for each element.

With PDFSharp. I did find a method fir generating the XGraphics from a Canvas but no way of then consuming that object to make a PDF Page

So does anybody know how I can skip or automate the PDF PrintDialog, or consume PDFSharp XGraphics to make
A page. Or any other ideas for directions to take this besides writing a whole library to convert each of my Canvas elements to PDF elements.

Answer: 
If you look at the output port of a recent windows installation of Microsoft Print To PDF

[![enter image description here](https://i.stack.imgur.com/nPQ1d.png)](https://i.stack.imgur.com/nPQ1d.png)

You may note it is set to PORTPROMP: and that is exactly what causes the request for a filename.

You might note lower down, I have several ports set to a filename, and the fourth one down is called "My Print to PDF"

So very last century methodology; when I print with a duplicate printer but give it a different name I can use different page ratios etc., without altering the built in standard one. The output for a file will naturally be built:-

A) Exactly in one repeatable location, that I can file monitor and rename it, based on the source calling the print sequence, such that if it is my current default printer I can right click files to print to a known \folder\file.pdf

B) The same port can be used via certain /pt (printto) command combinations to output, not just to that default port location, but to a given folder\name such as

```
"%ProgramFiles%\Windows NT\Accessories\WORDPAD.EXE" /pt listIN.doc "My Print to PDF" "My Print to PDF" "listOUT.pdf"

```

Other drivers usually charge for the convenience of WPF programmable renaming, but I will leave you that PrintVisual challenge for another of your three wishes.
MS suggest [XPS is best](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/printing-overview?view=netframeworkdesktop-4.8) But then they would be promoting it as a PDF competitor.

It does not need to be Doc[X]2PDF it could be [O]**XPS2PDF** or aPNG2PDF or many pages TIFF2PDF etc. etc. Any of those are Native to Win 10 also other 3rd party apps such as [Free]Office with a PrintTo verb will do XLS[X]2PDF. Imagination becomes pagination.
I had a great success in generating PDFs using PDFSharp in combination with SkiaSharp (for more advanced graphics).

Let me begin from the very end:

* you save the `PdfDocument` object in the following way:

```
PdfDocument yourDocument = ...;
string filename = @"your\file\path\document.pdf"
yourDocument.Save(filename);

```

* creating the `PdfDocument` with a page can be achieved the following way (adjust the parameters to fit your needs):

```
PdfDocument yourDocument = new PdfDocument();
yourDocument.PageLayout = PdfPageLayout.SinglePage;
yourDocument.Info.Title = "Your document title";
PdfPage yourPage = yourDocument.AddPage();
yourDocument.Orientation = PageOrientation.Landscape;
yourDocument.Size = PageSize.A4;

```

* the `PdfPage` object's content (as an example I'm putting a string and an image) is filled in the following way:

```
using (XGraphics gfx = XGraphics.FromPdfPage(yourPage))
{  
    XFont yourFont = new XFont("Helvetica", 20, XFontStyle.Bold);
    gfx.DrawString(
        "Your string in the page",
        yourFont,
        XBrushes.Black,
        new XRect(0, XUnit.FromMillimeter(10), page.Width, yourFont.GetHeight()),
        XStringFormats.Center);

    using (Stream s = new FileStream(@"path\to\your\image.png", FileMode.Open))
    {
        XImage image = XImage.FromStream(s);
        var imageRect = new XRect()
        {
            Location = new XPoint() { X = XUnit.FromMillimeter(42), Y = XUnit.FromMillimeter(42) },
            Size = new XSize() { Width = XUnit.FromMillimeter(42), Height = XUnit.FromMillimeter(42.0 * image.PixelHeight / image.PixelWidth) } 
        };

        gfx.DrawImage(image, imageRect);
    }
}

```

Of course, the font objects can be created as static members of your class.

And this is, in short to answer your question, how you consume the `XGraphics` object to create a PDF page.  

Let me know if you need more assistance.