Rust
PowerPoint reading and verification in pure Rust.
pptxboss is a workspace of focused crates sharing one version: a clean-room reader built from ECMA-376 Parts 1 to 4 with its own ZIP, DEFLATE, XML and Open Packaging Conventions layers, a reader for the PowerPoint 97-2003 binary format built from MS-CFB, MS-PPT and MS-ODRAW into the same slide model, a verifier with 72 clause-numbered rules, and a deterministic writer. Safe Rust, no C dependencies, no bindings to another engine.
Install
Add only what you use.
pptxboss-core alone reads decks; pptxboss-check verifies them and pptxboss-write creates them. All three build on the core’s package layer.
$ cargo add pptxboss-core
# optional: the verifier and the writer
$ cargo add pptxboss-check pptxboss-writeQuickstart
Open, read, report.
Document::open reads a .pptx or a legacy .ppt. Slides parse lazily; text_reporting returns the whole deck’s text with a report of everything skipped. Document is single-threaded; Document::seed() gives a Send + Sync handle from which any thread rebuilds a reader over the same archive, and map_slides spreads slides over every core unless with_threads caps the workers.
use pptxboss_core::Document;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = Document::open("deck.pptx")?;
for slide in doc.slides() {
let slide = slide?;
println!("{}: {}", slide.number(), slide.title().unwrap_or_default());
println!("{}", slide.text());
if let Some(notes) = slide.notes_text()? {
println!("notes: {notes}");
}
}
let (text, report) = doc.text_reporting(&Default::default());
for warning in report.warnings() {
eprintln!("warning: {warning}");
}
println!("{text}");
Ok(())
}Verifier
Check a package against ECMA-376.
check_bytes, check_path and check run the 72 rules and return findings sorted most severe first, each with a stable code, a Severity, the clause it enforces, the part and a message. CheckOptions caps the number of findings and turns XML well-formedness and CRC verification on or off.
let bytes = std::fs::read("deck.pptx")?;
let report = pptxboss_check::check_bytes(bytes, &Default::default())?;
for finding in &report.findings {
println!("{:?} {} [{}] {}", finding.severity, finding.code, finding.clause, finding.message);
}
assert!(report.findings.is_empty());Writer
Build a deck, read it back, verify it.
Presentation carries one master, four layouts and a theme; slides take titles, subtitles, bullets, paragraphs, text boxes, tables, pictures and notes, and the layout is inferred when not set. from_markdown builds the same from a Markdown string. Output is deterministic and passes the verifier with no findings.
use pptxboss_write::{Metadata, Paragraph, Presentation, Rect, Slide, SlideSize};
let deck = Presentation::new()
.size(SlideSize::WIDESCREEN)
.metadata(Metadata { title: Some("Review".into()), ..Metadata::default() })
.slide(Slide::title_slide("Quarterly review", Some("Q3 2026")))
.slide(Slide::titled("Highlights").bullet("Revenue up").sub_bullet("in every region", 1).notes("Pause here"))
.slide(Slide::titled("Free form")
.text_box(Rect::inches(1.0, 1.5, 5.0, 1.0), vec![Paragraph::text("Bold claim").bold().size(28)])
.picture(std::fs::read("chart.png")?, Rect::inches(7.0, 1.5, 5.0, 3.0))
.table(Rect::inches(1.0, 4.0, 11.0, 2.0), vec![vec!["Region".into(), "Growth".into()], vec!["EMEA".into(), "12%".into()]], true));
deck.write_to("review.pptx")?;
// round trip: read it back and verify it
let bytes = deck.to_bytes()?;
let doc = pptxboss_core::Document::load(bytes.clone())?;
assert_eq!(doc.slide(1)?.text(), "Highlights\nRevenue up\nin every region");
assert!(pptxboss_check::check_bytes(bytes, &Default::default())?.findings.is_empty());The workspace
Four crates on crates.io, one implementation.
Each crate’s API reference lives on docs.rs; the Rust reference chapter says where to start for reading, verifying and creating. Every error type is a thiserror enum per crate.
pptxboss-core
Reads .pptx and legacy .ppt decks: slides, notes, tables, charts, diagrams, comments, pictures, properties, text and Markdown extraction.
pptxboss-check
The verifier: 72 clause-numbered rules over package and presentation structure.
pptxboss-write
Creates decks: titles, bullets, paragraphs, text boxes, tables, pictures, notes; Markdown to slides; deterministic output.
pptxboss-cli
The pptxboss binary.
pptxboss-py
PyO3 bindings, shipped as the pptxboss wheel.
Design
What the crates promise.
- Lenient reading: bytes before the archive, a missing central directory and broken content types and relationships are tolerated, the slide list is recovered from relationships when the presentation part does not list it, and every skip is reported.
- Lazy slides and lazy media: opening a deck parses no slide, and image bytes are read only when asked for.
- Two views of a package: Package is the raw Open Packaging Conventions view with defects included; Document is the lenient reader built on it.
- Deterministic output from pptxboss-write: fixed timestamps, fixed part order, ids in insertion order.
- Strict and Transitional namespaces both read, and mc:AlternateContent resolved per Part 3.