use image::RgbaImage;
use rayon::prelude::*;
use crate::antialias;
use crate::color;
pub struct CompareResult {
pub diff_mask: Vec<bool>,
pub delta_map: Vec<f64>,
pub width: u32,
pub height: u32,
pub aa_pixel_count: u64,
}
pub struct CompareOptions {
pub threshold: f64,
pub detect_antialias: bool,
}
pub fn compare(img1: &RgbaImage, img2: &RgbaImage, options: &CompareOptions) -> CompareResult {
let width = img1.width().min(img2.width());
let height = img1.height().min(img2.height());
let max_width = img1.width().max(img2.width());
let max_height = img1.height().max(img2.height());
let total = max_width as usize * max_height as usize;
let mut diff_mask = vec![false; total];
let mut delta_map = vec![0.0f64; total];
if max_width > width || max_height > height {
for y in 0..max_height {
for x in 0..max_width {
if x >= width || y >= height {
let idx = (y * max_width + x) as usize;
diff_mask[idx] = true;
delta_map[idx] = 1.0;
}
}
}
}
let rows: Vec<(Vec<bool>, Vec<f64>, u64)> = (0..height)
.into_par_iter()
.map(|y| {
let mut row_mask = vec![false; width as usize];
let mut row_delta = vec![0.0f64; width as usize];
let mut row_aa = 0u64;
for x in 0..width {
let px1 = img1.get_pixel(x, y).0;
let px2 = img2.get_pixel(x, y).0;
if px1 == px2 {
continue;
}
let delta = color::color_delta(px1, px2, false);
row_delta[x as usize] = delta;
if delta > options.threshold {
if options.detect_antialias
&& (antialias::is_antialiased(img1, img2, x, y)
|| antialias::is_antialiased(img2, img1, x, y))
{
row_aa += 1;
} else {
row_mask[x as usize] = true;
}
}
}
(row_mask, row_delta, row_aa)
})
.collect();
let mut total_aa = 0u64;
for (y, (row_mask, row_delta, row_aa)) in rows.into_iter().enumerate() {
let row_start = y * max_width as usize;
for (x, (mask, delta)) in row_mask.into_iter().zip(row_delta).enumerate() {
diff_mask[row_start + x] = mask;
delta_map[row_start + x] = delta;
}
total_aa += row_aa;
}
CompareResult {
diff_mask,
delta_map,
width: max_width,
height: max_height,
aa_pixel_count: total_aa,
}
}