Skip to content

Commit 0cdf805

Browse files
committed
Rewrite hsl/hwb converters
1 parent 87470b2 commit 0cdf805

File tree

1 file changed

+34
-50
lines changed

1 file changed

+34
-50
lines changed

src/color.rs

+34-50
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,40 @@ pub enum SrgbColor {
225225
},
226226
}
227227

228+
/// <https://w3c.github.io/csswg-drafts/css-color-4/#hsl-to-rgb>
229+
#[inline]
230+
pub fn hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> (f32, f32, f32) {
231+
let mut hue = hue;
232+
233+
if hue < 0. {
234+
hue += 1.;
235+
}
236+
237+
let f = |n: f32| -> f32 {
238+
let k = (hue.mul_add(12., n)) % 12.;
239+
let a = saturation * lightness.min(1. - lightness);
240+
241+
a.mul_add(-(-1f32).max((k - 3.).min(9. - k).min(1.)), lightness)
242+
};
243+
244+
(f(0.), f(8.), f(4.))
245+
}
246+
247+
/// <https://w3c.github.io/csswg-drafts/css-color-4/#hwb-to-rgb>
248+
#[inline]
249+
pub fn hwb_to_rgb(hue: f32, whiteness: f32, blackness: f32) -> (f32, f32, f32) {
250+
if whiteness + blackness >= 1. {
251+
let gray = whiteness / (whiteness + blackness);
252+
return (gray, gray, gray);
253+
}
254+
255+
let (red, green, blue) = hsl_to_rgb(hue, 1., 0.5);
256+
257+
let f = |c: f32| -> f32 { c.mul_add(1. - whiteness - blackness, whiteness) };
258+
259+
(f(red), f(green), f(blue))
260+
}
261+
228262
impl SrgbColor {
229263
/// Construct an sRGB color from its component channels.
230264
pub fn new(
@@ -1551,56 +1585,6 @@ where
15511585
)))
15521586
}
15531587

1554-
/// https://w3c.github.io/csswg-drafts/css-color-4/#hwb-to-rgb
1555-
#[inline]
1556-
pub fn hwb_to_rgb(h: f32, w: f32, b: f32) -> (f32, f32, f32) {
1557-
if w + b >= 1.0 {
1558-
let gray = w / (w + b);
1559-
return (gray, gray, gray);
1560-
}
1561-
1562-
let (mut red, mut green, mut blue) = hsl_to_rgb(h, 1.0, 0.5);
1563-
let x = 1.0 - w - b;
1564-
red = red * x + w;
1565-
green = green * x + w;
1566-
blue = blue * x + w;
1567-
(red, green, blue)
1568-
}
1569-
1570-
/// https://w3c.github.io/csswg-drafts/css-color-4/#hsl-to-rgb
1571-
/// except with h pre-multiplied by 3, to avoid some rounding errors.
1572-
#[inline]
1573-
pub fn hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> (f32, f32, f32) {
1574-
fn hue_to_rgb(m1: f32, m2: f32, mut h3: f32) -> f32 {
1575-
if h3 < 0. {
1576-
h3 += 3.
1577-
}
1578-
if h3 > 3. {
1579-
h3 -= 3.
1580-
}
1581-
if h3 * 2. < 1. {
1582-
m1 + (m2 - m1) * h3 * 2.
1583-
} else if h3 * 2. < 3. {
1584-
m2
1585-
} else if h3 < 2. {
1586-
m1 + (m2 - m1) * (2. - h3) * 2.
1587-
} else {
1588-
m1
1589-
}
1590-
}
1591-
let m2 = if lightness <= 0.5 {
1592-
lightness * (saturation + 1.)
1593-
} else {
1594-
lightness + saturation - lightness * saturation
1595-
};
1596-
let m1 = lightness * 2. - m2;
1597-
let hue_times_3 = hue * 3.;
1598-
let red = hue_to_rgb(m1, m2, hue_times_3 + 1.);
1599-
let green = hue_to_rgb(m1, m2, hue_times_3);
1600-
let blue = hue_to_rgb(m1, m2, hue_times_3 - 1.);
1601-
(red, green, blue)
1602-
}
1603-
16041588
#[cfg(test)]
16051589
mod tests {
16061590
use crate::ParserInput;

0 commit comments

Comments
 (0)