1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use crate::cmyk::*;
use crate::hsl::*;
use min_max::*;
use std::convert::From;

pub(crate) const RGB_SCALE: u8 = 255;
pub(crate) const RGB_SCALE_FLOAT: f32 = 255.0;

#[derive(Debug, PartialEq, Eq)]
pub struct Rgb {
    pub r: u8,
    pub g: u8,
    pub b: u8,
}

impl Rgb {
    pub fn new(r: u8, g: u8, b: u8) -> Self {
        Self { r, g, b }
    }
}

#[derive(Debug, PartialEq)]
pub struct RgbScaled {
    pub r: f32,
    pub g: f32,
    pub b: f32,
}

impl From<Rgb> for RgbScaled {
    fn from(rgb: Rgb) -> Self {
        Self {
            r: rgb.r as f32 / RGB_SCALE_FLOAT,
            g: rgb.g as f32 / RGB_SCALE_FLOAT,
            b: rgb.b as f32 / RGB_SCALE_FLOAT,
        }
    }
}

impl From<RgbScaled> for Rgb {
    fn from(rgb: RgbScaled) -> Self {
        Self {
            r: (rgb.r * 255.0) as u8,
            g: (rgb.g * 255.0) as u8,
            b: (rgb.b * 255.0) as u8,
        }
    }
}

impl From<Cmyk> for RgbScaled {
    fn from(cmyk: Cmyk) -> Self {
        Self {
            r: (1.0 - cmyk.c) * (1.0 - cmyk.k),
            g: (1.0 - cmyk.m) * (1.0 - cmyk.k),
            b: (1.0 - cmyk.y) * (1.0 - cmyk.k),
        }
    }
}

impl From<Cmyk> for Rgb {
    fn from(cmyk: Cmyk) -> Self {
        Self::from(RgbScaled::from(cmyk))
    }
}

impl From<CmykInt> for Rgb {
    fn from(cmyk: CmykInt) -> Self {
        Self::from(RgbScaled::from(Cmyk::from(cmyk)))
    }
}

impl From<Hsl> for RgbScaled {
    // https://stackoverflow.com/questions/36721830/convert-hsl-to-rgb-and-hex/54014428#54014428
    fn from(hsl: Hsl) -> Self {
        fn hue_to_rgb(p: f32, q: f32, mut t: f32) -> f32 {
            if t < 0. {
                t += 1.
            } else if t > 1. {
                t -= 1.
            }
            if t < 1. / 6. {
                p + (q - p) * 6. * t
            } else if t < 1. / 2. {
                q
            } else if t < 2. / 3. {
                p + (q - p) * (2. / 3. - t) * 6.
            } else {
                p
            }
        }

        let Hsl { mut h, s, l } = hsl;

        h /= 360.0;

        if s < 1e-3 {
            Self { r: l, g: l, b: l }
        } else {
            let q = if l < 0.5 {
                l * (1.0 + s)
            } else {
                l + s - l * s
            };
            let p = 2.0 * l - q;
            Self {
                r: hue_to_rgb(p, q, h + 1. / 3.),
                g: hue_to_rgb(p, q, h),
                b: hue_to_rgb(p, q, h - 1. / 3.),
            }
        }
    }
}

impl From<Hsl> for Rgb {
    fn from(hsl: Hsl) -> Self {
        Self::from(RgbScaled::from(hsl))
    }
}

impl From<HslInt> for Rgb {
    fn from(hsl: HslInt) -> Self {
        Self::from(RgbScaled::from(Hsl::from(hsl)))
    }
}