Gradient Part 2a - Fix sharp gradients in SVG (#2307)

This commit is contained in:
Sébastien d'Herbais de Thun 2023-10-04 10:58:17 +02:00 committed by GitHub
parent 55095246bf
commit 57bc614cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 32 additions and 7 deletions

View File

@ -666,16 +666,27 @@ impl SVGRenderer {
self.xml.write_attribute("y2", &y2);
for window in linear.stops.windows(2) {
let (_, start_t) = window[0];
let (_, end_t) = window[1];
let (start_c, start_t) = window[0];
let (end_c, end_t) = window[1];
self.xml.start_element("stop");
self.xml
.write_attribute_fmt("offset", format_args!("{start_t:?}"));
self.xml.write_attribute("stop-color", &start_c.to_hex());
self.xml.end_element();
// Generate (256 / len) stops between the two stops.
// This is a workaround for a bug in many readers:
// They tend to just ignore the color space of the gradient.
// The goal is to have smooth gradients but not to balloon the file size
// too much if there are already a lot of stops as in most presets.
let len = (256 / linear.stops.len() as u32).max(1);
for i in 0..len {
let len = if gradient.anti_alias() {
(256 / linear.stops.len() as u32).max(2)
} else {
2
};
for i in 1..(len - 1) {
let t0 = i as f64 / (len - 1) as f64;
let t = start_t + (end_t - start_t) * t0;
let c = gradient.sample(RatioOrAngle::Ratio(t));
@ -685,6 +696,11 @@ impl SVGRenderer {
self.xml.write_attribute("stop-color", &c.to_hex());
self.xml.end_element();
}
self.xml.start_element("stop");
self.xml.write_attribute_fmt("offset", format_args!("{end_t:?}"));
self.xml.write_attribute("stop-color", &end_c.to_hex());
self.xml.end_element()
}
self.xml.end_element();

View File

@ -445,7 +445,7 @@ impl Gradient {
angle: grad.angle,
space: grad.space,
relative: grad.relative,
anti_alias: true,
anti_alias: grad.anti_alias,
})),
})
}
@ -762,7 +762,7 @@ fn sample_stops(stops: &[(Color, Ratio)], mixing_space: ColorSpace, t: f64) -> C
let hue_0 = if hue_0 < hue_1 { hue_0 + 360.0 } else { hue_0 };
let hue_1 = if hue_1 < hue_0 { hue_1 + 360.0 } else { hue_1 };
let hue = (hue_0 * (1.0 - t as f32) + hue_1 * t as f32).rem_euclid(360.0);
let hue = hue_0 * (1.0 - t as f32) + hue_1 * t as f32;
if mixing_space == ColorSpace::Hsl {
let [_, saturation, lightness, alpha] = out.to_hsl().to_vec4();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -1,4 +1,13 @@
// Test sharp gradients.
---
#square(size: 100pt, fill: gradient.linear(..color.map.rainbow).sharp(10))
#square(
size: 100pt,
fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10),
)
---
#square(
size: 100pt,
fill: gradient.linear(..color.map.rainbow, space: color.hsl).sharp(10, smoothness: 40%),
)