Skip to main content

r/interpreter/graphics/
pdf.rs

1//! PDF output via krilla + krilla-svg.
2//!
3//! Converts an SVG string (produced by the SVG renderer) into PDF bytes
4//! by parsing the SVG with `usvg` and drawing it onto a krilla `Document`.
5
6use krilla::geom::Size;
7use krilla::page::PageSettings;
8use krilla::Document;
9use krilla_svg::{SurfaceExt, SvgSettings};
10
11use crate::interpreter::value::{RError, RErrorKind};
12
13/// Convert an SVG string to PDF bytes.
14///
15/// `width_pt` and `height_pt` are the page dimensions in points (72 pt = 1 inch),
16/// matching the coordinate system used by the SVG renderer.
17pub(crate) fn svg_to_pdf(svg_str: &str, width_pt: f32, height_pt: f32) -> Result<Vec<u8>, RError> {
18    // Parse the SVG into a usvg tree.
19    let opts = usvg::Options::default();
20    let tree = usvg::Tree::from_str(svg_str, &opts).map_err(|e| {
21        RError::new(
22            RErrorKind::Other,
23            format!("failed to parse SVG for PDF conversion: {e}"),
24        )
25    })?;
26
27    // Create a krilla document with a single page matching the SVG dimensions.
28    let mut document = Document::new();
29    let size = Size::from_wh(width_pt, height_pt).ok_or_else(|| {
30        RError::new(
31            RErrorKind::Other,
32            format!("invalid PDF page dimensions: {width_pt} x {height_pt}"),
33        )
34    })?;
35
36    let mut page = document.start_page_with(PageSettings::new(size));
37    let mut surface = page.surface();
38
39    // Draw the SVG tree onto the PDF surface.
40    surface.draw_svg(&tree, size, SvgSettings::default());
41
42    surface.finish();
43    page.finish();
44
45    // Serialize the document to PDF bytes.
46    let pdf_bytes = document
47        .finish()
48        .map_err(|e| RError::new(RErrorKind::Other, format!("failed to generate PDF: {e:?}")))?;
49
50    Ok(pdf_bytes)
51}