epub-builder
| Language | Rust |
|---|---|
| License | MPL-2.0 |
| Repository | github.com/crowdagger/epub-builder |
| Documentation | docs.rs/epub-builder |
| Depends on | zip crate (or the zip command), upon (templates), html-escape, uuid, chrono |
| Read / write | no / yes (EPUB 2.0.1, 3.0.1, 3.3) |
epub-builder takes care of the EPUB boilerplate: you add XHTML chapters, images, a stylesheet and metadata, and it writes mimetype, container.xml, the OPF package, toc.ncx, the EPUB 3 nav.xhtml and an optional inline table of contents page, then zips everything. It’s used by Crowbook and other Rust tools that turn Markdown into e-books.
The default output is EPUB 2.0.1 for maximum compatibility; call epub_version to produce EPUB 3. Chapter content must be valid XHTML: the crate doesn’t convert or validate HTML.
Installation#
[dependencies]
epub-builder = "0.8"
The default features include both the pure-Rust ZIP writer (ZipLibrary) and a wrapper around the zip command (ZipCommand).
Basic usage: create an EPUB#
use epub_builder::{EpubBuilder, EpubContent, EpubVersion, ReferenceType, Result, ZipLibrary};
use std::fs::File;
fn chapter(title: &str, text: &str) -> String {
format!(
r#"<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
<head><title>{title}</title></head>
<body><h1>{title}</h1><p>{text}</p></body>
</html>"#
)
}
fn main() -> Result<()> {
let mut builder = EpubBuilder::new(ZipLibrary::new()?)?;
builder.epub_version(EpubVersion::V30);
builder
.metadata("author", "Jane Doe")?
.metadata("title", "My Book")?
.metadata("lang", "en")?
.stylesheet("body { font-family: serif; }".as_bytes())?
.add_content(
EpubContent::new("chapter_1.xhtml", chapter("Chapter 1", "First chapter.").as_bytes())
.title("Chapter 1")
.reftype(ReferenceType::Text),
)?
.add_content(
EpubContent::new("chapter_2.xhtml", chapter("Chapter 2", "Second chapter.").as_bytes())
.title("Chapter 2"),
)?;
let mut file = File::create("book.epub")?;
builder.generate(&mut file)?;
Ok(())
}
.title() puts the chapter in the table of contents; content without a title is in the reading order but not in the TOC.
How to add a cover image#
let cover = std::fs::read("cover.jpg")?;
builder.add_cover_image("cover.jpg", cover.as_slice(), "image/jpeg")?;
How to add images used in chapters#
let photo = std::fs::read("photo.png")?;
builder.add_resource("images/photo.png", photo.as_slice(), "image/png")?;
// in the chapter XHTML: <img src="images/photo.png" alt="photo"/>
How to build nested table of contents entries#
use epub_builder::TocElement;
builder.add_content(
EpubContent::new("part1.xhtml", part1_xhtml.as_bytes())
.title("Part 1")
.child(TocElement::new("part1.xhtml#ch1", "Chapter 1"))
.child(TocElement::new("part1.xhtml#ch2", "Chapter 2")),
)?;
// or: a following EpubContent with .level(2) is nested under the previous one
How to add an inline table of contents page#
builder.inline_toc();
This adds a table of contents page to the reading order, in addition to the navigation document that readers show in their menus.
Tips#
EpubVersion::V33writes an EPUB 3.3 package.builder.escape_html(false)stops escaping of metadata values if you pass already-escaped text.- Validate the output with EPUBCheck, especially when chapter XHTML comes from user input.