Un roman entier, mis en pages

Un roman anglais du domaine public, remis d'un seul tenant, et mis en pages sur cinquante-deux pages numérotées : le moteur choisit lui-même chaque coupure de ligne et chaque changement de page.

Rust write_book.rs 60 lignes
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Lays a whole English novel out and writes it as one PDF.
//!
//! It is what a document's weight really looks like. A novel draws the whole
//! alphabet in both cases, the digits and the punctuation, so the embedded font
//! carries far more outlines than an invoice does — and its metrics, which used
//! to be stated for every glyph of the face, are stated only for the glyphs the
//! book draws.
//!
//! Usage: `cargo run --example write_book -- tmp/book.pdf [font.ttf]`

use std::env;
use std::fs;
use std::path::{Path, PathBuf};

use hqf_pdf::{Document, Font};

#[path = "shared/out.rs"]
mod out;

#[path = "shared/licence.rs"]
mod licence;

#[path = "shared/book.rs"]
mod book;

/// The font the example draws with when none is given on the command line.
fn default_font() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("fonts")
        .join("DejaVuSans.ttf")
}

/// The novel this lays out, carried in full.
const BOOK: book::Book = book::Book {
    title: "Alice's Adventures in Wonderland",
    author: "Lewis Carroll",
    file: "wonderland.txt",
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut args = env::args().skip(1);
    let out = args.next().unwrap_or_else(|| out::default_path("book"));
    let font_path = args.next().map_or_else(default_font, PathBuf::from);

    let mut doc = Document::new();
    doc.set_license(licence::licensed());
    let handle = doc.add_font(Font::parse(fs::read(&font_path)?)?);

    let text = fs::read_to_string(BOOK.path())?;
    book::lay_out(&mut doc, &handle, &BOOK, &text)?;

    let bytes = doc.to_bytes()?;
    if let Some(parent) = Path::new(&out).parent() {
        fs::create_dir_all(parent)?;
    }
    fs::write(&out, &bytes)?;
    println!("wrote {out}: {} bytes", bytes.len());
    Ok(())
}