diff --git a/src/sanity_checks.rs b/src/sanity_checks.rs index 496b5dfd..8150d72d 100644 --- a/src/sanity_checks.rs +++ b/src/sanity_checks.rs @@ -1,15 +1,14 @@ -use image::{DynamicImage, GenericImageView, ImageFormat, Pixel}; +use image::{codecs::png::PngDecoder, *}; use log::{error, warn}; -use std::io::Cursor; /// Validate that the output png data still matches the original image pub fn validate_output(output: &[u8], original_data: &[u8]) -> bool { - let (old_png, new_png) = rayon::join( + let (old_frames, new_frames) = rayon::join( || load_png_image_from_memory(original_data), || load_png_image_from_memory(output), ); - match (new_png, old_png) { + match (new_frames, old_frames) { (Err(new_err), _) => { error!("Failed to read output image for validation: {}", new_err); false @@ -21,26 +20,40 @@ pub fn validate_output(output: &[u8], original_data: &[u8]) -> bool { warn!("Failed to read input image for validation: {}", old_err); true } - (Ok(new_png), Ok(old_png)) => images_equal(&old_png, &new_png), + (Ok(new_frames), Ok(old_frames)) if new_frames.len() != old_frames.len() => false, + (Ok(new_frames), Ok(old_frames)) => { + for (a, b) in old_frames.iter().zip(new_frames) { + if !images_equal(&a, &b) { + return false; + } + } + true + } } } -/// Loads a PNG image from memory to a [DynamicImage] -fn load_png_image_from_memory(png_data: &[u8]) -> Result { - let mut reader = image::io::Reader::new(Cursor::new(png_data)); - reader.set_format(ImageFormat::Png); - reader.no_limits(); - reader.decode() +/// Loads a PNG image from memory to frames of [RgbaImage] +fn load_png_image_from_memory(png_data: &[u8]) -> Result, image::ImageError> { + let decoder = PngDecoder::new(png_data)?; + if decoder.is_apng() { + decoder + .apng() + .into_frames() + .map(|f| f.map(|f| f.into_buffer())) + .collect() + } else { + DynamicImage::from_decoder(decoder).map(|i| vec![i.into_rgba8()]) + } } /// Compares images pixel by pixel for equivalent content -fn images_equal(old_png: &DynamicImage, new_png: &DynamicImage) -> bool { +fn images_equal(old_png: &RgbaImage, new_png: &RgbaImage) -> bool { let a = old_png.pixels().filter(|x| { - let p = x.2.channels(); + let p = x.channels(); !(p.len() == 4 && p[3] == 0) }); let b = new_png.pixels().filter(|x| { - let p = x.2.channels(); + let p = x.channels(); !(p.len() == 4 && p[3] == 0) }); a.eq(b)