expectation/extensions/
image.rs1use super::super::provider::{Provider, WriteRequester};
2use super::super::*;
3use expectation_shared::filesystem::ReadSeek;
4
5use std::io::{BufReader, Result as IoResult};
6use std::path::Path;
7
8use image::*;
9
10pub trait ImageDiffExtension {
11 fn png_writer<N>(&self, filename: N) -> Writer
12 where
13 N: AsRef<Path>;
14
15 fn rgb_image<N>(&self, filename: N, image: RgbImage) -> IoResult<()>
16 where
17 N: AsRef<Path>,
18 {
19 let mut w = self.png_writer(filename);
20 let dyn_image = DynamicImage::ImageRgb8(image);
21 dyn_image.write_to(&mut w, ImageOutputFormat::PNG).unwrap();
22 Ok(())
23 }
24
25 fn rgba_image<N>(&self, filename: N, image: RgbaImage) -> IoResult<()>
26 where
27 N: AsRef<Path>,
28 {
29 let mut w = self.png_writer(filename);
30 let dyn_image = DynamicImage::ImageRgba8(image);
31 dyn_image.write_to(&mut w, ImageOutputFormat::PNG).unwrap();
32 Ok(())
33 }
34}
35
36impl ImageDiffExtension for Provider {
37 fn png_writer<S>(&self, filename: S) -> Writer
38 where
39 S: AsRef<Path>,
40 {
41 self.custom_test(
42 filename,
43 |a, b| image_eq(a, b),
44 |a, b, c, d| image_diff(a, b, c, d),
45 )
46 }
47}
48
49fn image_eq<R1: ReadSeek, R2: ReadSeek>(r1: R1, r2: R2) -> IoResult<bool> {
50 let mut r1 = BufReader::new(r1);
51 let mut r2 = BufReader::new(r2);
52
53 let i1 = load(&mut r1, ImageFormat::PNG).unwrap();
54 let i2 = load(&mut r2, ImageFormat::PNG).unwrap();
55
56 match (i1, i2) {
57 (DynamicImage::ImageRgb8(i1), DynamicImage::ImageRgb8(i2)) => {
58 if i1.width() != i2.width() || i1.height() != i2.height() {
59 return Ok(false);
60 }
61 for x in 0..i1.width() {
62 for y in 0..i1.height() {
63 if i1.get_pixel(x, y) != i2.get_pixel(x, y) {
64 return Ok(false);
65 }
66 }
67 }
68 }
69 (DynamicImage::ImageRgba8(i1), DynamicImage::ImageRgba8(i2)) => {
70 if i1.width() != i2.width() || i1.height() != i2.height() {
71 return Ok(false);
72 }
73 for x in 0..i1.width() {
74 for y in 0..i1.height() {
75 if i1.get_pixel(x, y) != i2.get_pixel(x, y) {
76 return Ok(false);
77 }
78 }
79 }
80 }
81 (_, _) => return Ok(false),
82 }
83
84 Ok(true)
85}
86
87fn _add_extension(p: &Path, new_ext: &str) -> PathBuf {
88 let old_ext = match p.extension() {
89 Some(e) => e.to_string_lossy().into_owned(),
90 None => "".to_owned(),
91 };
92 p.with_extension(format!("{}{}", old_ext, new_ext))
93}
94
95fn image_diff<R1: ReadSeek, R2: ReadSeek>(
96 r1: R1,
97 r2: R2,
98 path: &Path,
99 write_requester: &mut WriteRequester,
100) -> IoResult<()> {
101 let mut r1 = BufReader::new(r1);
102 let mut r2 = BufReader::new(r2);
103
104 let i1 = load(&mut r1, ImageFormat::PNG).unwrap();
105 let i2 = load(&mut r2, ImageFormat::PNG).unwrap();
106
107 match (i1, i2) {
108 (DynamicImage::ImageRgb8(i1), DynamicImage::ImageRgb8(i2)) => {
109 if i1.width() != i2.width() || i1.height() != i2.height() {
110 return write_requester.request(path.join("img-size.txt"), |w| {
111 writeln!(w, "image dimensions are different")?;
112 writeln!(w, "actual: width: {} height: {}", i1.width(), i1.height())?;
113 writeln!(w, "expected: width: {} height: {}", i2.width(), i2.height())?;
114 Ok(())
115 });
116 }
117 Ok(())
119 }
121 (DynamicImage::ImageRgba8(i1), DynamicImage::ImageRgba8(i2)) => {
122 if i1.width() != i2.width() || i1.height() != i2.height() {
123 return write_requester.request(path.join("img-size.txt"), |w| {
124 writeln!(w, "image dimensions are different")?;
125 writeln!(w, "actual: width: {} height: {}", i1.width(), i1.height())?;
126 writeln!(w, "expected: width: {} height: {}", i2.width(), i2.height())?;
127 Ok(())
128 });
129 }
130 Ok(())
132 }
134 (DynamicImage::ImageRgb8(_), DynamicImage::ImageRgba8(_)) => {
135 return write_requester.request(path.join("img-format.txt"), |w| {
136 writeln!(w, "image formats are different");
137 writeln!(w, "actual: RGB8");
138 writeln!(w, "expected: RGBA8 (Alpha)");
139 Ok(())
140 });
141 }
142 (DynamicImage::ImageRgba8(_), DynamicImage::ImageRgb8(_)) => {
143 return write_requester.request(path.join("img-format.txt"), |w| {
144 writeln!(w, "image formats are different");
145 writeln!(w, "actual: RGBA8 (Alpha)");
146 writeln!(w, "expected: RGB8");
147 Ok(())
148 });
149 }
150 (_, _) => panic!(),
151 }
152}