diff --git a/src/bytemuck_impl.rs b/src/bytemuck_impl.rs index d798b3b..ad44b6e 100644 --- a/src/bytemuck_impl.rs +++ b/src/bytemuck_impl.rs @@ -1,4 +1,4 @@ -use crate::{Abgr, Argb, Bgr, Bgra, GrayA, Gray_v09, Grb, Rgb, Rgba, Rgbw}; +use crate::{Abgr, Argb, Bgr, Bgra, GrayA, GrayAlpha44, Gray_v09, Grb, Rgb, Rgba, Rgbw}; macro_rules! bytemuck { ($name:ident) => { @@ -7,6 +7,13 @@ macro_rules! bytemuck { }; } +macro_rules! bytemuck_no_generic { + ($name:ident) => { + unsafe impl ::bytemuck::Zeroable for $name {} + unsafe impl ::bytemuck::Pod for $name {} + }; +} + bytemuck!(Rgb); bytemuck!(Bgr); bytemuck!(Grb); @@ -17,6 +24,7 @@ bytemuck!(Argb); bytemuck!(Bgra); bytemuck!(Abgr); bytemuck!(GrayA); +bytemuck_no_generic!(GrayAlpha44); use crate::formats::gray_alpha::GrayAlpha_v08; bytemuck!(GrayAlpha_v08); @@ -39,6 +47,21 @@ impl crate::ComponentBytes for [Gray_v08] { } } +#[cfg(feature = "as-bytes")] +impl crate::ComponentBytes for [Gray_v09] { + #[inline] + fn as_bytes(&self) -> &[u8] { + assert_ne!(0, core::mem::size_of::()); + ::bytemuck::cast_slice(self) + } + + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + assert_ne!(0, core::mem::size_of::()); + ::bytemuck::cast_slice_mut(self) + } +} + #[cfg(feature = "as-bytes")] impl crate::ComponentBytes for [GrayAlpha_v08] { #[inline] @@ -53,3 +76,24 @@ impl crate::ComponentBytes for [GrayAlpha_v08] { ::bytemuck::cast_slice_mut(self) } } + +#[cfg(feature = "as-bytes")] +impl crate::ComponentBytes for [GrayAlpha44] { + #[inline] + fn as_bytes(&self) -> &[u8] { + ::bytemuck::cast_slice(self) + } + + #[inline] + fn as_bytes_mut(&mut self) -> &mut [u8] { + ::bytemuck::cast_slice_mut(self) + } +} + +#[test] +fn test_component_bytes_capable() { + assert_eq!( + core::mem::size_of::(), + core::mem::size_of::() + ); +} diff --git a/src/formats/gray_alpha44.rs b/src/formats/gray_alpha44.rs new file mode 100644 index 0000000..172137b --- /dev/null +++ b/src/formats/gray_alpha44.rs @@ -0,0 +1,39 @@ +#[repr(C)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "defmt-03", derive(defmt::Format))] +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] +/// A pixel for grayscale value (4 bit) + alpha components (4 bit). in total 8 bit +pub struct GrayAlpha44(pub(crate) u8); + +impl GrayAlpha44 { + /// Convert 16 bit gray+alpha into 8 bit gray+alpha with precision loss + /// Example: + /// ``` + /// use rgb::GrayAlpha44; + /// let g = GrayAlpha44::new(120, 20); + /// assert_eq!(112, g.v()); // due to loss of precision you got 112 instead of initial 120 + /// assert_eq!(16, g.a()); // due to loss of precision you got 16 instead of initial 20 + /// ``` + #[inline] + pub fn new(v: u8, a: u8) -> Self { + Self((v & 0xf0) | (a >> 4)) + } + + #[inline] + pub fn v(self) -> u8 { + self.0 & 0xf0 + } + + #[inline] + pub fn a(self) -> u8 { + self.0 << 4 + } +} + +#[test] +fn zero() { + let g = GrayAlpha44::new(0, 0); + assert_eq!(0, g.v()); + assert_eq!(0, g.a()); + assert_eq!(0, g.0); +} diff --git a/src/lib.rs b/src/lib.rs index b67d1ff..5ea521e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![no_std] +#[cfg(test)] #[macro_use] extern crate std; @@ -15,6 +16,7 @@ mod formats { pub mod gray; pub mod gray_a; pub mod gray_alpha; + pub mod gray_alpha44; pub mod grb; pub mod rgb; pub mod rgba; @@ -68,6 +70,7 @@ pub use formats::gray::Gray_v08 as Gray; pub use formats::gray::Gray_v09; pub use formats::gray_a::GrayA; pub use formats::gray_alpha::GrayAlpha_v08 as GrayAlpha; +pub use formats::gray_alpha44::GrayAlpha44; pub use formats::grb::Grb; pub use formats::rgb::Rgb; pub use formats::rgba::Rgba; @@ -111,6 +114,8 @@ pub type BGR8 = formats::bgr::Bgr; pub type BGRA8 = formats::bgra::Bgra; /// [`Gray`] pub type GRAY8 = formats::gray::Gray_v09; +/// 4 bit for gray and 4 bit for alpha +pub type GRAYA4 = formats::gray_alpha44::GrayAlpha44; /// [`GrayA`] pub type GRAYA8 = formats::gray_a::GrayA; /// [`Grb`]