From aa57554176f2fb996fd017251a81887f4d38d9fa Mon Sep 17 00:00:00 2001 From: Laurenz Stampfl <47084093+LaurenzV@users.noreply.github.com> Date: Sun, 15 Dec 2024 23:36:09 +0100 Subject: [PATCH] Add proper support for CMYK and luma --- crates/typst-pdf/src/krilla.rs | 15 ++++++++++----- crates/typst-pdf/src/paint.rs | 31 +++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/crates/typst-pdf/src/krilla.rs b/crates/typst-pdf/src/krilla.rs index 14efb135b..a04973d24 100644 --- a/crates/typst-pdf/src/krilla.rs +++ b/crates/typst-pdf/src/krilla.rs @@ -296,7 +296,7 @@ pub fn pdf( } KrillaError::ValidationError(ve) => { // We can only produce 1 error, so just take the first one. - let prefix = "validated export failed:"; + let prefix = format!("validated export for {} failed:", options.validator.as_str()); match &ve[0] { ValidationError::TooLongString => { bail!(Span::detached(), "{prefix} a PDF string longer than 32767 characters"; @@ -323,6 +323,7 @@ pub fn pdf( bail!(Span::detached(), "{prefix} the PDF has too many indirect objects"; hint: "reduce the size of your document"); } + // Can only occur if we have 27+ nested clip paths ValidationError::TooHighQNestingLevel => { bail!(Span::detached(), "{prefix} the PDF has too high q nesting"; hint: "reduce the number of nested containers"); @@ -337,11 +338,11 @@ pub fn pdf( } ValidationError::ContainsNotDefGlyph => { bail!(Span::detached(), "{prefix} the PDF contains the .notdef glyph"; - hint: "ensure all text can be displayed using a font"); + hint: "ensure all text can be displayed using an available font"); } ValidationError::InvalidCodepointMapping(_, _) => { bail!(Span::detached(), "{prefix} the PDF contains the disallowed codepoints"; - hint: "make sure you don't use the Unicode characters 0x0, 0xFEFF or 0xFFFE"); + hint: "make sure to not use the Unicode characters 0x0, 0xFEFF or 0xFFFE"); } ValidationError::UnicodePrivateArea(_, _) => { bail!(Span::detached(), "{prefix} the PDF contains characters from the Unicode private area"; @@ -349,11 +350,15 @@ pub fn pdf( } ValidationError::Transparency => { bail!(Span::detached(), "{prefix} document contains transparency"; - hint: "remove any transparency in your document and your SVGs"; + hint: "remove any transparency from your document (e.g. fills with opacity)"; + hint: "you might have to convert certain SVGs into a bitmap image if they contain transparency"; hint: "export using a different standard that supports transparency" ); } - // The below errors cannot occur yet, only once Typst supports PDF/A and PDF/UA. + + // The below errors cannot occur yet, only once Typst supports full PDF/A + // and PDF/UA. + // But let's still add a message just to be on the safe side. ValidationError::MissingAnnotationAltText => { bail!(Span::detached(), "{prefix} missing annotation alt text"; hint: "please report this as a bug"); diff --git a/crates/typst-pdf/src/paint.rs b/crates/typst-pdf/src/paint.rs index 1f549175b..6321f1027 100644 --- a/crates/typst-pdf/src/paint.rs +++ b/crates/typst-pdf/src/paint.rs @@ -57,7 +57,7 @@ fn dash(dash: &DashPattern) -> krilla::path::StrokeDash { } } -fn convert_color(color: &Color) -> (krilla::color::rgb::Color, u8) { +fn convert_to_rgb_color(color: &Color) -> (krilla::color::rgb::Color, u8) { let components = color.to_space(ColorSpace::Srgb).to_vec4_u8(); ( krilla::color::rgb::Color::new(components[0], components[1], components[2]) @@ -75,8 +75,31 @@ fn paint( ) -> SourceResult<(krilla::paint::Paint, u8)> { match paint { Paint::Solid(c) => { - let (c, alpha) = convert_color(c); - Ok((c.into(), alpha)) + let (p, alpha) = match c.space() { + ColorSpace::D65Gray => { + let components = c.to_vec4_u8(); + ( + krilla::color::luma::Color::new(components[0]) + .into(), + components[3], + ) + } + ColorSpace::Cmyk => { + let components = c.to_vec4_u8(); + ( + krilla::color::cmyk::Color::new(components[0], components[1], components[2], components[3]) + .into(), + // Typst doesn't support alpha on CMYK colors. + 255, + ) + } + _ => { + let (c, a) = convert_to_rgb_color(c); + (c.into(), a) + } + }; + + Ok((p, alpha)) } Paint::Gradient(g) => Ok(convert_gradient(g, on_text, transforms)), Paint::Pattern(p) => convert_pattern(gc, p, on_text, surface, transforms), @@ -154,7 +177,7 @@ fn convert_gradient( let mut stops: Vec> = vec![]; let mut add_single = |color: &Color, offset: Ratio| { - let (color, opacity) = convert_color(color); + let (color, opacity) = convert_to_rgb_color(color); let opacity = NormalizedF32::new((opacity as f32) / 255.0).unwrap(); let offset = NormalizedF32::new(offset.get() as f32).unwrap(); let stop = krilla::paint::Stop { offset, color, opacity };