diff --git a/src/dither.rs b/src/dither.rs index a82832c..4e29e9f 100644 --- a/src/dither.rs +++ b/src/dither.rs @@ -5,14 +5,11 @@ //! compares two colors. Instead, a version of each algorithm should be compiled //! for each color space and difference combination. -use std::{ - marker::PhantomData, - ops::{Add, Mul, Sub}, -}; +use std::marker::PhantomData; use image::RgbaImage; use palette::{ - color_difference::{Ciede2000, EuclideanDistance, HyAb}, + color_difference::{Ciede2000, HyAb}, Clamp, IntoColor, Lab, Srgb, }; use rand::{rngs::SmallRng, Rng, SeedableRng}; @@ -39,9 +36,12 @@ impl> Difference for DiffClamp { pub struct DiffEuclid; -impl> Difference for DiffEuclid { +impl> Difference for DiffEuclid { fn diff(a: C, b: C) -> f32 { - a.distance(b) + let [a1, a2, a3] = a.as_ref(); + let [b1, b2, b3] = b.as_ref(); + let squared = (a1 - b1).powi(2) + (a2 - b2).powi(2) + (a3 - b3).powi(2); + squared.sqrt() } } @@ -167,11 +167,36 @@ where } } +fn add>(mut a: C, mut b: C) -> C { + let [a1, a2, a3] = a.as_mut(); + let [b1, b2, b3] = b.as_mut(); + *a1 += *b1; + *a2 += *b2; + *a3 += *b3; + a +} + +fn sub>(mut a: C, mut b: C) -> C { + let [a1, a2, a3] = a.as_mut(); + let [b1, b2, b3] = b.as_mut(); + *a1 -= *b1; + *a2 -= *b2; + *a3 -= *b3; + a +} + +fn mul>(mut a: C, b: f32) -> C { + let [a1, a2, a3] = a.as_mut(); + *a1 *= b; + *a2 *= b; + *a3 *= b; + a +} + fn diffuse_error(image: &mut RgbaImage, error: C, x: u32, y: u32, dx: i32, dy: i32, factor: f32) where - C: Add, + C: AsMut<[f32; 3]>, C: IntoColor, - C: Mul, Srgb: IntoColor, { if x == 0 && dx < 0 { @@ -184,7 +209,7 @@ where let y = (y as i32 + dy) as u32; let Some(pixel) = image.get_pixel_mut_checked(x, y) else{ return; }; let color: C = util::pixel_to_color(*pixel); - let color = color + error * factor; + let color = add(color, mul(error, factor)); util::update_pixel_with_color(pixel, color); } @@ -192,11 +217,9 @@ pub struct AlgoFloydSteinberg; impl Algorithm for AlgoFloydSteinberg where - C: Add, + C: AsMut<[f32; 3]>, C: Copy, C: IntoColor, - C: Mul, - C: Sub, D: Difference, Srgb: IntoColor, { @@ -206,7 +229,7 @@ where let pixel = image.get_pixel(x, y); let before: C = util::pixel_to_color(*pixel); let after = palette.nearest::(before); - let error = before - after; + let error = sub(before, after); util::update_pixel_with_color(image.get_pixel_mut(x, y), after); diffuse_error(&mut image, error, x, y, 1, 0, 7.0 / 16.0); @@ -224,11 +247,9 @@ pub struct AlgoStucki; impl Algorithm for AlgoStucki where - C: Add, + C: AsMut<[f32; 3]>, C: Copy, C: IntoColor, - C: Mul, - C: Sub, D: Difference, Srgb: IntoColor, { @@ -238,7 +259,7 @@ where let pixel = image.get_pixel(x, y); let before: C = util::pixel_to_color(*pixel); let after = palette.nearest::(before); - let error = before - after; + let error = sub(before, after); util::update_pixel_with_color(image.get_pixel_mut(x, y), after); diff --git a/src/main.rs b/src/main.rs index 1cd340a..0b43601 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,6 @@ use std::{ fmt, io::{Cursor, Read, Write}, num::ParseIntError, - ops::{Add, Mul, Sub}, path::PathBuf, str::FromStr, }; @@ -25,10 +24,10 @@ use mark::{ bw, dither::{ AlgoFloydSteinberg, AlgoRandom, AlgoStucki, AlgoThreshold, Algorithm, DiffCiede2000, - DiffClamp, DiffEuclid, DiffHyAb, DiffManhattan, DiffManhattanSquare, Difference, Palette, + DiffClamp, DiffEuclid, DiffHyAb, DiffManhattan, Difference, Palette, }, }; -use palette::{color_difference::EuclideanDistance, Clamp, IntoColor, Lab, LinSrgb, Oklab, Srgb}; +use palette::{Clamp, IntoColor, Lab, Lch, LinSrgb, Luv, Okhsl, Okhsv, Oklab, Srgb}; #[derive(Debug, Clone, Copy, clap::ValueEnum)] enum BwMethod { @@ -80,7 +79,11 @@ enum DitherColorSpace { Srgb, LinSrgb, Cielab, + Cieluv, + Cielch, Oklab, + Okhsl, + Okhsv, } #[derive(Debug, Clone, Copy, clap::ValueEnum)] @@ -153,22 +156,22 @@ impl DitherCmd { DitherColorSpace::Srgb => self.run_c::(image), DitherColorSpace::LinSrgb => self.run_c::(image), DitherColorSpace::Cielab => self.run_c::(image), + DitherColorSpace::Cieluv => self.run_c::(image), + DitherColorSpace::Cielch => self.run_c::(image), DitherColorSpace::Oklab => self.run_c::(image), + DitherColorSpace::Okhsl => self.run_c::(image), + DitherColorSpace::Okhsv => self.run_c::(image), } } fn run_c(self, image: RgbaImage) -> RgbaImage where - C: Add, C: AsMut<[f32; 3]>, C: AsRef<[f32; 3]>, C: Clamp, C: Copy, - C: EuclideanDistance, C: IntoColor, C: IntoColor, - C: Mul, - C: Sub, Srgb: IntoColor, { use DitherDifference::*; @@ -186,13 +189,10 @@ impl DitherCmd { fn run_cd(self, image: RgbaImage) -> RgbaImage where - C: Add, C: AsMut<[f32; 3]>, C: Clamp, C: Copy, C: IntoColor, - C: Mul, - C: Sub, D: Difference, Srgb: IntoColor, {