palette/
convert.rs

1//! Traits for converting between color spaces.
2//!
3//! Each color space type, such as [`Rgb`](crate::rgb::Rgb) and
4//! [`Hsl`](crate::Hsl), implement a number of conversion traits:
5//!
6//! * [`FromColor`] - Similar to [`From`], converts from another color space.
7//! * [`IntoColor`] - Similar to [`Into`], converts into another color space.
8//! * [`FromColorUnclamped`] - The same as [`FromColor`], but the resulting
9//!   values may be outside the typical bounds.
10//! * [`IntoColorUnclamped`] - The same as [`IntoColor`], but the resulting
11//!   values may be outside the typical bounds.
12//!
13//! ```
14//! use palette::{FromColor, IntoColor, Srgb, Hsl};
15//!
16//! let rgb = Srgb::new(0.3f32, 0.8, 0.1);
17//!
18//! let hsl1: Hsl = rgb.into_color();
19//! let hsl2 = Hsl::from_color(rgb);
20//! ```
21//!
22//! Most of the color space types can be converted directly to each other, with
23//! these traits. If you look at the implemented traits for any color type, you
24//! will see a substantial list of `FromColorUnclamped` implementations. There
25//! are, however, exceptions and restrictions in some cases:
26//!
27//! * **It's not always possible to change the component type while
28//!   converting.** This can only be enabled in specific cases, to allow type
29//!   inference to work. The input and output component types need to be the
30//!   same in the general case.
31//! * **It's not always possible to change meta types while converting.** Meta
32//!   types are the additional input types on colors, such as white point or RGB
33//!   standard. Similar to component types, these are generally restricted to
34//!   help type inference.
35//! * **Some color spaces want specific component types.** For example,
36//!   [`Xyz`](crate::Xyz) and many other color spaces require real-ish numbers
37//!   (`f32`, `f64`, etc.).
38//! * **Some color spaces want specific meta types.** For example,
39//!   [`Oklab`](crate::Oklab) requires the white point to be
40//!   [`D65`](crate::white_point::D65).
41//!
42//! These limitations are usually the reason for why the compiler gives an error
43//! when calling `into_color`, `from_color`, or the corresponding unclamped
44//! methods. They are possible to work around by splitting the conversion into
45//! multiple steps.
46//!
47//! # In-place Conversion
48//!
49//! It's possible for some color spaces to be converted in-place, meaning the
50//! destination color will use the memory space of the source color. The
51//! requirement for this is that the source and destination color types have the
52//! same memory layout. That is, the same component types and the same number of
53//! components. This is verified by the [`ArrayCast`](crate::cast::ArrayCast)
54//! trait.
55//!
56//! In-place conversion is done with the [`FromColorMut`] and [`IntoColorMut`]
57//! traits, as well as their unclamped counterparts, [`FromColorUnclampedMut`]
58//! and [`IntoColorUnclampedMut`]. They work for both single colors and slices
59//! of colors.
60//!
61//! ```
62//! use palette::{convert::FromColorMut, Srgb, Hsl, Hwb};
63//!
64//! let mut rgb_colors: Vec<Srgb<f32>> = vec![/* ... */];
65//!
66//! {
67//!     // Creates a scope guard that prevents `rgb_colors` from being modified as RGB.
68//!     let hsl_colors = <[Hsl]>::from_color_mut(&mut rgb_colors);
69//!
70//!     // The converted colors can be converted again, without keeping the previous guard around.
71//!     let hwb_colors = hsl_colors.then_into_color_mut::<[Hwb]>();
72//!
73//!     // The colors are automatically converted back to RGB at the end of the scope.
74//!     // The use of `then_into_color_mut` above makes this conversion a single HWB -> RGB step,
75//!     // instead of HWB -> HSL -> RGB, since it consumed the HSL guard.
76//! }
77//! ```
78//!
79//! # Deriving
80//!
81//! `FromColorUnclamped` can be derived in a mostly automatic way. The other
82//! traits are blanket implemented based on it. The default minimum requirement
83//! is to implement `FromColorUnclamped<Xyz>`, but it can also be customized to
84//! make use of generics and have other manual implementations.
85//!
86//! It is also recommended to derive or implement
87//! [`WithAlpha`](crate::WithAlpha), to be able to convert between all `Alpha`
88//! wrapped color types.
89//!
90//! ## Configuration Attributes
91//!
92//! The derives can be configured using one or more `#[palette(...)]`
93//! attributes. They can be attached to either the item itself, or to the
94//! fields.
95//!
96//! ```
97//! # use palette::rgb::{RgbStandard, RgbSpace};
98//! # use palette::convert::FromColorUnclamped;
99//! # use palette::{Xyz, stimulus::Stimulus};
100//! #
101//! #[derive(FromColorUnclamped)]
102//! #[palette(
103//!     component = "T",
104//!     rgb_standard = "S",
105//! )]
106//! #[repr(C)]
107//! struct ExampleType<S, T> {
108//!     // ...
109//!     #[palette(alpha)]
110//!     alpha: T,
111//!     standard: std::marker::PhantomData<S>,
112//! }
113//!
114//! # impl<S, T> FromColorUnclamped<Xyz<<S::Space as RgbSpace>::WhitePoint, T>> for ExampleType<S, T>
115//! # where
116//! #   S: RgbStandard,
117//! #   T: Stimulus,
118//! # {
119//! #   fn from_color_unclamped(color: Xyz<<S::Space as RgbSpace>::WhitePoint, T>) -> Self {
120//! #       ExampleType {alpha: T::max_intensity(), standard: std::marker::PhantomData}
121//! #   }
122//! # }
123//! #
124//! # impl<S, T> FromColorUnclamped<ExampleType<S, T>> for Xyz<<S::Space as RgbSpace>::WhitePoint, T>
125//! # where
126//! #   S: RgbStandard,
127//! #   Self: Default,
128//! # {
129//! #   fn from_color_unclamped(color: ExampleType<S, T>) -> Self {
130//! #       Xyz::default()
131//! #   }
132//! # }
133//! ```
134//!
135//! ### Item Attributes
136//!
137//! * `skip_derives(Luma, Rgb)`: No conversion derives will be implemented for
138//! these colors. They are instead to be implemented manually, and serve as the
139//! basis for the automatic implementations.
140//!
141//! * `white_point = "some::white_point::Type"`: Sets the white point type that
142//! should be used when deriving. The default is `D65`, but it may be any other
143//! type, including type parameters.
144//!
145//! * `component = "some::component::Type"`: Sets the color component type that
146//! should be used when deriving. The default is `f32`, but it may be any other
147//! type, including type parameters.
148//!
149//! * `rgb_standard = "some::rgb_standard::Type"`: Sets the RGB standard type
150//! that should be used when deriving. The default is to either use `Srgb` or a
151//! best effort to convert between standards, but sometimes it has to be set to
152//! a specific type. This also accepts type parameters.
153//!
154//! * `luma_standard = "some::rgb_standard::Type"`: Sets the Luma standard type
155//! that should be used when deriving, similar to `rgb_standard`.
156//!
157//! ### Field Attributes
158//!
159//! * `alpha`: Specifies field as the color's transparency value.
160//!
161//! ## Examples
162//!
163//! Minimum requirements implementation:
164//!
165//! ```rust
166//! use palette::convert::FromColorUnclamped;
167//! use palette::{Srgb, Xyz, IntoColor};
168//!
169//! /// A custom version of Xyz that stores integer values from 0 to 100.
170//! #[derive(PartialEq, Debug, FromColorUnclamped)]
171//! struct Xyz100 {
172//!     x: u8,
173//!     y: u8,
174//!     z: u8,
175//! }
176//!
177//! // We have to implement at least one "manual" conversion. The default
178//! // is to and from `Xyz`, but it can be customized with `skip_derives(...)`.
179//! impl FromColorUnclamped<Xyz> for Xyz100 {
180//!     fn from_color_unclamped(color: Xyz) -> Xyz100 {
181//!         Xyz100 {
182//!             x: (color.x * 100.0) as u8,
183//!             y: (color.y * 100.0) as u8,
184//!             z: (color.z * 100.0) as u8,
185//!         }
186//!     }
187//! }
188//!
189//! impl FromColorUnclamped<Xyz100> for Xyz {
190//!     fn from_color_unclamped(color: Xyz100) -> Xyz {
191//!         Xyz::new(
192//!             color.x as f32 / 100.0,
193//!             color.y as f32 / 100.0,
194//!             color.z as f32 / 100.0,
195//!         )
196//!     }
197//! }
198//!
199//! // Start with an Xyz100 color.
200//! let xyz = Xyz100 {
201//!     x: 59,
202//!     y: 75,
203//!     z: 42,
204//! };
205//!
206//! // Convert the color to sRGB.
207//! let rgb: Srgb = xyz.into_color();
208//!
209//! assert_eq!(rgb.into_format(), Srgb::new(196u8, 238, 154));
210//! ```
211//!
212//! With generic components:
213//!
214//! ```rust
215//! #[macro_use]
216//! extern crate approx;
217//!
218//! use palette::cast::{ComponentsAs, ArrayCast};
219//! use palette::rgb::{Rgb, RgbSpace, RgbStandard};
220//! use palette::encoding::Linear;
221//! use palette::white_point::D65;
222//! use palette::convert::{FromColorUnclamped, IntoColorUnclamped};
223//! use palette::{Hsv, Srgb, IntoColor};
224//!
225//! /// sRGB, but with a reversed memory layout.
226//! #[derive(Copy, Clone, ArrayCast, FromColorUnclamped)]
227//! #[palette(
228//!     skip_derives(Rgb),
229//!     component = "T",
230//!     rgb_standard = "palette::encoding::Srgb"
231//! )]
232//! #[repr(C)] // Makes sure the memory layout is as we want it.
233//! struct Bgr<T> {
234//!     blue: T,
235//!     green: T,
236//!     red: T,
237//! }
238//!
239//! // It converts from and into any linear Rgb type that has the
240//! // D65 white point, which is the default if we don't specify
241//! // anything else with the `white_point` attribute argument.
242//! impl<S, T> FromColorUnclamped<Bgr<T>> for Rgb<S, T>
243//! where
244//!     S: RgbStandard,
245//!     S::Space: RgbSpace<WhitePoint = D65>,
246//!     Srgb<T>: IntoColorUnclamped<Rgb<S, T>>,
247//! {
248//!     fn from_color_unclamped(color: Bgr<T>) -> Rgb<S, T> {
249//!         Srgb::new(color.red, color.green, color.blue)
250//!             .into_color_unclamped()
251//!     }
252//! }
253//!
254//! impl<S, T> FromColorUnclamped<Rgb<S, T>> for Bgr<T>
255//! where
256//!     S: RgbStandard,
257//!     S::Space: RgbSpace<WhitePoint = D65>,
258//!     Srgb<T>: FromColorUnclamped<Rgb<S, T>>,
259//! {
260//!     fn from_color_unclamped(color: Rgb<S, T>) -> Bgr<T> {
261//!         let color = Srgb::from_color_unclamped(color);
262//!         Bgr {
263//!             blue: color.blue,
264//!             green: color.green,
265//!             red: color.red,
266//!         }
267//!     }
268//! }
269//!
270//! fn main() {
271//!     let buffer = vec![
272//!         0.0f64,
273//!         0.0,
274//!         0.0,
275//!         0.0,
276//!         0.5,
277//!         0.25,
278//!     ];
279//!     let buffer: &[Bgr<_>] = buffer.components_as();
280//!     let hsv: Hsv<_, f64> = buffer[1].into_color();
281//!
282//!     assert_relative_eq!(hsv, Hsv::new(90.0, 1.0, 0.5));
283//! }
284//! ```
285//!
286//! With alpha component:
287//!
288//! ```rust
289//! #[macro_use]
290//! extern crate approx;
291//!
292//! use palette::{LinSrgba, Srgb, IntoColor, WithAlpha};
293//! use palette::rgb::Rgb;
294//! use palette::convert::{FromColorUnclamped, IntoColorUnclamped};
295//!
296//! /// CSS style sRGB.
297//! #[derive(PartialEq, Debug, FromColorUnclamped, WithAlpha)]
298//! #[palette(
299//!     skip_derives(Rgb),
300//!     rgb_standard = "palette::encoding::Srgb"
301//! )]
302//! struct CssRgb {
303//!     red: u8,
304//!     green: u8,
305//!     blue: u8,
306//!     #[palette(alpha)]
307//!     alpha: f32,
308//! }
309//!
310//! // We will write a conversion function for opaque RGB and
311//! // `impl_default_conversions` will take care of preserving
312//! // the transparency for us.
313//! impl<S> FromColorUnclamped<Rgb<S, f32>> for CssRgb
314//! where
315//!     Srgb<f32>: FromColorUnclamped<Rgb<S, f32>>
316//! {
317//!     fn from_color_unclamped(color: Rgb<S, f32>) -> CssRgb{
318//!         let srgb = Srgb::from_color_unclamped(color)
319//!             .into_format();
320//!
321//!         CssRgb {
322//!             red: srgb.red,
323//!             green: srgb.green,
324//!             blue: srgb.blue,
325//!             alpha: 1.0
326//!         }
327//!     }
328//! }
329//!
330//! impl<S> FromColorUnclamped<CssRgb> for Rgb<S, f32>
331//! where
332//!     Srgb<f32>: IntoColorUnclamped<Rgb<S, f32>>
333//! {
334//!     fn from_color_unclamped(color: CssRgb) -> Rgb<S, f32>{
335//!         Srgb::new(color.red, color.green, color.blue)
336//!             .into_format()
337//!             .into_color_unclamped()
338//!     }
339//! }
340//!
341//! fn main() {
342//!     let css_color = CssRgb {
343//!         red: 187,
344//!         green: 0,
345//!         blue: 255,
346//!         alpha: 0.3,
347//!     };
348//!     let color: LinSrgba = css_color.into_color();
349//!
350//!     assert_relative_eq!(color, LinSrgba::new(0.496933, 0.0, 1.0, 0.3));
351//! }
352//! ```
353
354pub use self::{
355    from_into_color::*, from_into_color_mut::*, from_into_color_unclamped::*,
356    from_into_color_unclamped_mut::*, try_from_into_color::*,
357};
358
359mod from_into_color;
360mod from_into_color_mut;
361mod from_into_color_unclamped;
362mod from_into_color_unclamped_mut;
363mod try_from_into_color;
364
365#[cfg(test)]
366mod tests {
367    use core::marker::PhantomData;
368
369    use super::{FromColor, FromColorUnclamped, IntoColor};
370    use crate::{
371        bool_mask::{BoolMask, HasBoolMask},
372        encoding::linear::Linear,
373        luma::{Luma, LumaStandard},
374        num::{One, Zero},
375        rgb::{Rgb, RgbSpace},
376        Alpha, Clamp, Hsl, Hsluv, Hsv, Hwb, IsWithinBounds, Lab, Lch, Luv, Xyz, Yxy,
377    };
378
379    #[derive(FromColorUnclamped, WithAlpha)]
380    #[palette(
381        skip_derives(Xyz, Luma),
382        component = "f64",
383        rgb_standard = "Linear<S>",
384        palette_internal,
385        palette_internal_not_base_type
386    )]
387    struct WithXyz<S>(PhantomData<S>);
388
389    impl<S> Clone for WithXyz<S> {
390        fn clone(&self) -> Self {
391            *self
392        }
393    }
394
395    impl<S> Copy for WithXyz<S> {}
396
397    impl<S> HasBoolMask for WithXyz<S> {
398        type Mask = bool;
399    }
400
401    impl<S> IsWithinBounds for WithXyz<S> {
402        fn is_within_bounds(&self) -> bool {
403            true
404        }
405    }
406
407    impl<S> Clamp for WithXyz<S> {
408        fn clamp(self) -> Self {
409            self
410        }
411    }
412
413    impl<S1, S2> FromColorUnclamped<WithXyz<S2>> for WithXyz<S1>
414    where
415        S1: RgbSpace,
416        S2: RgbSpace<WhitePoint = S1::WhitePoint>,
417    {
418        fn from_color_unclamped(_color: WithXyz<S2>) -> Self {
419            WithXyz(PhantomData)
420        }
421    }
422
423    impl<S: RgbSpace> FromColorUnclamped<Xyz<S::WhitePoint, f64>> for WithXyz<S> {
424        fn from_color_unclamped(_color: Xyz<S::WhitePoint, f64>) -> Self {
425            WithXyz(PhantomData)
426        }
427    }
428
429    impl<S: RgbSpace> FromColorUnclamped<WithXyz<S>> for Xyz<S::WhitePoint, f64> {
430        fn from_color_unclamped(_color: WithXyz<S>) -> Xyz<S::WhitePoint, f64> {
431            Xyz::new(0.0, 1.0, 0.0)
432        }
433    }
434
435    impl<Rs: RgbSpace, Ls: LumaStandard<WhitePoint = Rs::WhitePoint>>
436        FromColorUnclamped<Luma<Ls, f64>> for WithXyz<Rs>
437    {
438        fn from_color_unclamped(_color: Luma<Ls, f64>) -> Self {
439            WithXyz(PhantomData)
440        }
441    }
442
443    impl<Rs: RgbSpace, Ls: LumaStandard<WhitePoint = Rs::WhitePoint>>
444        FromColorUnclamped<WithXyz<Rs>> for Luma<Ls, f64>
445    {
446        fn from_color_unclamped(_color: WithXyz<Rs>) -> Self {
447            Luma::new(1.0)
448        }
449    }
450
451    #[derive(Copy, Clone, FromColorUnclamped, WithAlpha)]
452    #[palette(
453        skip_derives(Lch, Luma),
454        white_point = "crate::white_point::E",
455        component = "T",
456        rgb_standard = "Linear<(crate::encoding::Srgb, crate::white_point::E)>",
457        palette_internal,
458        palette_internal_not_base_type
459    )]
460    struct WithoutXyz<T>(PhantomData<T>);
461
462    impl<T> HasBoolMask for WithoutXyz<T>
463    where
464        T: HasBoolMask,
465    {
466        type Mask = T::Mask;
467    }
468
469    impl<T> IsWithinBounds for WithoutXyz<T>
470    where
471        T: HasBoolMask,
472    {
473        fn is_within_bounds(&self) -> T::Mask {
474            T::Mask::from_bool(true)
475        }
476    }
477
478    impl<T> Clamp for WithoutXyz<T> {
479        fn clamp(self) -> Self {
480            self
481        }
482    }
483
484    impl<T> FromColorUnclamped<WithoutXyz<T>> for WithoutXyz<T> {
485        fn from_color_unclamped(color: WithoutXyz<T>) -> Self {
486            color
487        }
488    }
489
490    impl<T> FromColorUnclamped<Lch<crate::white_point::E, T>> for WithoutXyz<T> {
491        fn from_color_unclamped(_color: Lch<crate::white_point::E, T>) -> Self {
492            WithoutXyz(PhantomData)
493        }
494    }
495
496    impl<T: One + Zero> FromColorUnclamped<WithoutXyz<T>> for Lch<crate::white_point::E, T> {
497        fn from_color_unclamped(_color: WithoutXyz<T>) -> Lch<crate::white_point::E, T> {
498            Lch::new(T::one(), T::zero(), T::zero())
499        }
500    }
501
502    impl<T> FromColorUnclamped<Luma<Linear<crate::white_point::E>, T>> for WithoutXyz<T> {
503        fn from_color_unclamped(_color: Luma<Linear<crate::white_point::E>, T>) -> Self {
504            WithoutXyz(PhantomData)
505        }
506    }
507
508    impl<T: One> FromColorUnclamped<WithoutXyz<T>> for Luma<Linear<crate::white_point::E>, T> {
509        fn from_color_unclamped(_color: WithoutXyz<T>) -> Luma<Linear<crate::white_point::E>, T> {
510            Luma::new(T::one())
511        }
512    }
513
514    #[test]
515    fn from_with_xyz() {
516        let color: WithXyz<crate::encoding::Srgb> = WithXyz(Default::default());
517        let _ = WithXyz::<crate::encoding::Srgb>::from_color(color);
518
519        let xyz: Xyz<_, f64> = Default::default();
520        let _ = WithXyz::<crate::encoding::Srgb>::from_color(xyz);
521
522        let yxy: Yxy<_, f64> = Default::default();
523        let _ = WithXyz::<crate::encoding::Srgb>::from_color(yxy);
524
525        let lab: Lab<_, f64> = Default::default();
526        let _ = WithXyz::<crate::encoding::Srgb>::from_color(lab);
527
528        let lch: Lch<_, f64> = Default::default();
529        let _ = WithXyz::<crate::encoding::Srgb>::from_color(lch);
530
531        let luv: Hsl<_, f64> = Default::default();
532        let _ = WithXyz::<crate::encoding::Srgb>::from_color(luv);
533
534        let rgb: Rgb<_, f64> = Default::default();
535        let _ = WithXyz::<crate::encoding::Srgb>::from_color(rgb);
536
537        let hsl: Hsl<_, f64> = Default::default();
538        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsl);
539
540        let hsluv: Hsluv<_, f64> = Default::default();
541        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsluv);
542
543        let hsv: Hsv<_, f64> = Default::default();
544        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsv);
545
546        let hwb: Hwb<_, f64> = Default::default();
547        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hwb);
548
549        let luma: Luma<crate::encoding::Srgb, f64> = Default::default();
550        let _ = WithXyz::<crate::encoding::Srgb>::from_color(luma);
551    }
552
553    #[test]
554    fn from_with_xyz_alpha() {
555        let color: Alpha<WithXyz<crate::encoding::Srgb>, u8> =
556            Alpha::from(WithXyz(Default::default()));
557        let _ = WithXyz::<crate::encoding::Srgb>::from_color(color);
558
559        let xyz: Alpha<Xyz<_, f64>, u8> = Alpha::from(Xyz::default());
560        let _ = WithXyz::<crate::encoding::Srgb>::from_color(xyz);
561
562        let yxy: Alpha<Yxy<_, f64>, u8> = Alpha::from(Yxy::default());
563        let _ = WithXyz::<crate::encoding::Srgb>::from_color(yxy);
564
565        let lab: Alpha<Lab<_, f64>, u8> = Alpha::from(Lab::default());
566        let _ = WithXyz::<crate::encoding::Srgb>::from_color(lab);
567
568        let lch: Alpha<Lch<_, f64>, u8> = Alpha::from(Lch::default());
569        let _ = WithXyz::<crate::encoding::Srgb>::from_color(lch);
570
571        let luv: Alpha<Luv<_, f64>, u8> = Alpha::from(Luv::default());
572        let _ = WithXyz::<crate::encoding::Srgb>::from_color(luv);
573
574        let rgb: Alpha<Rgb<_, f64>, u8> = Alpha::from(Rgb::default());
575        let _ = WithXyz::<crate::encoding::Srgb>::from_color(rgb);
576
577        let hsl: Alpha<Hsl<_, f64>, u8> = Alpha::from(Hsl::default());
578        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsl);
579
580        let hsluv: Alpha<Hsluv<_, f64>, u8> = Alpha::from(Hsluv::default());
581        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsluv);
582
583        let hsv: Alpha<Hsv<_, f64>, u8> = Alpha::from(Hsv::default());
584        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hsv);
585
586        let hwb: Alpha<Hwb<_, f64>, u8> = Alpha::from(Hwb::default());
587        let _ = WithXyz::<crate::encoding::Srgb>::from_color(hwb);
588
589        let luma: Alpha<Luma<crate::encoding::Srgb, f64>, u8> =
590            Alpha::from(Luma::<crate::encoding::Srgb, f64>::default());
591        let _ = WithXyz::<crate::encoding::Srgb>::from_color(luma);
592    }
593
594    #[test]
595    fn from_with_xyz_into_alpha() {
596        let color: WithXyz<crate::encoding::Srgb> = WithXyz(Default::default());
597        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(color);
598
599        let xyz: Xyz<_, f64> = Default::default();
600        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(xyz);
601
602        let yxy: Yxy<_, f64> = Default::default();
603        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(yxy);
604
605        let lab: Lab<_, f64> = Default::default();
606        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(lab);
607
608        let lch: Lch<_, f64> = Default::default();
609        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(lch);
610
611        let luv: Hsl<_, f64> = Default::default();
612        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(luv);
613
614        let rgb: Rgb<_, f64> = Default::default();
615        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(rgb);
616
617        let hsl: Hsl<_, f64> = Default::default();
618        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsl);
619
620        let hsluv: Hsluv<_, f64> = Default::default();
621        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsluv);
622
623        let hsv: Hsv<_, f64> = Default::default();
624        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsv);
625
626        let hwb: Hwb<_, f64> = Default::default();
627        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hwb);
628
629        let luma: Luma<crate::encoding::Srgb, f64> = Default::default();
630        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(luma);
631    }
632
633    #[test]
634    fn from_with_xyz_alpha_into_alpha() {
635        let color: Alpha<WithXyz<crate::encoding::Srgb>, u8> =
636            Alpha::from(WithXyz(Default::default()));
637        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(color);
638
639        let xyz: Xyz<_, f64> = Default::default();
640        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(xyz);
641
642        let yxy: Yxy<_, f64> = Default::default();
643        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(yxy);
644
645        let lab: Lab<_, f64> = Default::default();
646        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(lab);
647
648        let lch: Lch<_, f64> = Default::default();
649        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(lch);
650
651        let luv: Luv<_, f64> = Default::default();
652        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(luv);
653
654        let rgb: Rgb<_, f64> = Default::default();
655        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(rgb);
656
657        let hsl: Hsl<_, f64> = Default::default();
658        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsl);
659
660        let hsluv: Hsluv<_, f64> = Default::default();
661        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsluv);
662
663        let hsv: Hsv<_, f64> = Default::default();
664        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hsv);
665
666        let hwb: Hwb<_, f64> = Default::default();
667        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(hwb);
668
669        let luma: Luma<crate::encoding::Srgb, f64> = Default::default();
670        let _ = Alpha::<WithXyz<crate::encoding::Srgb>, u8>::from_color(luma);
671    }
672
673    #[test]
674    fn into_from_with_xyz() {
675        let color = WithXyz::<crate::encoding::Srgb>(PhantomData);
676
677        let _self: WithXyz<crate::encoding::Srgb> = color.into_color();
678        let _xyz: Xyz<_, f64> = color.into_color();
679        let _yxy: Yxy<_, f64> = color.into_color();
680        let _lab: Lab<_, f64> = color.into_color();
681        let _lch: Lch<_, f64> = color.into_color();
682        let _luv: Luv<_, f64> = color.into_color();
683        let _rgb: Rgb<_, f64> = color.into_color();
684        let _hsl: Hsl<_, f64> = color.into_color();
685        let _hsluv: Hsluv<_, f64> = color.into_color();
686        let _hsv: Hsv<_, f64> = color.into_color();
687        let _hwb: Hwb<_, f64> = color.into_color();
688        let _luma: Luma<crate::encoding::Srgb, f64> = color.into_color();
689    }
690
691    #[test]
692    fn into_from_with_xyz_alpha() {
693        let color: Alpha<WithXyz<crate::encoding::Srgb>, u8> =
694            Alpha::from(WithXyz::<crate::encoding::Srgb>(PhantomData));
695
696        let _self: WithXyz<crate::encoding::Srgb> = color.into_color();
697        let _xyz: Xyz<_, f64> = color.into_color();
698        let _yxy: Yxy<_, f64> = color.into_color();
699        let _lab: Lab<_, f64> = color.into_color();
700        let _lch: Lch<_, f64> = color.into_color();
701        let _luv: Luv<_, f64> = color.into_color();
702        let _rgb: Rgb<_, f64> = color.into_color();
703        let _hsl: Hsl<_, f64> = color.into_color();
704        let _hsluv: Hsluv<_, f64> = color.into_color();
705        let _hsv: Hsv<_, f64> = color.into_color();
706        let _hwb: Hwb<_, f64> = color.into_color();
707        let _luma: Luma<crate::encoding::Srgb, f64> = color.into_color();
708    }
709
710    #[test]
711    fn into_alpha_from_with_xyz() {
712        let color = WithXyz::<crate::encoding::Srgb>(PhantomData);
713
714        let _self: Alpha<WithXyz<crate::encoding::Srgb>, u8> = color.into_color();
715        let _xyz: Alpha<Xyz<_, f64>, u8> = color.into_color();
716        let _yxy: Alpha<Yxy<_, f64>, u8> = color.into_color();
717        let _lab: Alpha<Lab<_, f64>, u8> = color.into_color();
718        let _lch: Alpha<Lch<_, f64>, u8> = color.into_color();
719        let _luv: Alpha<Luv<_, f64>, u8> = color.into_color();
720        let _rgb: Alpha<Rgb<_, f64>, u8> = color.into_color();
721        let _hsl: Alpha<Hsl<_, f64>, u8> = color.into_color();
722        let _hsluv: Alpha<Hsluv<_, f64>, u8> = color.into_color();
723        let _hsv: Alpha<Hsv<_, f64>, u8> = color.into_color();
724        let _hwb: Alpha<Hwb<_, f64>, u8> = color.into_color();
725        let _luma: Alpha<Luma<crate::encoding::Srgb, f64>, u8> = color.into_color();
726    }
727
728    #[test]
729    fn into_alpha_from_with_xyz_alpha() {
730        let color: Alpha<WithXyz<crate::encoding::Srgb>, u8> =
731            Alpha::from(WithXyz::<crate::encoding::Srgb>(PhantomData));
732
733        let _self: Alpha<WithXyz<crate::encoding::Srgb>, u8> = color.into_color();
734        let _xyz: Alpha<Xyz<_, f64>, u8> = color.into_color();
735        let _yxy: Alpha<Yxy<_, f64>, u8> = color.into_color();
736        let _lab: Alpha<Lab<_, f64>, u8> = color.into_color();
737        let _lch: Alpha<Lch<_, f64>, u8> = color.into_color();
738        let _luv: Alpha<Luv<_, f64>, u8> = color.into_color();
739        let _rgb: Alpha<Rgb<_, f64>, u8> = color.into_color();
740        let _hsl: Alpha<Hsl<_, f64>, u8> = color.into_color();
741        let _hsluv: Alpha<Hsluv<_, f64>, u8> = color.into_color();
742        let _hsv: Alpha<Hsv<_, f64>, u8> = color.into_color();
743        let _hwb: Alpha<Hwb<_, f64>, u8> = color.into_color();
744        let _luma: Alpha<Luma<crate::encoding::Srgb, f64>, u8> = color.into_color();
745    }
746
747    #[test]
748    fn from_without_xyz() {
749        let color: WithoutXyz<f64> = WithoutXyz(Default::default());
750        let _ = WithoutXyz::<f64>::from_color(color);
751
752        let xyz: Xyz<crate::white_point::E, f64> = Default::default();
753        let _ = WithoutXyz::<f64>::from_color(xyz);
754
755        let yxy: Yxy<crate::white_point::E, f64> = Default::default();
756        let _ = WithoutXyz::<f64>::from_color(yxy);
757
758        let lab: Lab<crate::white_point::E, f64> = Default::default();
759        let _ = WithoutXyz::<f64>::from_color(lab);
760
761        let lch: Lch<crate::white_point::E, f64> = Default::default();
762        let _ = WithoutXyz::<f64>::from_color(lch);
763
764        let luv: Luv<crate::white_point::E, f64> = Default::default();
765        let _ = WithoutXyz::<f64>::from_color(luv);
766
767        let rgb: Rgb<_, f64> = Default::default();
768        let _ = WithoutXyz::<f64>::from_color(rgb);
769
770        let hsl: Hsl<_, f64> = Default::default();
771        let _ = WithoutXyz::<f64>::from_color(hsl);
772
773        let hsluv: Hsluv<_, f64> = Default::default();
774        let _ = WithoutXyz::<f64>::from_color(hsluv);
775
776        let hsv: Hsv<_, f64> = Default::default();
777        let _ = WithoutXyz::<f64>::from_color(hsv);
778
779        let hwb: Hwb<_, f64> = Default::default();
780        let _ = WithoutXyz::<f64>::from_color(hwb);
781
782        let luma: Luma<Linear<crate::white_point::E>, f64> = Default::default();
783        let _ = WithoutXyz::<f64>::from_color(luma);
784    }
785
786    #[test]
787    fn into_without_xyz() {
788        let color = WithoutXyz::<f64>(PhantomData);
789
790        let _self: WithoutXyz<f64> = color.into_color();
791        let _xyz: Xyz<crate::white_point::E, f64> = color.into_color();
792        let _yxy: Yxy<crate::white_point::E, f64> = color.into_color();
793        let _lab: Lab<crate::white_point::E, f64> = color.into_color();
794        let _lch: Lch<crate::white_point::E, f64> = color.into_color();
795        let _luv: Luv<crate::white_point::E, f64> = color.into_color();
796        let _rgb: Rgb<_, f64> = color.into_color();
797        let _hsl: Hsl<_, f64> = color.into_color();
798        let _hsluv: Hsluv<_, f64> = color.into_color();
799        let _hsv: Hsv<_, f64> = color.into_color();
800        let _hwb: Hwb<_, f64> = color.into_color();
801        let _luma: Luma<Linear<crate::white_point::E>, f64> = color.into_color();
802    }
803}