PDFML is JetsonPDF's declarative XML language for PDFs — clean, prefix-free markup that renders deterministically to ISO 32000-2. Author a document as .pdfml, bind it to your data with WPF-style {Binding} expressions, and turn it into a PDF anywhere .NET runs — or drop the live PdfmlView control onto a WPF / OpenSilver form and watch it re-render as your data changes.
Three ways to use PDFML.
Render — new PdfmlRenderer().Render(pdfml, data). Runtime-independent: no WPF, no browser, no STA. Runs on desktop, server, Blazor, and CI.
Host — <jp:PdfmlView Markup="..." Model="..."/>. A drop-in WPF / OpenSilver control that renders PDFML as a live, data-bound vector view and refreshes automatically.
Author — edit .pdfml in Visual Studio with schema IntelliSense and a live, type-as-you-go PDF preview.
Overview
PDFML is purpose-built for one job — declaring a PDF — rather than retrofitting a screen-oriented format. SVG informed the graphics model and WPF/XAML the layout model, but neither constrained the design. The result is a document format that maps cleanly onto every PDF construct the JetsonPDF writer already produces.
Clean, prefix-free markup. One default namespace; everyday markup has no prefix: qualifiers — <Document>, <Page>, <TextBlock>, <Rectangle>.
PascalCase throughout. Element names, attribute names, enum values, and booleans are PascalCase (TextAlignment="Center", MultiPage="True"), matching WPF/XAML.
WPF layout panels.<StackPanel>, <DockPanel>, and <Grid> work as in WPF, with <Grid.ColumnDefinitions> + Grid.Row/Grid.Column placement. Those five panel attached properties are the only attached properties; everything else uses plain attributes, and absolute placement uses plain X/Y.
PDF-first vocabulary. Native cmyk() color, optional-content layers, page labels, named destinations, AcroForm fields, and PDF/A · PDF/UA conformance are core. Every construct maps to a concrete PDF object.
Page-spanning is a container capability. Any block container (<Document>, <Flow>, <StackPanel>, <DockPanel>, <Grid>) can carry <Header>/<Footer> furniture and MultiPage="True" — no separate template element.
Points + units. Default unit is the PDF point; values may carry pt/in/mm/cm.
<Document Dialect="WPF|PDF|Mixed"> declares the authoring vocabulary.
WPF (default) — the layout dialect. Flow containers (StackPanel/DockPanel/Grid/Flow with Header/Footer furniture) auto-paginate through the headless JetsonPDF.Fluent engine; fixed X/Y pages draw straight to the page.
PDF — a raw PDF imaging-model dialect: content-stream operators in PDF coordinates (bottom-left, y-up), no layout engine. For when you want byte-level control inside the same document.
Mixed — embeds WPF and PDF islands in each other via the <Dialect Use="…"> boundary, in either direction (a PDF island on a WPF page becomes a Form XObject; a WPF island on a PDF page is laid out and drawn in place).
Data binding
Data binding is native. Bind any attribute with a WPF-style {Binding path} expression, and use <ItemsControl> + <DataTemplate> for collections. StringFormat, FallbackValue, and TargetNullValue are supported. You supply a data context; the bindings resolve at render time and the emitted PDF is fully static — no live expressions leak into the file.
The JetsonPDF.Pdfml package turns PDFML into a PDF with no dependency on WPF, OpenSilver, or a browser, so it runs anywhere .NET runs — desktop, server, Blazor Server / WASM, and CI. Bindings resolve against a plain data object via reflection.
dotnet add package JetsonPDF.Pdfml
using JetsonPDF.Pdfml;
var data = new
{
Number = "INV-2026-001",
Title = "Invoice",
Customer = new { Name = "Acme Corporation" },
Lines = new[]
{
new { Description = "Design", Amount = 1200m },
new { Description = "Development", Amount = 4800m },
},
Total = 6000m,
};
var renderer = new PdfmlRenderer();
byte[] pdf = renderer.Render(pdfmlText, data); // {Binding} resolves against `data`
File.WriteAllBytes("invoice.pdf", pdf);
// Or stream straight to disk / the network:
using var fs = File.Create("invoice.pdf");
renderer.Render(pdfmlText, fs, data);
All three dialects (WPF, PDF, Mixed) and the binding engine ship in this package. Relative Source paths for fonts and images resolve against PdfmlOptions.BaseDirectory.
The PdfmlView control
Drop PdfmlView onto a XAML form, point it at PDFML markup and a data model, and it renders the resulting PDF as a live vector visual tree — then re-renders automatically when the markup or model changes (for example, when a timesheet's date range updates). Ships in both JetsonPDF.Wpf and JetsonPDF.OpenSilver from shared source.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:jp="clr-namespace:JetsonPDF.Wpf;assembly=JetsonPDF.Wpf">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<DatePicker SelectedDate="{Binding Start, Mode=TwoWay}"/>
<DatePicker SelectedDate="{Binding End, Mode=TwoWay}"/>
</StackPanel>
<!-- Markup is the .pdfml text; Model is the {Binding} data source
(falls back to DataContext when unset). -->
<jp:PdfmlView Markup="{Binding Template}" Model="{Binding}"/>
</DockPanel>
</Window>
Pipeline — Markup + Model → PdfmlRenderer → PDF → Reader → PdfToXamlConverter → a vector visual tree hosted in a ScrollViewer. All pieces are reused, nothing rasterised.
Auto-refresh — the control observes INotifyPropertyChanged on the model and re-renders on a short debounce, so changing a bound value updates the preview with no explicit call. Changing Markup or swapping Model refreshes too.
Surface — read-only PageCount / RenderError properties; Rendered, RenderFailed, and WidgetActionInvoked events; live AcroForm widgets work because the converter emits real controls.
Cross-platform — the same control compiles into JetsonPDF.Wpf (desktop) and JetsonPDF.OpenSilver (WebAssembly). The only per-platform difference is the runtime XAML parser.
A runnable WPF demo lives at samples/PdfmlViewDemo — a timesheet whose preview updates live as you change the date range.
Authoring in Visual Studio
The PDFML Language Support extension makes Visual Studio 2022 / 2026 treat .pdfml files as first-class XML and renders them to PDF as you type.
Live PDF preview — a preview pane docks beside the editor and re-renders on a ~350 ms debounce, in-process through PdfmlRenderer (no external process, no temp project). The result shows in an embedded WebView2 with scroll / zoom / print; PDFML and XML errors surface inline in a banner instead of blanking the preview.
Schema IntelliSense — element / attribute completion, enum value lists, and validation against the bundled PDFML 1.0 schema, plus the XML editor's outlining, brace matching, and well-formedness checks.
{Binding} expressions render against a null data context in the editor (there's no sample data), so binding-driven content shows its fallbacks.
Spec & examples
PDFML is a documented, draft standard with a normative XML Schema. The specification, schema, and a set of worked, schema-valid examples live under spec/pdfml/ in the JetsonPDF repository:
PDFML-1.0-Specification.md — the full specification (ISO-style clauses + annexes).
pdfml-1.0.xsd — the normative XML Schema, suitable for editor validation and IntelliSense.