diff --git a/crates/typst-cli/src/args.rs b/crates/typst-cli/src/args.rs index d6855d100..b29b2f076 100644 --- a/crates/typst-cli/src/args.rs +++ b/crates/typst-cli/src/args.rs @@ -241,6 +241,10 @@ pub struct CompileArgs { #[arg(long = "pages", value_delimiter = ',')] pub pages: Option>, + /// The version of the produced PDF. + #[arg(long = "pdf-version")] + pub pdf_version: Option, + /// One (or multiple comma-separated) PDF standards that Typst will enforce /// conformance with. #[arg(long = "pdf-standard", value_delimiter = ',')] @@ -463,23 +467,59 @@ pub enum Feature { display_possible_values!(Feature); +/// A PDF version. +#[derive(Debug, Copy, Clone, Eq, PartialEq, ValueEnum)] +#[allow(non_camel_case_types)] +pub enum PdfVersion { + /// PDF 1.4. + #[value(name = "1.4")] + V_1_4, + /// PDF 1.5. + #[value(name = "1.5")] + V_1_5, + /// PDF 1.5. + #[value(name = "1.6")] + V_1_6, + /// PDF 1.7. + #[value(name = "1.7")] + V_1_7, + /// PDF 2.0. + #[value(name = "2.0")] + V_2_0, +} + +display_possible_values!(PdfVersion); + /// A PDF standard that Typst can enforce conformance with. #[derive(Debug, Copy, Clone, Eq, PartialEq, ValueEnum)] #[allow(non_camel_case_types)] pub enum PdfStandard { - /// PDF 1.7. - #[value(name = "1.7")] - V_1_7, + /// PDF/A-1b. + #[value(name = "a-1b")] + A_1b, /// PDF/A-2b. #[value(name = "a-2b")] A_2b, - /// PDF/A-3b. + /// PDF/A-2u. + #[value(name = "a-2u")] + A_2u, + /// PDF/A-3u. #[value(name = "a-3b")] A_3b, + /// PDF/A-3u. + #[value(name = "a-3u")] + A_3u, + /// PDF/A-4. + #[value(name = "a-4")] + A_4, + /// PDF/A-4f. + #[value(name = "a-4f")] + A_4f, + /// PDF/A-4e. + #[value(name = "a-4e")] + A_4e, } -display_possible_values!(PdfStandard); - // Output file format for query command #[derive(Debug, Default, Copy, Clone, Eq, PartialEq, ValueEnum)] pub enum SerializationFormat { diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs index d8a2e771f..b76581aab 100644 --- a/crates/typst-cli/src/compile.rs +++ b/crates/typst-cli/src/compile.rs @@ -18,12 +18,9 @@ use typst::html::HtmlDocument; use typst::layout::{Frame, Page, PageRanges, PagedDocument}; use typst::syntax::{FileId, Source, Span}; use typst::WorldExt; -use typst_pdf::{PdfOptions, Timestamp}; +use typst_pdf::{PdfOptions, Timestamp, Validator}; -use crate::args::{ - CompileArgs, CompileCommand, DiagnosticFormat, Input, Output, OutputFormat, - PdfStandard, WatchCommand, -}; +use crate::args::{CompileArgs, CompileCommand, DiagnosticFormat, Input, Output, OutputFormat, PdfStandard, PdfVersion, WatchCommand}; #[cfg(feature = "http-server")] use crate::server::HtmlServer; use crate::timings::Timer; @@ -63,9 +60,10 @@ pub struct CompileConfig { /// Opens the output file with the default viewer or a specific program after /// compilation. pub open: Option>, - /// One (or multiple comma-separated) PDF standards that Typst will enforce - /// conformance with. - pub pdf_standards: PdfStandards, + /// The version that should be used to export the PDF. + pub pdf_version: Option, + /// A list of standards the PDF should conform to. + pub pdf_standard: Vec, /// A path to write a Makefile rule describing the current compilation. pub make_deps: Option, /// The PPI (pixels per inch) to use for PNG export. @@ -130,19 +128,6 @@ impl CompileConfig { PageRanges::new(export_ranges.iter().map(|r| r.0.clone()).collect()) }); - let pdf_standards = { - let list = args - .pdf_standard - .iter() - .map(|standard| match standard { - PdfStandard::V_1_7 => typst_pdf::PdfStandard::V_1_7, - PdfStandard::A_2b => typst_pdf::PdfStandard::A_2b, - PdfStandard::A_3b => typst_pdf::PdfStandard::A_3b, - }) - .collect::>(); - PdfStandards::new(&list)? - }; - #[cfg(feature = "http-server")] let server = match watch { Some(command) @@ -159,7 +144,8 @@ impl CompileConfig { output, output_format, pages, - pdf_standards, + pdf_version: args.pdf_version, + pdf_standard: args.pdf_standard.clone(), creation_timestamp: args.world.creation_timestamp, make_deps: args.make_deps.clone(), ppi: args.ppi, @@ -295,11 +281,45 @@ fn export_pdf(document: &PagedDocument, config: &CompileConfig) -> SourceResult< }) } }; + + let validator = match config.pdf_standard.first() { + None => None, + Some(s) => { + let validator = if config.pdf_standard.len() > 1 { + bail!(Span::detached(), "cannot export using more than one PDF standard"; + hint: "typst currently only supports export using \ + one standard at the same time"); + } else { + match s { + PdfStandard::A_1b => Validator::A_1b, + PdfStandard::A_2b => Validator::A_2b, + PdfStandard::A_2u => Validator::A_2u, + PdfStandard::A_3b => Validator::A_3b, + PdfStandard::A_3u => Validator::A_3u, + PdfStandard::A_4 => Validator::A_4, + PdfStandard::A_4f => Validator::A_4f, + PdfStandard::A_4e => Validator::A_4e + } + }; + + Some(validator) + } + }; + + let pdf_version = config.pdf_version.map(|v| match v { + PdfVersion::V_1_4 => typst_pdf::PdfVersion::Pdf14, + PdfVersion::V_1_5 => typst_pdf::PdfVersion::Pdf15, + PdfVersion::V_1_6 => typst_pdf::PdfVersion::Pdf16, + PdfVersion::V_1_7 => typst_pdf::PdfVersion::Pdf17, + PdfVersion::V_2_0 => typst_pdf::PdfVersion::Pdf20, + }); + let options = PdfOptions { ident: Smart::Auto, timestamp, page_ranges: config.pages.clone(), - standards: config.pdf_standards.clone(), + validator, + pdf_version }; let buffer = typst_pdf::pdf(document, &options)?; config diff --git a/crates/typst-pdf/src/lib.rs b/crates/typst-pdf/src/lib.rs index 1c1839583..43df44943 100644 --- a/crates/typst-pdf/src/lib.rs +++ b/crates/typst-pdf/src/lib.rs @@ -52,39 +52,40 @@ impl From for krilla::configure::PdfVersion { /// A validator for exporting PDF documents to a specific subset of PDF. #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[allow(non_camel_case_types)] pub enum Validator { /// The validator for the PDF/A1-A standard. A1_A, /// The validator for the PDF/A1-B standard. - A1_B, + A_1b, /// The validator for the PDF/A2-B standard. - A2_B, + A_2b, /// The validator for the PDF/A2-U standard. - A2_U, + A_2u, /// The validator for the PDF/A3-B standard. - A3_B, + A_3b, /// The validator for the PDF/A3-U standard. - A3_U, + A_3u, /// The validator for the PDF/A4 standard. - A4, + A_4, /// The validator for the PDF/A4f standard. - A4F, + A_4f, /// The validator for the PDF/A4e standard. - A4E, + A_4e, } impl From for krilla::configure::Validator { fn from(value: Validator) -> Self { match value { Validator::A1_A => krilla::configure::Validator::A1_A, - Validator::A1_B => krilla::configure::Validator::A1_B, - Validator::A2_B => krilla::configure::Validator::A2_B, - Validator::A2_U => krilla::configure::Validator::A2_U, - Validator::A3_B => krilla::configure::Validator::A3_B, - Validator::A3_U => krilla::configure::Validator::A3_U, - Validator::A4 => krilla::configure::Validator::A4, - Validator::A4F => krilla::configure::Validator::A4F, - Validator::A4E => krilla::configure::Validator::A4E, + Validator::A_1b => krilla::configure::Validator::A1_B, + Validator::A_2b => krilla::configure::Validator::A2_B, + Validator::A_2u => krilla::configure::Validator::A2_U, + Validator::A_3b => krilla::configure::Validator::A3_B, + Validator::A_3u => krilla::configure::Validator::A3_U, + Validator::A_4 => krilla::configure::Validator::A4, + Validator::A_4f => krilla::configure::Validator::A4F, + Validator::A_4e => krilla::configure::Validator::A4E, } } }