hyperion/color/
utils.rs

1//! Color utilities
2
3use palette::LinSrgb;
4
5use crate::models::{Color, Color16};
6
7/// Return the whitepoint for a given color temperature
8///
9/// # Parameters
10///
11/// * `t`: temperature in Kelvin
12fn kelvin_to_rgbf32(t: f32) -> LinSrgb {
13    let t = f64::from(t);
14
15    // http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
16    //
17    // Check bounds on temperature
18    let t = if t > 40000.0 { 40000.0 } else { t };
19    let t = if t < 1000.0 { 1000.0 } else { t };
20
21    // Scale
22    let t = t / 100.0;
23
24    let r = if t <= 66.0 {
25        255.0
26    } else {
27        329.698_727_446 * (t - 60.0).powf(-0.133_204_759_2)
28    };
29
30    let g = if t <= 66.0 {
31        99.470_802_586_1 * t.ln() - 161.119_568_166_1
32    } else {
33        288.122_169_528_3 * (t - 60.0).powf(-0.075_514_849_2)
34    };
35
36    let b = if t >= 66.0 {
37        255.0
38    } else if t <= 19.0 {
39        0.0
40    } else {
41        138.517_731_223_1 * (t - 10.0).ln() - 305.044_792_730_7
42    };
43
44    let r = if r > 255.0 { 255.0 } else { r };
45    let g = if g > 255.0 { 255.0 } else { g };
46    let b = if b > 255.0 { 255.0 } else { b };
47
48    LinSrgb::from_components(((r / 255.0) as f32, (g / 255.0) as f32, (b / 255.0) as f32))
49}
50
51pub fn kelvin_to_rgb16(t: u32) -> Color16 {
52    let (r, g, b) = kelvin_to_rgbf32(t as f32).into_components();
53    Color16::new(
54        (r * (u16::MAX as f32)) as u16,
55        (g * (u16::MAX as f32)) as u16,
56        (b * (u16::MAX as f32)) as u16,
57    )
58}
59
60/// Get the sRGB whitepoint
61pub fn srgb_white() -> Color16 {
62    Color16::new(u16::MAX, u16::MAX, u16::MAX)
63}
64
65/// Transforms the given color to fix its white balance
66///
67/// # Parameters
68///
69/// * `c`: color to transform
70/// * `src_white`: whitepoint of the current space of `c`
71/// * `dst_white`: whitepoint of the destination space of `c`
72pub fn whitebalance(c: Color16, src_white: Color16, dst_white: Color16) -> Color16 {
73    let (cr, cg, cb) = c.into_components();
74    let (sr, sg, sb) = src_white.into_components();
75    let (dr, dg, db) = dst_white.into_components();
76
77    Color16::new(
78        ((cr as u32 * dr as u32) / sr as u32).min(u16::MAX as u32) as u16,
79        ((cg as u32 * dg as u32) / sg as u32).min(u16::MAX as u32) as u16,
80        ((cb as u32 * db as u32) / sb as u32).min(u16::MAX as u32) as u16,
81    )
82}
83
84const FACTOR: u16 = 65535 / 255;
85
86pub fn color_to8(color: Color16) -> Color {
87    let (r, g, b) = color.into_components();
88    Color::new((r / FACTOR) as u8, (g / FACTOR) as u8, (b / FACTOR) as u8)
89}
90
91pub fn color_to16(color: Color) -> Color16 {
92    let (r, g, b) = color.into_components();
93    Color16::new(
94        (r as u16) * FACTOR,
95        (g as u16) * FACTOR,
96        (b as u16) * FACTOR,
97    )
98}