Skip to main content

pdfrum_anyrender/
write.rs

1//! Pages of recorded scenes written as one PDF.
2
3use crate::area::{GlyphArea, GlyphTally};
4use crate::prepare::Prepared;
5use crate::replay::Replay;
6use crate::sources::Sources;
7use anyrender::Scene;
8use pdfrum_common::Limits;
9use pdfrum_edit::{EditDoc, Error, Fill, SaveOptions, blank_document, save};
10use peniko::kurbo::{Affine, Rect, Size};
11
12/// One page: its sheet, what is painted on it, and where.
13#[derive(Debug, Clone)]
14pub struct Page {
15    /// The sheet, in PDF points.
16    pub size: Size,
17    /// What the page shows, in the renderer's coordinates.
18    pub scene: Scene,
19    /// Scene coordinates to the page's (PDF points, y up, origin at the sheet's lower left): a
20    /// renderer's y-down pixels on a sheet with margins are a scale, a flip and a move.
21    pub placement: Affine,
22    /// The part of the scene the page shows, in scene coordinates; anything outside is clipped.
23    pub clip: Rect,
24    /// Which glyphs the page keeps, in scene coordinates.
25    pub area: GlyphArea,
26}
27
28/// A written PDF and what became of its glyphs.
29#[derive(Debug, Clone, PartialEq)]
30pub struct Written {
31    /// The file.
32    pub bytes: Vec<u8>,
33    /// Over every page.
34    pub glyphs: GlyphTally,
35}
36
37/// `pages` as one PDF, their text and images looked up in `sources`.
38///
39/// # Errors
40///
41/// Whatever pdfrum refuses: a face it cannot read, subset or instance, an image it cannot
42/// embed, a page size with no area.
43pub fn write(pages: &[Page], sources: &Sources) -> Result<Written, Error> {
44    let sizes: Vec<Size> = pages.iter().map(|page| page.size).collect();
45    let base = blank_document(&sizes)?;
46    let mut edit = EditDoc::new(&base);
47    let prepared = Prepared::new(&mut edit, pages, &sources.images)?;
48    let mut glyphs = GlyphTally::default();
49    edit.draw_pages(&Limits::default(), |canvas| {
50        let Some(page) = canvas
51            .page()
52            .and_then(|index| pages.get(usize::try_from(u32::from(index)).ok()?))
53        else {
54            return;
55        };
56        canvas.saved(|canvas| {
57            canvas.transform(page.placement);
58            canvas.clip(page.clip, Fill::NonZero);
59            let mut replay = Replay::new(&prepared, sources, page.area);
60            replay.run(canvas, &mut page.scene.commands.iter());
61            glyphs = glyphs + replay.tally;
62        });
63    })?;
64    let mut bytes = Vec::new();
65    save(&edit, &SaveOptions::default(), &mut bytes)?;
66    Ok(Written { bytes, glyphs })
67}