color_gradient/helpers/sampler/
mod.rs1use color_core::{HSVA32, RGBA32};
2use image::{GenericImageView, ImageResult, Rgba32FImage};
3use std::{collections::BTreeMap, error::Error, io::Write, path::Path};
4
5#[derive(Debug)]
7pub struct GradientSampler {
8 pub points: usize,
10 pub margin_left: u32,
12 pub margin_right: u32,
14 pub margin_top: u32,
16 pub margin_bottom: u32,
18 pub maps: Vec<(String, BTreeMap<u32, RGBA32>)>,
20}
21
22impl GradientSampler {
23 pub fn new(points: usize) -> Self {
37 Self { points, margin_left: 0, margin_right: 0, margin_top: 0, margin_bottom: 0, maps: vec![] }
38 }
39 pub fn with_margin(mut self, margin: u32) -> Self {
53 self.margin_left = margin;
54 self.margin_right = margin;
55 self.margin_top = margin;
56 self.margin_bottom = margin;
57 self
58 }
59 pub fn sample(&self, image: &Rgba32FImage) -> BTreeMap<u32, RGBA32> {
73 let width = image.width() - self.margin_left - self.margin_right;
74 let height = image.height() - self.margin_top - self.margin_bottom;
75 let view = image.view(self.margin_left, self.margin_top, width, height);
76 let mut output = BTreeMap::new();
77 let step = width as usize / self.points;
78 for i in (0..=width).step_by(step) {
79 let color = view.get_pixel(i.saturating_sub(1), 0);
80 output.insert(i, RGBA32::new(color.0[0], color.0[1], color.0[2], color.0[3]));
81 }
82 output
85 }
86 pub fn sample_file<P>(&mut self, path: P, name: &str) -> Result<(), Box<dyn Error>>
100 where
101 P: AsRef<Path>,
102 {
103 let image_path = path.as_ref();
104 let image = image::open(image_path)?.to_rgba32f();
105 let map = self.sample(&image);
106 self.maps.push((name.to_string(), map));
107 Ok(())
108 }
109 pub fn export_hsv<P>(&self, path: P) -> ImageResult<()>
123 where
124 P: AsRef<Path>,
125 {
126 let mut file = std::fs::File::create(path)?;
127 writeln!(file, "impl HsvGradient {{")?;
128 for (name, map) in self.maps.iter() {
129 let width = *map.last_key_value().expect("Empty map").0;
130 writeln!(file, "/// {} color map in HSV color space.", name)?;
131 writeln!(file, "/// - step:")?;
132 writeln!(
133 file,
134 "/// ",
135 name = name.to_lowercase()
136 )?;
137 writeln!(file, "/// - linear:")?;
138 writeln!(
139 file,
140 "/// ",
141 name = name.to_lowercase()
142 )?;
143 writeln!(file, "pub fn {}(min: f32, max: f32) -> HsvGradient {{", name.to_lowercase())?;
144 writeln!(file, "let mut grad = HsvGradient::new(0.0, {:.2});", width as f32)?;
145 for (x, color) in map.iter() {
146 let hsva = HSVA32::from(*color);
147 writeln!(file, "grad.insert_hue({:.2}, {:.2});", *x as f32, hsva.h)?;
148 writeln!(file, "grad.insert_saturation({:.2}, {:.2});", *x as f32, hsva.s)?;
149 writeln!(file, "grad.insert_brightness({:.2}, {:.2});", *x as f32, hsva.v)?;
150 }
151 writeln!(file, "grad.rescale(min, max);")?;
152 writeln!(file, "grad")?;
153 writeln!(file, "}}")?;
154 }
155 writeln!(file, "}}")?;
156 Ok(())
157 }
158}