| 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 | |
| 114 | mod to_bytes; |
| 115 | |
| 116 | pub use to_bytes::ToBytes; |
| 117 | |
| 118 | /// Trait implemented by all `RawUx` types. |
| 119 | pub 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 |
| 147 | impl 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 | |
| 157 | impl private::Sealed for () {} |
| 158 | |
| 159 | macro_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 | |
| 234 | impl_raw_data!(RawU1: u8, 1, 0x01, "1 bit" ); |
| 235 | impl_raw_data!(RawU2: u8, 2, 0x03, "2 bits" ); |
| 236 | impl_raw_data!(RawU4: u8, 4, 0x0F, "4 bits" ); |
| 237 | impl_raw_data!(RawU8: u8, 8, 0xFF, "8 bits" ); |
| 238 | impl_raw_data!(RawU16: u16, 16, 0xFFFF, "16 bits" ); |
| 239 | impl_raw_data!(RawU24: u32, 24, 0xFF_FFFF, "24 bits" ); |
| 240 | impl_raw_data!(RawU32: u32, 32, 0xFFFF_FFFF, "32 bits" ); |
| 241 | |
| 242 | /// Raw data byte order. |
| 243 | pub 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))] |
| 248 | pub enum LittleEndian {} |
| 249 | |
| 250 | impl ByteOrder for LittleEndian {} |
| 251 | impl 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))] |
| 256 | pub enum BigEndian {} |
| 257 | |
| 258 | impl ByteOrder for BigEndian {} |
| 259 | impl private::Sealed for BigEndian {} |
| 260 | |
| 261 | mod private { |
| 262 | /// Sealed trait to prevent implementation of traits in other crates. |
| 263 | pub trait Sealed {} |
| 264 | } |
| 265 | |
| 266 | #[cfg (test)] |
| 267 | mod 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 | |