Skip to content

Commit c13859b

Browse files
committed
Rewrite hsl/hwb converters
1 parent 4e231ea commit c13859b

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
@@ -220,6 +220,40 @@ pub enum SrgbColor {
220220
},
221221
}
222222

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

1542-
/// https://w3c.github.io/csswg-drafts/css-color-4/#hwb-to-rgb
1543-
#[inline]
1544-
pub fn hwb_to_rgb(h: f32, w: f32, b: f32) -> (f32, f32, f32) {
1545-
if w + b >= 1.0 {
1546-
let gray = w / (w + b);
1547-
return (gray, gray, gray);
1548-
}
1549-
1550-
let (mut red, mut green, mut blue) = hsl_to_rgb(h, 1.0, 0.5);
1551-
let x = 1.0 - w - b;
1552-
red = red * x + w;
1553-
green = green * x + w;
1554-
blue = blue * x + w;
1555-
(red, green, blue)
1556-
}
1557-
1558-
/// https://w3c.github.io/csswg-drafts/css-color-4/#hsl-to-rgb
1559-
/// except with h pre-multiplied by 3, to avoid some rounding errors.
1560-
#[inline]
1561-
pub fn hsl_to_rgb(hue: f32, saturation: f32, lightness: f32) -> (f32, f32, f32) {
1562-
fn hue_to_rgb(m1: f32, m2: f32, mut h3: f32) -> f32 {
1563-
if h3 < 0. {
1564-
h3 += 3.
1565-
}
1566-
if h3 > 3. {
1567-
h3 -= 3.
1568-
}
1569-
if h3 * 2. < 1. {
1570-
m1 + (m2 - m1) * h3 * 2.
1571-
} else if h3 * 2. < 3. {
1572-
m2
1573-
} else if h3 < 2. {
1574-
m1 + (m2 - m1) * (2. - h3) * 2.
1575-
} else {
1576-
m1
1577-
}
1578-
}
1579-
let m2 = if lightness <= 0.5 {
1580-
lightness * (saturation + 1.)
1581-
} else {
1582-
lightness + saturation - lightness * saturation
1583-
};
1584-
let m1 = lightness * 2. - m2;
1585-
let hue_times_3 = hue * 3.;
1586-
let red = hue_to_rgb(m1, m2, hue_times_3 + 1.);
1587-
let green = hue_to_rgb(m1, m2, hue_times_3);
1588-
let blue = hue_to_rgb(m1, m2, hue_times_3 - 1.);
1589-
(red, green, blue)
1590-
}
1591-
15921576
#[cfg(test)]
15931577
mod tests {
15941578
use crate::ParserInput;

0 commit comments

Comments
 (0)