1 //! Functions for performing affine transformations.
2 
3 use buffer::{ImageBuffer, Pixel};
4 use image::GenericImageView;
5 
6 /// Rotate an image 90 degrees clockwise.
7 // TODO: Is the 'static bound on `I` really required? Can we avoid it?
rotate90<I: GenericImageView + 'static>( image: &I, ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static,8 pub fn rotate90<I: GenericImageView + 'static>(
9     image: &I,
10 ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
11 where
12     I::Pixel: 'static,
13     <I::Pixel as Pixel>::Subpixel: 'static,
14 {
15     let (width, height) = image.dimensions();
16     let mut out = ImageBuffer::new(height, width);
17 
18     for y in 0..height {
19         for x in 0..width {
20             let p = image.get_pixel(x, y);
21             out.put_pixel(height - 1 - y, x, p);
22         }
23     }
24 
25     out
26 }
27 
28 /// Rotate an image 180 degrees clockwise.
29 // TODO: Is the 'static bound on `I` really required? Can we avoid it?
rotate180<I: GenericImageView + 'static>( image: &I, ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static,30 pub fn rotate180<I: GenericImageView + 'static>(
31     image: &I,
32 ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
33 where
34     I::Pixel: 'static,
35     <I::Pixel as Pixel>::Subpixel: 'static,
36 {
37     let (width, height) = image.dimensions();
38     let mut out = ImageBuffer::new(width, height);
39 
40     for y in 0..height {
41         for x in 0..width {
42             let p = image.get_pixel(x, y);
43             out.put_pixel(width - 1 - x, height - 1 - y, p);
44         }
45     }
46 
47     out
48 }
49 
50 /// Rotate an image 270 degrees clockwise.
51 // TODO: Is the 'static bound on `I` really required? Can we avoid it?
rotate270<I: GenericImageView + 'static>( image: &I, ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static,52 pub fn rotate270<I: GenericImageView + 'static>(
53     image: &I,
54 ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
55 where
56     I::Pixel: 'static,
57     <I::Pixel as Pixel>::Subpixel: 'static,
58 {
59     let (width, height) = image.dimensions();
60     let mut out = ImageBuffer::new(height, width);
61 
62     for y in 0..height {
63         for x in 0..width {
64             let p = image.get_pixel(x, y);
65             out.put_pixel(y, width - 1 - x, p);
66         }
67     }
68 
69     out
70 }
71 
72 /// Flip an image horizontally
73 // TODO: Is the 'static bound on `I` really required? Can we avoid it?
flip_horizontal<I: GenericImageView + 'static>( image: &I, ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static,74 pub fn flip_horizontal<I: GenericImageView + 'static>(
75     image: &I,
76 ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
77 where
78     I::Pixel: 'static,
79     <I::Pixel as Pixel>::Subpixel: 'static,
80 {
81     let (width, height) = image.dimensions();
82     let mut out = ImageBuffer::new(width, height);
83 
84     for y in 0..height {
85         for x in 0..width {
86             let p = image.get_pixel(x, y);
87             out.put_pixel(width - 1 - x, y, p);
88         }
89     }
90 
91     out
92 }
93 
94 /// Flip an image vertically
95 // TODO: Is the 'static bound on `I` really required? Can we avoid it?
flip_vertical<I: GenericImageView + 'static>( image: &I, ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>> where I::Pixel: 'static, <I::Pixel as Pixel>::Subpixel: 'static,96 pub fn flip_vertical<I: GenericImageView + 'static>(
97     image: &I,
98 ) -> ImageBuffer<I::Pixel, Vec<<I::Pixel as Pixel>::Subpixel>>
99 where
100     I::Pixel: 'static,
101     <I::Pixel as Pixel>::Subpixel: 'static,
102 {
103     let (width, height) = image.dimensions();
104     let mut out = ImageBuffer::new(width, height);
105 
106     for y in 0..height {
107         for x in 0..width {
108             let p = image.get_pixel(x, y);
109             out.put_pixel(x, height - 1 - y, p);
110         }
111     }
112 
113     out
114 }
115 
116 #[cfg(test)]
117 mod test {
118     use super::{flip_horizontal, flip_vertical, rotate180, rotate270, rotate90};
119     use buffer::{GrayImage, ImageBuffer, Pixel};
120     use image::GenericImage;
121 
122     macro_rules! assert_pixels_eq {
123         ($actual:expr, $expected:expr) => {{
124             let actual_dim = $actual.dimensions();
125             let expected_dim = $expected.dimensions();
126 
127             if actual_dim != expected_dim {
128                 panic!(
129                     "dimensions do not match. \
130                      actual: {:?}, expected: {:?}",
131                     actual_dim, expected_dim
132                 )
133             }
134 
135             let diffs = pixel_diffs($actual, $expected);
136 
137             if !diffs.is_empty() {
138                 let mut err = "pixels do not match. ".to_string();
139 
140                 let diff_messages = diffs
141                     .iter()
142                     .take(5)
143                     .map(|d| format!("\nactual: {:?}, expected {:?} ", d.0, d.1))
144                     .collect::<Vec<_>>()
145                     .join("");
146 
147                 err.push_str(&diff_messages);
148                 panic!(err)
149             }
150         }};
151     }
152 
153     #[test]
test_rotate90()154     fn test_rotate90() {
155         let image: GrayImage =
156             ImageBuffer::from_raw(3, 2, vec![00u8, 01u8, 02u8, 10u8, 11u8, 12u8]).unwrap();
157 
158         let expected: GrayImage =
159             ImageBuffer::from_raw(2, 3, vec![10u8, 00u8, 11u8, 01u8, 12u8, 02u8]).unwrap();
160 
161         assert_pixels_eq!(&rotate90(&image), &expected);
162     }
163 
164     #[test]
test_rotate180()165     fn test_rotate180() {
166         let image: GrayImage =
167             ImageBuffer::from_raw(3, 2, vec![00u8, 01u8, 02u8, 10u8, 11u8, 12u8]).unwrap();
168 
169         let expected: GrayImage =
170             ImageBuffer::from_raw(3, 2, vec![12u8, 11u8, 10u8, 02u8, 01u8, 00u8]).unwrap();
171 
172         assert_pixels_eq!(&rotate180(&image), &expected);
173     }
174 
175     #[test]
test_rotate270()176     fn test_rotate270() {
177         let image: GrayImage =
178             ImageBuffer::from_raw(3, 2, vec![00u8, 01u8, 02u8, 10u8, 11u8, 12u8]).unwrap();
179 
180         let expected: GrayImage =
181             ImageBuffer::from_raw(2, 3, vec![02u8, 12u8, 01u8, 11u8, 00u8, 10u8]).unwrap();
182 
183         assert_pixels_eq!(&rotate270(&image), &expected);
184     }
185 
186     #[test]
test_flip_horizontal()187     fn test_flip_horizontal() {
188         let image: GrayImage =
189             ImageBuffer::from_raw(3, 2, vec![00u8, 01u8, 02u8, 10u8, 11u8, 12u8]).unwrap();
190 
191         let expected: GrayImage =
192             ImageBuffer::from_raw(3, 2, vec![02u8, 01u8, 00u8, 12u8, 11u8, 10u8]).unwrap();
193 
194         assert_pixels_eq!(&flip_horizontal(&image), &expected);
195     }
196 
197     #[test]
test_flip_vertical()198     fn test_flip_vertical() {
199         let image: GrayImage =
200             ImageBuffer::from_raw(3, 2, vec![00u8, 01u8, 02u8, 10u8, 11u8, 12u8]).unwrap();
201 
202         let expected: GrayImage =
203             ImageBuffer::from_raw(3, 2, vec![10u8, 11u8, 12u8, 00u8, 01u8, 02u8]).unwrap();
204 
205         assert_pixels_eq!(&flip_vertical(&image), &expected);
206     }
207 
pixel_diffs<I, J, P>(left: &I, right: &J) -> Vec<((u32, u32, P), (u32, u32, P))> where I: GenericImage<Pixel = P>, J: GenericImage<Pixel = P>, P: Pixel + Eq,208     fn pixel_diffs<I, J, P>(left: &I, right: &J) -> Vec<((u32, u32, P), (u32, u32, P))>
209     where
210         I: GenericImage<Pixel = P>,
211         J: GenericImage<Pixel = P>,
212         P: Pixel + Eq,
213     {
214         left.pixels()
215             .zip(right.pixels())
216             .filter(|&(p, q)| p != q)
217             .collect::<Vec<_>>()
218     }
219 }
220