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
use crate::color::PolarColor;
use crate::hsi::HsiOutOfGamutMode;
/// Traits and methods for converting between colors and representations
use crate::ycbcr::YCbCrOutOfGamutMode;
use angle;
use angle::{Angle, FromAngle};
use num_traits;
use num_traits::Float;

/// Infallibly convert between two color models
///
/// The `From` trait only apply when not changing color spaces. Thus, Rgb -> XYZ is not supported
/// via `FromColor`. Additionally, any conversion that may go out of gamut requires a different
/// conversion method or trait.
pub trait FromColor<From> {
    /// Construct `Self` from `from`
    fn from_color(from: &From) -> Self;
}
/// Convert from Hsi to another color model
///
/// This is a separate trait as Hsi can go out of gamut. This trait accepts an enum describing how to
/// handle out of gamut colors.
pub trait FromHsi<From> {
    /// Construct `Self` from `from`, describing what to do if the color is out of gamut for `Self`
    fn from_hsi(from: &From, out_of_gamut_mode: HsiOutOfGamutMode) -> Self;
}
/// Convert from YCbCr to another color model
///
/// This is a separate trait as YCbCr can go out of gamut. This trait accepts an enum describing how to
/// handle out of gamut colors.
pub trait FromYCbCr<From> {
    /// Construct `Self` from `from`, describing what to do if the color is out of gamut for `Self`
    fn from_ycbcr(from: &From, out_of_gamut_mode: YCbCrOutOfGamutMode) -> Self;
}

/// Return the chroma of a color
pub trait GetChroma {
    /// The type of the returned chroma value
    type ChromaType;
    /// Return the chroma for `self`
    fn get_chroma(&self) -> Self::ChromaType;
}

/// Return the chroma of a color
pub trait GetHue {
    /// The angle type used internally to compute the hue
    type InternalAngle: angle::Angle;
    /// Return the hue of `self` in the supplied angular unit.
    fn get_hue<U>(&self) -> U
    where
        U: Angle<Scalar = <Self::InternalAngle as Angle>::Scalar> + FromAngle<Self::InternalAngle>;
}

/// Compute the hexagonal segment that the hue falls under, as well as the distance into that segment
///
/// This is used internally to compute the hue in many conversions
pub fn decompose_hue_segment<Color>(
    color: &Color,
) -> (i32, <<Color as PolarColor>::Angular as Angle>::Scalar)
where
    Color: PolarColor + GetHue<InternalAngle = <Color as PolarColor>::Angular>,
    Color::Angular: Angle,
{
    let scaled_hue = (color.get_hue::<angle::Turns<_>>() * num_traits::cast(6.0).unwrap()).scalar();
    let hue_seg = scaled_hue.floor();

    (num_traits::cast(hue_seg).unwrap(), scaled_hue - hue_seg)
}