diff --git a/color-module/src/color_differ/cam16jch.rs b/color-module/src/color_differ/cam16jch.rs index cd6f583..3e86cd5 100644 --- a/color-module/src/color_differ/cam16jch.rs +++ b/color-module/src/color_differ/cam16jch.rs @@ -35,4 +35,38 @@ impl ColorDifference for Cam16Jch { }, } } + + fn difference_relative(&self, other: &Self) -> Self::Difference { + let hue = if self.hue.into_positive_degrees() == 0.0 { + 0.0 + } else { + (other.hue.into_positive_degrees() - self.hue.into_positive_degrees()) + / (1.0 - self.hue.into_positive_degrees()) + }; + let chroma = if self.chroma == 0.0 { + 0.0 + } else { + (other.chroma - self.chroma) / self.chroma + }; + let lightness = if self.lightness == 0.0 { + 0.0 + } else { + (other.lightness - self.lightness) / self.lightness + }; + + HctDiffference { + hue: Differ { + delta: other.hue.into_positive_degrees() - self.hue.into_positive_degrees(), + percent: hue, + }, + chroma: Differ { + delta: other.chroma - self.chroma, + percent: chroma, + }, + lightness: Differ { + delta: other.lightness - self.lightness, + percent: lightness, + }, + } + } } diff --git a/color-module/src/color_differ/hsl.rs b/color-module/src/color_differ/hsl.rs index d15571a..645fd8c 100644 --- a/color-module/src/color_differ/hsl.rs +++ b/color-module/src/color_differ/hsl.rs @@ -35,4 +35,38 @@ impl ColorDifference for Hsl { }, } } + + fn difference_relative(&self, other: &Self) -> Self::Difference { + let hue = if self.hue.into_positive_degrees() == 0.0 { + 0.0 + } else { + (other.hue.into_positive_degrees() - self.hue.into_positive_degrees()) + / (1.0 - self.hue.into_positive_degrees()) + }; + let saturation = if self.saturation == 0.0 { + 0.0 + } else { + (other.saturation - self.saturation) / (1.0 - self.saturation) + }; + let lightness = if self.lightness == 0.0 { + 0.0 + } else { + (other.lightness - self.lightness) / (1.0 - self.lightness) + }; + + HSLDifference { + hue: Differ { + delta: other.hue.into_positive_degrees() - self.hue.into_positive_degrees(), + percent: hue, + }, + saturation: Differ { + delta: other.saturation - self.saturation, + percent: saturation, + }, + lightness: Differ { + delta: other.lightness - self.lightness, + percent: lightness, + }, + } + } } diff --git a/color-module/src/color_differ/mod.rs b/color-module/src/color_differ/mod.rs index 0fe1083..b3c76ba 100644 --- a/color-module/src/color_differ/mod.rs +++ b/color-module/src/color_differ/mod.rs @@ -17,4 +17,5 @@ pub trait ColorDifference { type Difference; fn difference(&self, other: &Self) -> Self::Difference; + fn difference_relative(&self, other: &Self) -> Self::Difference; } diff --git a/color-module/src/color_differ/oklch.rs b/color-module/src/color_differ/oklch.rs index 3ed99c9..fedde47 100644 --- a/color-module/src/color_differ/oklch.rs +++ b/color-module/src/color_differ/oklch.rs @@ -35,4 +35,38 @@ impl ColorDifference for Oklch { }, } } + + fn difference_relative(&self, other: &Self) -> Self::Difference { + let hue = if self.hue.into_positive_degrees() == 0.0 { + 0.0 + } else { + (other.hue.into_positive_degrees() - self.hue.into_positive_degrees()) + / (1.0 - self.hue.into_positive_degrees()) + }; + let chroma = if self.chroma == 0.0 { + 0.0 + } else { + (other.chroma - self.chroma) / self.chroma + }; + let lightness = if self.l == 0.0 { + 0.0 + } else { + (other.l - self.l) / (1.0 - self.l) + }; + + OklchDifference { + hue: Differ { + delta: other.hue.into_positive_degrees() - self.hue.into_positive_degrees(), + percent: hue, + }, + chroma: Differ { + delta: other.chroma - self.chroma, + percent: chroma, + }, + lightness: Differ { + delta: other.l - self.l, + percent: lightness, + }, + } + } } diff --git a/color-module/src/color_differ/rgb.rs b/color-module/src/color_differ/rgb.rs index 813e47b..f959dd9 100644 --- a/color-module/src/color_differ/rgb.rs +++ b/color-module/src/color_differ/rgb.rs @@ -35,4 +35,37 @@ impl ColorDifference for Srgb { }, } } + + fn difference_relative(&self, other: &Self) -> Self::Difference { + let r = if self.red == 0.0 { + 0.0 + } else { + (other.red - self.red) / (1.0 - self.red) + }; + let g = if self.green == 0.0 { + 0.0 + } else { + (other.green - self.green) / (1.0 - self.green) + }; + let b = if self.blue == 0.0 { + 0.0 + } else { + (other.blue - self.blue) / (1.0 - self.blue) + }; + + RGBDifference { + r: Differ { + delta: other.red - self.red, + percent: r, + }, + g: Differ { + delta: other.green - self.green, + percent: g, + }, + b: Differ { + delta: other.blue - self.blue, + percent: b, + }, + } + } } diff --git a/color-module/src/lib.rs b/color-module/src/lib.rs index afbde93..af3938f 100644 --- a/color-module/src/lib.rs +++ b/color-module/src/lib.rs @@ -440,6 +440,20 @@ pub fn differ_in_rgb( Ok(srgb.difference(&other_srgb)) } +#[wasm_bindgen] +pub fn relative_differ_in_rgb( + color: &str, + other: &str, +) -> Result { + let srgb = Srgb::from_str(color) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? + .into_format::(); + let other_srgb = Srgb::from_str(other) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? + .into_format::(); + Ok(srgb.difference_relative(&other_srgb)) +} + #[wasm_bindgen] pub fn differ_in_hsl( color: &str, @@ -458,6 +472,24 @@ pub fn differ_in_hsl( Ok(hsl.difference(&other_hsl)) } +#[wasm_bindgen] +pub fn relative_differ_in_hsl( + color: &str, + other: &str, +) -> Result { + let hsl = Hsl::from_color( + Srgb::from_str(color) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? + .into_format::(), + ); + let other_hsl = Hsl::from_color( + Srgb::from_str(other) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? + .into_format::(), + ); + Ok(hsl.difference_relative(&other_hsl)) +} + #[wasm_bindgen] pub fn differ_in_hct( color: &str, @@ -480,6 +512,28 @@ pub fn differ_in_hct( Ok(hct.difference(&other_hct)) } +#[wasm_bindgen] +pub fn relative_differ_in_hct( + color: &str, + other: &str, +) -> Result { + let hct = Cam16Jch::from_xyz( + Srgb::from_str(color) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? + .into_format::() + .into_color(), + Parameters::default_static_wp(40.0), + ); + let other_hct = Cam16Jch::from_xyz( + Srgb::from_str(other) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? + .into_format::() + .into_color(), + Parameters::default_static_wp(40.0), + ); + Ok(hct.difference_relative(&other_hct)) +} + #[wasm_bindgen] pub fn differ_in_oklch( color: &str, @@ -498,6 +552,24 @@ pub fn differ_in_oklch( Ok(oklch.difference(&other_oklch)) } +#[wasm_bindgen] +pub fn relative_differ_in_oklch( + color: &str, + other: &str, +) -> Result { + let oklch = Oklch::from_color( + Srgb::from_str(color) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(color.to_string()))? + .into_format::(), + ); + let other_oklch = Oklch::from_color( + Srgb::from_str(other) + .map_err(|_| errors::ColorError::UnrecogniazedRGB(other.to_string()))? + .into_format::(), + ); + Ok(oklch.difference_relative(&other_oklch)) +} + #[wasm_bindgen] pub fn tint_scale( basic_color: &str,