tinymist_task/compute/
pdf.rs1use tinymist_std::time::ToUtcDateTime;
4use tinymist_world::args::PdfStandard;
5pub use typst_pdf::PdfStandard as TypstPdfStandard;
6pub use typst_pdf::pdf;
7
8use typst_pdf::{PdfOptions, PdfStandards, Timestamp};
9
10use super::*;
11use crate::model::ExportPdfTask;
12
13pub struct PdfExport;
15
16impl<F: CompilerFeat> ExportComputation<F, TypstPagedDocument> for PdfExport {
17 type Output = Bytes;
18 type Config = ExportPdfTask;
19
20 fn run(
21 _graph: &Arc<WorldComputeGraph<F>>,
22 doc: &Arc<TypstPagedDocument>,
23 config: &ExportPdfTask,
24 ) -> Result<Bytes> {
25 let creation_timestamp = config
26 .creation_timestamp
27 .map(|ts| ts.to_utc_datetime().context("timestamp is out of range"))
28 .transpose()?
29 .unwrap_or_else(tinymist_std::time::utc_now);
30 let timestamp = Timestamp::new_utc(tinymist_std::time::to_typst_time(creation_timestamp));
33
34 let standards = PdfStandards::new(
35 &config
36 .pdf_standards
37 .iter()
38 .map(|standard| match standard {
39 tinymist_world::args::PdfStandard::V_1_4 => typst_pdf::PdfStandard::V_1_4,
40 tinymist_world::args::PdfStandard::V_1_5 => typst_pdf::PdfStandard::V_1_5,
41 tinymist_world::args::PdfStandard::V_1_6 => typst_pdf::PdfStandard::V_1_6,
42 tinymist_world::args::PdfStandard::V_1_7 => typst_pdf::PdfStandard::V_1_7,
43 tinymist_world::args::PdfStandard::V_2_0 => typst_pdf::PdfStandard::V_2_0,
44 tinymist_world::args::PdfStandard::A_1b => typst_pdf::PdfStandard::A_1b,
45 tinymist_world::args::PdfStandard::A_1a => typst_pdf::PdfStandard::A_1a,
46 tinymist_world::args::PdfStandard::A_2b => typst_pdf::PdfStandard::A_2b,
47 tinymist_world::args::PdfStandard::A_2u => typst_pdf::PdfStandard::A_2u,
48 tinymist_world::args::PdfStandard::A_2a => typst_pdf::PdfStandard::A_2a,
49 tinymist_world::args::PdfStandard::A_3b => typst_pdf::PdfStandard::A_3b,
50 tinymist_world::args::PdfStandard::A_3u => typst_pdf::PdfStandard::A_3u,
51 tinymist_world::args::PdfStandard::A_3a => typst_pdf::PdfStandard::A_3a,
52 tinymist_world::args::PdfStandard::A_4 => typst_pdf::PdfStandard::A_4,
53 tinymist_world::args::PdfStandard::A_4f => typst_pdf::PdfStandard::A_4f,
54 tinymist_world::args::PdfStandard::A_4e => typst_pdf::PdfStandard::A_4e,
55 tinymist_world::args::PdfStandard::Ua_1 => typst_pdf::PdfStandard::Ua_1,
56 })
57 .collect::<Vec<_>>(),
58 )
59 .context_ut("prepare pdf standards")?;
60
61 let tagged = !config.no_pdf_tags && config.pages.is_none();
62 if config.pages.is_some() && !config.no_pdf_tags {
64 log::warn!(
65 "the resulting PDF will be inaccessible because using --pages implies --no-pdf-tags"
66 );
67 }
68 if !tagged {
69 const ACCESSIBLE: &[(PdfStandard, &str)] = &[
70 (PdfStandard::A_1a, "PDF/A-1a"),
71 (PdfStandard::A_2a, "PDF/A-2a"),
72 (PdfStandard::A_3a, "PDF/A-3a"),
73 (PdfStandard::Ua_1, "PDF/UA-1"),
74 ];
75
76 for (standard, name) in ACCESSIBLE {
77 if config.pdf_standards.contains(standard) {
78 if config.no_pdf_tags {
79 log::warn!("cannot disable PDF tags when exporting a {name} document");
80 } else {
81 log::warn!(
82 "cannot disable PDF tags when exporting a {name} document. Hint: using --pages implies --no-pdf-tags"
83 );
84 }
85 }
86 }
87 }
88
89 let options = PdfOptions {
90 page_ranges: config
91 .pages
92 .as_ref()
93 .map(|pages| exported_page_ranges(pages)),
94 timestamp: Some(timestamp),
95 standards,
96 tagged,
97 ..Default::default()
98 };
99 Ok(Bytes::new(typst_pdf::pdf(doc, &options)?))
104 }
105}