djvu-rs
| Language | Rust (edition 2024, Rust 1.88+) |
|---|---|
| License | MIT |
| Repository | github.com/matyushkin/djvu-rs |
| Documentation | docs.rs/djvu-rs, library guide |
| Depends on | no C libraries; optional features pull in image, miniz_oxide, zip, rayon, tokio |
| Read / write | yes / yes (JB2 and IW44 encoders, document editing) |
djvu-rs reads, renders, converts and creates DjVu files. It’s written from the DjVu v3 specification without DjVuLibre code, so it’s MIT-licensed. It decodes JB2, IW44, BZZ and JPEG layers, reads text and annotations, and exports to PDF (with selectable text and bookmarks), EPUB, TIFF, CBZ, hOCR and ALTO XML. The same crate builds the djvu command-line tool, WebAssembly bindings and the Python package.
The crate is new (first released in 2026) and the 0.x API still changes; pin the version in Cargo.toml. The core decoder needs only std; exporters and integrations are behind feature flags.
Installation#
cargo add djvu-rs # decode and render
cargo add djvu-rs --features pdf,image # plus PDF export and image crate integration
cargo install djvu-rs --features cli # the `djvu` command-line tool
Basic usage: open a document and render a page#
use djvu_rs::{DjVuDocument, djvu_render::{render_pixmap, RenderOptions}};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("book.djvu")?;
let doc = DjVuDocument::parse(&data)?;
println!("{} pages", doc.page_count());
let page = doc.page(0)?; // 0-based
println!("{}x{} @ {} dpi", page.width(), page.height(), page.dpi());
// Render at 150 dpi to RGBA.
let target_dpi = 150u32;
let opts = RenderOptions {
width: ((page.width() as u32 * target_dpi) / page.dpi() as u32).max(1),
height: ((page.height() as u32 * target_dpi) / page.dpi() as u32).max(1),
..Default::default()
};
let pixmap = render_pixmap(page, &opts)?;
// pixmap.data: RGBA bytes, pixmap.width x pixmap.height, top row first
std::fs::write("page1.ppm", pixmap.to_ppm())?;
Ok(())
}
How to save a DjVu page as PNG#
With the image feature, a page works as an image::ImageDecoder (also run cargo add image):
use djvu_rs::{DjVuDocument, image_compat::DjVuDecoder};
use image::DynamicImage;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("book.djvu")?;
let doc = DjVuDocument::parse(&data)?;
let page = doc.page(0)?;
let decoder = DjVuDecoder::new(page)?.with_size(1200, 1600);
let img = DynamicImage::from_decoder(decoder)?;
img.save("page1.png")?;
Ok(())
}
How to extract text from a DjVu file#
page.text() returns None when the page has no text layer:
use djvu_rs::DjVuDocument;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("book.djvu")?;
let doc = DjVuDocument::parse(&data)?;
for i in 0..doc.page_count() {
if let Some(text) = doc.page(i)?.text()? {
println!("--- page {} ---\n{text}", i + 1);
}
}
Ok(())
}
For word coordinates, djvu_rs::text_serialize::to_hocr exports the whole document as hOCR.
How to convert DjVu to PDF#
Needs the pdf feature. The PDF keeps the text layer, bookmarks and links:
use djvu_rs::{DjVuDocument, pdf::djvu_to_pdf};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = DjVuDocument::parse(&std::fs::read("book.djvu")?)?;
std::fs::write("book.pdf", djvu_to_pdf(&doc)?)?;
Ok(())
}
How to read bookmarks (table of contents)#
use djvu_rs::{DjVuBookmark, DjVuDocument};
fn print(b: &[DjVuBookmark], level: usize) {
for bm in b {
println!("{}{} -> {}", " ".repeat(level), bm.title, bm.url);
print(&bm.children, level + 1);
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let doc = DjVuDocument::parse(&std::fs::read("book.djvu")?)?;
print(doc.bookmarks(), 0);
Ok(())
}
How to list the chunks of a DjVu file#
The iff module parses the container without decoding anything:
use djvu_rs::iff::parse_form;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let data = std::fs::read("page.djvu")?;
let form = parse_form(&data)?;
println!("FORM type: {:?}", std::str::from_utf8(&form.form_type));
for chunk in &form.chunks {
println!(" {:?} ({} bytes)", std::str::from_utf8(&chunk.id), chunk.data.len());
}
Ok(())
}
Tips#
- The
djvuCLI covers most tasks without code:djvu info,djvu render --format pdf,djvu text --format hocr,djvu encode scan.png,djvu merge,djvu split. - For untrusted files,
DjVuDocument::parse_with_optionstakes resource limits. - Indirect (multi-file) documents need
parse_from_diror a resolver to load the page files.