//! 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(), ), } } }