From f7e216bb25b7df352c314e37ff30a951ac73baa2 Mon Sep 17 00:00:00 2001 From: nworbnhoj Date: Sat, 18 Jun 2022 07:07:08 +1000 Subject: [PATCH] convert RGB image immediately to greyscale on import code simplification/reduction, and memory/processing saving --- services/gam/src/bitmap.rs | 61 +++++++++++--------------------------- services/gam/src/lib.rs | 2 +- services/modals/src/lib.rs | 4 +-- 3 files changed, 21 insertions(+), 46 deletions(-) diff --git a/services/gam/src/bitmap.rs b/services/gam/src/bitmap.rs index 960989744..f57dec177 100644 --- a/services/gam/src/bitmap.rs +++ b/services/gam/src/bitmap.rs @@ -291,50 +291,37 @@ impl From<&Img> for Bitmap { } /* - * Image as a minimal flat buffer of RGB pixels; accessible by (x, y) + * Image as a minimal flat buffer of grey u8 pixels; accessible by (x, y) * * author: nworbnhoj */ - - #[derive(Debug, Clone, Copy)] -pub struct RGB(pub u8, pub u8, pub u8); - -impl RGB { - const R: u32 = 2126; - const G: u32 = 7152; - const B: u32 = 722; - const BLACK: u32 = RGB::R + RGB::G + RGB::B; - /// chromatic conversion from RGB to grey - pub fn to_grey(&self) -> u8 { - let grey_r = RGB::R * self.0 as u32; - let grey_g = RGB::G * self.1 as u32; - let grey_b = RGB::B * self.2 as u32; - ((grey_r + grey_g + grey_b) / RGB::BLACK).try_into().unwrap() - } -} - #[derive(Debug, Clone)] pub struct Img { - pixels: Vec, + pixels: Vec, width: usize, } impl Img { pub fn new(buf: Vec, width: usize) -> Self { + const R: u32 = 2126; + const G: u32 = 7152; + const B: u32 = 722; + const BLACK: u32 = R + G + B; let px_len = buf.len() / 3; - let mut pixels: Vec = Vec::with_capacity(px_len); + let mut pixels: Vec = Vec::with_capacity(px_len); for px in 0..px_len { let b = px * 3; - pixels.push(RGB { - 0: buf[b], - 1: buf[b + 1], - 2: buf[b + 2], - }); + let grey_r = R * buf[b] as u32; + let grey_g = G * buf[b + 1] as u32; + let grey_b = B * buf[b + 2] as u32; + pixels.push(((grey_r + grey_g + grey_b) / BLACK) + .try_into() + .unwrap()); } Self { pixels, width } } - pub fn get(&self, x: usize, y: usize) -> Option<&RGB> { + pub fn get(&self, x: usize, y: usize) -> Option<&u8> { let i: usize = (y * self.width) + x; self.pixels.get(i) } @@ -344,33 +331,24 @@ impl Img { let height: usize = length / width; (width, height, length) } - pub fn into_raw(&self) -> Vec { - let len = self.pixels.len() as usize; - let mut bytes: Vec = Vec::with_capacity(len); - for px in &self.pixels { - bytes.push(px.0); - bytes.push(px.1); - bytes.push(px.2); - } - bytes + pub fn as_slice(&self) -> &[u8] { + self.pixels.as_slice() } } - /* * Dithering involves aplying a threshold to each pixel to round down to Black * or up to White. The residual error from this blunt instrument is diffused amongst * the surrounding pixels. So the luminosity lost by forcing a pixel down to Black, * results in the surrounding pixels incrementally more likely to round up to White. * Pixels are processed from left to right and then top to bottom. The residual - * error from each Black/White determination is carried-forward to pixels to the + * error from each Black/White determination is carried-forward to pixels to the * right and below as per the diffusion scheme. * https://tannerhelland.com/2012/12/28/dithering-eleven-algorithms-source-code.html * * author: nworbnhoj */ - /// Burkes dithering diffusion scheme was chosen for its modest resource /// requirements with impressive quality outcome. /// Burkes dithering. Div=32. @@ -388,7 +366,6 @@ const BURKES: [(isize, isize, i16); 7] = [ (2, 1, 2), ]; - struct Dither { // the width of the image to be dithered width: usize, @@ -463,7 +440,7 @@ impl Dither { for y in 0..height { for x in 0..width { let pixel = match image.get(x, y) { - Some(rgb) => self.pixel(rgb.to_grey()), + Some(grey) => self.pixel(*grey), None => PixelColor::Dark, }; pixels.push(pixel); @@ -474,8 +451,6 @@ impl Dither { } } - - #[cfg(test)] mod tests { use super::*; diff --git a/services/gam/src/lib.rs b/services/gam/src/lib.rs index 42a3f80d6..2ca97ab0b 100644 --- a/services/gam/src/lib.rs +++ b/services/gam/src/lib.rs @@ -13,7 +13,7 @@ pub use apps::*; #[cfg(feature="ditherpunk")] pub mod bitmap; #[cfg(feature="ditherpunk")] -pub use bitmap::{Bitmap, Img, RGB}; +pub use bitmap::{Bitmap, Img}; use graphics_server::api::{TextOp, TextView}; use graphics_server::api::{Gid, Line, Circle, RoundedRectangle, TokenClaim}; diff --git a/services/modals/src/lib.rs b/services/modals/src/lib.rs index cb0edf1bd..06bd68fbd 100644 --- a/services/modals/src/lib.rs +++ b/services/modals/src/lib.rs @@ -262,8 +262,8 @@ impl Modals { let fir_img = fast_image_resize::Image::from_vec_u8( NonZeroU32::new(width).unwrap(), NonZeroU32::new(height).unwrap(), - img.into_raw(), - fast_image_resize::PixelType::U8x3, + img.as_slice().to_vec(), + fast_image_resize::PixelType::U8, ) .unwrap();