tinymist_task/compute/
png.rs

1//! The computation for png export.
2
3use std::sync::Arc;
4
5use tinymist_std::error::prelude::*;
6use tinymist_std::typst::TypstPagedDocument;
7use tinymist_world::{CompilerFeat, ExportComputation, WorldComputeGraph};
8use typst::foundations::Bytes;
9
10use crate::compute::{parse_color, parse_length, select_pages};
11use crate::model::ExportPngTask;
12use crate::{ImageOutput, PageMerge, PagedOutput};
13
14/// The computation for png export.
15pub struct PngExport;
16
17impl<F: CompilerFeat> ExportComputation<F, TypstPagedDocument> for PngExport {
18    type Output = ImageOutput<Bytes>;
19    type Config = ExportPngTask;
20
21    fn run(
22        _graph: &Arc<WorldComputeGraph<F>>,
23        doc: &Arc<TypstPagedDocument>,
24        config: &ExportPngTask,
25    ) -> Result<Self::Output> {
26        let ppi = config.ppi.to_f32();
27        if ppi <= 1e-6 {
28            bail!("invalid ppi: {ppi}");
29        }
30
31        let fill = if let Some(fill) = &config.fill {
32            Some(parse_color(fill).map_err(|err| anyhow::anyhow!("invalid fill ({err})"))?)
33        } else {
34            None
35        };
36
37        let ppp = ppi / 72.;
38
39        let exported_pages = select_pages(doc, &config.pages);
40        if let Some(PageMerge { ref gap }) = config.merge {
41            let dummy_doc = TypstPagedDocument {
42                pages: exported_pages
43                    .into_iter()
44                    .map(|(_, page)| page.clone())
45                    .collect(),
46                ..Default::default()
47            };
48            let gap = gap
49                .as_ref()
50                .and_then(|gap| parse_length(gap).ok())
51                .unwrap_or_default();
52            let pixmap = typst_render::render_merged(&dummy_doc, ppp, gap, fill);
53            let png = pixmap
54                .encode_png()
55                .map(Bytes::new)
56                .context_ut("failed to encode PNG")?;
57            Ok(ImageOutput::Merged(png))
58        } else {
59            let exported = exported_pages
60                .into_iter()
61                .map(|(i, page)| {
62                    let pixmap = typst_render::render(page, ppp);
63                    let png = pixmap
64                        .encode_png()
65                        .map(Bytes::new)
66                        .context_ut("failed to encode PNG")?;
67                    Ok(PagedOutput {
68                        page: i,
69                        value: png,
70                    })
71                })
72                .collect::<Result<Vec<_>>>()?;
73            Ok(ImageOutput::Paged(exported))
74        }
75    }
76}
77
78// impl<F: CompilerFeat> WorldComputable<F> for PngExport {
79//     type Output = Option<Bytes>;
80
81//     fn compute(graph: &Arc<WorldComputeGraph<F>>) -> Result<Self::Output> {
82//         OptionDocumentTask::run_export::<F, Self>(graph)
83//     }
84// }