imgdata/
manager.rs

1use crate::color::Color;
2use crate::io;
3use image::{Rgba, RgbaImage};
4use itertools::Itertools;
5use std::collections::hash_map::DefaultHasher;
6use std::collections::HashMap;
7use std::hash::{Hash, Hasher};
8
9pub struct Manager {
10    pub image: RgbaImage,
11    pub color_file: io::ColorFile,
12    pub lookup: HashMap<Rgba<u8>, String>,
13}
14
15pub struct ManagerOptions {
16    pub image_path: String,
17    pub color_file_path: String,
18}
19
20impl Manager {
21    pub fn new(opts: ManagerOptions) -> Manager {
22        let cf = io::read(&opts.color_file_path[..]);
23        return Manager {
24            image: io::open(&opts.image_path[..]),
25            color_file: cf.clone(),
26            lookup: cf.create_lookup(),
27        };
28    }
29
30    pub fn get(&self, x: u32, y: u32) -> PixelData {
31        let pixel = self.image.get_pixel(x, y);
32        match self.lookup.get(&pixel) {
33            Some(name) => {
34                return PixelData {
35                    x: x,
36                    y: y,
37                    color: pixel.clone(),
38                    color_name: name.clone(),
39                }
40            }
41            _ => {
42                return PixelData {
43                    x: x,
44                    y: y,
45                    color: pixel.clone(),
46                    color_name: String::from("UNKNOWN"),
47                }
48            }
49        }
50    }
51
52    pub fn hash(&self, x: u32, y: u32) -> u64 {
53        let mut hasher = DefaultHasher::new();
54        self.get(x, y).hash(&mut hasher);
55        return hasher.finish();
56    }
57
58    pub fn colors_hex(&self) -> Vec<String> {
59        self.lookup
60            .keys()
61            .map(|x| format!("0x{}", x.hex()))
62            .collect()
63    }
64
65    pub fn colors_rgb(&self) -> Vec<[u8; 3]> {
66        self.lookup.keys().map(|x| x.rgb()).collect()
67    }
68
69    pub fn color_names(&self) -> Vec<String> {
70        self.lookup.values().map(|x| x.clone()).collect()
71    }
72
73    pub fn unique_hex_colors(&self) -> Vec<String> {
74        self.image
75            .pixels()
76            .sorted_by(|a, b| a.compare(&b))
77            .dedup()
78            .map(|x| format!("0x{}", x.hex()))
79            .collect()
80    }
81
82    pub fn unique_rgb_colors(&self) -> Vec<[u8; 3]> {
83        self.image
84            .pixels()
85            .sorted_by(|a, b| a.compare(&b))
86            .dedup()
87            .map(|x| x.rgb())
88            .collect()
89    }
90
91    pub fn show_names(&self) {
92        for pixel in self.image.pixels() {
93            let c = pixel.paint("██");
94            match self.lookup.get(&pixel) {
95                Some(name) => print!("{} {} :: ", c, name),
96                _ => println!("Color {:?} not found in lookup ...", pixel),
97            }
98        }
99        println!();
100    }
101}
102
103pub struct PixelData {
104    pub x: u32,
105    pub y: u32,
106    pub color: Rgba<u8>,
107    pub color_name: String,
108}
109
110impl Hash for PixelData {
111    fn hash<H: Hasher>(&self, state: &mut H) {
112        self.x.hash(state);
113        self.y.hash(state);
114        self.color.hash(state);
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_manager_get() {
124        let opts = ManagerOptions {
125            image_path: String::from("src/test-image.png"),
126            color_file_path: String::from("src/test-color-file.ron"),
127        };
128        let manager = Manager::new(opts);
129        let pixel_data = manager.get(0, 0);
130        assert_eq!(pixel_data.x, 0);
131        assert_eq!(pixel_data.y, 0);
132        assert_eq!(pixel_data.color.rgba(), [255, 0, 0, 255]);
133        assert_eq!(pixel_data.color_name, "red");
134    }
135
136    #[test]
137    fn test_manager_hash() {
138        let opts = ManagerOptions {
139            image_path: String::from("src/test-image.png"),
140            color_file_path: String::from("src/test-color-file.ron"),
141        };
142        let manager = Manager::new(opts);
143        assert_eq!(manager.hash(0, 0), 14349191598533205778);
144    }
145}