diff --git a/Cargo.toml b/Cargo.toml index 6cfd118a46..595e4c15bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -131,6 +131,11 @@ path = "tests/reference_images.rs" name = "reference_images" harness = false +[[test]] +path = "tests/imageops_reference.rs" +name = "imageops_reference" +harness = false + # because of https://github.com/image-rs/image/pull/2583 # TODO: remove when shipping the next major release after 0.25 [package.metadata.cargo-semver-checks.lints] diff --git a/tests/assets/bw-edge.png b/tests/assets/bw-edge.png new file mode 100644 index 0000000000..29256c4886 Binary files /dev/null and b/tests/assets/bw-edge.png differ diff --git a/tests/assets/cat.png b/tests/assets/cat.png new file mode 100644 index 0000000000..adba03ee08 Binary files /dev/null and b/tests/assets/cat.png differ diff --git a/tests/assets/noise.png b/tests/assets/noise.png new file mode 100644 index 0000000000..b5cb9dd5f9 Binary files /dev/null and b/tests/assets/noise.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=0.1.png b/tests/imageops/blur/bw-edge blur sigma=0.1.png new file mode 100644 index 0000000000..ae34f26a70 Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=0.1.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=0.5.png b/tests/imageops/blur/bw-edge blur sigma=0.5.png new file mode 100644 index 0000000000..e4ef08adda Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=0.5.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=1.0.png b/tests/imageops/blur/bw-edge blur sigma=1.0.png new file mode 100644 index 0000000000..d91d00ccd5 Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=1.0.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=1.5.png b/tests/imageops/blur/bw-edge blur sigma=1.5.png new file mode 100644 index 0000000000..b8af0b110c Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=1.5.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=10.0.png b/tests/imageops/blur/bw-edge blur sigma=10.0.png new file mode 100644 index 0000000000..039bfe406c Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=10.0.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=2.0.png b/tests/imageops/blur/bw-edge blur sigma=2.0.png new file mode 100644 index 0000000000..4418ac3b0e Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=2.0.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=5.0.png b/tests/imageops/blur/bw-edge blur sigma=5.0.png new file mode 100644 index 0000000000..9a73372d5c Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=5.0.png differ diff --git a/tests/imageops/blur/bw-edge blur sigma=50.0.png b/tests/imageops/blur/bw-edge blur sigma=50.0.png new file mode 100644 index 0000000000..e4ced1a70b Binary files /dev/null and b/tests/imageops/blur/bw-edge blur sigma=50.0.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=0.1.png b/tests/imageops/blur/bw-edge fast_blur sigma=0.1.png new file mode 100644 index 0000000000..b859ab6613 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=0.1.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=0.5.png b/tests/imageops/blur/bw-edge fast_blur sigma=0.5.png new file mode 100644 index 0000000000..b859ab6613 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=0.5.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=1.0.png b/tests/imageops/blur/bw-edge fast_blur sigma=1.0.png new file mode 100644 index 0000000000..b859ab6613 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=1.0.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=1.5.png b/tests/imageops/blur/bw-edge fast_blur sigma=1.5.png new file mode 100644 index 0000000000..b859ab6613 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=1.5.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=10.0.png b/tests/imageops/blur/bw-edge fast_blur sigma=10.0.png new file mode 100644 index 0000000000..b28baec97b Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=10.0.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=2.0.png b/tests/imageops/blur/bw-edge fast_blur sigma=2.0.png new file mode 100644 index 0000000000..3ac06eae87 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=2.0.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=5.0.png b/tests/imageops/blur/bw-edge fast_blur sigma=5.0.png new file mode 100644 index 0000000000..8aa3c037a5 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=5.0.png differ diff --git a/tests/imageops/blur/bw-edge fast_blur sigma=50.0.png b/tests/imageops/blur/bw-edge fast_blur sigma=50.0.png new file mode 100644 index 0000000000..d0a348c283 Binary files /dev/null and b/tests/imageops/blur/bw-edge fast_blur sigma=50.0.png differ diff --git a/tests/imageops/blur/noise blur sigma=0.1.png b/tests/imageops/blur/noise blur sigma=0.1.png new file mode 100644 index 0000000000..cc1cc0d556 Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=0.1.png differ diff --git a/tests/imageops/blur/noise blur sigma=0.5.png b/tests/imageops/blur/noise blur sigma=0.5.png new file mode 100644 index 0000000000..3dfe87eb5b Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=0.5.png differ diff --git a/tests/imageops/blur/noise blur sigma=1.0.png b/tests/imageops/blur/noise blur sigma=1.0.png new file mode 100644 index 0000000000..b435dcf50c Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=1.0.png differ diff --git a/tests/imageops/blur/noise blur sigma=1.5.png b/tests/imageops/blur/noise blur sigma=1.5.png new file mode 100644 index 0000000000..d9ab315b53 Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=1.5.png differ diff --git a/tests/imageops/blur/noise blur sigma=10.0.png b/tests/imageops/blur/noise blur sigma=10.0.png new file mode 100644 index 0000000000..2c1d6026f8 Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=10.0.png differ diff --git a/tests/imageops/blur/noise blur sigma=2.0.png b/tests/imageops/blur/noise blur sigma=2.0.png new file mode 100644 index 0000000000..840edc6e6a Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=2.0.png differ diff --git a/tests/imageops/blur/noise blur sigma=5.0.png b/tests/imageops/blur/noise blur sigma=5.0.png new file mode 100644 index 0000000000..b126b095c3 Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=5.0.png differ diff --git a/tests/imageops/blur/noise blur sigma=50.0.png b/tests/imageops/blur/noise blur sigma=50.0.png new file mode 100644 index 0000000000..a10b95b226 Binary files /dev/null and b/tests/imageops/blur/noise blur sigma=50.0.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=0.1.png b/tests/imageops/blur/noise fast_blur sigma=0.1.png new file mode 100644 index 0000000000..92a775ccc9 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=0.1.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=0.5.png b/tests/imageops/blur/noise fast_blur sigma=0.5.png new file mode 100644 index 0000000000..92a775ccc9 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=0.5.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=1.0.png b/tests/imageops/blur/noise fast_blur sigma=1.0.png new file mode 100644 index 0000000000..92a775ccc9 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=1.0.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=1.5.png b/tests/imageops/blur/noise fast_blur sigma=1.5.png new file mode 100644 index 0000000000..92a775ccc9 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=1.5.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=10.0.png b/tests/imageops/blur/noise fast_blur sigma=10.0.png new file mode 100644 index 0000000000..74cac98ecb Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=10.0.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=2.0.png b/tests/imageops/blur/noise fast_blur sigma=2.0.png new file mode 100644 index 0000000000..dc0aa03242 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=2.0.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=5.0.png b/tests/imageops/blur/noise fast_blur sigma=5.0.png new file mode 100644 index 0000000000..9f0bb897a0 Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=5.0.png differ diff --git a/tests/imageops/blur/noise fast_blur sigma=50.0.png b/tests/imageops/blur/noise fast_blur sigma=50.0.png new file mode 100644 index 0000000000..72f177bb0a Binary files /dev/null and b/tests/imageops/blur/noise fast_blur sigma=50.0.png differ diff --git a/tests/imageops/filter3x3 box blur.png b/tests/imageops/filter3x3 box blur.png new file mode 100644 index 0000000000..d43c5db9f1 Binary files /dev/null and b/tests/imageops/filter3x3 box blur.png differ diff --git a/tests/imageops/filter3x3 laplace.png b/tests/imageops/filter3x3 laplace.png new file mode 100644 index 0000000000..52fcf80317 Binary files /dev/null and b/tests/imageops/filter3x3 laplace.png differ diff --git a/tests/imageops/filter3x3 sharpen.png b/tests/imageops/filter3x3 sharpen.png new file mode 100644 index 0000000000..655c967346 Binary files /dev/null and b/tests/imageops/filter3x3 sharpen.png differ diff --git a/tests/imageops/huerotate angle=-45.png b/tests/imageops/huerotate angle=-45.png new file mode 100644 index 0000000000..df72d4cf85 Binary files /dev/null and b/tests/imageops/huerotate angle=-45.png differ diff --git a/tests/imageops/huerotate angle=0.png b/tests/imageops/huerotate angle=0.png new file mode 100644 index 0000000000..9f328050dc Binary files /dev/null and b/tests/imageops/huerotate angle=0.png differ diff --git a/tests/imageops/huerotate angle=180.png b/tests/imageops/huerotate angle=180.png new file mode 100644 index 0000000000..6802bf8a80 Binary files /dev/null and b/tests/imageops/huerotate angle=180.png differ diff --git a/tests/imageops/huerotate angle=30.png b/tests/imageops/huerotate angle=30.png new file mode 100644 index 0000000000..ac84ef29d8 Binary files /dev/null and b/tests/imageops/huerotate angle=30.png differ diff --git a/tests/imageops/huerotate grayscale.png b/tests/imageops/huerotate grayscale.png new file mode 100644 index 0000000000..204ef15c1e Binary files /dev/null and b/tests/imageops/huerotate grayscale.png differ diff --git a/tests/imageops/invert.png b/tests/imageops/invert.png new file mode 100644 index 0000000000..b5d605b962 Binary files /dev/null and b/tests/imageops/invert.png differ diff --git a/tests/imageops_reference.rs b/tests/imageops_reference.rs new file mode 100644 index 0000000000..a842406949 --- /dev/null +++ b/tests/imageops_reference.rs @@ -0,0 +1,166 @@ +use image::{DynamicImage, GenericImageView, GrayImage, RgbImage, RgbaImage}; +use std::{ + path::{Path, PathBuf}, + sync::OnceLock, +}; + +use libtest_mimic::{Arguments, Trial}; + +fn main() -> std::process::ExitCode { + let tests_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests"); + let assets_dir = tests_dir.join("assets"); + let reference_dir = tests_dir.join("imageops"); + + static IMAGES: OnceLock<[Image; 3]> = OnceLock::new(); + let [bw_edge, noise, cat] = IMAGES.get_or_init(|| { + [ + Image::open(&assets_dir.join("bw-edge.png")), + Image::open(&assets_dir.join("noise.png")), + Image::open(&assets_dir.join("cat.png")), + ] + }); + + let mut trials = ImageTrials::new(reference_dir); + + // blur & fast_blur with various sigmas + for image in [bw_edge, noise] { + for sigma in [0.1, 0.5, 1.0, 1.5, 2.0, 5.0, 10.0, 50.0] { + trials.add( + format!("blur/{} blur sigma={sigma:.1}", image.name), + move || { + image::imageops::blur_advanced( + &image.rgb, + image::imageops::GaussianBlurParameters::new_from_sigma(sigma), + ) + }, + ); + trials.add( + format!("blur/{} fast_blur sigma={sigma:.1}", image.name), + move || image::imageops::fast_blur(&image.rgb, sigma), + ); + } + } + + // huerotate with various angles + for angle in [0, 30, 180, -45] { + trials.add(format!("huerotate angle={angle}"), move || { + image::imageops::huerotate(&cat.rgba, angle) + }); + } + trials.add("huerotate grayscale", move || { + image::imageops::huerotate(&cat.gray, 180) + }); + + // invert + trials.add("invert", move || { + let mut img = cat.rgba.clone(); + image::imageops::invert(&mut img); + img + }); + + // filter3x3 + trials.add("filter3x3 laplace", move || { + image::imageops::filter3x3(&cat.rgb, &[1.0, 1.0, 1.0, 1.0, -8.0, 1.0, 1.0, 1.0, 1.0]) + }); + trials.add("filter3x3 box blur", move || { + image::imageops::filter3x3(&cat.rgb, &[1.0 / 9.0; 9]) + }); + trials.add("filter3x3 sharpen", move || { + image::imageops::filter3x3(&cat.rgb, &[0.0, -0.5, 0.0, -0.5, 3.0, -0.5, 0.0, -0.5, 0.0]) + }); + + let args = Arguments::from_args(); + libtest_mimic::run(&args, trials.trials).exit_code() +} + +struct ImageTrials { + trials: Vec, + reference_dir: PathBuf, +} +impl ImageTrials { + fn new(reference_dir: PathBuf) -> Self { + Self { + trials: Vec::new(), + reference_dir, + } + } + fn add>( + &mut self, + name: impl AsRef, + f: impl FnOnce() -> I + Send + 'static, + ) { + if !cfg!(feature = "png") { + self.trials + .push(Trial::test(name.as_ref(), move || Ok(())).with_ignored_flag(true)); + return; + } + + let path = self.reference_dir.join(format!("{}.png", name.as_ref())); + self.trials.push(Trial::test(name.as_ref(), move || { + let image = f().into(); + compare_to_output(&path, image); + Ok(()) + })); + } +} + +struct Image { + name: String, + rgba: RgbaImage, + rgb: RgbImage, + gray: GrayImage, +} +impl Image { + fn open(path: &Path) -> Self { + let name = path.file_stem().unwrap().to_str().unwrap().to_string(); + + let image = if cfg!(feature = "png") { + image::open(path).unwrap() + } else { + DynamicImage::new_rgb8(8, 8) + }; + + Self { + name, + rgba: image.to_rgba8(), + rgb: image.to_rgb8(), + gray: image.to_luma8(), + } + } +} + +fn compare_to_output(path: &Path, image: DynamicImage) { + let name = path.file_stem().unwrap().to_str().unwrap(); + + if !path.exists() { + #[cfg(feature = "png")] + save_png(path, image); + panic!("Saved output for {name} to {path:?}. Please verify it is correct and commit it."); + } + + let reference = image::open(path).unwrap(); + assert_eq!( + image.dimensions(), + reference.dimensions(), + "Output dimensions differ for {name}" + ); + assert_eq!( + image.as_bytes(), + reference.as_bytes(), + "Output pixel data differs for {name}" + ); +} +#[cfg(feature = "png")] +fn save_png(path: &Path, image: DynamicImage) { + use image::codecs::png::{CompressionType, FilterType, PngEncoder}; + + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + + image + .write_with_encoder(PngEncoder::new_with_quality( + std::io::BufWriter::new(std::fs::File::create(path).unwrap()), + CompressionType::Best, + FilterType::Adaptive, + )) + .unwrap(); +}