feat(palette): add palette expansion via color interpolation
Add `Color::euclidian_distance` and `Rgb::lerp`, then use them in a new `Palette<T>` type whose `expand` method adds colors between close pairs. Split `palette.rs` into a module, with `NORD_PALETTE` in its own file.
This commit is contained in:
+56
-3
@@ -1,7 +1,14 @@
|
||||
use std::sync::LazyLock;
|
||||
use wide::f64x4;
|
||||
|
||||
pub trait Color {}
|
||||
pub trait Color {
|
||||
/// Computes the Euclidean distance between `self` and `other`.
|
||||
///
|
||||
/// This method finds the difference of each component, squares each
|
||||
/// difference, sums the squares, then takes the square root of the
|
||||
/// sum.
|
||||
fn euclidian_distance(&self, other: &Self) -> f64;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Rgb {
|
||||
@@ -10,7 +17,36 @@ pub struct Rgb {
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Color for Rgb {}
|
||||
impl Color for Rgb {
|
||||
fn euclidian_distance(&self, other: &Self) -> f64 {
|
||||
let diff_r = (self.r as f64) - (other.r as f64);
|
||||
let diff_g = (self.g as f64) - (other.g as f64);
|
||||
let diff_b = (self.b as f64) - (other.b as f64);
|
||||
(diff_r * diff_r + diff_g * diff_g + diff_b * diff_b).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
impl Rgb {
|
||||
/// Blends `self` and `other` by `alpha`.
|
||||
///
|
||||
/// This method finds a color between `self` and `other`. An `alpha`
|
||||
/// of `0.0` returns `self`. An `alpha` of `1.0` returns `other`. A
|
||||
/// value between `0.0` and `1.0` mixes the two colors in that
|
||||
/// proportion.
|
||||
///
|
||||
/// The name `lerp` is short for "linear interpolation," a common term
|
||||
/// in graphics code.
|
||||
pub fn lerp(&self, other: &Rgb, alpha: f64) -> Rgb {
|
||||
let r = (1.0 - alpha) * self.r as f64 + alpha * other.r as f64;
|
||||
let g = (1.0 - alpha) * self.g as f64 + alpha * other.g as f64;
|
||||
let b = (1.0 - alpha) * self.b as f64 + alpha * other.b as f64;
|
||||
Rgb {
|
||||
r: r as u8,
|
||||
g: g as u8,
|
||||
b: b as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Lab {
|
||||
@@ -19,7 +55,14 @@ pub struct Lab {
|
||||
pub b: f64,
|
||||
}
|
||||
|
||||
impl Color for Lab {}
|
||||
impl Color for Lab {
|
||||
fn euclidian_distance(&self, other: &Self) -> f64 {
|
||||
let diff_l = self.l - other.l;
|
||||
let diff_a = self.a - other.a;
|
||||
let diff_b = self.b - other.b;
|
||||
(diff_l * diff_l + diff_a * diff_a + diff_b * diff_b).sqrt()
|
||||
}
|
||||
}
|
||||
|
||||
/// Constants for the sRGB transfer function. `srgb_to_linear` uses these
|
||||
/// to convert a normalized (`0.0..=1.0`) sRGB channel value to linear-light
|
||||
@@ -264,6 +307,16 @@ impl RgbPlanar {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[Rgb]> for RgbPlanar {
|
||||
fn from(value: &[Rgb]) -> Self {
|
||||
// let collected: Vec<(u8, u8, u8)> = value.iter().map(|rgb| (rgb.r, rgb.g, rgb.b)).collect();
|
||||
let r: Vec<f64> = value.iter().map(|rgb| rgb.r as f64).collect();
|
||||
let g: Vec<f64> = value.iter().map(|rgb| rgb.g as f64).collect();
|
||||
let b: Vec<f64> = value.iter().map(|rgb| rgb.b as f64).collect();
|
||||
Self { r, g, b }
|
||||
}
|
||||
}
|
||||
|
||||
impl PlanarColor<Rgb> for RgbPlanar {
|
||||
fn len(&self) -> usize {
|
||||
self.r.len()
|
||||
|
||||
Reference in New Issue
Block a user