1use std::fmt;
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub struct Image {
5 pub pixels: Vec<u8>, }
7
8impl Image {
9 pub fn invert(&mut self) {
10 self.pixels = self.pixels.iter().map(|pixel| 1 - pixel).collect();
11 }
12
13 pub fn flip(&mut self) {
15 let mut pixels = Vec::with_capacity(64);
16
17 for row in self.pixels.chunks(8).rev() {
18 for pixel in row {
19 pixels.push(*pixel);
20 }
21 }
22
23 self.pixels = pixels;
24 }
25
26 pub fn mirror(&mut self) {
28 let mut pixels = Vec::with_capacity(64);
29
30 for row in self.pixels.chunks(8) {
31 for i in (0..8).rev() {
32 pixels.push(row[i]);
33 }
34 }
35
36 self.pixels = pixels;
37 }
38
39 pub fn rotate(&mut self) {
41 let mut pixels = Vec::with_capacity(64);
42
43 for x in 0..8 {
47 for y in (0..8).rev() {
48 pixels.push(self.pixels[(y * 8) + x]);
49 }
50 }
51
52 self.pixels = pixels;
53 }
54
55 fn from_str(str: &str) -> Result<(Image, Vec<crate::Error>), crate::Error> {
56 let mut warnings = Vec::new();
57
58 if str.contains("NaN") {
59 warnings.push(crate::Error::Image);
60 }
61
62 let string = str.trim().replace("NaN", "0");
63
64 let lines: Vec<&str> = string.lines().collect();
65 let dimension = lines.len();
66 let mut pixels: Vec<u8> = Vec::new();
67
68 for line in lines {
69 let line = &line[..dimension];
70 for char in line.chars().into_iter() {
71 pixels.push(match char {'1' => 1, _ => 0});
73 }
74 }
75
76 if [64, 256].contains(&pixels.len()) {
77 Ok((Image { pixels }, warnings))
78 } else {
79 Err(crate::Error::Image)
80 }
81 }
82}
83
84impl fmt::Display for Image {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 let mut string = String::new();
87
88 let sqrt = (self.pixels.len() as f64).sqrt() as usize; for line in self.pixels.chunks(sqrt) {
90 for pixel in line {
91 string.push_str(&format!("{}", *pixel));
92 }
93 string.push('\n');
94 }
95
96 string.pop(); write!(f, "{}", string)
99 }
100}
101
102pub fn animation_frames_from_str(str: &str) -> Vec<Image> {
104 str
105 .split('>')
106 .collect::<Vec<&str>>()
107 .iter()
108 .map(|&frame| Image::from_str(frame).unwrap().0)
109 .collect()
110}
111
112#[cfg(test)]
113mod test {
114 use crate::image::{Image, animation_frames_from_str};
115 use crate::mock;
116
117 #[test]
118 fn image_from_string() {
119 let (output, _) = Image::from_str(include_str!("test-resources/image")).unwrap();
120
121 let expected = Image {
122 pixels: vec![
123 1, 1, 1, 1, 1, 1, 1, 1,
124 1, 1, 0, 0, 1, 1, 1, 1,
125 1, 0, 1, 1, 1, 1, 1, 1,
126 1, 1, 1, 1, 1, 1, 1, 1,
127 1, 1, 1, 1, 1, 1, 1, 1,
128 1, 1, 1, 1, 1, 1, 1, 1,
129 1, 1, 1, 1, 1, 1, 1, 1,
130 1, 1, 1, 1, 1, 1, 1, 1,
131 ],
132 };
133
134 assert_eq!(output, expected);
135 }
136
137 #[test]
138 fn image_to_string() {
139 let output = mock::image::chequers_1().to_string();
140 let expected = include_str!("test-resources/image-chequers-1").to_string();
141 assert_eq!(output, expected);
142 }
143
144 #[test]
145 fn test_animation_frames_from_string() {
146 let output = animation_frames_from_str(
147 include_str!("test-resources/animation_frames")
148 );
149
150 let expected = mock::image::animation_frames();
151
152 assert_eq!(output, expected);
153 }
154
155 #[test]
158 fn image_out_of_bounds() {
159 let (output, _) = Image::from_str(include_str!("test-resources/image-oob")).unwrap();
160
161 let expected = Image {
162 pixels: vec![
163 1,1,1,1,1,1,1,1,
164 1,1,0,0,1,1,1,1,
165 1,0,1,1,1,1,1,1,
166 1,1,1,1,1,1,1,1,
167 1,1,1,1,1,1,1,1,
168 1,1,1,1,1,1,1,1,
169 1,1,1,1,1,1,1,1,
170 0,0,0,0,0,0,0,0,
171 ]
172 };
173
174 assert_eq!(output, expected);
175 }
176
177 #[test]
178 fn invert() {
179 let mut output = crate::mock::image::chequers_1();
180 output.invert();
181 let expected = crate::mock::image::chequers_2();
182 assert_eq!(output, expected);
183 }
184
185 #[test]
186 fn flip() {
187 let mut image = crate::mock::image::asymmetrical();
188 image.flip();
189
190 let flipped = Image { pixels: vec![
191 0,0,0,1,0,0,0,0,
192 0,0,1,0,0,0,0,0,
193 0,1,0,0,0,0,0,0,
194 1,0,0,0,0,0,0,0,
195 1,0,0,0,0,0,0,0,
196 0,1,0,0,0,0,0,0,
197 0,0,0,0,0,0,0,0,
198 0,0,0,0,0,0,0,0,
199 ]};
200
201 assert_eq!(image, flipped);
202 }
203
204 #[test]
205 fn mirror() {
206 let mut image = crate::mock::image::asymmetrical();
207 image.mirror();
208
209 let mirrored = Image { pixels: vec![
210 0,0,0,0,0,0,0,0,
211 0,0,0,0,0,0,0,0,
212 0,0,0,0,0,0,1,0,
213 0,0,0,0,0,0,0,1,
214 0,0,0,0,0,0,0,1,
215 0,0,0,0,0,0,1,0,
216 0,0,0,0,0,1,0,0,
217 0,0,0,0,1,0,0,0,
218 ]};
219
220 assert_eq!(image, mirrored);
221 }
222
223 #[test]
224 fn rotate() {
225 let mut image = crate::mock::image::asymmetrical();
226 image.rotate();
227
228 let rotated = Image { pixels: vec![
229 0,0,0,1,1,0,0,0,
230 0,0,1,0,0,1,0,0,
231 0,1,0,0,0,0,0,0,
232 1,0,0,0,0,0,0,0,
233 0,0,0,0,0,0,0,0,
234 0,0,0,0,0,0,0,0,
235 0,0,0,0,0,0,0,0,
236 0,0,0,0,0,0,0,0,
237 ]};
238
239 assert_eq!(image, rotated);
240 }
241}