1use crate::utils::mean;
2use crate::color::{Color, ColorChannel};
3
4#[cfg(feature = "image")]
5extern crate image;
6#[cfg(feature = "image")]
7use image::GenericImageView;
8
9#[derive(Debug, PartialEq)]
13pub struct ColorBucket {
14 colors: Vec<Color>,
15}
16
17impl ColorBucket {
18 pub fn from_pixels(pixels: Vec<Color>) -> Option<Self> {
35 if pixels.is_empty() {
36 None
37 } else {
38 Some(Self { colors: pixels })
39 }
40 }
41
42 #[cfg(feature = "image")]
43 pub fn from_image(image_path: &str) -> Option<Self> {
60 if let Ok(img) = image::open(image_path) {
61 let mut colors = Vec::new();
62
63 for p in img.pixels() {
64 let color = Color {
65 r: p.2.0[0],
66 g: p.2.0[1],
67 b: p.2.0[2],
68 a: p.2.0[3]
69 };
70
71 colors.push(color);
72 }
73
74 Some (Self { colors })
75 } else {
76 println!("Unable to load image at: {}", image_path);
77 None
78 }
79 }
80
81 fn recurse(&mut self, iter_count: u8, result: &mut Vec<Color>) {
92 if iter_count == 0 {
93 result.push(self.color_mean())
94 } else {
95 let new_buckets = self.median_cut();
96 if let Some(mut bucket) = new_buckets.0 {
97 bucket.recurse(iter_count - 1, result);
98 }
99 if let Some(mut bucket) = new_buckets.1 {
100 bucket.recurse(iter_count - 1, result);
101 }
102 }
103 }
104
105 pub fn make_palette(&mut self, iter_count: u8) -> Vec<Color> {
123 let mut result = vec![];
124 self.recurse(iter_count, &mut result);
125 result
126 }
127
128 fn median_cut(&mut self) -> (Option<ColorBucket>, Option<ColorBucket>) {
132 let highest_range_channel = self.highest_range_channel();
133 let median = self.color_median(highest_range_channel);
134 let mut above_median = vec![];
135 let mut below_median = vec![];
136 for color in &self.colors {
137 if color[highest_range_channel] > median {
138 above_median.push(*color);
139 } else {
140 below_median.push(*color);
141 }
142 }
143
144 (ColorBucket::from_pixels(above_median), ColorBucket::from_pixels(below_median))
145 }
146
147 fn highest_range_channel(&self) -> ColorChannel {
151 let ranges = self.color_ranges();
152 let mut highest_range_channel = ColorChannel::R;
153 let mut highest_value = ranges.r;
154
155 if ranges.g > highest_value {
156 highest_range_channel = ColorChannel::G;
157 highest_value = ranges.g;
158 }
159
160 if ranges.b > highest_value {
161 highest_range_channel = ColorChannel::B;
162 }
163
164 highest_range_channel
165 }
166
167 fn color_ranges(&self) -> Color {
170 Color {
172 r: self.colors.iter().max_by_key(|c| c.r).unwrap().r - self.colors.iter().min_by_key(|c| c.r).unwrap().r,
173 g: self.colors.iter().max_by_key(|c| c.g).unwrap().g - self.colors.iter().min_by_key(|c| c.g).unwrap().g,
174 b: self.colors.iter().max_by_key(|c| c.b).unwrap().b - self.colors.iter().min_by_key(|c| c.b).unwrap().b,
175 a: self.colors.iter().max_by_key(|c| c.a).unwrap().a - self.colors.iter().min_by_key(|c| c.a).unwrap().a,
176 }
177 }
178
179 fn sort_colors(&mut self, channel: ColorChannel) {
186 self.colors.sort_by_key(|x| x[channel])
187 }
188
189 fn color_median(&mut self, channel: ColorChannel) -> u8 {
196 self.sort_colors(channel);
197
198 let mid = self.colors.len() / 2;
199 if self.colors.len() % 2 == 0 {
200 let bucket = ColorBucket::from_pixels(vec![self.colors[mid - 1], self.colors[mid]]).unwrap();
201 bucket.channel_mean(channel)
202 } else {
203 self.channel_value_by_index(mid, channel)
204 }
205 }
206
207 fn channel_value_by_index(&self, index: usize, channel: ColorChannel) -> u8 {
215 self.colors[index][channel]
216 }
217
218 fn channel_mean(&self, channel: ColorChannel) -> u8 {
226 mean(self.colors.iter().map(|x| x[channel]))
227 }
228
229 fn color_mean(&self) -> Color {
232 let r = mean(self.colors.iter().map(|c| c.r));
233 let g = mean(self.colors.iter().map(|c| c.g));
234 let b = mean(self.colors.iter().map(|c| c.b));
235 let a = mean(self.colors.iter().map(|c| c.a));
236
237 Color { r, g, b, a }
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn from_pixels_ut() {
247 let bucket = ColorBucket::from_pixels(vec![]);
248 assert_eq!(bucket, None);
249
250 let data = vec![Color { r: 15, g: 131, b: 0, a: 255 }, Color { r: 221, g: 11, b: 22, a: 130 }, Color { r: 81, g: 11, b: 16, a: 0 }];
251 let bucket = ColorBucket::from_pixels(data.clone()).expect("Passed empty color vector to test.");
252 assert_eq!(bucket.colors, data);
253 }
254
255 #[test]
256 fn recurse_ut() {
257 let pixels = vec![Color { r: 255, g: 0, b: 0, a: 255 }, Color { r: 0, g: 255, b: 0, a: 255 }];
258 let mut bucket = ColorBucket::from_pixels(pixels.clone()).expect("Passed empty color vector to test.");
259 let mut result = vec![];
260 bucket.recurse(1, &mut result);
261 assert_eq!(result, pixels);
262 }
263
264 #[test]
265 fn make_palette_ut() {
266 let pixels = vec![Color { r: 100, g: 120, b: 120, a: 0 }, Color { r: 150, g: 150, b: 150, a: 0 }, Color { r: 255, g: 255, b: 255, a: 0 }];
267 let mut bucket = ColorBucket::from_pixels(pixels.clone()).expect("Passed empty color vector to test.");
268
269 let colors = bucket.make_palette(3);
270 let expected = vec![Color { r: 255, g: 255, b: 255, a: 0 }, Color { r: 150, g: 150, b: 150, a: 0 }, Color { r: 100, g: 120, b: 120, a: 0 }];
271 assert_eq!(colors, expected);
272 }
273
274 #[test]
275 pub fn sort_colors_ut() {
276 let colors = generate_unsorted_colors();
277 let mut bucket = ColorBucket::from_pixels(colors.clone()).expect("Passed empty color vector to test");
278 bucket.sort_colors(ColorChannel::R);
279
280 assert_eq!(bucket.colors[0], Color { r: 0, g: 2, b: 1, a: 20 });
281 assert_eq!(bucket.colors[1], Color { r: 1, g: 23, b: 16, a: 20 });
282 assert_eq!(bucket.colors[2], Color { r: 3, g: 4, b: 15, a: 2 });
283 assert_eq!(bucket.colors[3], Color { r: 55, g: 17, b: 0, a: 118 });
284 }
285
286 #[test]
287 pub fn color_median_ut() {
288 let colors = generate_unsorted_colors();
289 let mut bucket = ColorBucket::from_pixels(colors.clone()).expect("Passed empty color vector to test");
290 let result = bucket.color_median(ColorChannel::R);
291 assert_eq!(result, 2);
292 }
293
294 #[test]
295 fn channel_value_by_index_ut() {
296 let colors = vec![
297 Color { r: 100, g: 22, b: 12, a: 0 },
298 Color { r: 126, g: 175, b: 137, a: 1 },
299 Color { r: 221, g: 225, b: 0, a: 113 },
300 Color { r: 13, g: 226, b: 0, a: 17 },
301 ];
302
303 let bucket = ColorBucket::from_pixels(colors).expect("Passing empty color vector to test");
304
305 assert_eq!(100, bucket.channel_value_by_index(0, ColorChannel::R));
306 assert_eq!(22, bucket.channel_value_by_index(0, ColorChannel::G));
307 assert_eq!(12, bucket.channel_value_by_index(0, ColorChannel::B));
308 assert_eq!(0, bucket.channel_value_by_index(0, ColorChannel::A));
309
310 assert_eq!(126, bucket.channel_value_by_index(1, ColorChannel::R));
311 assert_eq!(175, bucket.channel_value_by_index(1, ColorChannel::G));
312 assert_eq!(137, bucket.channel_value_by_index(1, ColorChannel::B));
313 assert_eq!(1, bucket.channel_value_by_index(1, ColorChannel::A));
314
315 assert_eq!(221, bucket.channel_value_by_index(2, ColorChannel::R));
316 assert_eq!(225, bucket.channel_value_by_index(2, ColorChannel::G));
317 assert_eq!(0, bucket.channel_value_by_index(2, ColorChannel::B));
318 assert_eq!(113, bucket.channel_value_by_index(2, ColorChannel::A));
319
320 assert_eq!(13, bucket.channel_value_by_index(3, ColorChannel::R));
321 assert_eq!(226, bucket.channel_value_by_index(3, ColorChannel::G));
322 assert_eq!(0, bucket.channel_value_by_index(3, ColorChannel::B));
323 assert_eq!(17, bucket.channel_value_by_index(3, ColorChannel::A));
324 }
325
326 #[test]
327 fn channel_mean_ut() {
328 let colors = vec![
329 Color { r: 100, g: 50, b: 12, a: 255 },
330 Color { r: 100, g: 50, b: 12, a: 255 },
331 Color { r: 100, g: 50, b: 12, a: 255 },
332 Color { r: 100, g: 50, b: 12, a: 255 },
333 ];
334
335 let bucket = ColorBucket::from_pixels(colors).expect("Passed empty color vector to test.");
336 let mut result = bucket.channel_mean(ColorChannel::R);
337 assert_eq!(100, result);
338 result = bucket.channel_mean(ColorChannel::G);
339 assert_eq!(50, result);
340 result = bucket.channel_mean(ColorChannel::B);
341 assert_eq!(12, result);
342 result = bucket.channel_mean(ColorChannel::A);
343 assert_eq!(255, result);
344
345 let colors = vec![
347 Color { r: 100, g: 22, b: 12, a: 0 },
348 Color { r: 126, g: 175, b: 137, a: 1 },
349 Color { r: 221, g: 225, b: 0, a: 113 },
350 Color { r: 13, g: 226, b: 0, a: 17 },
351 ];
352
353 let bucket = ColorBucket::from_pixels(colors).expect("Passed empty color vector to test.");
354
355 result = bucket.channel_mean(ColorChannel::R);
356 assert_eq!(115, result);
357 result = bucket.channel_mean(ColorChannel::G);
358 assert_eq!(162, result);
359 result = bucket.channel_mean(ColorChannel::B);
360 assert_eq!(37, result);
361 result = bucket.channel_mean(ColorChannel::A);
362 assert_eq!(32, result);
363 }
364
365 #[test]
366 pub fn ut_color_mean() {
367 let colors = generate_unsorted_colors();
368 let bucket = ColorBucket::from_pixels(colors).expect("Passed empty color vector to test.");
369
370 let result = bucket.color_mean();
371 let expected = Color { r: 14, g: 11, b: 8, a: 40 };
372 assert_eq!(expected, result);
373 }
374
375 #[test]
376 fn median_cut_ut() {
377 let mut bucket = ColorBucket::from_pixels(generate_unsorted_colors()).expect("Passed empty color vector to test.");
378 let result = bucket.median_cut();
379 assert_eq!(
380 result.0,
381 Some(ColorBucket::from_pixels(vec![Color { r: 3, g: 4, b: 15, a: 2 }, Color { r: 55, g: 17, b: 0, a: 118 }]).unwrap())
382 );
383 assert_eq!(
384 result.1,
385 Some(ColorBucket::from_pixels(vec![Color { r: 0, g: 2, b: 1, a: 20 }, Color { r: 1, g: 23, b: 16, a: 20 }]).unwrap())
386 );
387
388 let mut bucket = ColorBucket::from_pixels(vec![Color { r: 0, g: 0, b: 0, a: 0 }]).expect("Passed empty color vector to test.");
389 let result = bucket.median_cut();
390 assert_eq!(result.0, None);
391 assert_eq!(result.1, Some(ColorBucket::from_pixels(vec![Color { r: 0, g: 0, b: 0, a: 0 }])).unwrap());
392 }
393
394 #[test]
395 fn highest_range_channel_ut() {
396 let bucket = ColorBucket::from_pixels(generate_unsorted_colors()).expect("Passed empty color vector to test");
397 assert_eq!(ColorChannel::R, bucket.highest_range_channel());
398 assert_ne!(ColorChannel::G, bucket.highest_range_channel());
399 assert_ne!(ColorChannel::B, bucket.highest_range_channel());
400 assert_ne!(ColorChannel::A, bucket.highest_range_channel());
401 }
402
403 #[test]
404 fn color_ranges_ut() {
405 let bucket = ColorBucket::from_pixels(generate_unsorted_colors()).expect("Passed empty color vector to test");
406 let expected = Color { r: 55, g: 21, b: 16, a: 116 };
407 assert_eq!(expected, bucket.color_ranges());
408 }
409
410 fn generate_unsorted_colors() -> Vec<Color> {
411 vec![
412 Color { r: 55, g: 17, b: 0, a: 118 },
413 Color { r: 0, g: 2, b: 1, a: 20 },
414 Color { r: 3, g: 4, b: 15, a: 2 },
415 Color { r: 1, g: 23, b: 16, a: 20 },
416 ]
417 }
418}