typst-cffi 0.6.0

FFI to Typst
Documentation
// Copyright ©2025 The typst-cffi Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

use typst_layout::PagedDocument;
use typst_pdf::pdf;
use typst_pdf::PdfOptions;

pub(crate) struct Document {
    doc: PagedDocument,
}

impl Document {
    pub(crate) fn new(doc: PagedDocument) -> Document {
        Document { doc }
    }

    pub(crate) fn npages(&self) -> usize {
        self.doc.pages().len()
    }

    pub(crate) fn compile_pdf(&self) -> Result<Vec<u8>, String> {
        let opts = PdfOptions::default();
        pdf(&self.doc, &opts).map_err(|err| format!("PDF generation failed: {err:?}"))
    }

    pub(crate) fn compile_png(&self, i: usize, ppi: f32) -> Result<Vec<u8>, String> {
        let pages = &self.doc.pages();
        if i >= pages.len() {
            let n = pages.len();
            return Err(format!("invalid page index {} (pages={})", i, n));
        }

        let ppi = if ppi == 0.0 { 144.0 } else { ppi };

        let page = &pages[i];
        let pixmap = typst_render::render(
            page,
            &typst_render::RenderOptions {
                pixel_per_pt: typst::utils::Scalar::new(f64::from(ppi/72.0)),
                render_bleed: false,
            },
        );
        pixmap
            .encode_png()
            .map_err(|err| format!("failed to encode PNG page {i} ({err})"))
    }

    pub(crate) fn compile_svg(&self) -> Result<Vec<u8>, String> {
        //let pages = doc.pages.iter().enumerate().filter(...).collect::<Vec<_>>(); // TODO(sbinet): collect+filter.

        let pages = self.doc.pages();
        if pages.len() != 1 {
            let n = pages.len();
            return Err(format!("invalid number of pages (pages={})", n));
        }

        let page = &pages[0];
        let svg = typst_svg::svg(page, &typst_svg::SvgOptions::default());
        Ok(svg.into_bytes())
    }
}