use embedded_graphics_core::{
pixelcolor::{BinaryColor, Gray4, Rgb888},
prelude::{GrayColor, PixelColor, RgbColor},
};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)]
#[cfg_attr(feature = "defmt", derive(::defmt::Format))]
pub struct Gray5(u8);
impl Gray5 {
pub const fn new(luma: u8) -> Gray5 {
Gray5(luma & 0b11111)
}
}
impl PixelColor for Gray5 {
type Raw = (); }
impl GrayColor for Gray5 {
fn luma(&self) -> u8 {
self.0
}
const BLACK: Self = Self::new(0);
const WHITE: Self = Self::new(0b11111);
}
impl From<u8> for Gray5 {
fn from(other: u8) -> Self {
Self::new(other)
}
}
impl From<Gray5> for u8 {
fn from(other: Gray5) -> Self {
other.0
}
}
impl From<Rgb888> for Gray5 {
fn from(other: Rgb888) -> Self {
let luma = (other.r() as u16 * 77 + other.g() as u16 * 150 + other.b() as u16 * 29) / 256;
Self::new((luma >> 3) as u8)
}
}
impl From<BinaryColor> for Gray5 {
fn from(other: BinaryColor) -> Self {
match other {
BinaryColor::Off => Self::BLACK,
BinaryColor::On => Self::WHITE,
}
}
}
impl From<Gray4> for Gray5 {
fn from(other: Gray4) -> Self {
Self::new(convert_channel::<0b1111, 0b11111>(other.luma()))
}
}
const fn convert_channel<const FROM_MAX: u8, const TO_MAX: u8>(value: u8) -> u8 {
if TO_MAX != FROM_MAX {
const SHIFT: usize = 24;
const CONST_0_5: u32 = 1 << (SHIFT - 1);
let result = value as u32 * (((TO_MAX as u32) << SHIFT) / FROM_MAX as u32);
((result + CONST_0_5) >> SHIFT) as u8
} else {
value
}
}