System.Windows.Xps
| Language | C# (.NET 6+ with WPF, .NET Framework 3.0+), Windows only |
|---|---|
| License | MIT (open source in dotnet/wpf) |
| Repository | github.com/dotnet/wpf |
| Documentation | System.Windows.Xps.Packaging, XpsDocument, XpsDocumentWriter |
| Depends on | WPF (Windows Desktop runtime) |
| Read / write | yes / yes (XPS 1.0; not OpenXPS .oxps) |
XPS and WPF were designed together: an XPS page is serialized WPF markup (FixedPage with Path, Glyphs and Canvas). System.Windows.Xps.Packaging.XpsDocument opens or creates the ZIP package, GetFixedDocumentSequence() loads it as WPF objects, and XpsDocumentWriter saves any WPF visual, FixedDocument or paginated document as XPS. The same writer can send output to a printer.
It’s Windows only, needs a WPF project, and must run on an STA thread. It handles XPS 1.0; OpenXPS files from the Windows 8+ XPS Document Writer use different namespaces and fail to load.
Installation#
Nothing to install: enable WPF in the project file.
XML
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
Basic usage: create an XPS document#
C#
using System;
using System.IO;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Xps;
using System.Windows.Xps.Packaging;
class Program
{
[STAThread]
static void Main()
{
var page = new FixedPage { Width = 816, Height = 1056 }; // Letter, 1/96 inch
var title = new TextBlock { Text = "Hello, XPS", FontSize = 32 };
FixedPage.SetLeft(title, 96);
FixedPage.SetTop(title, 96);
page.Children.Add(title);
var box = new Rectangle { Width = 300, Height = 100, Fill = Brushes.SteelBlue };
FixedPage.SetLeft(box, 96);
FixedPage.SetTop(box, 180);
page.Children.Add(box);
var document = new FixedDocument();
document.Pages.Add(new PageContent { Child = page });
File.Delete("out.xps");
using var xps = new XpsDocument("out.xps", FileAccess.ReadWrite);
XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(xps);
writer.Write(document);
}
}
How to extract text from an XPS file#
Text is in the UnicodeString of Glyphs elements:
C#
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Xps.Packaging;
static IEnumerable<T> Descendants<T>(DependencyObject root) where T : DependencyObject
{
foreach (object child in LogicalTreeHelper.GetChildren(root))
{
if (child is not DependencyObject d) continue;
if (d is T t) yield return t;
foreach (T x in Descendants<T>(d)) yield return x;
}
}
using var xps = new XpsDocument("in.xps", FileAccess.Read);
FixedDocumentSequence seq = xps.GetFixedDocumentSequence();
foreach (DocumentReference docRef in seq.References)
{
FixedDocument doc = docRef.GetDocument(false);
foreach (PageContent pc in doc.Pages)
{
FixedPage page = pc.GetPageRoot(false);
foreach (Glyphs g in Descendants<Glyphs>(page))
Console.WriteLine(g.UnicodeString);
}
}
How to render XPS pages to PNG#
C#
using System.IO;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Xps.Packaging;
using var xps = new XpsDocument("in.xps", FileAccess.Read);
DocumentPaginator paginator = xps.GetFixedDocumentSequence().DocumentPaginator;
const double dpi = 150;
for (int i = 0; i < paginator.PageCount; i++)
{
using DocumentPage page = paginator.GetPage(i);
var bitmap = new RenderTargetBitmap(
(int)(page.Size.Width * dpi / 96), (int)(page.Size.Height * dpi / 96),
dpi, dpi, PixelFormats.Pbgra32);
bitmap.Render(page.Visual); // transparent where the page draws nothing
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using var file = File.Create($"page-{i + 1:D3}.png");
encoder.Save(file);
}
Run this on an STA thread ([STAThread] on Main).
How to read the title and author#
C#
using var xps = new XpsDocument("in.xps", FileAccess.Read);
var props = xps.CoreDocumentProperties; // System.IO.Packaging.PackageProperties
Console.WriteLine($"title: {props.Title}, creator: {props.Creator}, created: {props.Created}");
Tips#
XpsDocumentWriter.Write(visual)saves any WPF control (a chart, a form) as a one-page XPS document.- To print an XPS file, get a
PrintQueue(new LocalPrintServer().DefaultPrintQueue) and callPrintQueue.CreateXpsDocumentWriter(queue).Write(seq). - For
.oxpsfiles or non-Windows systems, use MuPDF or PyMuPDF.