polygon-art/src/context/palette.rs

117 lines
4.3 KiB
Rust

//! Color palate generator.
use crate::RandomExt;
use palette::rgb::Rgb;
use palette::FromColor;
use palette::Hsl;
use palette::Hsv;
use palette::IntoColor;
use rand::prelude::*;
/// The palette that is used
/// to generate the image.
pub struct Palette {
pub background_color: Rgb,
pub fill_color: Rgb,
}
impl Palette {
/// generate a random color that is not to dark
/// and to color less.
#[allow(dead_code)]
pub fn random_color(mut rng: StdRng) -> Rgb {
let hue: f32 = rng.gen_interval(0., 360.);
let saturation: f32 = rng.gen_interval(0.9, 1.0);
let value: f32 = rng.gen_interval(0.8, 1.0);
Palette::color(hue, saturation, value)
}
pub fn color(hue: f32, saturation: f32, value: f32) -> Rgb {
Rgb::from_linear(Hsv::new(hue, saturation, value).into_rgb())
}
/// generate a palette from the tint and shade palette
/// algorithm. choose a dark background, and a bright filling color
pub fn bright_on_dark(input: Rgb) -> Palette {
let tint_and_shade_palette = TintAndShadePalette::create(input);
Palette {
background_color: tint_and_shade_palette.base_shade_30,
fill_color: tint_and_shade_palette.inverse_saturation_tint_30,
}
}
/// generate a palette from the tint and shade palette
/// algorithm. choose a bright background, and a dark filling color
pub fn dark_on_bright(input: Rgb) -> Palette {
let tint_and_shade_palette = TintAndShadePalette::create(input);
Palette {
background_color: tint_and_shade_palette.base_tint_30,
fill_color: tint_and_shade_palette.inverse_saturation_shade_30,
}
}
}
/// The Tint and Shade Palette from https://gitlab.com/cameralibre/tint-and-shade
/// Thank you, Sam
struct TintAndShadePalette {
base_color: Rgb,
base_tint_30: Rgb,
base_tint_15: Rgb,
base_shade_15: Rgb,
base_shade_30: Rgb,
complement_tint_30: Rgb,
complement_tint_15: Rgb,
complement_color: Rgb,
complement_shade_15: Rgb,
complement_shade_30: Rgb,
inverse_saturation_tint_30: Rgb,
inverse_saturation_tint_15: Rgb,
inverse_saturation_color: Rgb,
inverse_saturation_shade_15: Rgb,
inverse_saturation_shade_30: Rgb,
}
impl TintAndShadePalette {
/// create a Palette based on one input color
pub fn create(input: Rgb) -> TintAndShadePalette {
let hsl: Hsl = Hsl::from_rgb(input.into_linear());
let h = hsl.hue;
let s = hsl.saturation;
let l = hsl.lightness;
let complement = h + 180.0 % 360.0;
let tint_15 = l + 0.15;
let tint_30 = l + 0.30;
let shade_15 = l - 0.15;
let shade_30 = l - 0.30;
let inverse_saturation = 1.0 - s;
TintAndShadePalette {
base_color: Rgb::from_linear(Hsl::new(h, s, l).into_rgb()),
base_tint_15: Rgb::from_linear(Hsl::new(h, s, tint_15).into_rgb()),
base_tint_30: Rgb::from_linear(Hsl::new(h, s, tint_30).into_rgb()),
base_shade_15: Rgb::from_linear(Hsl::new(h, s, shade_15).into_rgb()),
base_shade_30: Rgb::from_linear(Hsl::new(h, s, shade_30).into_rgb()),
complement_color: Rgb::from_linear(Hsl::new(complement, s, l).into_rgb()),
complement_tint_15: Rgb::from_linear(Hsl::new(complement, s, tint_15).into_rgb()),
complement_tint_30: Rgb::from_linear(Hsl::new(complement, s, tint_30).into_rgb()),
complement_shade_15: Rgb::from_linear(Hsl::new(complement, s, shade_15).into_rgb()),
complement_shade_30: Rgb::from_linear(Hsl::new(complement, s, shade_30).into_rgb()),
inverse_saturation_color: Rgb::from_linear(
Hsl::new(complement, inverse_saturation, l).into_rgb(),
),
inverse_saturation_tint_15: Rgb::from_linear(
Hsl::new(complement, inverse_saturation, tint_15).into_rgb(),
),
inverse_saturation_tint_30: Rgb::from_linear(
Hsl::new(complement, inverse_saturation, tint_30).into_rgb(),
),
inverse_saturation_shade_15: Rgb::from_linear(
Hsl::new(complement, inverse_saturation, shade_15).into_rgb(),
),
inverse_saturation_shade_30: Rgb::from_linear(
Hsl::new(complement, inverse_saturation, shade_30).into_rgb(),
),
}
}
}