I needed to generate images for an HTML document I'm generating, for which I use create a DrawingVisual and render it to a RenderTargetBitmap before saving to a PNG file. Now I would like to save the same visual to an XPS document. The benefit of having an XPS document is that you can zoom it at any size you wand or even print it out. So after working on the original XPS implementation seven years ago, I'm back with XPS again.

Here is the code I'm using:

RenderTargetBitmap image = new RenderTargetBitmap(m_width, m_height, 96, 96, PixelFormats.Pbgra32);
                        
image.Render(m_visual);

string pngFile = fileName + ".png";

using (FileStream stream = new FileStream(pngFile, FileMode.Create))
{
    PngBitmapEncoder encoder = new PngBitmapEncoder();

    encoder.Frames.Add(BitmapFrame.Create(image));
    encoder.Save(stream);
}

string xpsFile = fileName + ".xps";

using (Package container = Package.Open(xpsFile, FileMode.Create))
{
    using (XpsDocument xpsDoc = new XpsDocument(container, CompressionOption.Maximum))
    {
         XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xpsDoc);

         VisualPaginator page = new VisualPaginator(m_visual, m_width, m_height);

         writer.Write(page);
    }
}

 Although XpsDocumentWriter can directly handle an Visual as input, there is no easy way to specifiy a custom page size. So I'm using a VisualPaginator class:

public class VisualPaginator : DocumentPaginator
{
    Size   m_size;
    Visual m_visual;

    public VisualPaginator(Visual visual, double width, double height)
    {
        m_visual = visual;
        m_size   = new Size(width, height);
    }

    public override IDocumentPaginatorSource Source 
    {
        get 
        { 
            return null; 
        }
    }

    public override DocumentPage GetPage(int pageNumber)
    {
        Rect box = new Rect(0, 0, m_size.Width, m_size.Height);

        return new DocumentPage(m_visual, m_size, box, box);
    }

    public override bool IsPageCountValid
    {
        get 
        { 
            return true; 
        }
    }

    public override int PageCount
    {
        get 
        { 
            return 1; 
        }
    }

    public override System.Windows.Size PageSize
    {
        get
        {
            return m_size;
        }
        set
        {
            m_size = value;
        }
    }

}