use rpdfium_graphics::Bitmap;
pub fn pixel_match_percentage(a: &Bitmap, b: &Bitmap) -> f64 {
if a.width != b.width || a.height != b.height || a.format != b.format {
return 0.0;
}
let bpp = a.bytes_per_pixel() as usize;
let total = (a.width * a.height) as usize;
if total == 0 {
return 100.0;
}
let matching = a
.data
.chunks(bpp)
.zip(b.data.chunks(bpp))
.filter(|(pa, pb)| pa == pb)
.count();
(matching as f64 / total as f64) * 100.0
}
pub fn pixel_match_with_tolerance(a: &Bitmap, b: &Bitmap, tolerance: u8) -> f64 {
if a.width != b.width || a.height != b.height || a.format != b.format {
return 0.0;
}
let bpp = a.bytes_per_pixel() as usize;
let total = (a.width * a.height) as usize;
if total == 0 {
return 100.0;
}
let matching = a
.data
.chunks(bpp)
.zip(b.data.chunks(bpp))
.filter(|(pa, pb)| {
pa.iter().zip(pb.iter()).all(|(&a_val, &b_val)| {
(a_val as i16 - b_val as i16).unsigned_abs() <= tolerance as u16
})
})
.count();
(matching as f64 / total as f64) * 100.0
}
#[cfg(test)]
mod tests {
use super::*;
use rpdfium_graphics::BitmapFormat;
#[test]
fn test_identical_bitmaps_100_percent() {
let a = Bitmap::new_white(10, 10, BitmapFormat::Rgba32);
let b = Bitmap::new_white(10, 10, BitmapFormat::Rgba32);
assert_eq!(pixel_match_percentage(&a, &b), 100.0);
}
#[test]
fn test_different_size_0_percent() {
let a = Bitmap::new(10, 10, BitmapFormat::Rgba32);
let b = Bitmap::new(20, 20, BitmapFormat::Rgba32);
assert_eq!(pixel_match_percentage(&a, &b), 0.0);
}
#[test]
fn test_tolerance_matching() {
let mut a = Bitmap::new(1, 1, BitmapFormat::Rgba32);
a.data = vec![100, 100, 100, 255];
let mut b = Bitmap::new(1, 1, BitmapFormat::Rgba32);
b.data = vec![105, 100, 100, 255];
assert_eq!(pixel_match_with_tolerance(&a, &b, 5), 100.0);
assert_eq!(pixel_match_with_tolerance(&a, &b, 4), 0.0);
}
}