1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
extern crate image; use image::{ImageBuffer, Rgb}; pub struct Image { path: String, image: ImageBuffer<Rgb<u8>, Vec<u8>>, } impl Image { pub fn from_path(path: String) -> Result<Image, image::ImageError> { let image = image::open(path.clone())?.into_rgb(); Ok(Image { path, image }) } pub fn subtract(&self, sub_image: &Image) -> Result<Image, &str> { if self.image.dimensions() != sub_image.image.dimensions() { return Err("Image dimensions do not match!"); } let mut warn_about_channels = false; let mut output = Image { image: self.image.clone(), path: self.path.clone(), }; for (x, y, pixel) in output.image.enumerate_pixels_mut() { if pixel[0] != pixel[1] && pixel[1] != pixel[2] { warn_about_channels = true; } let subt_pixel = sub_image.image.get_pixel(x, y); let r = pixel[0] as f64 - subt_pixel[0] as f64; let g = pixel[1] as f64 - subt_pixel[1] as f64; let b = pixel[2] as f64 - subt_pixel[2] as f64; let luminance = 0.30 * r + 0.59 * g + 0.11 * b; if luminance >= 0.0 { *pixel = Rgb([0, 0, luminance as u8]); } else { let luminance = (-luminance) as u8; *pixel = Rgb([luminance, 0, 0]); } } if warn_about_channels { eprintln!("WARNING: Image has pixel values that are not the same across RGB color channels!\n{}", self.path); } Ok(output) } pub fn set_path(&mut self, path: String) { self.path = path; } pub fn save(&self) -> image::ImageResult<()> { self.image.save(self.path.clone()) } }