From 6d8e60240841333b49b2080190df1dbc698bfc95 Mon Sep 17 00:00:00 2001 From: Erik Hedvall Date: Sun, 11 Jul 2021 18:52:05 +0200 Subject: [PATCH 1/3] Remove ColorDifference from Oklab and Oklch --- palette/src/oklab.rs | 35 +++------------------------------ palette/src/oklch.rs | 47 -------------------------------------------- 2 files changed, 3 insertions(+), 79 deletions(-) diff --git a/palette/src/oklab.rs b/palette/src/oklab.rs index 7d6f261ff..dc240f8a7 100644 --- a/palette/src/oklab.rs +++ b/palette/src/oklab.rs @@ -8,8 +8,6 @@ use rand::distributions::{Distribution, Standard}; #[cfg(feature = "random")] use rand::Rng; -use crate::color_difference::ColorDifference; -use crate::color_difference::{get_ciede_difference, LabColorDiff}; use crate::convert::FromColorUnclamped; use crate::encoding::pixel::RawPixel; use crate::matrix::multiply_xyz; @@ -61,9 +59,9 @@ pub type Oklaba = Alpha, T>; /// The [Oklab color space](https://bottosson.github.io/posts/oklab/). /// -/// Oklab is a perceptually-uniform color space similar in structure to [L\*a\*b\*](crate::Lab), but -/// with better perceptual uniformity. It assumes a D65 whitepoint and normal well-lit viewing -/// conditions. +/// Oklab is a perceptually-uniform color space similar in structure to +/// [L\*a\*b\*](crate::Lab), but tries to have a better perceptual uniformity. +/// It assumes a D65 whitepoint and normal well-lit viewing conditions. #[derive(Debug, PartialEq, Pixel, FromColorUnclamped, WithAlpha)] #[cfg_attr(feature = "serializing", derive(Serialize, Deserialize))] #[palette( @@ -370,33 +368,6 @@ where } } -impl ColorDifference for Oklab -where - T: FloatComponent, -{ - type Scalar = T; - - fn get_color_difference(&self, other: &Self) -> Self::Scalar { - // Color difference calculation requires Lab and chroma components. This - // function handles the conversion into those components which are then - // passed to `get_ciede_difference()` where calculation is completed. - let self_params = LabColorDiff { - l: self.l, - a: self.a, - b: self.b, - chroma: (self.a * self.a + self.b * self.b).sqrt(), - }; - let other_params = LabColorDiff { - l: other.l, - a: other.a, - b: other.b, - chroma: (other.a * other.a + other.b * other.b).sqrt(), - }; - - get_ciede_difference(&self_params, &other_params) - } -} - impl ComponentWise for Oklab where T: FloatComponent, diff --git a/palette/src/oklch.rs b/palette/src/oklch.rs index 8e2f3a091..6676789ad 100644 --- a/palette/src/oklch.rs +++ b/palette/src/oklch.rs @@ -8,7 +8,6 @@ use rand::distributions::{Distribution, Standard}; #[cfg(feature = "random")] use rand::Rng; -use crate::color_difference::{get_ciede_difference, ColorDifference, LabColorDiff}; use crate::convert::{FromColorUnclamped, IntoColorUnclamped}; use crate::encoding::pixel::RawPixel; use crate::white_point::D65; @@ -355,52 +354,6 @@ where } } -/// CIEDE2000 distance metric for color difference. -impl ColorDifference for Oklch -where - T: FloatComponent, -{ - type Scalar = T; - - fn get_color_difference(&self, other: &Oklch) -> Self::Scalar { - // Prepare a* and b* from Oklch components to calculate color difference - let self_a = clamp( - self.chroma.max(T::zero()) * self.hue.to_radians().cos(), - from_f64(0.0), - from_f64(1.0), - ); - let self_b = clamp( - self.chroma.max(T::zero()) * self.hue.to_radians().sin(), - from_f64(0.0), - from_f64(1.0), - ); - let other_a = clamp( - other.chroma.max(T::zero()) * other.hue.to_radians().cos(), - from_f64(0.0), - from_f64(1.0), - ); - let other_b = clamp( - other.chroma.max(T::zero()) * other.hue.to_radians().sin(), - from_f64(0.0), - from_f64(1.0), - ); - let self_params = LabColorDiff { - l: self.l, - a: self_a, - b: self_b, - chroma: self.chroma, - }; - let other_params = LabColorDiff { - l: other.l, - a: other_a, - b: other_b, - chroma: other.chroma, - }; - - get_ciede_difference(&self_params, &other_params) - } -} - impl Saturate for Oklch where T: FloatComponent, From 99d20ac3a073bd9997f5ac6ffcecb2f6b44201f9 Mon Sep 17 00:00:00 2001 From: Erik Hedvall Date: Mon, 12 Jul 2021 14:43:53 +0200 Subject: [PATCH 2/3] Separate documentation of named gradients into two pargraphs. --- palette/build/named.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/palette/build/named.rs b/palette/build/named.rs index 193dfb425..bd9ff671c 100644 --- a/palette/build/named.rs +++ b/palette/build/named.rs @@ -76,6 +76,7 @@ pub fn build_gradients(writer: &mut File) { .parse() .unwrap_or_else(|_| panic!("couldn't parse the number of colors for color {}", name)); writeln!(writer, "/// New matplotlib colormap by Nathaniel J. Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.").unwrap(); + writeln!(writer, "///").unwrap(); writeln!(writer, "/// This gradient is perfectly perceptually-uniform, both in regular form and also when converted to black-and-white.").unwrap(); writeln!( writer, From b2d5d667a685731d408cae5cfec7caffa9ab5de5 Mon Sep 17 00:00:00 2001 From: Erik Hedvall Date: Mon, 12 Jul 2021 15:10:26 +0200 Subject: [PATCH 3/3] Add a randomization example --- palette/examples/random.rs | 116 +++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 palette/examples/random.rs diff --git a/palette/examples/random.rs b/palette/examples/random.rs new file mode 100644 index 000000000..aeb4a4962 --- /dev/null +++ b/palette/examples/random.rs @@ -0,0 +1,116 @@ +#[cfg(not(feature = "random"))] +fn main() { + println!("You can't use the `rand` integration without the \"random\" feature"); +} + +#[cfg(feature = "random")] +fn main() { + use palette::{FromColor, Hsl, Hsv, Hwb, Pixel, RgbHue, Srgb}; + + use image::{GenericImage, GenericImageView, RgbImage}; + use rand::Rng; + + let mut image = RgbImage::new(512, 256); + let mut rng = rand_mt::Mt::default(); + + // RGB + { + let mut sub_image = image.sub_image(0, 0, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = Srgb::::new(rng.gen(), rng.gen(), rng.gen()); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + { + let mut sub_image = image.sub_image(0, 128, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = rng.gen::(); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + // HSV + { + let mut sub_image = image.sub_image(128, 0, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = + Srgb::from_color(Hsv::new(rng.gen::(), rng.gen(), rng.gen())); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + { + let mut sub_image = image.sub_image(128, 128, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = Srgb::from_color(rng.gen::()); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + // HSL + { + let mut sub_image = image.sub_image(256, 0, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = + Srgb::from_color(Hsl::new(rng.gen::(), rng.gen(), rng.gen())); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + { + let mut sub_image = image.sub_image(256, 128, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = Srgb::from_color(rng.gen::()); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + // HWB + { + let mut sub_image = image.sub_image(384, 0, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = + Srgb::from_color(Hwb::new(rng.gen::(), rng.gen(), rng.gen())); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + { + let mut sub_image = image.sub_image(384, 128, 128, 128); + let (width, height) = sub_image.dimensions(); + for x in 0..width { + for y in 0..height { + let random_color = Srgb::from_color(rng.gen::()); + sub_image.put_pixel(x, y, image::Rgb(random_color.into_format().into_raw())); + } + } + } + + let _ = std::fs::create_dir("example-data/output"); + match image.save("example-data/output/random.png") { + Ok(()) => println!("see 'example-data/output/random.png' for the result"), + Err(e) => println!("failed to write 'example-data/output/random.png': {}", e), + } +}