diff --git a/tests/reference/bmp/images/imagemagick_invalid_run_length_issue_2321.bmp.png b/tests/reference/bmp/images/imagemagick_invalid_run_length_issue_2321.bmp.png new file mode 100644 index 0000000000..6c62861e00 Binary files /dev/null and b/tests/reference/bmp/images/imagemagick_invalid_run_length_issue_2321.bmp.png differ diff --git a/tests/reference/bmp/images/lenient/badpalettesize.bmp.png b/tests/reference/bmp/images/lenient/badpalettesize.bmp.png new file mode 100644 index 0000000000..5e65b6d21e Binary files /dev/null and b/tests/reference/bmp/images/lenient/badpalettesize.bmp.png differ diff --git a/tests/reference/bmp/images/lenient/badplanes.bmp.png b/tests/reference/bmp/images/lenient/badplanes.bmp.png new file mode 100644 index 0000000000..4c979f2ac5 Binary files /dev/null and b/tests/reference/bmp/images/lenient/badplanes.bmp.png differ diff --git a/tests/reference/bmp/images/lenient/pal8oversizepal.bmp.png b/tests/reference/bmp/images/lenient/pal8oversizepal.bmp.png new file mode 100644 index 0000000000..5e65b6d21e Binary files /dev/null and b/tests/reference/bmp/images/lenient/pal8oversizepal.bmp.png differ diff --git a/tests/reference/bmp/images/lenient/rgb16-880.bmp.png b/tests/reference/bmp/images/lenient/rgb16-880.bmp.png new file mode 100644 index 0000000000..43cf534a44 Binary files /dev/null and b/tests/reference/bmp/images/lenient/rgb16-880.bmp.png differ diff --git a/tests/reference/bmp/images/lenient/rletopdown.bmp.png b/tests/reference/bmp/images/lenient/rletopdown.bmp.png new file mode 100644 index 0000000000..5e65b6d21e Binary files /dev/null and b/tests/reference/bmp/images/lenient/rletopdown.bmp.png differ diff --git a/tests/reference/exr/cropping - data window differs display window.exr.tiff b/tests/reference/exr/cropping - data window differs display window.exr.tiff new file mode 100644 index 0000000000..d7ff479ce8 Binary files /dev/null and b/tests/reference/exr/cropping - data window differs display window.exr.tiff differ diff --git a/tests/reference/exr/cropping - uncropped original.exr.tiff b/tests/reference/exr/cropping - uncropped original.exr.tiff new file mode 100644 index 0000000000..d7ff479ce8 Binary files /dev/null and b/tests/reference/exr/cropping - uncropped original.exr.tiff differ diff --git a/tests/reference/exr/overexposed gradient - data window equals display window.exr.tiff b/tests/reference/exr/overexposed gradient - data window equals display window.exr.tiff new file mode 100644 index 0000000000..da684f0f0a Binary files /dev/null and b/tests/reference/exr/overexposed gradient - data window equals display window.exr.tiff differ diff --git a/tests/reference/exr/overexposed gradient.hdr.tiff b/tests/reference/exr/overexposed gradient.hdr.tiff new file mode 100644 index 0000000000..a9f9f57c24 Binary files /dev/null and b/tests/reference/exr/overexposed gradient.hdr.tiff differ diff --git a/tests/reference/farbfeld/transparency/acid2.ff.png b/tests/reference/farbfeld/transparency/acid2.ff.png new file mode 100644 index 0000000000..42e4cda4a8 Binary files /dev/null and b/tests/reference/farbfeld/transparency/acid2.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbbn0g04.ff.png b/tests/reference/farbfeld/transparency/tbbn0g04.ff.png new file mode 100644 index 0000000000..1268b3113f Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbbn0g04.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbbn3p08.ff.png b/tests/reference/farbfeld/transparency/tbbn3p08.ff.png new file mode 100644 index 0000000000..4367b5b87a Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbbn3p08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbgn3p08.ff.png b/tests/reference/farbfeld/transparency/tbgn3p08.ff.png new file mode 100644 index 0000000000..4367b5b87a Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbgn3p08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbrn2c08.ff.png b/tests/reference/farbfeld/transparency/tbrn2c08.ff.png new file mode 100644 index 0000000000..91b80b900b Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbrn2c08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbwn3p08.ff.png b/tests/reference/farbfeld/transparency/tbwn3p08.ff.png new file mode 100644 index 0000000000..4367b5b87a Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbwn3p08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tbyn3p08.ff.png b/tests/reference/farbfeld/transparency/tbyn3p08.ff.png new file mode 100644 index 0000000000..4367b5b87a Binary files /dev/null and b/tests/reference/farbfeld/transparency/tbyn3p08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tm3n3p02.ff.png b/tests/reference/farbfeld/transparency/tm3n3p02.ff.png new file mode 100644 index 0000000000..9957808bdc Binary files /dev/null and b/tests/reference/farbfeld/transparency/tm3n3p02.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tp0n0g08.ff.png b/tests/reference/farbfeld/transparency/tp0n0g08.ff.png new file mode 100644 index 0000000000..711f24176e Binary files /dev/null and b/tests/reference/farbfeld/transparency/tp0n0g08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tp0n2c08.ff.png b/tests/reference/farbfeld/transparency/tp0n2c08.ff.png new file mode 100644 index 0000000000..f3ee3247be Binary files /dev/null and b/tests/reference/farbfeld/transparency/tp0n2c08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tp0n3p08.ff.png b/tests/reference/farbfeld/transparency/tp0n3p08.ff.png new file mode 100644 index 0000000000..e8a4d77d41 Binary files /dev/null and b/tests/reference/farbfeld/transparency/tp0n3p08.ff.png differ diff --git a/tests/reference/farbfeld/transparency/tp1n3p08.ff.png b/tests/reference/farbfeld/transparency/tp1n3p08.ff.png new file mode 100644 index 0000000000..4367b5b87a Binary files /dev/null and b/tests/reference/farbfeld/transparency/tp1n3p08.ff.png differ diff --git a/tests/reference/gif/anim/any-disposal.gif.anim_01.png b/tests/reference/gif/anim/any-disposal.gif.anim_01.png new file mode 100644 index 0000000000..c533ee9933 Binary files /dev/null and b/tests/reference/gif/anim/any-disposal.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/any-disposal.gif.anim_02.png b/tests/reference/gif/anim/any-disposal.gif.anim_02.png new file mode 100644 index 0000000000..0afd31d09e Binary files /dev/null and b/tests/reference/gif/anim/any-disposal.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/any-disposal.gif.anim_03.png b/tests/reference/gif/anim/any-disposal.gif.anim_03.png new file mode 100644 index 0000000000..8340dba9a8 Binary files /dev/null and b/tests/reference/gif/anim/any-disposal.gif.anim_03.png differ diff --git a/tests/reference/gif/anim/any-disposal.gif.anim_04.png b/tests/reference/gif/anim/any-disposal.gif.anim_04.png new file mode 100644 index 0000000000..69601127c9 Binary files /dev/null and b/tests/reference/gif/anim/any-disposal.gif.anim_04.png differ diff --git a/tests/reference/gif/anim/any-disposal.gif.anim_05.png b/tests/reference/gif/anim/any-disposal.gif.anim_05.png new file mode 100644 index 0000000000..c8172d4cdd Binary files /dev/null and b/tests/reference/gif/anim/any-disposal.gif.anim_05.png differ diff --git a/tests/reference/gif/anim/border_touching_layers.gif.anim_01.png b/tests/reference/gif/anim/border_touching_layers.gif.anim_01.png new file mode 100644 index 0000000000..9fb6606484 Binary files /dev/null and b/tests/reference/gif/anim/border_touching_layers.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/border_touching_layers.gif.anim_02.png b/tests/reference/gif/anim/border_touching_layers.gif.anim_02.png new file mode 100644 index 0000000000..66ebb93989 Binary files /dev/null and b/tests/reference/gif/anim/border_touching_layers.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/issue_1455_undersized.gif.anim_01.png b/tests/reference/gif/anim/issue_1455_undersized.gif.anim_01.png new file mode 100644 index 0000000000..2b79f4f471 Binary files /dev/null and b/tests/reference/gif/anim/issue_1455_undersized.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/issue_1455_undersized.gif.anim_02.png b/tests/reference/gif/anim/issue_1455_undersized.gif.anim_02.png new file mode 100644 index 0000000000..69b62c10dd Binary files /dev/null and b/tests/reference/gif/anim/issue_1455_undersized.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_01.png b/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_01.png new file mode 100644 index 0000000000..319566996e Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_02.png b/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_02.png new file mode 100644 index 0000000000..30cca1ef60 Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-combine.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-combine.gif.png b/tests/reference/gif/anim/large-gif-anim-combine.gif.png new file mode 100644 index 0000000000..319566996e Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-combine.gif.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_01.png b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_01.png new file mode 100644 index 0000000000..52d8d6ff1a Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_02.png b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_02.png new file mode 100644 index 0000000000..6c26ef8a76 Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.png b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.png new file mode 100644 index 0000000000..52d8d6ff1a Binary files /dev/null and b/tests/reference/gif/anim/large-gif-anim-full-frame-replace.gif.png differ diff --git a/tests/reference/gif/anim/mixed-disposal.gif.anim_01.png b/tests/reference/gif/anim/mixed-disposal.gif.anim_01.png new file mode 100644 index 0000000000..c533ee9933 Binary files /dev/null and b/tests/reference/gif/anim/mixed-disposal.gif.anim_01.png differ diff --git a/tests/reference/gif/anim/mixed-disposal.gif.anim_02.png b/tests/reference/gif/anim/mixed-disposal.gif.anim_02.png new file mode 100644 index 0000000000..0afd31d09e Binary files /dev/null and b/tests/reference/gif/anim/mixed-disposal.gif.anim_02.png differ diff --git a/tests/reference/gif/anim/mixed-disposal.gif.anim_03.png b/tests/reference/gif/anim/mixed-disposal.gif.anim_03.png new file mode 100644 index 0000000000..41d1417743 Binary files /dev/null and b/tests/reference/gif/anim/mixed-disposal.gif.anim_03.png differ diff --git a/tests/reference/gif/anim/mixed-disposal.gif.anim_04.png b/tests/reference/gif/anim/mixed-disposal.gif.anim_04.png new file mode 100644 index 0000000000..049b954fc0 Binary files /dev/null and b/tests/reference/gif/anim/mixed-disposal.gif.anim_04.png differ diff --git a/tests/reference/gif/anim/mixed-disposal.gif.anim_05.png b/tests/reference/gif/anim/mixed-disposal.gif.anim_05.png new file mode 100644 index 0000000000..33f7fad4df Binary files /dev/null and b/tests/reference/gif/anim/mixed-disposal.gif.anim_05.png differ diff --git a/tests/reference/ico/images/bmp_v5_with_icc.ico.png b/tests/reference/ico/images/bmp_v5_with_icc.ico.png new file mode 100644 index 0000000000..0baa39e6c3 Binary files /dev/null and b/tests/reference/ico/images/bmp_v5_with_icc.ico.png differ diff --git a/tests/reference/jpg/exif-xmp-metadata.jpg.png b/tests/reference/jpg/exif-xmp-metadata.jpg.png new file mode 100644 index 0000000000..c63dc0c099 Binary files /dev/null and b/tests/reference/jpg/exif-xmp-metadata.jpg.png differ diff --git a/tests/reference/jpg/iptc.jpg.png b/tests/reference/jpg/iptc.jpg.png new file mode 100644 index 0000000000..962ff12ec8 Binary files /dev/null and b/tests/reference/jpg/iptc.jpg.png differ diff --git a/tests/reference/jpg/portrait_2.jpg.png b/tests/reference/jpg/portrait_2.jpg.png new file mode 100644 index 0000000000..d9a4d7efa1 Binary files /dev/null and b/tests/reference/jpg/portrait_2.jpg.png differ diff --git a/tests/reference/png/16bpc/basi0g16.png.png b/tests/reference/png/16bpc/basi0g16.png.png new file mode 100644 index 0000000000..9d5fc6a6ad Binary files /dev/null and b/tests/reference/png/16bpc/basi0g16.png.png differ diff --git a/tests/reference/png/16bpc/basn2c16.png.png b/tests/reference/png/16bpc/basn2c16.png.png new file mode 100644 index 0000000000..1eeecf602e Binary files /dev/null and b/tests/reference/png/16bpc/basn2c16.png.png differ diff --git a/tests/reference/png/bugfixes/issue#2026.png.png b/tests/reference/png/bugfixes/issue#2026.png.png new file mode 100644 index 0000000000..33b44bd3ef Binary files /dev/null and b/tests/reference/png/bugfixes/issue#2026.png.png differ diff --git a/tests/reference/png/iptc.png.png b/tests/reference/png/iptc.png.png new file mode 100644 index 0000000000..a04ae148a1 Binary files /dev/null and b/tests/reference/png/iptc.png.png differ diff --git a/tests/reference/png/transparency/tp1n3p08_xmp.png.png b/tests/reference/png/transparency/tp1n3p08_xmp.png.png new file mode 100644 index 0000000000..cc19979dae Binary files /dev/null and b/tests/reference/png/transparency/tp1n3p08_xmp.png.png differ diff --git a/tests/reference/qoi/basic-test.qoi.png b/tests/reference/qoi/basic-test.qoi.png new file mode 100644 index 0000000000..cbaa10936b Binary files /dev/null and b/tests/reference/qoi/basic-test.qoi.png differ diff --git a/tests/reference/tga/encoding/black_white.tga.png b/tests/reference/tga/encoding/black_white.tga.png new file mode 100644 index 0000000000..3d3322a352 Binary files /dev/null and b/tests/reference/tga/encoding/black_white.tga.png differ diff --git a/tests/reference/tga/testsuite/ccm8.tga.png b/tests/reference/tga/testsuite/ccm8.tga.png new file mode 100644 index 0000000000..4c8f83ff11 Binary files /dev/null and b/tests/reference/tga/testsuite/ccm8.tga.png differ diff --git a/tests/reference/tga/testsuite/ucm8.tga.png b/tests/reference/tga/testsuite/ucm8.tga.png new file mode 100644 index 0000000000..4c8f83ff11 Binary files /dev/null and b/tests/reference/tga/testsuite/ucm8.tga.png differ diff --git a/tests/reference/tga/testsuite/utc16.tga.png b/tests/reference/tga/testsuite/utc16.tga.png new file mode 100644 index 0000000000..4c8f83ff11 Binary files /dev/null and b/tests/reference/tga/testsuite/utc16.tga.png differ diff --git a/tests/reference/tiff/testsuite/l1_xmp.tiff.png b/tests/reference/tiff/testsuite/l1_xmp.tiff.png new file mode 100644 index 0000000000..33b21d14f6 Binary files /dev/null and b/tests/reference/tiff/testsuite/l1_xmp.tiff.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_01.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_01.png new file mode 100644 index 0000000000..7416c725b5 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_01.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_02.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_02.png new file mode 100644 index 0000000000..02e2882c5c Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_02.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_03.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_03.png new file mode 100644 index 0000000000..569704a897 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_03.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_04.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_04.png new file mode 100644 index 0000000000..db301fad56 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_04.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_05.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_05.png new file mode 100644 index 0000000000..d0fab0ca72 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_05.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_06.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_06.png new file mode 100644 index 0000000000..33c4c272da Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_06.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_07.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_07.png new file mode 100644 index 0000000000..585eab11fe Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_07.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_08.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_08.png new file mode 100644 index 0000000000..ad4c2e1e7e Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_08.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_09.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_09.png new file mode 100644 index 0000000000..68d7698ac7 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_09.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_10.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_10.png new file mode 100644 index 0000000000..c8b2c58246 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_10.png differ diff --git a/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_11.png b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_11.png new file mode 100644 index 0000000000..866e8001e6 Binary files /dev/null and b/tests/reference/webp/extended_images/advertises_rgba_but_frames_are_rgb.webp.anim_11.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_01.png b/tests/reference/webp/extended_images/anim.webp.anim_01.png new file mode 100644 index 0000000000..206ec37061 Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_01.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_02.png b/tests/reference/webp/extended_images/anim.webp.anim_02.png new file mode 100644 index 0000000000..f3f0a7779d Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_02.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_03.png b/tests/reference/webp/extended_images/anim.webp.anim_03.png new file mode 100644 index 0000000000..a1e0170dcd Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_03.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_04.png b/tests/reference/webp/extended_images/anim.webp.anim_04.png new file mode 100644 index 0000000000..d3df7ea37d Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_04.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_05.png b/tests/reference/webp/extended_images/anim.webp.anim_05.png new file mode 100644 index 0000000000..65769f9e37 Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_05.png differ diff --git a/tests/reference/webp/extended_images/anim.webp.anim_06.png b/tests/reference/webp/extended_images/anim.webp.anim_06.png new file mode 100644 index 0000000000..f66d716baf Binary files /dev/null and b/tests/reference/webp/extended_images/anim.webp.anim_06.png differ diff --git a/tests/reference/webp/lossless_images/simple_xmp.webp.png b/tests/reference/webp/lossless_images/simple_xmp.webp.png new file mode 100644 index 0000000000..e3979a6ef5 Binary files /dev/null and b/tests/reference/webp/lossless_images/simple_xmp.webp.png differ diff --git a/tests/reference_images.rs b/tests/reference_images.rs index f56d1dc87b..c1596aabf6 100644 --- a/tests/reference_images.rs +++ b/tests/reference_images.rs @@ -1,16 +1,15 @@ //! Compares the decoding results with reference renderings. //! //! This test harness automatically detects all reference images in -//! `tests/reference/...` and compares them to the associated file in -//! `tests/images/...`. +//! `tests/images/...` and compares them to the associated file in +//! `tests/reference/...`. -use std::fs; +use std::error::Error; use std::fs::File; -use std::io::{self, BufWriter}; -use std::path::Path; -use std::str::FromStr; +use std::io::BufWriter; +use std::path::{Path, PathBuf}; -use image::ColorType; +use image::{ColorType, GenericImageView}; use image::{DynamicImage, ImageFormat}; use libtest_mimic::{Arguments, Failed, Trial}; use walkdir::WalkDir; @@ -28,161 +27,96 @@ fn main() { .join("tests") .join("output"); - for entry in WalkDir::new(&reference_dir) { + for entry in WalkDir::new(&image_dir) { let entry = entry.unwrap(); - if !entry.file_type().is_file() || entry.path().extension() == Some("txt".as_ref()) { + if !entry.file_type().is_file() + || entry.path().extension().is_none() + || entry.path().extension() == Some("txt".as_ref()) + { continue; } - let relative_path = entry - .path() - .strip_prefix(&reference_dir) - .unwrap() - .to_path_buf(); - let Ok(case) = ReferenceTestCase::from_str(entry.file_name().to_str().unwrap()) else { - trials.push(Trial::test( - format!("reference_images {}", relative_path.display()), - || Err("Malformed reference image filename".into()), - )); - continue; - }; - let path = entry.into_path(); - - let original_relative_path = relative_path.parent().unwrap().join(&case.orig_filename); - let img_path = image_dir.join(&original_relative_path); - - let test_name = match case.kind { - ReferenceTestKind::AnimatedFrame { frame } => format!( - "reference tests/images/{}[{}]", - original_relative_path.display(), - frame + 1 - ), - ReferenceTestKind::SingleImage => { - format!( - "reference tests/images/{}", - original_relative_path.display() - ) - } - }; + let relative_path = entry.path().strip_prefix(&image_dir).unwrap().to_path_buf(); + let test_name = format!("image {}", relative_path.display()); - let image_format = img_path.extension().and_then(ImageFormat::from_extension); - let reference_format = relative_path - .extension() - .and_then(ImageFormat::from_extension) - .expect("reference image with unknown extension"); + let image_path = entry.into_path(); + let output_base_path = output_dir.join(&relative_path); + let reference_base_path = reference_dir.join(&relative_path); - if image_format.is_none() { + let Ok(image_format) = ImageFormat::from_path(&image_path) else { trials.push(Trial::test( test_name, || Err("Unknown image format".into()), )); continue; - } + }; - if !image_format.unwrap().reading_enabled() || !reference_format.reading_enabled() { + // ignore if we can't read the test image + if !image_format.reading_enabled() { + trials.push(Trial::test(test_name, || Ok(())).with_ignored_flag(true)); + continue; + } + // ignore if we can't read the reference image + if !ImageFormat::Png.reading_enabled() || !ImageFormat::Tiff.reading_enabled() { + trials.push(Trial::test(test_name, || Ok(())).with_ignored_flag(true)); + continue; + } + // QOI is broken on big endian targets + // See https://github.com/image-rs/image/issues/2808 + if image_format == ImageFormat::Qoi && cfg!(target_endian = "big") { trials.push(Trial::test(test_name, || Ok(())).with_ignored_flag(true)); continue; } - let output_dir = output_dir.clone(); trials.push(Trial::test(test_name, move || -> Result<(), Failed> { // Load the test image - let mut test_img = match case.kind { - ReferenceTestKind::SingleImage => { - // Read the input file as a single image - image::open(&img_path)? - } - ReferenceTestKind::AnimatedFrame { frame: frame_num } => { - // TODO: Once there's a generic API for animated images, switch to that instead. - match image_format { - #[cfg(feature = "gif")] - Some(image::ImageFormat::Gif) => { - // Interpret the input file as an animation file - use image::AnimationDecoder; - let stream = io::BufReader::new(fs::File::open(&img_path).unwrap()); - let decoder = image::codecs::gif::GifDecoder::new(stream)?; - let mut frames = decoder.into_frames().collect_frames()?; - - // Select a single frame - let frame = frames.drain(frame_num..).next().unwrap(); - - // Convert the frame to a`RgbaImage` - DynamicImage::from(frame.into_buffer()) - } - - #[cfg(feature = "png")] - Some(image::ImageFormat::Png) => { - // Interpret the input file as an animation file - use image::AnimationDecoder; - let stream = io::BufReader::new(fs::File::open(&img_path).unwrap()); - let decoder = image::codecs::png::PngDecoder::new(stream)?.apng()?; - let mut frames = decoder.into_frames().collect_frames()?; - - // Select a single frame - let frame = frames.drain(frame_num..).next().unwrap(); - - // Convert the frame to a`RgbaImage` - DynamicImage::from(frame.into_buffer()) - } - _ => unreachable!( - "Format is unspported or disabled. Should have been detected earlier" - ), - } - } - }; + let mut image = image::open(&image_path)?; + + if image_format == ImageFormat::Tiff + && matches!(image.color(), ColorType::Rgb32F | ColorType::Rgba32F) + { + // The 32-bit image are stored as TIFF in references. So if we + // were to do the same for TIFF test images, we would use the + // same decoder for both test and references images, defeating + // the purpose of this test. Instead, we'll convert 32-bit TIFF + // test images to 16-bit and store them as PNG. + image = match image.color() { + ColorType::Rgb32F => image.to_rgb16().into(), + ColorType::Rgba32F => image.to_rgba16().into(), + _ => unreachable!(), + }; + } - if reference_format == ImageFormat::Png && image_format == Some(ImageFormat::Tiff) { - match test_img { - DynamicImage::ImageRgb32F(_) => { - test_img = test_img.to_rgb16().into(); - } - DynamicImage::ImageRgba32F(_) => { - test_img = test_img.to_rgba16().into(); - } - _ => {} - } + if let Err(e) = compare_to_reference( + &image, + &get_reference_path(&reference_base_path, None, &image), + ) { + // The image doesn't match the reference. Save the decoded version to the + // output directory for inspection. + let output_path = get_reference_path(&output_base_path, None, &image); + save_image(&output_path, &image)?; + return Err(e.into()); } - let mut error: String = if image::open(&path)?.as_bytes() != test_img.as_bytes() { - "Reference rendering does not match".into() - } else { - // The image exactly matches the reference. Success! - return Ok(()); - }; - - // The image doesn't match the reference. Save the decoded version to the - // output directory for inspection. - let ext = match test_img.color() { - ColorType::Rgb32F | ColorType::Rgba32F => "tiff", - _ => "png", - }; - let output_filename = format!("{}.{ext}", case.orig_filename); - let output_path = output_dir.join(output_filename); - fs::create_dir_all(output_dir).unwrap(); - - let ret = match test_img.color() { - ColorType::Rgb32F | ColorType::Rgba32F => test_img.save(&output_path), - #[cfg(feature = "png")] - _ => { - use image::codecs::png::{CompressionType, FilterType, PngEncoder}; - test_img.write_with_encoder(PngEncoder::new_with_quality( - BufWriter::new(File::create(&output_path).unwrap()), - CompressionType::Best, - FilterType::Adaptive, - )) + // Load animation + if let Some(frames) = open_animation(&image_path)? { + for (i, frame) in frames.into_iter().enumerate() { + let frame_number = i + 1; + if let Err(e) = compare_to_reference( + &frame, + &get_reference_path(&reference_base_path, Some(frame_number), &frame), + ) { + // The frame doesn't match the reference. Save the decoded version to the + // output directory for inspection. + let output_path = + get_reference_path(&output_base_path, Some(frame_number), &frame); + save_image(&output_path, &frame)?; + return Err(format!("Frame {frame_number}: {e}").into()); + } } - #[cfg(not(feature = "png"))] - _ => unreachable!(), - }; - - match ret { - Ok(()) => error.push_str(&format!( - "\n\n New reference saved to: {}", - output_path.display() - )), - Err(e) => error.push_str(&format!("\n\n Failed to save new reference: {e}")), } - Err(error.into()) + + Ok(()) })); } @@ -190,54 +124,118 @@ fn main() { libtest_mimic::run(&args, trials).exit(); } -/// Describes a single test case of `check_references`. -struct ReferenceTestCase { - orig_filename: String, - kind: ReferenceTestKind, +fn get_reference_path( + base_path: &Path, + frame_number: Option, + image: &DynamicImage, +) -> PathBuf { + let mut suffix = String::from("."); + if let Some(frame_number) = frame_number { + suffix += &format!("anim_{frame_number:02}."); + } + + let ext = match image.color() { + ColorType::Rgb32F | ColorType::Rgba32F => "tiff", + _ => "png", + }; + suffix += ext; + + base_path.with_file_name(format!( + "{}{}", + base_path.file_name().unwrap().to_string_lossy(), + suffix + )) } -enum ReferenceTestKind { - /// The test image is loaded using `image::open`, and the result is compared - /// against the reference image. - SingleImage, - - /// From the test image file, a single frame is extracted using a fitting animation decoder and - /// the result is compared against the reference image. - AnimatedFrame { - /// A zero-based frame number. - frame: usize, - }, +fn compare_to_reference(image: &DynamicImage, reference_path: &Path) -> Result<(), Box> { + if !reference_path.exists() { + return Err("Missing reference image".into()); + } + + // load reference + let reference = + image::open(reference_path).map_err(|e| format!("Failed to open reference image: {e}"))?; + + // compare + if image.dimensions() != reference.dimensions() { + return Err(format!( + "Dimension mismatch: image {:?} vs reference {:?}", + image.dimensions(), + reference.dimensions() + ) + .into()); + } + if image.as_bytes() != reference.as_bytes() { + return Err("Reference image does not match".into()); + } + + Ok(()) } -impl std::str::FromStr for ReferenceTestCase { - type Err = &'static str; - - /// Construct `ReferenceTestCase` from the file name of a reference - /// image. - fn from_str(filename: &str) -> Result { - let mut filename_parts: Vec<&str> = filename.split('.').collect(); - - // Ignore the file extension - filename_parts.pop(); - - // Figure out if it's an animation. Uses the format `anim_` - let mut kind = ReferenceTestKind::SingleImage; - let last = *filename_parts.last().ok_or("missing metadata part")?; - let meta = last.split('_').collect::>(); - if meta.len() == 2 && meta[0] == "anim" { - let frame: usize = meta[1].parse().map_err(|_| "malformed frame number")?; - kind = ReferenceTestKind::AnimatedFrame { - frame: frame.checked_sub(1).ok_or("frame number must be 1-based")?, - }; - filename_parts.pop(); - } +fn save_image(path: &Path, image: &DynamicImage) -> Result<(), Box> { + std::fs::create_dir_all(path.parent().unwrap())?; + + // special path for PNG to apply more compression + #[cfg(feature = "png")] + if path.extension() == Some("png".as_ref()) { + use image::codecs::png::{CompressionType, FilterType, PngEncoder}; + image.write_with_encoder(PngEncoder::new_with_quality( + BufWriter::new(File::create(path).unwrap()), + CompressionType::Best, + FilterType::Adaptive, + ))?; + return Ok(()); + } - // The remaining part represents the original file name - let orig_filename = filename_parts.join("."); + image.save(path)?; + Ok(()) +} + +/// Returns `Some` with a list of animation frames if the file is an +/// animation, or `None` otherwise. +fn open_animation(path: &Path) -> Result>, Box> { + use image::AnimationDecoder; + + let format = ImageFormat::from_path(path)?; + assert!( + format.reading_enabled(), + "Format should have been detected earlier" + ); + + // TODO: Once there's a generic API for animated images, switch to that instead. + let reader = std::io::BufReader::new(std::fs::File::open(path)?); + let frames: image::Frames<'_> = match format { + #[cfg(feature = "gif")] + ImageFormat::Gif => image::codecs::gif::GifDecoder::new(reader)?.into_frames(), + #[cfg(feature = "png")] + ImageFormat::Png => { + let decoder = image::codecs::png::PngDecoder::new(reader)?; + if !decoder.is_apng()? { + return Ok(None); + } + decoder.apng()?.into_frames() + } + #[cfg(feature = "webp")] + ImageFormat::WebP => { + let decoder = image::codecs::webp::WebPDecoder::new(reader)?; + if !decoder.has_animation() { + return Ok(None); + } + decoder.into_frames() + } + _ => { + return Ok(None); // format doesn't support animations + } + }; - Ok(Self { - orig_filename, - kind, - }) + let frames = frames.collect_frames()?; + if frames.len() < 2 { + return Ok(None); // not actually animated } + Ok(Some( + frames + .into_iter() + .map(|f| DynamicImage::from(f.into_buffer())) + .collect(), + )) }