palette/
cast.rs

1//! Traits and functions for casting colors to and from other data types.
2//!
3//! The functions and traits in this module cast without changing the underlying
4//! data. See the [`convert`](crate::convert) module for how to convert between
5//! color spaces.
6//!
7//! # Traits or Functions?
8//!
9//! This module provides both a set of traits ([`FromComponents`],
10//! [`IntoUints`], etc.) and a set of functions ([`from_component_slice`],
11//! [`into_uint_array`], etc.) that effectively implement the same
12//! functionality. The traits are all implemented using the functions, so they
13//! can be seen as bits of more implicit syntax sugar for the more explicit
14//! functions.
15//!
16//! A general recommendation is to use the traits, since they provide mostly
17//! better ergonomics.
18//!
19//! # Arrays and Slices
20//!
21//! Types that implement [`ArrayCast`] can be cast to and from arrays and slices
22//! with little to no overhead. This makes it easy to work with image buffers
23//! and types from other crates without having to copy the data first.
24//!
25//! Casting can be either be done with the free functions in this module, or
26//! using the helper traits.
27//!
28//! ## Casting Arrays
29//!
30//! Arrays can be type checked to have the correct size at compile time, making
31//! casting free after optimization has removed the overhead from asserts. The
32//! same is true for arrays in slices and `Vec`s, because the length stays the
33//! same after casting.
34//!
35//! ```
36//! use palette::{cast::{self, ArraysAsMut}, Srgb, IntoColor};
37//!
38//! let color = cast::from_array::<Srgb<u8>>([23, 198, 76]).into_linear();
39//! // Note: `Srgb::<u8>::from([23, 198, 76])` works too.
40//!
41//! let mut buffer = [[64, 139, 10], [93, 18, 214]];
42//! let color_buffer: &mut [Srgb<u8>] = buffer.arrays_as_mut();
43//!
44//! for destination in color_buffer {
45//!     let linear_dst = destination.into_linear::<f32>();
46//!     *destination = (linear_dst + color).into_encoding();
47//! }
48//! ```
49//!
50//! Trying to cast a single array of the wrong size will not compile:
51//!
52//! ```compile_fail
53//! use palette::{cast, Srgb};
54//!
55//! let color = cast::from_array::<Srgb<u8>>([23, 198]); // Too few components.
56//! ```
57//!
58//! ## Casting Component Buffers
59//!
60//! This is a common situation is image processing, where you have an image
61//! buffer, such as `&mut [u8]`, `&mut [f32]`, `Vec<u8>` or `Vec<f32>`, that you
62//! want to work with as colors. This buffer may, for example, be the content of
63//! an image file or shared with the GPU.
64//!
65//! The downside, compared to having fixed size arrays, is that the length
66//! cannot be statically known to be a multiple of the color type's array
67//! length. This adds a bit of error handling overhead, as well as for dividing
68//! or multiplying the length.
69//!
70//! ```
71//! use palette::{cast::{self, TryComponentsAs}, Srgb};
72//!
73//! let correct_buffer = [64, 139, 10, 93, 18, 214];
74//! let should_be_ok: Result<&[Srgb<u8>], _> = correct_buffer.try_components_as();
75//! assert!(should_be_ok.is_ok());
76//!
77//! let incorrect_buffer = [64, 139, 10, 93, 18, 214, 198, 76];
78//! let should_be_err: Result<&[Srgb<u8>], _> = incorrect_buffer.try_components_as();
79//! assert!(should_be_err.is_err());
80//! ```
81//!
82//! An alternative, for when the length can be trusted to be correct, is to use
83//! methods without the `try_*` prefix, such as `ComponentsAs::components_as`,
84//! or the `from_component_*` functions, that panic on error.
85//!
86//! This works:
87//!
88//! ```
89//! use palette::{cast::ComponentsAs, Srgb};
90//!
91//! let correct_buffer = [64, 139, 10, 93, 18, 214];
92//! let color_buffer: &[Srgb<u8>] = correct_buffer.components_as();
93//! ```
94//!
95//! But this panics:
96//!
97//! ```should_panic
98//! use palette::{cast::ComponentsAs, Srgb};
99//!
100//! let incorrect_buffer = [64, 139, 10, 93, 18, 214, 198, 76];
101//! let color_buffer: &[Srgb<u8>] = incorrect_buffer.components_as();
102//! ```
103//!
104//! ## Casting Single Colors
105//!
106//! The built-in color types implement `AsRef`, `AsMut`, `From`, `Into`,
107//! `TryFrom` and `TryInto` in addition to `ArrayCast` for convenient casting of
108//! single colors:
109//!
110//! ```
111//! use core::convert::TryFrom;
112//! use palette::Srgb;
113//!
114//! let color = Srgb::from([23u8, 198, 76]);
115//! let array: [u8; 3] = color.into();
116//!
117//! let slice: &[u8] = color.as_ref();
118//! assert!(<&Srgb<u8>>::try_from(slice).is_ok());
119//!
120//! let short_slice: &[f32] = &[0.1, 0.5];
121//! assert!(<&Srgb>::try_from(short_slice).is_err()); // Too few components.
122//! ```
123//!
124//! ## Component Order
125//!
126//! The component order in an array or slice is not always the same as in the
127//! color types. For example, a byte buffer that is encoded as ARGB will not
128//! cast to correct `Rgba` values. The components can be reordered after casting
129//! by using the [`Packed`] wrapper as an intermediate representation.
130//!
131//! ```
132//! // `PackedArgb` is an alias for `Packed<rgb::channels::Argb, P = u32>`.
133//! use palette::{rgb::PackedArgb, cast::ComponentsAs, Srgba};
134//!
135//! let components = [1.0f32, 0.8, 0.2, 0.3, 1.0, 0.5, 0.7, 0.6];
136//! let colors: &[PackedArgb<_>] = components.components_as();
137//!
138//! // Notice how the alpha values have moved from the beginning to the end:
139//! assert_eq!(Srgba::from(colors[0]), Srgba::new(0.8, 0.2, 0.3, 1.0));
140//! assert_eq!(Srgba::from(colors[1]), Srgba::new(0.5, 0.7, 0.6, 1.0));
141//! ```
142//!
143//! # Unsigned Integers
144//!
145//! Types that implement [`UintCast`] can be cast to and from unsigned integers
146//! of the same size. It's a bit more limited than slices and arrays but it's
147//! useful for common patterns like representing RGBA values as hexadecimal
148//! unsigned integers.
149//!
150//! The [`Packed`] wrapper can be used as an intermediate format to make
151//! unpacking the values as simple as `from` or `into`. It's also possible to
152//! choose a channel order to be something other than what the default `From`
153//! implementations would use.
154//!
155//! ```
156//! // `PackedArgb` is an alias for `Packed<rgb::channels::Argb, P = u32>`.
157//! use palette::{rgb::PackedArgb, cast::UintsAs, Srgba};
158//!
159//! let raw = [0xFF7F0080u32, 0xFF60BBCC];
160//! let colors: &[PackedArgb] = raw.uints_as();
161//!
162//! assert_eq!(colors.len(), 2);
163//! assert_eq!(Srgba::from(colors[0]), Srgba::new(0x7F, 0x00, 0x80, 0xFF));
164//! assert_eq!(Srgba::from(colors[1]), Srgba::new(0x60, 0xBB, 0xCC, 0xFF));
165//! ```
166
167mod array;
168mod as_arrays_traits;
169mod as_components_traits;
170mod as_uints_traits;
171mod from_into_arrays_traits;
172mod from_into_components_traits;
173mod from_into_uints_traits;
174mod packed;
175mod uint;
176
177pub use self::{
178    array::*, as_arrays_traits::*, as_components_traits::*, as_uints_traits::*,
179    from_into_arrays_traits::*, from_into_components_traits::*, from_into_uints_traits::*,
180    packed::*, uint::*,
181};