flexpdf
flexpdf is a Rust library that renders a small, React-PDF-like XML syntax (or a Rust document model) into a PDF byte buffer. It aims for compatibility with react-pdf layouts and styling. It is built on a flexbox layout engine and is designed to be easy to embed into other Rust programs.
Features
- Render PDF from XML strings.
- Build documents directly in Rust without XML.
- Flexbox-based layout (via Taffy).
- Aiming for react-pdf compatibility.
- Embedded fonts (Google Fonts, local files, and PDF standard fonts).
- Images, links, annotations, and bookmarks.
Installation
[]
= { = "./flexpdf" }
TLS backend selection
By default, flexpdf uses reqwest with native TLS:
[]
= "0.1.4"
To use rustls instead:
[]
= { = "0.1.4", = false, = ["tls-rustls"] }
Available TLS features:
tls-native(default) -> enablesreqwest/default-tlstls-rustls-> enablesreqwest/rustls-tls
tls-native and tls-rustls are mutually exclusive.
Powered by
- Taffy for flexbox layout.
- Parley for text layout.
- skrifa and read-fonts for font parsing and metrics.
- quick-xml for XML parsing.
- reqwest for font downloads.
Usage (XML)
use render_xml;
let xml = r#"
<Document title="Quarterly Brief" author="Acme Studio">
<Fonts>
<Font family="Manrope" google="Manrope" />
</Fonts>
<Page size="A4">
<View style="width: 100%; height: 100%; padding: 32; gap: 20; backgroundColor: #f8fafc; fontFamily: Manrope; color: #0f172a;">
<View style="padding: 16; borderRadius: 12; backgroundColor: #2563eb; flexDirection: row; alignItems: center; justifyContent: space-between;">
<Text style="color: #ffffff; fontSize: 18; fontWeight: 600;">Launch Brief</Text>
<Text style="color: #ffffff; fontSize: 12;">Q2 2025</Text>
</View>
<View style="gap: 16; flexGrow: 1;">
<Text style="fontSize: 16; fontWeight: 600;">Highlights</Text>
<View style="flexDirection: row; gap: 12;">
<View style="flexGrow: 1; padding: 14; borderRadius: 10; backgroundColor: #dbeafe;">
<Text style="fontSize: 10; color: #64748b;">Signups</Text>
<Text style="fontSize: 18; fontWeight: 700;">3,482</Text>
</View>
<View style="flexGrow: 1; padding: 14; borderRadius: 10; backgroundColor: #dcfce7;">
<Text style="fontSize: 10; color: #64748b;">Retention</Text>
<Text style="fontSize: 18; fontWeight: 700;">68%</Text>
</View>
<View style="flexGrow: 1; padding: 14; borderRadius: 10; backgroundColor: #fef3c7;">
<Text style="fontSize: 10; color: #64748b;">NPS</Text>
<Text style="fontSize: 18; fontWeight: 700;">54</Text>
</View>
</View>
<View style="padding: 16; borderRadius: 10; backgroundColor: #e2e8f0;">
<Text style="fontWeight: 600;">Next steps</Text>
<Text style="color: #64748b;">Finalize onboarding and ship the analytics refresh.</Text>
</View>
</View>
<View style="flexDirection: row; justifyContent: space-between; alignItems: center;">
<Text style="color: #64748b; fontSize: 10;">Acme Studio • Internal</Text>
<Text style="color: #64748b; fontSize: 10;">Page {pageNumber} of {totalPages}</Text>
</View>
</View>
</Page>
</Document>
"#;
let pdf_bytes = render_xml?;
write?;
# Ok::
Usage (Rust model)
use ;
use ;
let doc = document
.title
.page_with
.build;
let pdf_bytes = render_document?;
write?;
# Ok::
Import existing PDF pages
You can include imported pages anywhere in the document flow:
use ;
use ;
let input_bytes = read?;
let doc = document
.page_with
.import_pdf_bytes_pages
.page_with
.import_pdf_pages
.page_with
.build;
let pdf_bytes = render_document?;
write?;
# Ok::
XML supports the same flow with <ImportPdf /> as a sibling of <Page>:
Dynamic A
Dynamic B
Dynamic C
pages accepts comma-separated page numbers and ranges (1,3-5).
Use import_pdf_pages(path, pages) for file paths and import_pdf_bytes_pages(bytes, pages) for in-memory Rust Vec<u8> data.
Native import supports both classic xref-table PDFs and xref-stream/object-stream PDFs.
Library entry points
render_xml(xml: &str) -> Result<Vec<u8>, Error>parse_xml(xml: &str) -> Result<Document, Error>render_document(doc: &Document) -> Result<Vec<u8>, Error>
CLI (optional)
A small CLI binary is included for development:
License
This project is dual-licensed under either of:
- Apache License, Version 2.0 (
LICENSE-APACHE) - MIT License (
LICENSE-MIT)
The AFM font metric data in assets/pdfkit/afm is derived from PDFKit and is licensed under the MIT license in assets/pdfkit/LICENSE.