From 712eaaa5f404aff51163919d43361d9c2bb19873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20d=27Herbais=20de=20Thun?= Date: Mon, 8 Jan 2024 16:53:22 +0100 Subject: [PATCH] Fix CMYK on gradients (#3142) --- crates/typst-pdf/src/gradient.rs | 34 +++++++++++++++--------- tests/ref/bugs/gradient-cmyk-encode.png | Bin 0 -> 875 bytes tests/typ/bugs/gradient-cmyk-encode.typ | 27 +++++++++++++++++++ 3 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 tests/ref/bugs/gradient-cmyk-encode.png create mode 100644 tests/typ/bugs/gradient-cmyk-encode.typ diff --git a/crates/typst-pdf/src/gradient.rs b/crates/typst-pdf/src/gradient.rs index 523d67b90..7dd289a93 100644 --- a/crates/typst-pdf/src/gradient.rs +++ b/crates/typst-pdf/src/gradient.rs @@ -39,15 +39,20 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) { let shading = ctx.alloc.bump(); ctx.gradient_refs.push(shading); + let color_space = if gradient.space().hue_index().is_some() { + ColorSpace::Oklab + } else { + gradient.space() + }; + let mut shading_pattern = match &gradient { Gradient::Linear(_) => { - let shading_function = shading_function(ctx, &gradient); + let shading_function = shading_function(ctx, &gradient, color_space); let mut shading_pattern = ctx.pdf.shading_pattern(shading); let mut shading = shading_pattern.function_shading(); shading.shading_type(FunctionShadingType::Axial); - ctx.colors - .write(gradient.space(), shading.color_space(), &mut ctx.alloc); + ctx.colors.write(color_space, shading.color_space(), &mut ctx.alloc); let (mut sin, mut cos) = (angle.sin(), angle.cos()); @@ -74,13 +79,12 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) { shading_pattern } Gradient::Radial(radial) => { - let shading_function = shading_function(ctx, &gradient); + let shading_function = shading_function(ctx, &gradient, color_space); let mut shading_pattern = ctx.pdf.shading_pattern(shading); let mut shading = shading_pattern.function_shading(); shading.shading_type(FunctionShadingType::Radial); - ctx.colors - .write(gradient.space(), shading.color_space(), &mut ctx.alloc); + ctx.colors.write(color_space, shading.color_space(), &mut ctx.alloc); shading .anti_alias(gradient.anti_alias()) @@ -99,7 +103,7 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) { shading_pattern } - Gradient::Conic(conic) => { + Gradient::Conic(_) => { let vertices = compute_vertex_stream(&gradient, aspect_ratio); let stream_shading_id = ctx.alloc.bump(); @@ -107,12 +111,12 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) { ctx.pdf.stream_shading(stream_shading_id, &vertices); ctx.colors.write( - conic.space, + color_space, stream_shading.color_space(), &mut ctx.alloc, ); - let range = conic.space.range(); + let range = color_space.range(); stream_shading .bits_per_coordinate(16) .bits_per_component(16) @@ -138,7 +142,11 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) { } /// Writes an expotential or stitched function that expresses the gradient. -fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref { +fn shading_function( + ctx: &mut PdfContext, + gradient: &Gradient, + color_space: ColorSpace, +) -> Ref { let function = ctx.alloc.bump(); let mut functions = vec![]; let mut bounds = vec![]; @@ -158,7 +166,7 @@ fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref { let real_t = first.1.get() * (1.0 - t) + second.1.get() * t; let c = gradient.sample(RatioOrAngle::Ratio(Ratio::new(real_t))); - functions.push(single_gradient(ctx, last_c, c, ColorSpace::Oklab)); + functions.push(single_gradient(ctx, last_c, c, color_space)); bounds.push(real_t as f32); encode.extend([0.0, 1.0]); last_c = c; @@ -166,7 +174,7 @@ fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref { } bounds.push(second.1.get() as f32); - functions.push(single_gradient(ctx, first.0, second.0, gradient.space())); + functions.push(single_gradient(ctx, first.0, second.0, color_space)); encode.extend([0.0, 1.0]); } @@ -182,7 +190,7 @@ fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref { ctx.pdf .stitching_function(function) .domain([0.0, 1.0]) - .range(gradient.space().range()) + .range(color_space.range()) .functions(functions) .bounds(bounds) .encode(encode); diff --git a/tests/ref/bugs/gradient-cmyk-encode.png b/tests/ref/bugs/gradient-cmyk-encode.png new file mode 100644 index 0000000000000000000000000000000000000000..7bd82ccef48bfa82462a9a1fe8dab50e0e3bda7a GIT binary patch literal 875 zcmeAS@N?(olHy`uVBq!ia0y~yU|a%Z|KMN(k~*TSQ49>sMxHK?Ar-gYTyxAjWFX*h zab}nFROTt%U(W2E8GThqnmhW)w5E&I-2$rLSR!gvf%@R!UYy(Y>**`K-yIJ+&o8_B z(~E0Al0N&kbsxWeJM%E7yPua&PW;A=U#9Esu0A#A+oR0gMSHUUHqDuRLGRql%%4Xd zr^(Niyn4R;Sh9Q-{~q3r%t!bf-Y{Sg0@e&0nK1}#DuH5HR072?%mnMkFcYjBX7INV z2D67}K`z2#CQK2U!Elug(+fM--8NNveEx65tDg&#L*?#D#pmohS@7{km36Mg!xNsJ zoo}_xrv2NLTJAsda-2dvpY^JcN}-kXdavI=DkN$eOz!wsMm zCV^GuPi}I2fT9QCO|t-sL*?s#<;Ab&l)QUqcJTbi;y;Sjz8}(nKE(75*oRoW1Pl