Fix CMYK on gradients (#3142)

This commit is contained in:
Sébastien d'Herbais de Thun 2024-01-08 16:53:22 +01:00 committed by GitHub
parent 67a0afe9bd
commit 712eaaa5f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 13 deletions

View File

@ -39,15 +39,20 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) {
let shading = ctx.alloc.bump(); let shading = ctx.alloc.bump();
ctx.gradient_refs.push(shading); 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 { let mut shading_pattern = match &gradient {
Gradient::Linear(_) => { 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_pattern = ctx.pdf.shading_pattern(shading);
let mut shading = shading_pattern.function_shading(); let mut shading = shading_pattern.function_shading();
shading.shading_type(FunctionShadingType::Axial); shading.shading_type(FunctionShadingType::Axial);
ctx.colors ctx.colors.write(color_space, shading.color_space(), &mut ctx.alloc);
.write(gradient.space(), shading.color_space(), &mut ctx.alloc);
let (mut sin, mut cos) = (angle.sin(), angle.cos()); let (mut sin, mut cos) = (angle.sin(), angle.cos());
@ -74,13 +79,12 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) {
shading_pattern shading_pattern
} }
Gradient::Radial(radial) => { 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_pattern = ctx.pdf.shading_pattern(shading);
let mut shading = shading_pattern.function_shading(); let mut shading = shading_pattern.function_shading();
shading.shading_type(FunctionShadingType::Radial); shading.shading_type(FunctionShadingType::Radial);
ctx.colors ctx.colors.write(color_space, shading.color_space(), &mut ctx.alloc);
.write(gradient.space(), shading.color_space(), &mut ctx.alloc);
shading shading
.anti_alias(gradient.anti_alias()) .anti_alias(gradient.anti_alias())
@ -99,7 +103,7 @@ pub(crate) fn write_gradients(ctx: &mut PdfContext) {
shading_pattern shading_pattern
} }
Gradient::Conic(conic) => { Gradient::Conic(_) => {
let vertices = compute_vertex_stream(&gradient, aspect_ratio); let vertices = compute_vertex_stream(&gradient, aspect_ratio);
let stream_shading_id = ctx.alloc.bump(); 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.pdf.stream_shading(stream_shading_id, &vertices);
ctx.colors.write( ctx.colors.write(
conic.space, color_space,
stream_shading.color_space(), stream_shading.color_space(),
&mut ctx.alloc, &mut ctx.alloc,
); );
let range = conic.space.range(); let range = color_space.range();
stream_shading stream_shading
.bits_per_coordinate(16) .bits_per_coordinate(16)
.bits_per_component(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. /// 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 function = ctx.alloc.bump();
let mut functions = vec![]; let mut functions = vec![];
let mut bounds = 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 real_t = first.1.get() * (1.0 - t) + second.1.get() * t;
let c = gradient.sample(RatioOrAngle::Ratio(Ratio::new(real_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); bounds.push(real_t as f32);
encode.extend([0.0, 1.0]); encode.extend([0.0, 1.0]);
last_c = c; last_c = c;
@ -166,7 +174,7 @@ fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref {
} }
bounds.push(second.1.get() as f32); 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]); encode.extend([0.0, 1.0]);
} }
@ -182,7 +190,7 @@ fn shading_function(ctx: &mut PdfContext, gradient: &Gradient) -> Ref {
ctx.pdf ctx.pdf
.stitching_function(function) .stitching_function(function)
.domain([0.0, 1.0]) .domain([0.0, 1.0])
.range(gradient.space().range()) .range(color_space.range())
.functions(functions) .functions(functions)
.bounds(bounds) .bounds(bounds)
.encode(encode); .encode(encode);

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

View File

@ -0,0 +1,27 @@
// Test that CMYK works on gradients
---
#set page(margin: 0pt, width: 200pt, height: auto)
#let violet = cmyk(75%, 80%, 0%, 0%)
#let blue = cmyk(75%, 30%, 0%, 0%)
#rect(
width: 100%,
height: 30pt,
fill: gradient.linear(violet, blue)
)
#rect(
width: 100%,
height: 30pt,
fill: gradient.linear(rgb(violet), rgb(blue))
)
// In PDF format, this gradient can look different from the others.
// This is because PDF readers do weird things with CMYK.
#rect(
width: 100%,
height: 30pt,
fill: gradient.linear(violet, blue, space: cmyk)
)