diff options
Diffstat (limited to 'src/difference.rs')
-rw-r--r-- | src/difference.rs | 54 |
1 files changed, 40 insertions, 14 deletions
diff --git a/src/difference.rs b/src/difference.rs index 42c4c4f..b52b34f 100644 --- a/src/difference.rs +++ b/src/difference.rs @@ -1,30 +1,56 @@ -//! A set of difference functions you can use with [SquasherBuilder::difference] +//! A set of difference functions you can use with [SquasherBuilder::difference()] +//! +//! # Writing your own difference function +//! The type you want is `dyn Fn(&RGB8, &RGB8) -> f32` +//! (defined as [`DiffFn`]) +//! +//! The first argument is the color already in the palette and the second is +//! the color we're checking. These are [RGB8] which is a rexport from the `rgb` +//! crate. +//! +//! The value returned is between 0 and 768, but that's not a hard-rule. If you +//! return a value out of that range you'll have to adjust the tolerance with +//! [Squasher::set_tolerance()] or [SquasherBuilder::tolerance]. +//! +//! The difference functions have the possibility of being called hundreds of +//! thousands of times; you might want to `#[inline(always)]` + +// This is used in the module level documentation just above. Without it we'd +// have to fully qualify the interlink which is also how it'd be displayed. +#[allow(unused_imports)] +use crate::{Squasher, SquasherBuilder}; // rexport this so people don't need to add the rgb crate to their project. this // also helps avoid crate version mismatch +/// rexport from the [`rgb`](https://docs.rs/rgb/0.8.37/rgb/) crate. pub use rgb::RGB8; +/// Type definition for difference functions. +pub type DiffFn = dyn Fn(&RGB8, &RGB8) -> f32; + /// A naïve comparison just summing the channel differences /// I.E. `|a.red - b.red| + |a.green - b.green| + |a.blue - b.blue|` #[allow(clippy::many_single_char_names)] #[inline(always)] -pub fn rgb_difference(a: &RGB8, b: &RGB8) -> f32 { - let absdiff = |a: u8, b: u8| (a as f32 - b as f32).abs(); - absdiff(a.r, b.r) + absdiff(a.g, b.g) + absdiff(a.b, b.b) +pub fn rgb(a: &RGB8, b: &RGB8) -> f32 { + let absdiff = |a: u8, b: u8| (a as f32 - b as f32).abs(); + absdiff(a.r, b.r) + absdiff(a.g, b.g) + absdiff(a.b, b.b) } // https://en.wikipedia.org/wiki/Color_difference#sRGB +/// a slightly more intelligent algorithm that weighs the channels in an attempt +/// to better align with human color perception. #[inline(always)] -pub fn redmean_difference(a: &RGB8, b: &RGB8) -> f32 { - let delta_r = a.r as f32 - b.r as f32; - let delta_g = a.g as f32 - b.g as f32; - let delta_b = a.b as f32 - b.b as f32; - // reasonably sure calling it prime is wrong, but - let r_prime = 0.5 * (a.r as f32 + b.r as f32); +pub fn redmean(a: &RGB8, b: &RGB8) -> f32 { + let delta_r = a.r as f32 - b.r as f32; + let delta_g = a.g as f32 - b.g as f32; + let delta_b = a.b as f32 - b.b as f32; + // reasonably sure calling it prime is wrong, but + let r_prime = 0.5 * (a.r as f32 + b.r as f32); - let red_part = (2.0 + (r_prime / 256.0)) * (delta_r * delta_r); - let green_part = 4.0 * (delta_g * delta_g); - let blue_part = (2.0 + (255.0 - r_prime) / 256.0) * (delta_b * delta_b); + let red_part = (2.0 + (r_prime / 256.0)) * (delta_r * delta_r); + let green_part = 4.0 * (delta_g * delta_g); + let blue_part = (2.0 + (255.0 - r_prime) / 256.0) * (delta_b * delta_b); - (red_part + green_part + blue_part).sqrt() + (red_part + green_part + blue_part).sqrt() } |