# rbook
[](https://crates.io/crates/rbook)
[](https://docs.rs/rbook)
[](LICENSE)

A fast, format-agnostic, ergonomic ebook library with a focus on EPUB.
## Features
| **EPUB 2 and 3** | Read-only (for now) view of EPUB `2` and `3` formats | [epub module](https://docs.rs/rbook/latest/rbook/ebook/epub) |
| **Reader** | Random‐access or sequential iteration over readable content. | [reader module](https://docs.rs/rbook/latest/rbook/reader) |
| **Detailed Types** | Abstractions built on expressive traits and types. | |
| **Metadata** | Typed access to titles, creators, publishers, languages, tags, roles, attributes, and more. | [metadata module](https://docs.rs/rbook/latest/rbook/ebook/metadata) |
| **Manifest** | Lookup and traverse contained resources such as readable content (XHTML) and images. | [manifest module](https://docs.rs/rbook/latest/rbook/ebook/manifest) |
| **Spine** | Chronological reading order and preferred page direction | [spine module](https://docs.rs/rbook/latest/rbook/ebook/spine) |
| **Table of Contents (ToC)** | Navigation points, including the EPUB 2 guide and EPUB 3 landmarks. | [toc module](https://docs.rs/rbook/latest/rbook/ebook/toc) |
| **Resources** | Retrieve bytes or UTF-8 strings for any manifest resource | [resource module](https://docs.rs/rbook/latest/rbook/ebook/resource) |
## Usage
```toml
[dependencies]
rbook = "0.6.3" # with default features
# rbook = { version = "0.6.3", default-features = false } # excluding default features
```
Default crate features:
- `prelude`: Convenience prelude ***only*** including common traits.
- `threadsafe`: Enables constraint and support for `Send + Sync`.
## WebAssembly
The `wasm32-unknown-unknown` target is supported by default.
## Examples
- Opening and reading an EPUB file:
```rust
use rbook::epub::{Epub, EpubSettings};
use rbook::prelude::*;
fn main() {
let epub = Epub::open_with(
"tests/ebooks/example_epub",
EpubSettings::builder().strict(false),
).unwrap();
assert_eq!("Example EPUB", epub.metadata().title().unwrap().value());
let mut reader = epub.reader(); while let Some(Ok(data)) = reader.read_next() {
let media_type = data.manifest_entry().media_type();
assert_eq!("application/xhtml+xml", media_type);
println!("{}", data.content());
}
assert_eq!(Some(4), reader.current_position());
}
```
- Accessing a metadata element:
```rust
use rbook::Epub;
use rbook::prelude::*;
fn main() {
let epub = Epub::open("tests/ebooks/example_epub").unwrap();
let creator = epub.metadata().creators().next().unwrap();
assert_eq!("John Doe", creator.value());
assert_eq!(Some("Doe, John"), creator.file_as());
assert_eq!(0, creator.order());
let role = creator.main_role().unwrap();
assert_eq!("aut", role.code());
assert_eq!(Some("marc:relators"), role.source());
}
```
- Extracting images from the manifest:
```rust
use rbook::Epub;
use rbook::prelude::*;
use std::fs::{self, File};
use std::path::Path;
use std::io::Write;
fn main() {
let epub = Epub::open("example.epub").unwrap();
let dir = Path::new("extracted_images");
fs::create_dir(&dir).unwrap();
for image in epub.manifest().images() {
let img_href = image.href().as_str();
let img_data = image.read_bytes().unwrap();
let file_name = Path::new(img_href).file_name().unwrap();
let mut file = fs::File::create(dir.join(file_name)).unwrap();
file.write_all(&img_data).unwrap();
}
}
```
- Manifest media overlay and fallbacks:
```rust
use rbook::Epub;
use rbook::prelude::*;
fn main() {
let epub = Epub::open("tests/ebooks/example_epub").unwrap();
let chapter_1 = epub.manifest().by_id("c1").unwrap();
let media_overlay = chapter_1.media_overlay().unwrap();
let duration = media_overlay.refinements().by_property("media:duration").next().unwrap().value();
assert_eq!("0:32:29", duration);
let webm_cover = epub.manifest().cover_image().unwrap();
let kind = webm_cover.resource_kind();
assert_eq!(("image", "webm"), (kind.maintype(), kind.subtype()));
let mut fallbacks = webm_cover.fallbacks();
let avif_cover = fallbacks.next().unwrap();
assert_eq!("image/avif", avif_cover.media_type());
let png_cover = fallbacks.next().unwrap();
assert_eq!("image/png", png_cover.media_type());
assert_eq!(None, fallbacks.next());
}
```
- More examples are available in the documentation: <https://docs.rs/rbook>