summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/typst/src/export/svg.rs24
-rw-r--r--crates/typst/src/geom/gradient.rs4
-rw-r--r--tests/ref/visualize/gradient-sharp.pngbin16748 -> 45753 bytes
-rw-r--r--tests/typ/visualize/gradient-sharp.typ11
4 files changed, 32 insertions, 7 deletions
diff --git a/crates/typst/src/export/svg.rs b/crates/typst/src/export/svg.rs
index 2b99c3ff..03e12181 100644
--- a/crates/typst/src/export/svg.rs
+++ b/crates/typst/src/export/svg.rs
@@ -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();
diff --git a/crates/typst/src/geom/gradient.rs b/crates/typst/src/geom/gradient.rs
index 8f920f3b..38763626 100644
--- a/crates/typst/src/geom/gradient.rs
+++ b/crates/typst/src/geom/gradient.rs
@@ -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();
diff --git a/tests/ref/visualize/gradient-sharp.png b/tests/ref/visualize/gradient-sharp.png
index 8e50f597..30e6fb66 100644
--- a/tests/ref/visualize/gradient-sharp.png
+++ b/tests/ref/visualize/gradient-sharp.png
Binary files differ
diff --git a/tests/typ/visualize/gradient-sharp.typ b/tests/typ/visualize/gradient-sharp.typ
index e19df58f..424beb8b 100644
--- a/tests/typ/visualize/gradient-sharp.typ
+++ b/tests/typ/visualize/gradient-sharp.typ
@@ -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%),
+)