pixelmatch 0.1.0

Pixel-level image comparison
Documentation
use paste::paste;
use pixelmatch::{pixelmatch, Options};
use std::{env, fs, path::PathBuf};

macro_rules! diff_test {
  ($img1_path: ident, $img2_path: ident, $diff_path: ident, $options: expr, $options_name: ident, $expected_mismatch: literal) => {
    paste! {
      #[test]
      fn [<comparing_ $img1_path _to_ $img2_path _ $options_name>]() -> Result<(), Box<dyn std::error::Error>>{
        let img1: &[u8] = include_bytes!(concat!("fixtures/", stringify!([< $img1_path >]), ".png"));
        let img2: &[u8] = include_bytes!(concat!("fixtures/", stringify!([< $img2_path >]), ".png"));

        let mut img_out = Vec::new();
        let output = Some(&mut img_out);

        let mismatch1 = pixelmatch(img1, img2, output, None, None, $options)?;
        let mismatch2 = pixelmatch(img1, img2, Option::<&mut Vec<u8>>::None, None, None, $options)?;

        if env::var("UPDATE").is_ok() {
          let mut diff_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
          diff_path.push(concat!("tests/fixtures/", stringify!([< $diff_path >]), ".png"));
          fs::write(diff_path, img_out)?;
        } else {
          let expected_diff: &[u8] = include_bytes!(concat!("fixtures/", stringify!([< $diff_path >]), ".png"));
          assert_eq!(img_out, expected_diff);
        }

        assert_eq!(mismatch1, $expected_mismatch);
        assert_eq!(mismatch1, mismatch2);

        Ok(())
      }
    }
  };
}

diff_test!(
    img_1a,
    img_1b,
    img_1diff,
    Some(Options {
        threshold: 0.05,
        ..Default::default()
    }),
    normal,
    143
);
diff_test!(
    img_1a,
    img_1b,
    img_1diffmask,
    Some(Options {
        threshold: 0.05,
        include_aa: false,
        diff_mask: true,
        ..Default::default()
    }),
    diffmask,
    143
);
diff_test!(
    img_1a,
    img_1a,
    img_1emptydiffmask,
    Some(Options {
        threshold: 0.0,
        diff_mask: true,
        ..Default::default()
    }),
    emptydiffmask,
    0
);
diff_test!(
    img_2a,
    img_2b,
    img_2diff,
    Some(Options {
        threshold: 0.05,
        alpha: 0.5,
        aa_color: [0, 192, 0, 255],
        diff_color: [255, 0, 255, 255],
        ..Default::default()
    }),
    alpha_antialias_color_diff_color,
    12437
);
diff_test!(
    img_3a,
    img_3b,
    img_3diff,
    Some(Options {
        threshold: 0.05,
        ..Default::default()
    }),
    normal,
    212
);
diff_test!(
    img_4a,
    img_4b,
    img_4diff,
    Some(Options {
        threshold: 0.05,
        ..Default::default()
    }),
    normal,
    36049
);
diff_test!(
    img_5a,
    img_5b,
    img_5diff,
    Some(Options {
        threshold: 0.05,
        ..Default::default()
    }),
    normal,
    0
);
diff_test!(
    img_6a,
    img_6b,
    img_6diff,
    Some(Options {
        threshold: 0.05,
        ..Default::default()
    }),
    normal,
    51
);
diff_test!(
    img_6a,
    img_6a,
    img_6empty,
    Some(Options {
        threshold: 0.0,
        ..Default::default()
    }),
    empty,
    0
);
diff_test!(
    img_7a,
    img_7b,
    img_7diff,
    Some(Options {
        diff_color_alt: Some([0, 255, 0, 255]),
        ..Default::default()
    }),
    diff_color_alt,
    2448
);

#[test]
fn throws_error_if_image_sizes_do_not_match() {
    let img1: &[u8] = include_bytes!("fixtures/img_1a.png");
    let img2: &[u8] = include_bytes!("fixtures/img_2a.png");
    let output: Option<&mut Vec<u8>> = None;
    assert_eq!(
        pixelmatch(img1, img2, output, Some(2), Some(1), None).map_err(|err| err.to_string()),
        Err(String::from("Image sizes do not match."))
    );
}