Rust
Word documents read, rendered and written in pure Rust.
docboss is a workspace of crates sharing one version: readers for WordprocessingML and the Word binary format into one document model, text, Markdown, HTML and JSON output, a layout engine and rasterizer, a deterministic DOCX writer and an async reader for remote files. Safe Rust, its own ZIP, XML, compound-file and font code, no C dependencies.
Install
Add only what you use.
docboss-core opens a document and re-exports the model, so most programs start from docboss_core::open and add one consumer after it.
$ cargo add docboss-core docboss-output docboss-layout docboss-render docboss-write
$ cargo add docboss-aio --features http # async and remote readsQuickstart
Open, extract, lay out, render, write.
open reads a path, read bytes, and detect reports the format from the leading bytes. Everything after reading works on the model, so it behaves the same for DOCX and DOC.
use docboss_output::{to_markdown, to_text, MarkdownOptions, TextOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = docboss_core::open("report.docx")?; // DOCX or DOC, detected from the bytes
println!("{}", to_text(&doc, &TextOptions::default()));
println!("{}", to_markdown(&doc, &MarkdownOptions::default()));
let layout = docboss_layout::layout_document(&doc);
println!("{} pages", layout.pages.len());
docboss_render::render_page(&layout, 0, 2.0)?.save("page.png")?;
docboss_write::save(&doc, "copy.docx")?; // deterministic DOCX
Ok(())
}Layout
Pages as positioned items, then pixels.
Each laid-out page holds positioned glyph runs, rectangles, lines and images in points, so a program can inspect geometry without rasterizing. render_pages uses all cores, and docboss_layout::layout takes an explicit FontDatabase when several documents should share one.
use docboss_render::Format;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = docboss_core::open("report.docx")?;
let layout = docboss_layout::layout_document(&doc);
for (index, page) in docboss_render::render_pages(&layout, 2.0).into_iter().enumerate() {
std::fs::write(format!("page-{}.png", index + 1), page?.encode(Format::Png)?)?;
}
Ok(())
}Passwords and diagnostics
Errors as values, damage as diagnostics.
Errors are thiserror enums per crate; docboss_core::Error wraps the readers’ errors and adds Encrypted and Unsupported. No library function panics on input bytes: damaged input gives an error or a document with diagnostics.
use docboss_output::{to_html, HtmlOptions};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let options = docboss_core::Options { password: Some("secret".into()) };
let doc = docboss_core::open_with("locked.docx", &options)?;
for diagnostic in &doc.diagnostics {
eprintln!("{:?} {}: {}", diagnostic.severity, diagnostic.location, diagnostic.message);
}
let html = to_html(&doc, &HtmlOptions { standalone: true, ..HtmlOptions::default() });
std::fs::write("locked.html", html)?;
Ok(())
}Async
Remote reads with docboss-aio.
With the http feature, AsyncDocument::open_url fetches only the byte ranges the reader needs. ReadOptions { media: true, .. } fetches images too; open, from_bytes and from_backend give the same interface over files, memory and any other byte source.
use docboss_aio::{AsyncDocument, ReadOptions};
let remote = AsyncDocument::open_url("https://example.com/report.docx").await?;
let doc = remote.read(&ReadOptions::default()).await?;
println!("{} of {} bytes fetched", remote.bytes_fetched(), remote.len());The workspace
One crate per concern.
The Rust reference chapter lists the entry points of each crate.
docboss-core
Format detection and one open/read over both readers; re-exports the model.
docboss-model
The document model both readers produce: sections, runs, tables, styles, numbering, notes, comments, media, diagnostics.
docboss-output
Text, Markdown, HTML, JSON and the per-block view.
docboss-layout
Pages from the model: line breaking, tabs, lists, tables, sections, headers, footers, footnotes, images.
docboss-render
Anti-aliased rasterizer and the PNG, PPM, BMP and JPEG encoders.
docboss-write
DOCX from the model, a builder API, Markdown to DOCX.
docboss-aio
Async reads over files or HTTP, fetching only the byte ranges needed.
docboss-docx
OPC packages and WordprocessingML, parts parsed on separate threads.
docboss-doc
Word binary documents, Word 6 and 95 formatting, RC4 and RC4 CryptoAPI.
docboss-zip
ZIP reader and deterministic writer, ZIP64, recovery from local headers.
docboss-xml
Zero-copy pull XML tokenizer with namespace resolution.
docboss-cfb
Compound files and OLE property sets.
docboss-crypt
Agile and Standard encrypted DOCX, XOR-obfuscated DOC.
docboss-font
TrueType, OpenType CFF, GSUB and GPOS; font discovery and substitution.
docboss-metafile
WMF and EMF pictures played into paths, text and bitmaps; DIB decoding.
docboss-mtef
Equation Editor 3 equations read into the math model.
docboss-cli
The docboss binary.
docboss-tui
The terminal explorer.
docboss-py
The PyO3 extension, shipped as the docboss wheel.
Design
What the crates promise.
- Lenient reading: a broken ZIP central directory, a looping sector chain or malformed XML is worked around, and every approximated or dropped item is a Diagnostic.
- No panics on input bytes: offsets are bounds-checked, and recursion, allocation sizes and loop counts derived from the file are capped.
- Independent DOCX parts are parsed on separate threads, and pages render on all cores.
- Deterministic DOCX output: the same input gives identical bytes, with a fixed ZIP timestamp.
- Specification citations in the code and tests, held to the conformance ledger by a Lean 4 gate.