Skip to main content

chromashift/
color_space.rs

1/// Identifies a colour space for gamut containment checks.
2///
3/// Used with [`crate::Color::in_gamut_of`] to test whether a colour can be represented in a target space without
4/// clamping.
5///
6/// Implements [`PartialOrd`] based on gamut containment - `a >= b` means every colour representable in `b` is also
7/// representable in `a`. This is a *partial* order because some pairs (e.g. Display P3 and A98 RGB) overlap without
8/// either being a strict superset.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum ColorSpace {
11	Srgb,
12	DisplayP3,
13	A98Rgb,
14	ProphotoRgb,
15	Rec2020,
16}
17
18impl PartialOrd for ColorSpace {
19	fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
20		if self == other {
21			return Some(core::cmp::Ordering::Equal);
22		}
23		match (self.contains(*other), other.contains(*self)) {
24			(true, false) => Some(core::cmp::Ordering::Greater),
25			(false, true) => Some(core::cmp::Ordering::Less),
26			_ => None,
27		}
28	}
29}
30
31impl ColorSpace {
32	/// Returns `true` if every colour representable in `other` is also representable in `self`.
33	///
34	/// ```text
35	/// sRGB ⊂ Display P3 ⊂ Rec 2020 ⊂ ProPhoto RGB
36	/// sRGB ⊂ A98 RGB ⊂ ProPhoto RGB
37	/// ```
38	pub const fn contains(self, other: ColorSpace) -> bool {
39		match (self, other) {
40			(Self::Srgb, Self::Srgb) => true,
41			(Self::Srgb, _) => false,
42			(Self::DisplayP3, Self::Srgb | Self::DisplayP3) => true,
43			(Self::DisplayP3, _) => false,
44			(Self::A98Rgb, Self::Srgb | Self::A98Rgb) => true,
45			(Self::A98Rgb, _) => false,
46			(Self::ProphotoRgb, _) => true,
47			(Self::Rec2020, Self::Srgb | Self::DisplayP3 | Self::Rec2020) => true,
48			(Self::Rec2020, _) => false,
49		}
50	}
51}