agent_image_diff/
compare.rs1use image::RgbaImage;
2use rayon::prelude::*;
3
4use crate::antialias;
5use crate::color;
6
7pub struct CompareResult {
8 pub diff_mask: Vec<bool>,
9 pub delta_map: Vec<f64>,
10 pub width: u32,
11 pub height: u32,
12 pub aa_pixel_count: u64,
13}
14
15pub struct CompareOptions {
16 pub threshold: f64,
17 pub detect_antialias: bool,
18}
19
20pub fn compare(img1: &RgbaImage, img2: &RgbaImage, options: &CompareOptions) -> CompareResult {
26 let width = img1.width().min(img2.width());
27 let height = img1.height().min(img2.height());
28 let max_width = img1.width().max(img2.width());
29 let max_height = img1.height().max(img2.height());
30
31 let total = max_width as usize * max_height as usize;
32 let mut diff_mask = vec![false; total];
33 let mut delta_map = vec![0.0f64; total];
34
35 if max_width > width || max_height > height {
37 for y in 0..max_height {
38 for x in 0..max_width {
39 if x >= width || y >= height {
40 let idx = (y * max_width + x) as usize;
41 diff_mask[idx] = true;
42 delta_map[idx] = 1.0;
43 }
44 }
45 }
46 }
47
48 let rows: Vec<(Vec<bool>, Vec<f64>, u64)> = (0..height)
50 .into_par_iter()
51 .map(|y| {
52 let mut row_mask = vec![false; width as usize];
53 let mut row_delta = vec![0.0f64; width as usize];
54 let mut row_aa = 0u64;
55
56 for x in 0..width {
57 let px1 = img1.get_pixel(x, y).0;
58 let px2 = img2.get_pixel(x, y).0;
59
60 if px1 == px2 {
62 continue;
63 }
64
65 let delta = color::color_delta(px1, px2, false);
66 row_delta[x as usize] = delta;
67
68 if delta > options.threshold {
69 if options.detect_antialias
70 && (antialias::is_antialiased(img1, img2, x, y)
71 || antialias::is_antialiased(img2, img1, x, y))
72 {
73 row_aa += 1;
74 } else {
75 row_mask[x as usize] = true;
76 }
77 }
78 }
79
80 (row_mask, row_delta, row_aa)
81 })
82 .collect();
83
84 let mut total_aa = 0u64;
86 for (y, (row_mask, row_delta, row_aa)) in rows.into_iter().enumerate() {
87 let row_start = y * max_width as usize;
88 for (x, (mask, delta)) in row_mask.into_iter().zip(row_delta).enumerate() {
89 diff_mask[row_start + x] = mask;
90 delta_map[row_start + x] = delta;
91 }
92 total_aa += row_aa;
93 }
94
95 CompareResult {
96 diff_mask,
97 delta_map,
98 width: max_width,
99 height: max_height,
100 aa_pixel_count: total_aa,
101 }
102}