1use std::{cell::RefCell, collections::HashMap, rc::Rc};
2
3use error::ImageError;
4use image::{
5 DynamicImage,
6 ImageError::{IoError, Unsupported},
7 RgbImage, RgbaImage,
8};
9
10mod error;
11
12pub fn load(path: &str) -> Result<Vec<Record>, ImageError> {
23 OcTree::load_with_maxcolor(path, 16)
24}
25
26pub fn load_with_maxcolor(path: &str, max_color: u32) -> Result<Vec<Record>, ImageError> {
37 OcTree::load_with_maxcolor(path, max_color)
38}
39
40#[derive(Debug)]
41struct OcTree {
42 leaf_num: u32,
43 to_reduce: [Vec<Rc<RefCell<Node>>>; 8],
44 max_color: u32,
45}
46
47impl OcTree {
48 fn load_with_maxcolor(path: &str, max_color: u32) -> Result<Vec<Record>, ImageError> {
49 const ARRAY_REPEAT_VALUE: Vec<Rc<RefCell<Node>>> = Vec::new();
50 let mut tree = OcTree {
51 leaf_num: 0,
52 to_reduce: [ARRAY_REPEAT_VALUE; 8],
53 max_color,
54 };
55
56 let image = image::open(&path).map_err(|error| match error {
57 Unsupported(error) => ImageError::UnsupportedFile(error),
58 IoError(error) => ImageError::IoError(error),
59 error => ImageError::Unknown(error),
60 })?;
61
62 let image_data = ImageData::try_from(&image)?;
63
64 let root = Node::new();
65 let root_share: Rc<RefCell<Node>> = Rc::new(RefCell::new(root));
66
67 for color in image_data.data {
68 tree.add_color(&root_share, color, 0);
69
70 while tree.leaf_num > tree.max_color {
71 tree.reduce_tree();
72 }
73 }
74
75 let mut map: HashMap<String, u32> = HashMap::new();
76 colors_stats(&root_share, &mut map);
77 let mut list = Vec::new();
78 for (color, count) in map {
79 list.push(Record { color, count });
80 }
81 list.sort_by(|a, b| b.count.cmp(&a.count));
82 Ok(list)
83 }
84
85 fn create_node(&mut self, level: usize) -> Rc<RefCell<Node>> {
86 let node = Node::new();
87 let node_share: Rc<RefCell<Node>> = Rc::new(RefCell::new(node));
88
89 if level == 7 {
90 let mut node_mut: std::cell::RefMut<Node> = node_share.borrow_mut();
91 node_mut.is_leaf = true;
92 self.leaf_num += 1;
93 } else {
94 let a: Rc<RefCell<Node>> = Rc::clone(&node_share);
95 self.to_reduce[level].push(a);
96 self.to_reduce[level].sort_by_key(|k: &Rc<RefCell<Node>>| k.borrow().pixel_count);
97 }
98
99 node_share
100 }
101
102 fn add_color(&mut self, node_share: &Rc<RefCell<Node>>, color: Color, level: usize) {
103 let mut node: std::cell::RefMut<Node> = node_share.borrow_mut();
104 if node.is_leaf {
105 node.pixel_count += 1;
106 node.r += color.0 as u32;
107 node.g += color.1 as u32;
108 node.b += color.2 as u32;
109 } else {
110 let r = color.0 >> (7 - level) & 1;
111 let g = color.1 >> (7 - level) & 1;
112 let b = color.2 >> (7 - level) & 1;
113
114 let idx = ((r << 2) + (g << 1) + b) as usize;
115
116 if node.children[idx].is_none() {
117 let child_share: Rc<RefCell<Node>> = self.create_node(level + 1);
118 node.children[idx] = Some(child_share);
119 }
120
121 self.add_color(node.children[idx].as_ref().unwrap(), color, level + 1);
122 }
123 }
124
125 fn reduce_tree(&mut self) {
126 let mut lv: isize = 6;
128
129 while lv >= 0 && self.to_reduce[lv as usize].len() == 0 {
130 lv -= 1;
131 }
132 if lv < 0 {
133 return;
134 }
135
136 let node_share = self.to_reduce[lv as usize].pop().unwrap();
137 let mut node = node_share.borrow_mut();
138
139 let mut r = 0;
141 let mut g = 0;
142 let mut b = 0;
143 let mut pixel_count = 0;
144
145 for i in 0..8 {
146 if node.children[i].is_none() {
147 continue;
148 }
149 let child_share = node.children[i].as_ref().unwrap();
150 let child = child_share.borrow();
151
152 r += child.r;
153 g += child.g;
154 b += child.b;
155 pixel_count += child.pixel_count;
156 self.leaf_num -= 1;
157 }
158
159 node.is_leaf = true;
160 node.r = r;
161 node.g = g;
162 node.b = b;
163 node.pixel_count = pixel_count;
164
165 self.leaf_num += 1;
166 }
167}
168
169fn colors_stats(node_share: &Rc<RefCell<Node>>, map: &mut HashMap<String, u32>) {
170 let node = node_share.borrow_mut();
171 if node.is_leaf {
172 let r = format!("{:0>2}", format!("{:X}", node.r / node.pixel_count));
173 let g = format!("{:0>2}", format!("{:X}", node.g / node.pixel_count));
174 let b = format!("{:0>2}", format!("{:X}", node.b / node.pixel_count));
175 let color = format!("#{}{}{}", r, g, b);
176 if let Some(x) = map.get_mut(&color) {
177 *x = *x + node.pixel_count;
178 } else {
179 map.insert(color, node.pixel_count);
180 }
181 } else {
182 for i in 0..8 {
183 if node.children[i].is_some() {
184 colors_stats(node.children[i].as_ref().unwrap(), map);
185 }
186 }
187 }
188}
189
190impl TryFrom<&DynamicImage> for ImageData {
191 type Error = ImageError;
192
193 fn try_from(image: &DynamicImage) -> Result<Self, Self::Error> {
194 match image {
195 image::DynamicImage::ImageRgb8(image) => Ok(ImageData::from(image)),
196 image::DynamicImage::ImageRgba8(image) => Ok(ImageData::from(image)),
197 _ => Err(ImageError::UnsupportedType(image.color())),
198 }
199 }
200}
201
202impl From<&RgbImage> for ImageData {
203 fn from(image: &RgbImage) -> Self {
204 let (width, height) = image.dimensions();
205 let size = (width * height) as usize;
206
207 let data = image
208 .pixels()
209 .fold(Vec::with_capacity(size), |mut pixels, pixel| {
210 pixels.push(Color(pixel[0], pixel[1], pixel[2]));
211 pixels
212 });
213
214 Self { data }
215 }
216}
217
218impl From<&RgbaImage> for ImageData {
219 fn from(image: &RgbaImage) -> Self {
220 let (width, height) = image.dimensions();
221 let size = (width * height) as usize;
222
223 let data = image.pixels().filter(|pixels| pixels[3] > 0).fold(
224 Vec::with_capacity(size),
225 |mut pixels, pixel| {
226 pixels.push(Color(pixel[0], pixel[1], pixel[2]));
227 pixels
228 },
229 );
230
231 Self { data }
232 }
233}
234
235struct ImageData {
236 data: Vec<Color>,
237}
238
239#[derive(Debug)]
240struct Node {
241 is_leaf: bool,
242 r: u32,
243 g: u32,
244 b: u32,
245 pixel_count: u32,
246 children: [Option<Rc<RefCell<Node>>>; 8],
247}
248
249impl Node {
250 fn new() -> Node {
251 const ARRAY_REPEAT_VALUE: Option<Rc<RefCell<Node>>> = None;
252 Node {
253 is_leaf: false,
254 r: 0,
255 g: 0,
256 b: 0,
257 pixel_count: 0,
258 children: [ARRAY_REPEAT_VALUE; 8],
259 }
260 }
261}
262
263#[derive(Debug)]
264struct Color(u8, u8, u8);
265
266#[derive(Debug)]
267pub struct Record {
268 color: String,
269 count: u32,
270}
271
272impl Record {
273 pub fn color(&self) -> &str {
274 &self.color
275 }
276 pub fn count(&self) -> u32 {
277 self.count
278 }
279}