1//! Raw color types.
2//!
3//! This module contains structs to represent the raw data used to store color
4//! information. Colors that implement the [`PixelColor`] trait can use the
5//! associated [`Raw`] type to define their raw data representation.
6//!
7//! Specifying a [`Raw`] type for a [`PixelColor`] is required to use that color
8//! with the [`Image`] struct.
9//!
10//! # Converting colors to raw data
11//!
12//! Colors can be converted into raw data by using two different methods. The [`into_storage`]
13//! method is used to convert a color into a single integer value. To convert a color into a byte
14//! array the methods provided by the [`ToBytes`] trait can be used. By using [`to_be_bytes`] the
15//! color components will have the same order in memory as in the name of the type.
16//!
17//! ```
18//! use embedded_graphics::{pixelcolor::Rgb888, prelude::*};
19//!
20//! let color = Rgb888::new(0x11, 0x22, 0x33);
21//!
22//! assert_eq!(color.into_storage(), 0x00112233);
23//!
24//! assert_eq!(color.to_be_bytes(), [0x11, 0x22, 0x33]);
25//! ```
26//!
27//! # Implementing PixelColor with Raw support
28//!
29//! This example shows how to implement a new [`PixelColor`] that can be used
30//! with images.
31//!
32//! The RGBI color type uses 4 bits per pixel, one for each color channel and
33//! an additional intensity bit.
34//!
35//! ```rust
36//! use embedded_graphics::{image::ImageRaw, pixelcolor::raw::RawU4, prelude::*};
37//!
38//! /// RGBI color
39//! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
40//! pub struct RGBI(RawU4);
41//!
42//! impl RGBI {
43//! /// Creates a RGBI color.
44//! pub fn new(red: bool, green: bool, blue: bool, intensity: bool) -> Self {
45//! let mut value = 0;
46//!
47//! if red {
48//! value |= 0b0100;
49//! }
50//! if green {
51//! value |= 0b0010;
52//! }
53//! if blue {
54//! value |= 0b0001;
55//! }
56//! if intensity {
57//! value |= 0b1000;
58//! }
59//!
60//! Self(RawU4::new(value))
61//! }
62//! }
63//!
64//! /// Implement `PixelColor` to associate a raw data type with the `RGBI` struct.
65//! impl PixelColor for RGBI {
66//! type Raw = RawU4;
67//! }
68//!
69//! /// `From<RawU4>` is used by `Image` to construct RGBI colors.
70//! impl From<RawU4> for RGBI {
71//! fn from(data: RawU4) -> Self {
72//! Self(data)
73//! }
74//! }
75//!
76//! /// Raw image data with 2 pixels per byte.
77//! #[rustfmt::skip]
78//! const IMAGE_DATA: &[u8] = &[
79//! 0b0001_0010,
80//! 0b0100_1111,
81//! ];
82//!
83//! // Create new image with RGBI colors.
84//! let image_raw: ImageRaw<RGBI> = ImageRaw::new(IMAGE_DATA, 2);
85//!
86//! // In a real application the image could now be drawn to a display:
87//! // display.draw(&image);
88//! #
89//! # use embedded_graphics::{mock_display::MockDisplay, image::Image};
90//! #
91//! # let mut display = MockDisplay::new();
92//! # Image::new(&image_raw, Point::zero()).draw(&mut display).unwrap();
93//! #
94//! # let expected_pixels = [
95//! # Pixel(Point::new(0, 0), RGBI::new(false, false, true, false)),
96//! # Pixel(Point::new(1, 0), RGBI::new(false, true, false, false)),
97//! # Pixel(Point::new(0, 1), RGBI::new(true, false, false, false)),
98//! # Pixel(Point::new(1, 1), RGBI::new(true, true, true, true)),
99//! # ];
100//! #
101//! # let mut expected_display = MockDisplay::new();
102//! # expected_pixels.iter().copied().draw(&mut expected_display).unwrap();
103//! #
104//! # // assert_eq can't be used because ColorMapping isn't implemented for RGBI
105//! # assert!(display.eq(&expected_display));
106//! ```
107//!
108//! [`PixelColor`]: super::PixelColor
109//! [`Raw`]: super::PixelColor::Raw
110//! [`Image`]: https://docs.rs/embedded-graphics/latest/embedded_graphics/image/struct.Image.html
111//! [`into_storage`]: super::IntoStorage::into_storage
112//! [`to_be_bytes`]: ToBytes::to_be_bytes
113
114mod to_bytes;
115
116pub use to_bytes::ToBytes;
117
118/// Trait implemented by all `RawUx` types.
119pub trait RawData: Sized + private::Sealed + From<<Self as RawData>::Storage> + ToBytes {
120 /// Storage type.
121 ///
122 /// A primitive unsigned integer storage type that contains at least `BITS_PER_PIXEL` bits.
123 type Storage;
124
125 /// Bits per pixel.
126 const BITS_PER_PIXEL: usize;
127
128 /// Converts this raw data into the storage type.
129 ///
130 /// If the primitive integer types used as the storage type contains more bits
131 /// than used by this type the unused most significant bits are set to `0`.
132 fn into_inner(self) -> Self::Storage;
133
134 /// Converts a `u32` into a `RawData` type.
135 ///
136 /// This method can be used to generically construct all `RawData` types from
137 /// the same integer type. If the width of the `RawData` type is less than
138 /// 32 bits only the least significant bits are used.
139 fn from_u32(value: u32) -> Self;
140}
141
142/// Dummy implementation for `()`.
143///
144/// `()` can be used as [`PixelColor::Raw`] if raw data conversion isn't required.
145///
146/// [`PixelColor::Raw`]: super::PixelColor::Raw
147impl RawData for () {
148 type Storage = ();
149
150 const BITS_PER_PIXEL: usize = 0;
151
152 fn into_inner(self) {}
153
154 fn from_u32(_value: u32) {}
155}
156
157impl private::Sealed for () {}
158
159macro_rules! impl_raw_data {
160 ($type:ident : $storage_type:ident, $bpp:expr, $mask:expr, $bpp_str:expr, $doc:expr) => {
161 #[doc = $bpp_str]
162 #[doc = "per pixel raw data."]
163 #[doc = ""]
164 #[doc = $doc]
165 #[doc = ""]
166 #[doc = "See the [module-level documentation](super) for more information."]
167 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
168 #[cfg_attr(feature = "defmt", derive(::defmt::Format))]
169 pub struct $type($storage_type);
170
171 impl $type {
172 /// Creates a new color from the least significant
173 #[doc = $bpp_str]
174 /// of value.
175 #[inline]
176 pub const fn new(value: $storage_type) -> Self {
177 $type(value & $mask)
178 }
179 }
180
181 impl RawData for $type {
182 type Storage = $storage_type;
183
184 const BITS_PER_PIXEL: usize = $bpp;
185
186 fn into_inner(self) -> Self::Storage {
187 self.0
188 }
189
190 fn from_u32(value: u32) -> Self {
191 #[allow(trivial_numeric_casts)]
192 Self::new(value as $storage_type)
193 }
194 }
195
196 impl From<$storage_type> for $type {
197 #[inline]
198 fn from(value: $storage_type) -> Self {
199 Self::new(value)
200 }
201 }
202
203 impl private::Sealed for $type {}
204 };
205 ($type:ident : $storage_type:ident, $bpp:expr, $mask:expr, $bpp_str:expr) => {
206 impl_raw_data!(
207 $type: $storage_type,
208 $bpp,
209 $mask,
210 $bpp_str,
211 concat!(
212 "`",
213 stringify!($type),
214 "` is internally stored in an `",
215 stringify!($storage_type),
216 "`. It can be constructed from an [`",
217 stringify!($storage_type),
218 "`] by using the ",
219 "[`new`](Self::new) method or by calling `",
220 stringify!($type),
221 "::from(",
222 stringify!($storage_type),
223 "_value)`. ",
224 "To convert a `",
225 stringify!($type),
226 "` back into a [`",
227 stringify!($storage_type),
228 "`] the [`into_inner`](Self::into_inner) method can be used."
229 )
230 );
231 };
232}
233
234impl_raw_data!(RawU1: u8, 1, 0x01, "1 bit");
235impl_raw_data!(RawU2: u8, 2, 0x03, "2 bits");
236impl_raw_data!(RawU4: u8, 4, 0x0F, "4 bits");
237impl_raw_data!(RawU8: u8, 8, 0xFF, "8 bits");
238impl_raw_data!(RawU16: u16, 16, 0xFFFF, "16 bits");
239impl_raw_data!(RawU24: u32, 24, 0xFF_FFFF, "24 bits");
240impl_raw_data!(RawU32: u32, 32, 0xFFFF_FFFF, "32 bits");
241
242/// Raw data byte order.
243pub trait ByteOrder: private::Sealed {}
244
245/// Little endian byte order marker.
246#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
247#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
248pub enum LittleEndian {}
249
250impl ByteOrder for LittleEndian {}
251impl private::Sealed for LittleEndian {}
252
253/// Big endian byte order marker.
254#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
255#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
256pub enum BigEndian {}
257
258impl ByteOrder for BigEndian {}
259impl private::Sealed for BigEndian {}
260
261mod private {
262 /// Sealed trait to prevent implementation of traits in other crates.
263 pub trait Sealed {}
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn upper_bits_are_masked() {
272 assert_eq!(RawU1::new(u8::max_value()).0, 0x1);
273 assert_eq!(RawU2::new(u8::max_value()).0, 0x3);
274 assert_eq!(RawU4::new(u8::max_value()).0, 0xF);
275 assert_eq!(RawU24::new(u32::max_value()).0, 0xFFFFFF);
276 }
277}
278