rpdfium 7676.6.4

A faithful Rust port of Google's PDFium PDF rendering engine
Documentation
//! Differential testing helpers for comparing rendered bitmaps.

use rpdfium_graphics::Bitmap;

/// Calculate the percentage of pixels that match exactly between two bitmaps.
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
}

/// Calculate the percentage of pixels that match within a tolerance.
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);
    }
}