Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
350
third-party/vendor/image/tests/reference_images.rs
vendored
Normal file
350
third-party/vendor/image/tests/reference_images.rs
vendored
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
//! Compares the decoding results with reference renderings.
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::u32;
|
||||
|
||||
use crc32fast::Hasher as Crc32;
|
||||
use image::DynamicImage;
|
||||
|
||||
const BASE_PATH: [&str; 2] = [".", "tests"];
|
||||
const IMAGE_DIR: &str = "images";
|
||||
const OUTPUT_DIR: &str = "output";
|
||||
const REFERENCE_DIR: &str = "reference";
|
||||
|
||||
fn process_images<F>(dir: &str, input_decoder: Option<&str>, func: F)
|
||||
where
|
||||
F: Fn(&PathBuf, PathBuf, &str),
|
||||
{
|
||||
let base: PathBuf = BASE_PATH.iter().collect();
|
||||
let decoders = &[
|
||||
"tga", "tiff", "png", "gif", "bmp", "ico", "jpg", "hdr", "pbm", "webp",
|
||||
];
|
||||
for decoder in decoders {
|
||||
let mut path = base.clone();
|
||||
path.push(dir);
|
||||
path.push(decoder);
|
||||
path.push("**");
|
||||
path.push(
|
||||
"*.".to_string()
|
||||
+ match input_decoder {
|
||||
Some(val) => val,
|
||||
None => decoder,
|
||||
},
|
||||
);
|
||||
let pattern = &*format!("{}", path.display());
|
||||
for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
|
||||
func(&base, path, decoder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "png")]
|
||||
#[test]
|
||||
fn render_images() {
|
||||
process_images(IMAGE_DIR, None, |base, path, decoder| {
|
||||
println!("render_images {}", path.display());
|
||||
let img = match image::open(&path) {
|
||||
Ok(img) => img,
|
||||
// Do not fail on unsupported error
|
||||
// This might happen because the testsuite contains unsupported images
|
||||
// or because a specific decoder included via a feature.
|
||||
Err(image::ImageError::Unsupported(e)) => {
|
||||
println!("UNSUPPORTED {}: {}", path.display(), e);
|
||||
return;
|
||||
}
|
||||
Err(err) => panic!("decoding of {:?} failed with: {}", path, err),
|
||||
};
|
||||
let mut crc = Crc32::new();
|
||||
crc.update(img.as_bytes());
|
||||
|
||||
let (filename, testsuite) = {
|
||||
let mut path: Vec<_> = path.components().collect();
|
||||
(path.pop().unwrap(), path.pop().unwrap())
|
||||
};
|
||||
let mut out_path = base.clone();
|
||||
|
||||
out_path.push(OUTPUT_DIR);
|
||||
out_path.push(decoder);
|
||||
out_path.push(testsuite.as_os_str());
|
||||
fs::create_dir_all(&out_path).unwrap();
|
||||
out_path.push(format!(
|
||||
"{}.{:x}.png",
|
||||
filename.as_os_str().to_str().unwrap(),
|
||||
crc.finalize(),
|
||||
));
|
||||
img.save(out_path).unwrap();
|
||||
})
|
||||
}
|
||||
|
||||
/// Describes a single test case of `check_references`.
|
||||
struct ReferenceTestCase {
|
||||
orig_filename: String,
|
||||
crc: u32,
|
||||
kind: ReferenceTestKind,
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
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<Self, Self::Err> {
|
||||
let mut filename_parts = filename.rsplitn(3, '.');
|
||||
|
||||
// Ignore the file extension
|
||||
filename_parts.next().unwrap();
|
||||
|
||||
// The penultimate part of `filename_parts` represents the metadata,
|
||||
// describing the test type and other details.
|
||||
let meta_str = filename_parts.next().ok_or("missing metadata part")?;
|
||||
let meta = meta_str.split('_').collect::<Vec<_>>();
|
||||
let (crc, kind);
|
||||
|
||||
if meta.len() == 1 {
|
||||
// `CRC`
|
||||
crc = parse_crc(meta[0]).ok_or("malformed CRC")?;
|
||||
kind = ReferenceTestKind::SingleImage;
|
||||
} else if meta.len() == 3 && meta[0] == "anim" {
|
||||
// `anim_FRAME_CRC`
|
||||
crc = parse_crc(meta[2]).ok_or("malformed CRC")?;
|
||||
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")?,
|
||||
};
|
||||
} else {
|
||||
return Err("unrecognized reference image metadata format");
|
||||
}
|
||||
|
||||
// The remaining part represents the original file name
|
||||
let orig_filename = filename_parts
|
||||
.next()
|
||||
.ok_or("missing original file name")?
|
||||
.to_owned();
|
||||
|
||||
Ok(Self {
|
||||
orig_filename,
|
||||
crc,
|
||||
kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse the given string as a hexadecimal CRC hash, used by `check_references`.
|
||||
fn parse_crc(src: &str) -> Option<u32> {
|
||||
u32::from_str_radix(src, 16).ok()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_references() {
|
||||
process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| {
|
||||
println!("check_references {}", path.display());
|
||||
|
||||
let ref_img = match image::open(&path) {
|
||||
Ok(img) => img,
|
||||
// Do not fail on unsupported error
|
||||
// This might happen because the testsuite contains unsupported images
|
||||
// or because a specific decoder included via a feature.
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => panic!("{}", err),
|
||||
};
|
||||
|
||||
let (filename, testsuite) = {
|
||||
let mut path: Vec<_> = path.components().collect();
|
||||
(path.pop().unwrap(), path.pop().unwrap())
|
||||
};
|
||||
|
||||
// Parse the file name to obtain the test case information
|
||||
let filename_str = filename.as_os_str().to_str().unwrap();
|
||||
let case: ReferenceTestCase = filename_str.parse().unwrap();
|
||||
|
||||
let mut img_path = base.clone();
|
||||
img_path.push(IMAGE_DIR);
|
||||
img_path.push(decoder);
|
||||
img_path.push(testsuite.as_os_str());
|
||||
img_path.push(case.orig_filename);
|
||||
|
||||
// Load the test image
|
||||
let mut test_img = None;
|
||||
|
||||
match case.kind {
|
||||
ReferenceTestKind::AnimatedFrame { frame: frame_num } => {
|
||||
let format = image::io::Reader::open(&img_path)
|
||||
.unwrap()
|
||||
.with_guessed_format()
|
||||
.unwrap()
|
||||
.format();
|
||||
|
||||
#[cfg(feature = "gif")]
|
||||
if format == 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 = match image::codecs::gif::GifDecoder::new(stream) {
|
||||
Ok(decoder) => decoder,
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => {
|
||||
panic!("decoding of {:?} failed with: {}", img_path, err)
|
||||
}
|
||||
};
|
||||
|
||||
let mut frames = match decoder.into_frames().collect_frames() {
|
||||
Ok(frames) => frames,
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => {
|
||||
panic!("collecting frames of {:?} failed with: {}", img_path, err)
|
||||
}
|
||||
};
|
||||
|
||||
// Select a single frame
|
||||
let frame = frames.drain(frame_num..).next().unwrap();
|
||||
|
||||
// Convert the frame to a`RgbaImage`
|
||||
test_img = Some(DynamicImage::from(frame.into_buffer()));
|
||||
}
|
||||
|
||||
#[cfg(feature = "png")]
|
||||
if format == 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 = match image::codecs::png::PngDecoder::new(stream) {
|
||||
Ok(decoder) => decoder.apng(),
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => {
|
||||
panic!("decoding of {:?} failed with: {}", img_path, err)
|
||||
}
|
||||
};
|
||||
|
||||
let mut frames = match decoder.into_frames().collect_frames() {
|
||||
Ok(frames) => frames,
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => {
|
||||
panic!("collecting frames of {:?} failed with: {}", img_path, err)
|
||||
}
|
||||
};
|
||||
|
||||
// Select a single frame
|
||||
let frame = frames.drain(frame_num..).next().unwrap();
|
||||
|
||||
// Convert the frame to a`RgbaImage`
|
||||
test_img = Some(DynamicImage::from(frame.into_buffer()));
|
||||
}
|
||||
|
||||
if test_img.is_none() {
|
||||
println!("Skipping - GIF codec is not enabled");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ReferenceTestKind::SingleImage => {
|
||||
// Read the input file as a single image
|
||||
match image::open(&img_path) {
|
||||
Ok(img) => test_img = Some(img),
|
||||
// Do not fail on unsupported error
|
||||
// This might happen because the testsuite contains unsupported images
|
||||
// or because a specific decoder included via a feature.
|
||||
Err(image::ImageError::Unsupported(_)) => return,
|
||||
Err(err) => panic!("decoding of {:?} failed with: {}", img_path, err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let test_img = match test_img.as_ref() {
|
||||
Some(img) => img,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let test_crc_actual = {
|
||||
let mut hasher = Crc32::new();
|
||||
match test_img {
|
||||
DynamicImage::ImageLuma8(_)
|
||||
| DynamicImage::ImageLumaA8(_)
|
||||
| DynamicImage::ImageRgb8(_)
|
||||
| DynamicImage::ImageRgba8(_) => hasher.update(test_img.as_bytes()),
|
||||
DynamicImage::ImageLuma16(_)
|
||||
| DynamicImage::ImageLumaA16(_)
|
||||
| DynamicImage::ImageRgb16(_)
|
||||
| DynamicImage::ImageRgba16(_) => {
|
||||
for v in test_img.as_bytes().chunks(2) {
|
||||
hasher.update(&u16::from_ne_bytes(v.try_into().unwrap()).to_le_bytes());
|
||||
}
|
||||
}
|
||||
DynamicImage::ImageRgb32F(_) | DynamicImage::ImageRgba32F(_) => {
|
||||
for v in test_img.as_bytes().chunks(4) {
|
||||
hasher.update(&f32::from_ne_bytes(v.try_into().unwrap()).to_le_bytes());
|
||||
}
|
||||
}
|
||||
_ => panic!("Unsupported image format"),
|
||||
}
|
||||
hasher.finalize()
|
||||
};
|
||||
|
||||
if test_crc_actual != case.crc {
|
||||
panic!(
|
||||
"{}: The decoded image's hash does not match (expected = {:08x}, actual = {:08x}).",
|
||||
img_path.display(),
|
||||
case.crc,
|
||||
test_crc_actual
|
||||
);
|
||||
}
|
||||
|
||||
if ref_img.as_bytes() != test_img.as_bytes() {
|
||||
panic!("Reference rendering does not match.");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "hdr")]
|
||||
#[test]
|
||||
fn check_hdr_references() {
|
||||
let mut ref_path: PathBuf = BASE_PATH.iter().collect();
|
||||
ref_path.push(REFERENCE_DIR);
|
||||
ref_path.push("hdr");
|
||||
let mut path: PathBuf = BASE_PATH.iter().collect();
|
||||
path.push(IMAGE_DIR);
|
||||
path.push("hdr");
|
||||
path.push("*");
|
||||
path.push("*.hdr");
|
||||
let pattern = &*format!("{}", path.display());
|
||||
for path in glob::glob(pattern).unwrap().filter_map(Result::ok) {
|
||||
use std::path::Component::Normal;
|
||||
let mut ref_path = ref_path.clone();
|
||||
// append 2 last components of image path to reference path
|
||||
for c in path
|
||||
.components()
|
||||
.rev()
|
||||
.take(2)
|
||||
.collect::<Vec<_>>()
|
||||
.iter()
|
||||
.rev()
|
||||
{
|
||||
match *c {
|
||||
Normal(name) => ref_path.push(name),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
ref_path.set_extension("raw");
|
||||
println!("{}", ref_path.display());
|
||||
println!("{}", path.display());
|
||||
let decoder =
|
||||
image::codecs::hdr::HdrDecoder::new(io::BufReader::new(fs::File::open(&path).unwrap()))
|
||||
.unwrap();
|
||||
let decoded = decoder.read_image_hdr().unwrap();
|
||||
let reference = image::codecs::hdr::read_raw_file(&ref_path).unwrap();
|
||||
assert_eq!(decoded, reference);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue