From 4d6e0fd36fcb82645d17b3ad635e64fc90b152e7 Mon Sep 17 00:00:00 2001 From: Erik Hedvall Date: Sat, 26 May 2018 14:50:03 +0200 Subject: [PATCH] Add conversion to and from component tuples --- palette/src/hsl.rs | 86 +++++++++++++++++++++++------ palette/src/hsv.rs | 79 +++++++++++++++++++++----- palette/src/hwb.rs | 110 ++++++++++++++++++++++++++++--------- palette/src/lab.rs | 72 ++++++++++++++++++++---- palette/src/lch.rs | 75 +++++++++++++++++++++---- palette/src/luma/luma.rs | 99 +++++++++++++++++++++++++-------- palette/src/rgb/rgb.rs | 116 +++++++++++++++++++++++++++------------ palette/src/xyz.rs | 82 ++++++++++++++++++++++----- palette/src/yxy.rs | 96 ++++++++++++++++++++++++++++---- 9 files changed, 650 insertions(+), 165 deletions(-) diff --git a/palette/src/hsl.rs b/palette/src/hsl.rs index 7744ffb3e..fac549c79 100644 --- a/palette/src/hsl.rs +++ b/palette/src/hsl.rs @@ -1,15 +1,17 @@ -use num_traits::Float; use approx::ApproxEq; +use num_traits::Float; -use std::ops::{Add, Sub}; -use std::marker::PhantomData; use std::any::TypeId; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; -use {cast, clamp, Alpha, Component, FromColor, GetHue, Hsv, Hue, IntoColor, Limited, Mix, Pixel, - RgbHue, Saturate, Shade, Xyz}; -use rgb::{Rgb, RgbSpace}; -use encoding::{Linear, Srgb}; use encoding::pixel::RawPixel; +use encoding::{Linear, Srgb}; +use rgb::{Rgb, RgbSpace}; +use { + cast, clamp, Alpha, Component, FromColor, GetHue, Hsv, Hue, IntoColor, Limited, Mix, Pixel, + RgbHue, Saturate, Shade, Xyz, +}; /// Linear HSL with an alpha component. See the [`Hsla` implementation in /// `Alpha`](struct.Alpha.html#Hsla). @@ -24,7 +26,8 @@ pub type Hsla = Alpha, T>; ///especially good for operations like changing green to red, making a color ///more gray, or making it darker. /// -///See [HSV](struct.Hsv.html) for a very similar color space, with brightness instead of lightness. +///See [HSV](struct.Hsv.html) for a very similar color space, with brightness +/// instead of lightness. #[derive(Debug, PartialEq, FromColor, Pixel)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[palette_internal] @@ -105,6 +108,16 @@ where } } + /// Convert to a `(hue, saturation, lightness)` tuple. + pub fn into_components(self) -> (RgbHue, T, T) { + (self.hue, self.saturation, self.lightness) + } + + /// Convert from a `(hue, saturation, lightness)` tuple. + pub fn from_components>>((hue, saturation, lightness): (H, T, T)) -> Self { + Self::with_wp(hue, saturation, lightness) + } + fn from_hsl_internal>(hsl: Hsl) -> Self { if TypeId::of::() == TypeId::of::() { hsl.reinterpret_as() @@ -171,12 +184,13 @@ where } ///[`Hsla`](type.Hsla.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///HSL and transparency for linear sRGB. - pub fn new>>(hue: H, saturation: T, lightness: T, alpha: T) -> Hsla { + pub fn new>>(hue: H, saturation: T, lightness: T, alpha: A) -> Self { Alpha { color: Hsl::new(hue, saturation, lightness), alpha: alpha, @@ -185,23 +199,31 @@ where } ///[`Hsla`](type.Hsla.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, S: RgbSpace, { ///Linear HSL and transparency. - pub fn with_wp>>( - hue: H, - saturation: T, - lightness: T, - alpha: T, - ) -> Hsla { + pub fn with_wp>>(hue: H, saturation: T, lightness: T, alpha: A) -> Self { Alpha { color: Hsl::with_wp(hue, saturation, lightness), alpha: alpha, } } + + /// Convert to a `(hue, saturation, lightness, alpha)` tuple. + pub fn into_components(self) -> (RgbHue, T, T, A) { + (self.hue, self.saturation, self.lightness, self.alpha) + } + + /// Convert from a `(hue, saturation, lightness, alpha)` tuple. + pub fn from_components>>( + (hue, saturation, lightness, alpha): (H, T, T, A), + ) -> Self { + Self::with_wp(hue, saturation, lightness, alpha) + } } impl From> for Hsl @@ -251,6 +273,34 @@ where } } +impl>> From<(H, T, T)> for Hsl { + fn from(components: (H, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T)> for Hsl { + fn into(self) -> (RgbHue, T, T) { + self.into_components() + } +} + +impl>, A: Component> From<(H, T, T, A)> + for Alpha, A> +{ + fn from(components: (H, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (RgbHue, T, T, A) { + self.into_components() + } +} + impl Limited for Hsl where T: Component + Float, @@ -508,8 +558,8 @@ where #[cfg(test)] mod test { use super::Hsl; - use {Hsv, LinSrgb}; use encoding::Srgb; + use {Hsv, LinSrgb}; #[test] fn red() { diff --git a/palette/src/hsv.rs b/palette/src/hsv.rs index e81411358..d44d54a5a 100644 --- a/palette/src/hsv.rs +++ b/palette/src/hsv.rs @@ -1,16 +1,16 @@ -use num_traits::Float; use approx::ApproxEq; +use num_traits::Float; -use std::ops::{Add, Sub}; -use std::marker::PhantomData; use std::any::TypeId; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; +use encoding::pixel::RawPixel; +use encoding::{Linear, Srgb}; +use rgb::{Rgb, RgbSpace}; +use {cast, clamp}; use {Alpha, Hsl, Hwb, Xyz}; use {Component, FromColor, GetHue, Hue, Limited, Mix, Pixel, RgbHue, Saturate, Shade}; -use {cast, clamp}; -use rgb::{Rgb, RgbSpace}; -use encoding::{Linear, Srgb}; -use encoding::pixel::RawPixel; /// Linear HSV with an alpha component. See the [`Hsva` implementation in /// `Alpha`](struct.Alpha.html#Hsva). @@ -105,6 +105,16 @@ where } } + /// Convert to a `(hue, saturation, value)` tuple. + pub fn into_components(self) -> (RgbHue, T, T) { + (self.hue, self.saturation, self.value) + } + + /// Convert from a `(hue, saturation, value)` tuple. + pub fn from_components>>((hue, saturation, value): (H, T, T)) -> Self { + Self::with_wp(hue, saturation, value) + } + fn from_hsv_internal>(hsv: Hsv) -> Self { if TypeId::of::() == TypeId::of::() { hsv.reinterpret_as() @@ -166,12 +176,13 @@ where } ///[`Hsva`](type.Hsva.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///HSV and transparency for linear sRGB. - pub fn new>>(hue: H, saturation: T, value: T, alpha: T) -> Hsva { + pub fn new>>(hue: H, saturation: T, value: T, alpha: A) -> Self { Alpha { color: Hsv::new(hue, saturation, value), alpha: alpha, @@ -180,18 +191,31 @@ where } ///[`Hsva`](type.Hsva.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, S: RgbSpace, { ///Linear HSV and transparency. - pub fn with_wp>>(hue: H, saturation: T, value: T, alpha: T) -> Hsva { + pub fn with_wp>>(hue: H, saturation: T, value: T, alpha: A) -> Self { Alpha { color: Hsv::with_wp(hue, saturation, value), alpha: alpha, } } + + /// Convert to a `(hue, saturation, value, alpha)` tuple. + pub fn into_components(self) -> (RgbHue, T, T, A) { + (self.hue, self.saturation, self.value, self.alpha) + } + + /// Convert from a `(hue, saturation, value, alpha)` tuple. + pub fn from_components>>( + (hue, saturation, value, alpha): (H, T, T, A), + ) -> Self { + Self::with_wp(hue, saturation, value, alpha) + } } impl From> for Hsv @@ -260,6 +284,34 @@ where } } +impl>> From<(H, T, T)> for Hsv { + fn from(components: (H, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T)> for Hsv { + fn into(self) -> (RgbHue, T, T) { + self.into_components() + } +} + +impl>, A: Component> From<(H, T, T, A)> + for Alpha, A> +{ + fn from(components: (H, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (RgbHue, T, T, A) { + self.into_components() + } +} + impl Limited for Hsv where T: Component + Float, @@ -517,8 +569,8 @@ where #[cfg(test)] mod test { use super::Hsv; - use {Hsl, LinSrgb}; use encoding::Srgb; + use {Hsl, LinSrgb}; #[test] fn red() { @@ -599,7 +651,8 @@ mod test { #[cfg(feature = "serde")] #[test] fn deserialize() { - let deserialized: Hsv = ::serde_json::from_str(r#"{"hue":0.3,"saturation":0.8,"value":0.1}"#).unwrap(); + let deserialized: Hsv = + ::serde_json::from_str(r#"{"hue":0.3,"saturation":0.8,"value":0.1}"#).unwrap(); assert_eq!(deserialized, Hsv::new(0.3, 0.8, 0.1)); } diff --git a/palette/src/hwb.rs b/palette/src/hwb.rs index 30f96ff7a..7333ae328 100644 --- a/palette/src/hwb.rs +++ b/palette/src/hwb.rs @@ -1,15 +1,17 @@ -use num_traits::Float; use approx::ApproxEq; +use num_traits::Float; -use std::ops::{Add, Sub}; -use std::marker::PhantomData; use std::any::TypeId; +use std::marker::PhantomData; +use std::ops::{Add, Sub}; -use {clamp, Alpha, Component, FromColor, GetHue, Hsv, Hue, IntoColor, Limited, Mix, Pixel, RgbHue, - Shade, Xyz}; -use rgb::RgbSpace; -use encoding::Srgb; use encoding::pixel::RawPixel; +use encoding::Srgb; +use rgb::RgbSpace; +use { + clamp, Alpha, Component, FromColor, GetHue, Hsv, Hue, IntoColor, Limited, Mix, Pixel, RgbHue, + Shade, Xyz, +}; /// Linear HWB with an alpha component. See the [`Hwba` implementation in /// `Alpha`](struct.Alpha.html#Hwba). @@ -18,10 +20,12 @@ pub type Hwba = Alpha, T>; ///Linear HWB color space. /// ///HWB is a cylindrical version of [RGB](rgb/struct.LinRgb.html) and it's very -///closely related to [HSV](struct.Hsv.html). It describes colors with a starting hue, -///then a degree of whiteness and blackness to mix into that base hue. +///closely related to [HSV](struct.Hsv.html). It describes colors with a +/// starting hue, then a degree of whiteness and blackness to mix into that +/// base hue. /// -///It is very intuitive for humans to use and many color-pickers are based on the HWB color system +///It is very intuitive for humans to use and many color-pickers are based on +/// the HWB color system #[derive(Debug, PartialEq, FromColor, Pixel)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[palette_internal] @@ -40,15 +44,16 @@ where #[palette_unsafe_same_layout_as = "T"] pub hue: RgbHue, - ///The whiteness of the color. It specifies the amount white to mix into the hue. - ///It varies from 0 to 1, with 1 being always full white and 0 - ///always being the color shade (a mixture of a pure hue with black) chosen with the other two - ///controls. + ///The whiteness of the color. It specifies the amount white to mix into + /// the hue. It varies from 0 to 1, with 1 being always full white and 0 + ///always being the color shade (a mixture of a pure hue with black) + /// chosen with the other two controls. pub whiteness: T, - ///The blackness of the color. It specifies the amount black to mix into the hue. - ///It varies from 0 to 1, with 1 being always full black and 0 always - ///being the color tint (a mixture of a pure hue with white) chosen with the other two + ///The blackness of the color. It specifies the amount black to mix into + /// the hue. It varies from 0 to 1, with 1 being always full black and + /// 0 always being the color tint (a mixture of a pure hue with white) + /// chosen with the other two //controls. pub blackness: T, @@ -106,6 +111,16 @@ where } } + /// Convert to a `(hue, whiteness, blackness)` tuple. + pub fn into_components(self) -> (RgbHue, T, T) { + (self.hue, self.whiteness, self.blackness) + } + + /// Convert from a `(hue, whiteness, blackness)` tuple. + pub fn from_components>>((hue, whiteness, blackness): (H, T, T)) -> Self { + Self::with_wp(hue, whiteness, blackness) + } + fn from_hwb_internal>(color: Hwb) -> Self { if TypeId::of::() == TypeId::of::() { color.reinterpret_as() @@ -126,12 +141,13 @@ where } ///[`Hwba`](type.Hwba.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///HWB and transparency for linear sRGB. - pub fn new>>(hue: H, whiteness: T, blackness: T, alpha: T) -> Hwba { + pub fn new>>(hue: H, whiteness: T, blackness: T, alpha: A) -> Self { Alpha { color: Hwb::new(hue, whiteness, blackness), alpha: alpha, @@ -140,18 +156,31 @@ where } ///[`Hwba`](type.Hwba.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, S: RgbSpace, { ///Linear HWB and transparency. - pub fn with_wp>>(hue: H, whiteness: T, blackness: T, alpha: T) -> Hwba { + pub fn with_wp>>(hue: H, whiteness: T, blackness: T, alpha: A) -> Self { Alpha { color: Hwb::with_wp(hue, whiteness, blackness), alpha: alpha, } } + + /// Convert to a `(hue, whiteness, blackness, alpha)` tuple. + pub fn into_components(self) -> (RgbHue, T, T, A) { + (self.hue, self.whiteness, self.blackness, self.alpha) + } + + /// Convert from a `(hue, whiteness, blackness, alpha)` tuple. + pub fn from_components>>( + (hue, whiteness, blackness, alpha): (H, T, T, A), + ) -> Self { + Self::with_wp(hue, whiteness, blackness, alpha) + } } impl From> for Hwb @@ -183,6 +212,34 @@ where } } +impl>> From<(H, T, T)> for Hwb { + fn from(components: (H, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T)> for Hwb { + fn into(self) -> (RgbHue, T, T) { + self.into_components() + } +} + +impl>, A: Component> From<(H, T, T, A)> + for Alpha, A> +{ + fn from(components: (H, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(RgbHue, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (RgbHue, T, T, A) { + self.into_components() + } +} + impl Limited for Hwb where T: Component + Float, @@ -412,9 +469,11 @@ where epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool { - let equal_shade = self.whiteness + let equal_shade = self + .whiteness .relative_eq(&other.whiteness, epsilon, max_relative) - && self.blackness + && self + .blackness .relative_eq(&other.blackness, epsilon, max_relative); // The hue doesn't matter that much when the color is gray, and may fluctuate @@ -447,8 +506,8 @@ where #[cfg(test)] mod test { use super::Hwb; - use {Limited, LinSrgb}; use encoding::Srgb; + use {Limited, LinSrgb}; #[test] fn red() { @@ -533,7 +592,8 @@ mod test { #[cfg(feature = "serde")] #[test] fn deserialize() { - let deserialized: Hwb = ::serde_json::from_str(r#"{"hue":0.3,"whiteness":0.8,"blackness":0.1}"#).unwrap(); + let deserialized: Hwb = + ::serde_json::from_str(r#"{"hue":0.3,"whiteness":0.8,"blackness":0.1}"#).unwrap(); assert_eq!(deserialized, Hwb::new(0.3, 0.8, 0.1)); } diff --git a/palette/src/lab.rs b/palette/src/lab.rs index 850377c0e..a3f58d3d9 100644 --- a/palette/src/lab.rs +++ b/palette/src/lab.rs @@ -1,13 +1,13 @@ use num_traits::Float; -use std::ops::{Add, Div, Mul, Sub}; use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Sub}; +use encoding::pixel::RawPixel; +use white_point::{D65, WhitePoint}; +use {cast, clamp}; use {Alpha, LabHue, Lch, Xyz}; use {Component, ComponentWise, GetHue, Limited, Mix, Pixel, Shade}; -use {cast, clamp}; -use white_point::{D65, WhitePoint}; -use encoding::pixel::RawPixel; /// CIE L\*a\*b\* (CIELAB) with an alpha component. See the [`Laba` /// implementation in `Alpha`](struct.Alpha.html#Laba). @@ -22,8 +22,8 @@ pub type Laba = Alpha, T>; ///means that the perceptual difference between two colors is equal to their ///numerical difference. /// -///The parameters of L\*a\*b\* are quite different, compared to many other color -///spaces, so manipulating them manually may be unintuitive. +///The parameters of L\*a\*b\* are quite different, compared to many other +/// color spaces, so manipulating them manually may be unintuitive. #[derive(Debug, PartialEq, FromColor, Pixel)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[palette_internal] @@ -99,15 +99,26 @@ where white_point: PhantomData, } } + + /// Convert to a `(L\*, a\*, b\*)` tuple. + pub fn into_components(self) -> (T, T, T) { + (self.l, self.a, self.b) + } + + /// Convert from a `(L\*, a\*, b\*)` tuple. + pub fn from_components((l, a, b): (T, T, T)) -> Self { + Self::with_wp(l, a, b) + } } ///[`Laba`](type.Laba.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///CIE L\*a\*b\* and transparency and white point D65. - pub fn new(l: T, a: T, b: T, alpha: T) -> Laba { + pub fn new(l: T, a: T, b: T, alpha: A) -> Self { Alpha { color: Lab::new(l, a, b), alpha: alpha, @@ -116,18 +127,29 @@ where } ///[`Laba`](type.Laba.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, Wp: WhitePoint, { ///CIE L\*a\*b\* and transparency. - pub fn with_wp(l: T, a: T, b: T, alpha: T) -> Laba { + pub fn with_wp(l: T, a: T, b: T, alpha: A) -> Self { Alpha { color: Lab::with_wp(l, a, b), alpha: alpha, } } + + /// Convert to a `(L\*, a\*, b\*, alpha)` tuple. + pub fn into_components(self) -> (T, T, T, A) { + (self.l, self.a, self.b, self.alpha) + } + + /// Convert from a `(L\*, a\*, b\*, alpha)` tuple. + pub fn from_components((l, a, b, alpha): (T, T, T, A)) -> Self { + Self::with_wp(l, a, b, alpha) + } } impl From> for Lab @@ -182,6 +204,34 @@ where } } +impl From<(T, T, T)> for Lab { + fn from(components: (T, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T)> for Lab { + fn into(self) -> (T, T, T) { + self.into_components() + } +} + +impl From<(T, T, T, A)> + for Alpha, A> +{ + fn from(components: (T, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (T, T, T, A) { + self.into_components() + } +} + impl Limited for Lab where T: Component + Float, @@ -456,8 +506,8 @@ where #[cfg(test)] mod test { use super::Lab; - use LinSrgb; use white_point::D65; + use LinSrgb; #[test] fn red() { diff --git a/palette/src/lch.rs b/palette/src/lch.rs index f9366e50d..c869efc93 100644 --- a/palette/src/lch.rs +++ b/palette/src/lch.rs @@ -1,13 +1,13 @@ use num_traits::Float; -use std::ops::{Add, Sub}; use std::marker::PhantomData; +use std::ops::{Add, Sub}; +use encoding::pixel::RawPixel; +use white_point::{D65, WhitePoint}; +use {cast, clamp}; use {Alpha, Hue, Lab, LabHue, Xyz}; use {Component, FromColor, GetHue, IntoColor, Limited, Mix, Pixel, Saturate, Shade}; -use {cast, clamp}; -use white_point::{D65, WhitePoint}; -use encoding::pixel::RawPixel; /// CIE L\*C\*h° with an alpha component. See the [`Lcha` implementation in /// `Alpha`](struct.Alpha.html#Lcha). @@ -15,8 +15,8 @@ pub type Lcha = Alpha, T>; ///CIE L\*C\*h°, a polar version of [CIE L\*a\*b\*](struct.Lab.html). /// -///L\*C\*h° shares its range and perceptual uniformity with L\*a\*b\*, but it's a -///cylindrical color space, like [HSL](struct.Hsl.html) and +///L\*C\*h° shares its range and perceptual uniformity with L\*a\*b\*, but +/// it's a cylindrical color space, like [HSL](struct.Hsl.html) and ///[HSV](struct.Hsv.html). This gives it the same ability to directly change ///the hue and colorfulness of a color, while preserving other visual aspects. #[derive(Debug, PartialEq, FromColor, Pixel)] @@ -99,15 +99,26 @@ where white_point: PhantomData, } } + + /// Convert to a `(L\*, C\*, h°)` tuple. + pub fn into_components(self) -> (T, T, LabHue) { + (self.l, self.chroma, self.hue) + } + + /// Convert from a `(L\*, C\*, h°)` tuple. + pub fn from_components>>((l, chroma, hue): (T, T, H)) -> Self { + Self::with_wp(l, chroma, hue) + } } ///[`Lcha`](type.Lcha.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///CIE L\*C\*h° and transparency with white point D65. - pub fn new>>(l: T, chroma: T, hue: H, alpha: T) -> Lcha { + pub fn new>>(l: T, chroma: T, hue: H, alpha: A) -> Self { Alpha { color: Lch::new(l, chroma, hue), alpha: alpha, @@ -116,18 +127,29 @@ where } ///[`Lcha`](type.Lcha.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, Wp: WhitePoint, { ///CIE L\*C\*h° and transparency. - pub fn with_wp>>(l: T, chroma: T, hue: H, alpha: T) -> Lcha { + pub fn with_wp>>(l: T, chroma: T, hue: H, alpha: A) -> Self { Alpha { color: Lch::with_wp(l, chroma, hue), alpha: alpha, } } + + /// Convert to a `(L\*, C\*, h°, alpha)` tuple. + pub fn into_components(self) -> (T, T, LabHue, A) { + (self.l, self.chroma, self.hue, self.alpha) + } + + /// Convert from a `(L\*, C\*, h°, alpha)` tuple. + pub fn from_components>>((l, chroma, hue, alpha): (T, T, H, A)) -> Self { + Self::with_wp(l, chroma, hue, alpha) + } } impl From> for Lch @@ -156,6 +178,34 @@ where } } +impl>> From<(T, T, H)> for Lch { + fn from(components: (T, T, H)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, LabHue)> for Lch { + fn into(self) -> (T, T, LabHue) { + self.into_components() + } +} + +impl>, A: Component> From<(T, T, H, A)> + for Alpha, A> +{ + fn from(components: (T, T, H, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, LabHue, A)> + for Alpha, A> +{ + fn into(self) -> (T, T, LabHue, A) { + self.into_components() + } +} + impl Limited for Lch where T: Component + Float, @@ -372,8 +422,8 @@ where #[cfg(test)] mod test { - use Lch; use white_point::D65; + use Lch; #[test] fn ranges() { @@ -405,7 +455,8 @@ mod test { #[cfg(feature = "serde")] #[test] fn deserialize() { - let deserialized: Lch = ::serde_json::from_str(r#"{"l":0.3,"chroma":0.8,"hue":0.1}"#).unwrap(); + let deserialized: Lch = + ::serde_json::from_str(r#"{"l":0.3,"chroma":0.8,"hue":0.1}"#).unwrap(); assert_eq!(deserialized, Lch::new(0.3, 0.8, 0.1)); } diff --git a/palette/src/luma/luma.rs b/palette/src/luma/luma.rs index 51e492c3e..9cd32b7dc 100644 --- a/palette/src/luma/luma.rs +++ b/palette/src/luma/luma.rs @@ -1,20 +1,20 @@ -use std::ops::{Add, Div, Mul, Sub}; -use std::marker::PhantomData; use std::fmt; +use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Sub}; use approx::ApproxEq; use num_traits::Float; -use {Alpha, Xyz, Yxy}; -use {Blend, Component, ComponentWise, FromColor, IntoColor, Limited, Mix, Pixel, Shade}; -use luma::LumaStandard; -use encoding::{Linear, Srgb, TransferFn}; +use blend::PreAlpha; +use clamp; use encoding::linear::LinearFn; use encoding::pixel::RawPixel; +use encoding::{Linear, Srgb, TransferFn}; +use luma::LumaStandard; use white_point::WhitePoint; -use clamp; -use blend::PreAlpha; +use {Alpha, Xyz, Yxy}; +use {Blend, Component, ComponentWise, FromColor, IntoColor, Limited, Mix, Pixel, Shade}; /// Luminance with an alpha component. See the [`Lumaa` implementation /// in `Alpha`](struct.Alpha.html#Lumaa). @@ -90,6 +90,16 @@ where pub fn from_format(color: Luma) -> Self { color.into_format() } + + /// Convert to a `(luma,)` tuple. + pub fn into_components(self) -> (T,) { + (self.luma,) + } + + /// Convert from a `(luma,)` tuple. + pub fn from_components((luma,): (T,)) -> Self { + Self::new(luma) + } } impl Luma @@ -125,13 +135,14 @@ where } ///[`Lumaa`](type.Lumaa.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component, + A: Component, S: LumaStandard, { /// Create a luminance color with transparency. - pub fn new(luma: T, alpha: T) -> Self { + pub fn new(luma: T, alpha: A) -> Self { Alpha { color: Luma::new(luma), alpha: alpha, @@ -139,35 +150,51 @@ where } /// Convert into another component type. - pub fn into_format(self) -> Lumaa { - Lumaa::new(self.luma.convert(), self.alpha.convert()) + pub fn into_format(self) -> Alpha, B> { + Alpha::, B>::new(self.luma.convert(), self.alpha.convert()) } /// Convert from another component type. - pub fn from_format(color: Lumaa) -> Self { + pub fn from_format(color: Alpha, B>) -> Self { color.into_format() } + + /// Convert to a `(luma, alpha)` tuple. + pub fn into_components(self) -> (T, A) { + (self.luma, self.alpha) + } + + /// Convert from a `(luma, alpha)` tuple. + pub fn from_components((luma, alpha): (T, A)) -> Self { + Self::new(luma, alpha) + } } ///[`Lumaa`](type.Lumaa.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, S: LumaStandard, { /// Convert the color to linear luminance with transparency. - pub fn into_linear(self) -> Lumaa, T> { - Lumaa::new(S::TransferFn::into_linear(self.luma), self.alpha) + pub fn into_linear(self) -> Alpha, T>, A> { + Alpha::, T>, A>::new( + S::TransferFn::into_linear(self.luma), + self.alpha, + ) } /// Convert linear luminance to nonlinear luminance with transparency. - pub fn from_linear(color: Lumaa, T>) -> Lumaa { - Lumaa::new(S::TransferFn::from_linear(color.luma), color.alpha) + pub fn from_linear(color: Alpha, T>, A>) -> Alpha, A> { + Alpha::, A>::new(S::TransferFn::from_linear(color.luma), color.alpha) } /// Convert the color to a different encoding with transparency. - pub fn into_encoding>(self) -> Lumaa { - Lumaa::new( + pub fn into_encoding>( + self, + ) -> Alpha, A> { + Alpha::, A>::new( St::TransferFn::from_linear(S::TransferFn::into_linear(self.luma)), self.alpha, ) @@ -175,9 +202,9 @@ where /// Convert luminance from a different encoding with transparency. pub fn from_encoding>( - color: Lumaa, - ) -> Lumaa { - Lumaa::new( + color: Alpha, A>, + ) -> Alpha, A> { + Alpha::, A>::new( S::TransferFn::from_linear(St::TransferFn::into_linear(color.luma)), color.alpha, ) @@ -210,6 +237,30 @@ where } } +impl From<(T,)> for Luma { + fn from(components: (T,)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T,)> for Luma { + fn into(self) -> (T,) { + self.into_components() + } +} + +impl From<(T, A)> for Alpha, A> { + fn from(components: (T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, A)> for Alpha, A> { + fn into(self) -> (T, A) { + self.into_components() + } +} + impl IntoColor for Luma where S: LumaStandard, @@ -558,8 +609,8 @@ where #[cfg(test)] mod test { - use Luma; use encoding::Srgb; + use Luma; #[test] fn ranges() { diff --git a/palette/src/rgb/rgb.rs b/palette/src/rgb/rgb.rs index 41d66e20f..7f789d8cf 100644 --- a/palette/src/rgb/rgb.rs +++ b/palette/src/rgb/rgb.rs @@ -1,24 +1,24 @@ -use std::marker::PhantomData; -use std::ops::{Add, Div, Mul, Sub}; use std::any::TypeId; use std::fmt; +use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Sub}; -use num_traits::Float; use approx::ApproxEq; +use num_traits::Float; -use rgb::{RgbSpace, RgbStandard, TransferFn}; -use luma::LumaStandard; -use encoding::{Linear, Srgb}; -use encoding::linear::LinearFn; -use encoding::pixel::RawPixel; use alpha::Alpha; -use convert::{FromColor, IntoColor}; -use white_point::WhitePoint; use blend::PreAlpha; +use convert::{FromColor, IntoColor}; +use encoding::linear::LinearFn; +use encoding::pixel::RawPixel; +use encoding::{Linear, Srgb}; +use luma::LumaStandard; use matrix::{matrix_inverse, multiply_xyz_to_rgb, rgb_to_xyz_matrix}; -use {Hsl, Hsv, Hwb, Lab, Lch, Luma, RgbHue, Xyz, Yxy}; -use {Blend, Component, ComponentWise, GetHue, Limited, Mix, Pixel, Shade}; +use rgb::{RgbSpace, RgbStandard, TransferFn}; +use white_point::WhitePoint; use {cast, clamp}; +use {Blend, Component, ComponentWise, GetHue, Limited, Mix, Pixel, Shade}; +use {Hsl, Hsv, Hwb, Lab, Lch, Luma, RgbHue, Xyz, Yxy}; /// Generic RGB with an alpha component. See the [`Rgba` implementation in /// `Alpha`](../struct.Alpha.html#Rgba). @@ -31,10 +31,10 @@ pub type Rgba = Alpha, T>; /// light, where gray scale colors are created when these three channels are /// equal in strength. /// -/// Many conversions and operations on this color space requires that it's linear, -/// meaning that gamma correction is required when converting to and from a -/// displayable RGB, such as sRGB. See the [`pixel`](pixel/index.html) module -/// for encoding formats. +/// Many conversions and operations on this color space requires that it's +/// linear, meaning that gamma correction is required when converting to and +/// from a displayable RGB, such as sRGB. See the [`pixel`](pixel/index.html) +/// module for encoding formats. #[derive(Debug, PartialEq, FromColor, Pixel)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[palette_internal] @@ -44,16 +44,16 @@ pub type Rgba = Alpha, T>; #[palette_manual_from(Xyz, Hsv, Hsl, Luma, Rgb = "from_rgb_internal")] #[repr(C)] pub struct Rgb { - /// The amount of red light, where 0.0 is no red light and 1.0f (or 255u8) is the - /// highest displayable amount. + /// The amount of red light, where 0.0 is no red light and 1.0f (or 255u8) + /// is the highest displayable amount. pub red: T, - /// The amount of green light, where 0.0 is no green light and 1.0f (or 255u8) is the - /// highest displayable amount. + /// The amount of green light, where 0.0 is no green light and 1.0f (or + /// 255u8) is the highest displayable amount. pub green: T, - /// The amount of blue light, where 0.0 is no blue light and 1.0f (or 255u8) is the - /// highest displayable amount. + /// The amount of blue light, where 0.0 is no blue light and 1.0f (or + /// 255u8) is the highest displayable amount. pub blue: T, /// The kind of RGB standard. sRGB is the default. @@ -95,6 +95,16 @@ impl Rgb { pub fn from_format(color: Rgb) -> Self { color.into_format() } + + /// Convert to a `(red, green, blue)` tuple. + pub fn into_components(self) -> (T, T, T) { + (self.red, self.green, self.blue) + } + + /// Convert from a `(red, green, blue)` tuple. + pub fn from_components((red, green, blue): (T, T, T)) -> Self { + Self::new(red, green, blue) + } } impl Rgb { @@ -162,9 +172,9 @@ impl, T: Component> Rgb { } /// [`Rgba`](rgb/type.Rgba.html) implementations. -impl Alpha, T> { +impl Alpha, A> { /// Nonlinear RGB. - pub fn new(red: T, green: T, blue: T, alpha: T) -> Rgba { + pub fn new(red: T, green: T, blue: T, alpha: A) -> Self { Alpha { color: Rgb::new(red, green, blue), alpha: alpha, @@ -172,8 +182,8 @@ impl Alpha, T> { } /// Convert into another component type. - pub fn into_format(self) -> Alpha, U> { - Rgba::new( + pub fn into_format(self) -> Alpha, B> { + Alpha::, B>::new( self.red.convert(), self.green.convert(), self.blue.convert(), @@ -182,16 +192,26 @@ impl Alpha, T> { } /// Convert from another component type. - pub fn from_format(color: Alpha, U>) -> Self { + pub fn from_format(color: Alpha, B>) -> Self { color.into_format() } + + /// Convert to a `(red, green, blue, alpha)` tuple. + pub fn into_components(self) -> (T, T, T, A) { + (self.red, self.green, self.blue, self.alpha) + } + + /// Convert from a `(red, green, blue, alpha)` tuple. + pub fn from_components((red, green, blue, alpha): (T, T, T, A)) -> Self { + Self::new(red, green, blue, alpha) + } } /// [`Rgba`](rgb/type.Rgba.html) implementations. -impl Alpha, T> { +impl Alpha, A> { /// Convert the color to linear RGB with transparency. - pub fn into_linear(self) -> Rgba, T> { - Rgba::new( + pub fn into_linear(self) -> Alpha, T>, A> { + Alpha::, T>, A>::new( S::TransferFn::into_linear(self.red), S::TransferFn::into_linear(self.green), S::TransferFn::into_linear(self.blue), @@ -200,8 +220,8 @@ impl Alpha, T> { } /// Convert linear RGB to nonlinear RGB with transparency. - pub fn from_linear(color: Rgba, T>) -> Rgba { - Rgba::new( + pub fn from_linear(color: Alpha, T>, A>) -> Self { + Self::new( S::TransferFn::from_linear(color.red), S::TransferFn::from_linear(color.green), S::TransferFn::from_linear(color.blue), @@ -210,8 +230,8 @@ impl Alpha, T> { } /// Convert the color to a different encoding with transparency. - pub fn into_encoding>(self) -> Rgba { - Rgba::new( + pub fn into_encoding>(self) -> Alpha, A> { + Alpha::, A>::new( St::TransferFn::from_linear(S::TransferFn::into_linear(self.red)), St::TransferFn::from_linear(S::TransferFn::into_linear(self.green)), St::TransferFn::from_linear(S::TransferFn::into_linear(self.blue)), @@ -220,8 +240,8 @@ impl Alpha, T> { } /// Convert RGB from a different encoding with transparency. - pub fn from_encoding>(color: Rgba) -> Rgba { - Rgba::new( + pub fn from_encoding>(color: Alpha, A>) -> Self { + Self::new( S::TransferFn::from_linear(St::TransferFn::into_linear(color.red)), S::TransferFn::from_linear(St::TransferFn::into_linear(color.green)), S::TransferFn::from_linear(St::TransferFn::into_linear(color.blue)), @@ -619,6 +639,30 @@ where } } +impl From<(T, T, T)> for Rgb { + fn from(components: (T, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T)> for Rgb { + fn into(self) -> (T, T, T) { + self.into_components() + } +} + +impl From<(T, T, T, A)> for Alpha, A> { + fn from(components: (T, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T, A)> for Alpha, A> { + fn into(self) -> (T, T, T, A) { + self.into_components() + } +} + impl IntoColor for Rgb where S: RgbStandard, diff --git a/palette/src/xyz.rs b/palette/src/xyz.rs index 1b2862264..6f3e0bf31 100644 --- a/palette/src/xyz.rs +++ b/palette/src/xyz.rs @@ -1,16 +1,16 @@ use num_traits::Float; -use std::ops::{Add, Div, Mul, Sub}; use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Sub}; -use {Alpha, Lab, Luma, Yxy}; -use {Component, ComponentWise, Limited, Mix, Pixel, Shade}; -use white_point::{D65, WhitePoint}; -use rgb::{Rgb, RgbSpace, RgbStandard}; -use luma::LumaStandard; use encoding::pixel::RawPixel; +use luma::LumaStandard; use matrix::{multiply_rgb_to_xyz, rgb_to_xyz_matrix}; +use rgb::{Rgb, RgbSpace, RgbStandard}; +use white_point::{D65, WhitePoint}; use {cast, clamp}; +use {Alpha, Lab, Luma, Yxy}; +use {Component, ComponentWise, Limited, Mix, Pixel, Shade}; /// CIE 1931 XYZ with an alpha component. See the [`Xyza` implementation in /// `Alpha`](struct.Alpha.html#Xyza). @@ -23,7 +23,8 @@ pub type Xyza = Alpha, T>; ///converting from one color space to an other, and requires a standard ///illuminant and a standard observer to be defined. /// -///Conversions and operations on this color space depend on the defined white point +///Conversions and operations on this color space depend on the defined white +/// point #[derive(Debug, PartialEq, FromColor, Pixel)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[palette_internal] @@ -44,8 +45,9 @@ where ///Y is the luminance of the color, where 0.0 is black and 1.0 is white. pub y: T, - ///Z is the scale of what can be seen as the blue stimulation. Its range depends - ///on the white point and goes from 0.0 to 1.08883 for the defautl D65. + ///Z is the scale of what can be seen as the blue stimulation. Its range + /// depends on the white point and goes from 0.0 to 1.08883 for the + /// defautl D65. pub z: T, ///The white point associated with the color's illuminant and observer. @@ -101,15 +103,26 @@ where white_point: PhantomData, } } + + /// Convert to a `(X, Y, Z)` tuple. + pub fn into_components(self) -> (T, T, T) { + (self.x, self.y, self.z) + } + + /// Convert from a `(X, Y, Z)` tuple. + pub fn from_components((x, y, z): (T, T, T)) -> Self { + Self::with_wp(x, y, z) + } } ///[`Xyza`](type.Xyza.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///CIE Yxy and transparency with white point D65. - pub fn new(x: T, y: T, luma: T, alpha: T) -> Xyza { + pub fn new(x: T, y: T, luma: T, alpha: A) -> Self { Alpha { color: Xyz::new(x, y, luma), alpha: alpha, @@ -118,18 +131,29 @@ where } ///[`Xyza`](type.Xyza.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, Wp: WhitePoint, { ///CIE XYZ and transparency. - pub fn with_wp(x: T, y: T, z: T, alpha: T) -> Xyza { + pub fn with_wp(x: T, y: T, z: T, alpha: A) -> Self { Alpha { color: Xyz::with_wp(x, y, z), alpha: alpha, } } + + /// Convert to a `(X, Y, Z, alpha)` tuple. + pub fn into_components(self) -> (T, T, T, A) { + (self.x, self.y, self.z, self.alpha) + } + + /// Convert from a `(X, Y, Z, alpha)` tuple. + pub fn from_components((x, y, z, alpha): (T, T, T, A)) -> Self { + Self::with_wp(x, y, z, alpha) + } } impl From> for Xyz @@ -201,6 +225,34 @@ where } } +impl From<(T, T, T)> for Xyz { + fn from(components: (T, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T)> for Xyz { + fn into(self) -> (T, T, T) { + self.into_components() + } +} + +impl From<(T, T, T, A)> + for Alpha, A> +{ + fn from(components: (T, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (T, T, T, A) { + self.into_components() + } +} + impl Limited for Xyz where T: Component + Float, @@ -461,9 +513,9 @@ where #[cfg(test)] mod test { use super::Xyz; - use LinSrgb; - use LinLuma; use white_point::D65; + use LinLuma; + use LinSrgb; const X_N: f64 = 0.95047; const Y_N: f64 = 1.0; const Z_N: f64 = 1.08883; diff --git a/palette/src/yxy.rs b/palette/src/yxy.rs index 3f21d9e50..f9b331f57 100644 --- a/palette/src/yxy.rs +++ b/palette/src/yxy.rs @@ -1,14 +1,14 @@ use num_traits::Float; -use std::ops::{Add, Div, Mul, Sub}; use std::marker::PhantomData; +use std::ops::{Add, Div, Mul, Sub}; -use {Alpha, Luma, Xyz}; +use clamp; +use encoding::pixel::RawPixel; use luma::LumaStandard; -use {Component, ComponentWise, IntoColor, Limited, Mix, Pixel, Shade}; use white_point::{D65, WhitePoint}; -use encoding::pixel::RawPixel; -use clamp; +use {Alpha, Luma, Xyz}; +use {Component, ComponentWise, IntoColor, Limited, Mix, Pixel, Shade}; /// CIE 1931 Yxy (xyY) with an alpha component. See the [`Yxya` implementation /// in `Alpha`](struct.Alpha.html#Yxya). @@ -99,15 +99,38 @@ where white_point: PhantomData, } } + + /// Convert to a `(y, x, luma)`, a.k.a. `(y, x, Y)` tuple. + pub fn into_components(self) -> (T, T, T) { + (self.y, self.x, self.luma) + } + + /// Convert from a `(y, x, luma)`, a.k.a. `(y, x, Y)` tuple. + pub fn from_components((y, x, luma): (T, T, T)) -> Self { + Self::with_wp(y, x, luma) + } + + /// Convert to a `(x, y, luma)`, a.k.a. `(x, y, Y)` tuple, which is the + /// more classical component order. + pub fn into_xyy_components(self) -> (T, T, T) { + (self.x, self.y, self.luma) + } + + /// Convert from a `(x, y, luma)`, a.k.a. `(x, y, Y)` tuple, which is the + /// more classical component order. + pub fn from_xyy_components((x, y, luma): (T, T, T)) -> Self { + Self::with_wp(y, x, luma) + } } ///[`Yxya`](type.Yxya.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, { ///CIE Yxy and transparency with white point D65. - pub fn new(x: T, y: T, luma: T, alpha: T) -> Yxya { + pub fn new(x: T, y: T, luma: T, alpha: A) -> Self { Alpha { color: Yxy::new(x, y, luma), alpha: alpha, @@ -115,18 +138,41 @@ where } } ///[`Yxya`](type.Yxya.html) implementations. -impl Alpha, T> +impl Alpha, A> where T: Component + Float, + A: Component, Wp: WhitePoint, { ///CIE Yxy and transparency. - pub fn with_wp(x: T, y: T, luma: T, alpha: T) -> Yxya { + pub fn with_wp(x: T, y: T, luma: T, alpha: A) -> Self { Alpha { color: Yxy::with_wp(x, y, luma), alpha: alpha, } } + + /// Convert to a `(y, x, luma)`, a.k.a. `(y, x, Y)` tuple. + pub fn into_components(self) -> (T, T, T, A) { + (self.y, self.x, self.luma, self.alpha) + } + + /// Convert from a `(y, x, luma)`, a.k.a. `(y, x, Y)` tuple. + pub fn from_components((y, x, luma, alpha): (T, T, T, A)) -> Self { + Self::with_wp(y, x, luma, alpha) + } + + /// Convert to a `(x, y, luma)`, a.k.a. `(x, y, Y)` tuple, which is the + /// more classical component order. + pub fn into_xyy_components(self) -> (T, T, T, A) { + (self.x, self.y, self.luma, self.alpha) + } + + /// Convert from a `(x, y, luma)`, a.k.a. `(x, y, Y)` tuple, which is the + /// more classical component order. + pub fn from_xyy_components((x, y, luma, alpha): (T, T, T, A)) -> Self { + Self::with_wp(y, x, luma, alpha) + } } impl From> for Yxy @@ -164,6 +210,34 @@ where } } +impl From<(T, T, T)> for Yxy { + fn from(components: (T, T, T)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T)> for Yxy { + fn into(self) -> (T, T, T) { + self.into_components() + } +} + +impl From<(T, T, T, A)> + for Alpha, A> +{ + fn from(components: (T, T, T, A)) -> Self { + Self::from_components(components) + } +} + +impl Into<(T, T, T, A)> + for Alpha, A> +{ + fn into(self) -> (T, T, T, A) { + self.into_components() + } +} + impl Limited for Yxy where T: Component + Float, @@ -429,9 +503,9 @@ where #[cfg(test)] mod test { use super::Yxy; - use LinSrgb; - use LinLuma; use white_point::D65; + use LinLuma; + use LinSrgb; #[test] fn luma() {