use crate::format::ser::{Ser, Sink, Source}; #[derive(Copy, Clone, Debug, Default)] pub struct Pixel { pub r: u8, pub g: u8, pub b: u8, } impl Ser for Pixel { fn write(&self, sink: &mut impl std::io::Write) -> anyhow::Result<()> { sink.put((self.r, self.g, self.b)) } fn read(source: &mut impl std::io::Read) -> anyhow::Result { let (r, g, b) = source.get()?; Ok(Self { r, g, b }) } } impl Pixel { pub const BLACK: Pixel = Pixel { r: 0, g: 0, b: 0 }; #[inline] pub fn distance(a: Pixel, b: Pixel) -> usize { let (rd, gd, bd) = ( a.r.abs_diff(b.r) as usize, a.r.abs_diff(b.r) as usize, a.r.abs_diff(b.r) as usize, ); // fast_sqrt(rd * rd + gd * gd + bd * bd) SQRT[rd + gd + bd] } #[inline] pub fn average(a: Pixel, b: Pixel) -> Pixel { Pixel { r: ((a.r as u16 + b.r as u16) >> 1) as u8, g: ((a.g as u16 + b.g as u16) >> 1) as u8, b: ((a.b as u16 + b.b as u16) >> 1) as u8, } } #[inline] pub fn scale(&self, factor: f32) -> Pixel { Pixel { r: ((self.r as f32) * factor).clamp(0.0, 255.0) as u8, g: ((self.g as f32) * factor).clamp(0.0, 255.0) as u8, b: ((self.b as f32) * factor).clamp(0.0, 255.0) as u8, } } } pub const SQRT: [usize; 256 * 3] = gen_sqrt_lookup(); const fn gen_sqrt_lookup() -> [usize; N] { let mut arr = [0; N]; let mut i = 0; while i < N { arr[i] = sqrt(i as f32) as usize; i += 1; } arr } const fn sqrt(x: f32) -> f32 { let a = 1.0; let a = (a + x / a) * 0.5; let a = (a + x / a) * 0.5; let a = (a + x / a) * 0.5; a } pub fn fast_sqrt(x: usize) -> usize { let a = 1; let a = (a + x / (a + 1)) / 2; let a = (a + x / (a + 1)) / 2; // let a = (a + x / (a + 1)) / 2; // let a = (a + x / (a + 1)) / 2; a }