Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
263
vendor/exr/tests/across_compression.rs
vendored
Normal file
263
vendor/exr/tests/across_compression.rs
vendored
Normal file
@ -0,0 +1,263 @@
|
||||
use std::path::Path;
|
||||
use exr::prelude::*;
|
||||
use exr::image::validate_results::ValidateResult;
|
||||
|
||||
fn dir() -> &'static Path { Path::new("tests/images/valid/custom/compression_methods") }
|
||||
|
||||
fn expect_eq_other(sub_dir: &str, image_name: &str, expected: &str) {
|
||||
let path = dir().join(sub_dir).join(image_name);
|
||||
|
||||
match read_first_flat_layer_from_file(path) {
|
||||
Err(Error::NotSupported(message)) => println!("skipping ({})", message),
|
||||
Err(error) => panic!("unexpected error: {}", error),
|
||||
Ok(mut decompressed) => {
|
||||
let decompressed_path = dir().join(sub_dir).join(expected);
|
||||
let mut expected_decompressed = read_first_flat_layer_from_file(decompressed_path)
|
||||
.expect("uncompressed image could not be loaded");
|
||||
|
||||
// HACK: make metadata match artificially, to avoid failing the check due to meta data mismatch
|
||||
// (the name of the compression methods should not be equal, as we test between compression methods)
|
||||
expected_decompressed.layer_data.encoding.compression = Compression::Uncompressed;
|
||||
decompressed.layer_data.encoding.compression = Compression::Uncompressed;
|
||||
|
||||
debug_assert_eq!(expected_decompressed.layer_data.attributes, decompressed.layer_data.attributes, "attributes should not be affected by compression");
|
||||
debug_assert_eq!(expected_decompressed.layer_data.size, decompressed.layer_data.size, "size should not be affected by compression");
|
||||
|
||||
// Note: Unimplemented methods may still work, if each compressed tile would be larger than uncompressed.
|
||||
expected_decompressed.assert_equals_result(&decompressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// comparing to a different format, png,
|
||||
// is the only real way to check that
|
||||
// little endian data is unpacked correctly on big endian systems
|
||||
// it does not attempt to compare NaN
|
||||
fn expect_eq_png(image_name: &str) {
|
||||
type Rgb16Image = ::image::ImageBuffer<::image::Rgb<u16>, Vec<u16>>;
|
||||
|
||||
let exr_path = dir().join("u16").join(image_name);
|
||||
let png_from_exr = read_first_rgba_layer_from_file(
|
||||
exr_path,
|
||||
|
||||
|resolution, _channels: &RgbaChannels| -> Rgb16Image {
|
||||
::image::ImageBuffer::new(
|
||||
resolution.width() as u32,
|
||||
resolution.height() as u32
|
||||
)
|
||||
},
|
||||
|
||||
// set each pixel in the png buffer from the exr file
|
||||
|png_pixels: &mut Rgb16Image, position: Vec2<usize>, (r,g,b,_): (f32,f32,f32,f32)| {
|
||||
png_pixels.put_pixel(
|
||||
position.x() as u32, position.y() as u32,
|
||||
::image::Rgb([to_u16(r), to_u16(g), to_u16(b)])
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
fn to_u16(num: f32) -> u16 { (num.powf(1.0/2.14).clamp(0.0, 1.0) * u16::MAX as f32).round() as u16 }
|
||||
|
||||
match png_from_exr {
|
||||
Err(Error::NotSupported(message)) => println!("skipping ({})", message),
|
||||
Err(error) => panic!("unexpected error: {}", error),
|
||||
Ok(decompressed) => {
|
||||
let truth_path = dir().join("u16").join("ground_truth.png");
|
||||
let truth_dyn_img = image::open(truth_path).unwrap();
|
||||
|
||||
let ground_truth_png = truth_dyn_img.to_rgb16();
|
||||
let exr_as_png_px = decompressed.layer_data.channel_data.pixels;
|
||||
debug_assert_eq!(ground_truth_png.dimensions(), exr_as_png_px.dimensions(), "size should not be affected by compression");
|
||||
|
||||
let expected_px = ground_truth_png.pixels()
|
||||
.flat_map(|px| px.0.iter().copied());
|
||||
|
||||
let actual_px = exr_as_png_px.pixels()
|
||||
.flat_map(|px| px.0.iter().copied());
|
||||
|
||||
let max_diff = u16::MAX/10;
|
||||
for (exp, val) in expected_px.zip(actual_px) {
|
||||
assert!(
|
||||
exp.abs_diff(val) < max_diff,
|
||||
"values not similar enough: found {}, expected {}", val, exp
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn expect_eq_uncompressed(sub_dir: &str, image_name: &str) {
|
||||
expect_eq_other(sub_dir, image_name, "uncompressed.exr")
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_zip_f32() {
|
||||
expect_eq_uncompressed("f32", "zip.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_zip_f16() {
|
||||
expect_eq_uncompressed("f16", "zip.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_zips_f32() {
|
||||
expect_eq_uncompressed("f32", "zips.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_zips_f16() {
|
||||
expect_eq_uncompressed("f16", "zips.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_b44_f32() {
|
||||
expect_eq_uncompressed("f32", "b44.exr"); // f32s are not compressed in b44 and can be compared exactly
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_b44_f16() {
|
||||
expect_eq_other("f16", "b44.exr", "decompressed_b44.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_b44a_f32() {
|
||||
expect_eq_uncompressed("f32", "b44a.exr"); // f32s are not compressed in b44 and can be compared exactly
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_b44a_f16() {
|
||||
expect_eq_other("f16", "b44a.exr", "decompressed_b44a.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_dwaa_f32() {
|
||||
expect_eq_other("f32", "dwaa.exr", "decompressed_dwaa.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_dwaa_f16() {
|
||||
expect_eq_other("f16", "dwaa.exr", "decompressed_dwaa.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_dwab_f32() {
|
||||
expect_eq_other("f32", "dwab.exr", "decompressed_dwab.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_dwab_f16() {
|
||||
expect_eq_other("f16", "dwab.exr", "decompressed_dwab.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_piz_f32() {
|
||||
expect_eq_uncompressed("f32", "piz.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_piz_f16() {
|
||||
expect_eq_uncompressed("f16", "piz.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_rle_f32() {
|
||||
expect_eq_uncompressed("f32", "rle.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_compression_contents_rle_f16() {
|
||||
expect_eq_uncompressed("f16", "rle.exr");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "little")] // TODO make it work on big endian
|
||||
fn compare_compression_contents_pxr24_f16() {
|
||||
expect_eq_other("f16", "pxr24.exr", "decompressed_pxr24.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "little")] // TODO make it work on big endian
|
||||
fn compare_compression_contents_pxr24_f32() {
|
||||
expect_eq_other("f32", "pxr24.exr", "decompressed_pxr24.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_uncompressed_f16() {
|
||||
expect_eq_png("f16_uncompressed.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_piz_f16() {
|
||||
expect_eq_png("f16_piz.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_rle_f16() {
|
||||
expect_eq_png("f16_rle.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_zip_f16() {
|
||||
expect_eq_png("f16_zip.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_zips_f16() {
|
||||
expect_eq_png("f16_zips.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_dwaa_f16() {
|
||||
expect_eq_png("f16_dwaa.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_b44_f16() {
|
||||
expect_eq_png("f16_b44.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_b44a_f16() {
|
||||
expect_eq_png("f16_b44a.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "little")] // TODO make it work on big endian
|
||||
fn compare_png_to_pxr24_f16() {
|
||||
expect_eq_png("f16_pxr24.exr");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_uncompressed_f32() {
|
||||
expect_eq_png("f32_uncompressed.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_piz_f32() {
|
||||
expect_eq_png("f32_piz.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_rle_f32() {
|
||||
expect_eq_png("f32_rle.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_zip_f32() {
|
||||
expect_eq_png("f32_zip.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compare_png_to_dwaa_f32() {
|
||||
expect_eq_png("f32_dwaa.exr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "little")] // TODO make it work on big endian
|
||||
fn compare_png_to_pxr24_f32() {
|
||||
expect_eq_png("f32_pxr24.exr");
|
||||
}
|
86
vendor/exr/tests/dev.rs
vendored
Normal file
86
vendor/exr/tests/dev.rs
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
//! Contains some "test" functions that were be used for developing.
|
||||
|
||||
extern crate exr;
|
||||
extern crate smallvec;
|
||||
|
||||
use exr::prelude::*;
|
||||
|
||||
use std::path::{PathBuf};
|
||||
use std::ffi::OsStr;
|
||||
use std::io::{Cursor};
|
||||
use exr::meta::header::Header;
|
||||
use exr::image::validate_results::ValidateResult;
|
||||
use rayon::prelude::IntoParallelIterator;
|
||||
use rayon::iter::ParallelIterator;
|
||||
|
||||
fn exr_files() -> impl Iterator<Item=PathBuf> {
|
||||
walkdir::WalkDir::new("tests/images/valid").into_iter().map(std::result::Result::unwrap)
|
||||
.filter(|entry| entry.path().extension() == Some(OsStr::new("exr")))
|
||||
.map(walkdir::DirEntry::into_path)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn print_meta_of_all_files() {
|
||||
let files: Vec<PathBuf> = exr_files().collect();
|
||||
|
||||
files.into_par_iter().for_each(|path| {
|
||||
let meta = MetaData::read_from_file(&path, false);
|
||||
println!("{:?}: \t\t\t {:?}", path.file_name().unwrap(), meta.unwrap());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn search_previews_of_all_files() {
|
||||
let files: Vec<PathBuf> = exr_files().collect();
|
||||
|
||||
files.into_par_iter().for_each(|path| {
|
||||
let meta = MetaData::read_from_file(&path, false).unwrap();
|
||||
let has_preview = meta.headers.iter().any(|header: &Header|
|
||||
header.own_attributes.preview.is_some() || header.own_attributes.other.values()
|
||||
.any(|value| match value { AttributeValue::Preview(_) => true, _ => false })
|
||||
);
|
||||
|
||||
if has_preview {
|
||||
println!("Found preview attribute in {:?}", path.file_name().unwrap());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// use this command for big endian testing:
|
||||
// cross test --target mips-unknown-linux-gnu --verbose --test dev test_roundtrip -- --ignored
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn test_roundtrip() {
|
||||
// works
|
||||
//let path = "tests/images/fuzzed/b44_overly_restrictive_assert.exr";
|
||||
let path = "tests/images/valid/custom/compression_methods/f32/pxr24.exr";
|
||||
|
||||
// worksn't
|
||||
// let path = "tests/images/valid/openexr/Chromaticities/Rec709_YC.exr"; // subsampling
|
||||
// let path = "tests/images/valid/openexr/LuminanceChroma/Flowers.exr"; // subsampling
|
||||
|
||||
// let path = "tests/images/valid/openexr/IlmfmlmflmTest/test_native1.exr";
|
||||
// let path = "tests/images/valid/openexr/IlmfmlmflmTest/test_native2.exr"; // contains NaN
|
||||
|
||||
// deep data?
|
||||
// let path = "tests/images/valid/openexr/v2/Stereo/Balls.exr";
|
||||
// let path = "tests/images/valid/openexr/v2/Stereo/Ground.exr";
|
||||
|
||||
println!("{:?}", exr::meta::MetaData::read_from_file(path, true));
|
||||
|
||||
let read_image = read()
|
||||
.no_deep_data().all_resolution_levels().all_channels().all_layers().all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image = read_image.clone().from_file(path).unwrap();
|
||||
|
||||
let mut tmp_bytes = Vec::new();
|
||||
image.write().to_buffered(Cursor::new(&mut tmp_bytes)).unwrap();
|
||||
image.write().to_file("debug_pxr24.exr").unwrap();
|
||||
|
||||
let image2 = read_image.from_buffered(Cursor::new(tmp_bytes)).unwrap();
|
||||
|
||||
image.assert_equals_result(&image2);
|
||||
}
|
176
vendor/exr/tests/fuzz.rs
vendored
Normal file
176
vendor/exr/tests/fuzz.rs
vendored
Normal file
@ -0,0 +1,176 @@
|
||||
//! Fuzzy testing.
|
||||
//! Tries to discover panics with random bytes.
|
||||
//! This test is expensive and therefore marked with `#[ignore]`. To run this test, use `cargo test -- --ignored`.
|
||||
|
||||
use std::panic::{catch_unwind};
|
||||
use rand::rngs::{StdRng};
|
||||
use rand::{Rng};
|
||||
|
||||
extern crate exr;
|
||||
use exr::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs::File;
|
||||
use std::io::{Write, Cursor};
|
||||
use exr::image::read::read_first_rgba_layer_from_file;
|
||||
use exr::image::pixel_vec::PixelVec;
|
||||
|
||||
fn exr_files(path: &'static str, filter: bool) -> impl Iterator<Item=PathBuf> {
|
||||
walkdir::WalkDir::new(path).into_iter().map(std::result::Result::unwrap)
|
||||
.filter(|entry| entry.path().is_file())
|
||||
|
||||
.filter(move |entry| !filter || entry.path().extension() == Some(OsStr::new("exr")))
|
||||
.map(walkdir::DirEntry::into_path)
|
||||
}
|
||||
|
||||
|
||||
/// Just don't panic.
|
||||
#[test]
|
||||
pub fn fuzzed(){
|
||||
for ref file in exr_files("tests/images/fuzzed", false) {
|
||||
let _ = read().no_deep_data().largest_resolution_level().all_channels()
|
||||
.first_valid_layer().all_attributes().pedantic().from_file(file);
|
||||
|
||||
let _ = read().no_deep_data().all_resolution_levels().all_channels()
|
||||
.all_layers().all_attributes().pedantic().from_file(file);
|
||||
}
|
||||
}
|
||||
|
||||
/// Require an error but no panic.
|
||||
#[test]
|
||||
pub fn damaged(){
|
||||
let mut passed = true;
|
||||
|
||||
for ref file in exr_files("tests/images/invalid", false) {
|
||||
let result = catch_unwind(move || {
|
||||
let _meta_data = MetaData::read_from_file(file, false)?;
|
||||
|
||||
{
|
||||
let _minimal = read().no_deep_data()
|
||||
.largest_resolution_level()
|
||||
.rgba_channels(
|
||||
|_size, _channels| (),
|
||||
|_: &mut (), _position: Vec2<usize>, _pixel: (Sample, Sample, Sample, Sample)| {}
|
||||
)
|
||||
.first_valid_layer().all_attributes()
|
||||
.from_file(&file)?;
|
||||
}
|
||||
|
||||
{
|
||||
let _minimal = read().no_deep_data()
|
||||
.largest_resolution_level() // TODO all levels
|
||||
.rgba_channels(
|
||||
|_size, _channels| (),
|
||||
|_: &mut (), _position: Vec2<usize>, _pixel: (Sample, Sample, Sample, Sample)| {}
|
||||
)
|
||||
.all_layers().all_attributes()
|
||||
.pedantic()
|
||||
.from_file(&file)?;
|
||||
}
|
||||
|
||||
{
|
||||
let _rgba = read_first_rgba_layer_from_file(
|
||||
file,
|
||||
PixelVec::<(Sample, Sample, Sample, Sample)>::constructor,
|
||||
PixelVec::set_pixel
|
||||
)?;
|
||||
}
|
||||
|
||||
{
|
||||
let _full = read_all_data_from_file(file)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// this should not panic, only err:
|
||||
passed = passed && match result {
|
||||
Ok(Err(Error::Invalid(message))) => {
|
||||
println!("✓ Recognized as invalid ({}): {:?}", message, file);
|
||||
true
|
||||
},
|
||||
|
||||
Ok(Err(Error::NotSupported(message))) => {
|
||||
println!("- Unsupported ({}): {:?}", message, file);
|
||||
true
|
||||
},
|
||||
|
||||
Ok(Err(Error::Io(error))) => {
|
||||
println!("✗ Unexpected IO Error: {:?}, {:?}", file, error);
|
||||
false
|
||||
},
|
||||
|
||||
Err(_) => {
|
||||
println!("✗ Not recognized as invalid: {:?}", file);
|
||||
false
|
||||
},
|
||||
|
||||
Ok(Ok(_)) => {
|
||||
let meta_data = MetaData::read_from_file(file, true);
|
||||
|
||||
if let Err(error) = meta_data {
|
||||
println!("✓ Recognized as invalid when pedantic ({}): {:?}", error, file);
|
||||
true
|
||||
}
|
||||
else {
|
||||
println!("✗ Oh no, there is nothing wrong with: {:#?}", file);
|
||||
false
|
||||
}
|
||||
},
|
||||
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
||||
assert!(passed, "A damaged file was not handled correctly");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn fuzz(){
|
||||
println!("started fuzzing");
|
||||
let files: Vec<PathBuf> = exr_files("tests/images", true).collect();
|
||||
|
||||
let seed = [92,1,0,130,211,8,21,70,74,4,9,5,0,23,0,3,20,25,6,5,229,30,0,34,218,0,40,7,5,2,7,0,];
|
||||
let mut random: StdRng = rand::SeedableRng::from_seed(seed);
|
||||
|
||||
let mut records = File::create("tests/images/fuzzed/list.txt").unwrap();
|
||||
records.write_all(format!("seed = {:?}", seed).as_bytes()).unwrap();
|
||||
|
||||
let start_index = 0; // default is 0. increase this integer for debugging a specific fuzz case
|
||||
for fuzz_index in 0 .. 1024_u64 * 2048 * 4 {
|
||||
|
||||
let file_1_name = &files[random.gen_range(0 .. files.len())];
|
||||
let mutation_point = random.gen::<f32>().powi(3);
|
||||
let mutation = random.gen::<u8>();
|
||||
|
||||
if fuzz_index >= start_index {
|
||||
let mut file = std::fs::read(file_1_name).unwrap();
|
||||
let index = ((mutation_point * file.len() as f32) as usize + 4) % file.len();
|
||||
file[index] = mutation;
|
||||
|
||||
let file = file.as_slice();
|
||||
let result = catch_unwind(move || {
|
||||
let read_all_data = read().no_deep_data()
|
||||
.all_resolution_levels().all_channels().all_layers().all_attributes();
|
||||
|
||||
match read_all_data.from_buffered(Cursor::new(file)) {
|
||||
Err(Error::Invalid(error)) => println!("✓ No Panic. [{}]: Invalid: {}.", fuzz_index, error),
|
||||
Err(Error::NotSupported(error)) => println!("- No Panic. [{}]: Unsupported: {}.", fuzz_index, error),
|
||||
_ => {},
|
||||
}
|
||||
});
|
||||
|
||||
if let Err(_) = result {
|
||||
records.write_all(fuzz_index.to_string().as_bytes()).unwrap();
|
||||
records.flush().unwrap();
|
||||
|
||||
let seed = seed.iter().map(|num| num.to_string()).collect::<Vec<String>>().join("-");
|
||||
let mut saved = File::create(format!("tests/images/fuzzed/fuzz_{}_{}.exr", fuzz_index, seed)).unwrap();
|
||||
saved.write_all(file).unwrap();
|
||||
|
||||
println!("✗ PANIC! [{}]", fuzz_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
376
vendor/exr/tests/roundtrip.rs
vendored
Normal file
376
vendor/exr/tests/roundtrip.rs
vendored
Normal file
@ -0,0 +1,376 @@
|
||||
extern crate exr;
|
||||
|
||||
extern crate smallvec;
|
||||
|
||||
use std::{panic};
|
||||
use std::io::{Cursor};
|
||||
use std::panic::catch_unwind;
|
||||
use std::path::{PathBuf, Path};
|
||||
use std::ffi::OsStr;
|
||||
|
||||
use exr::prelude::*;
|
||||
use exr::error::{Error, UnitResult};
|
||||
use exr::prelude::pixel_vec::PixelVec;
|
||||
use exr::image::validate_results::ValidateResult;
|
||||
use rayon::prelude::IntoParallelIterator;
|
||||
use rayon::iter::ParallelIterator;
|
||||
use exr::block::samples::IntoNativeSample;
|
||||
|
||||
#[test]
|
||||
fn roundtrip_all_files_in_repository_x4(){
|
||||
check_all_files_in_repo(|path|{
|
||||
let file = std::fs::read(path).expect("cannot open file");
|
||||
|
||||
round_trip_simple(&file)?;
|
||||
round_trip_full(&file)?;
|
||||
round_trip_rgba_file(path, &file)?;
|
||||
round_trip_parallel_file(&file)?;
|
||||
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
fn round_trip_full(file: &[u8]) -> Result<()> {
|
||||
let read_image = read()
|
||||
.no_deep_data().all_resolution_levels().all_channels().all_layers().all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image = read_image.clone().from_buffered(Cursor::new(file))?;
|
||||
|
||||
let mut tmp_bytes = Vec::with_capacity(file.len());
|
||||
image.write().non_parallel().to_buffered(Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image2 = read_image.from_buffered(Cursor::new(tmp_bytes))?;
|
||||
|
||||
image.assert_equals_result(&image2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn round_trip_simple(file: &[u8]) -> Result<()> {
|
||||
let read_image = read()
|
||||
.no_deep_data().largest_resolution_level().all_channels().all_layers().all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image = read_image.clone().from_buffered(Cursor::new(file))?;
|
||||
|
||||
let mut tmp_bytes = Vec::with_capacity(file.len());
|
||||
image.write().non_parallel().to_buffered(&mut Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image2 = read_image.from_buffered(Cursor::new(&tmp_bytes))?;
|
||||
|
||||
image.assert_equals_result(&image2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn round_trip_rgba_file(path: &Path, file: &[u8]) -> Result<()> {
|
||||
// these files are known to be invalid, because they do not contain any rgb channels
|
||||
let blacklist = [
|
||||
Path::new("tests/images/valid/openexr/LuminanceChroma/Garden.exr"),
|
||||
Path::new("tests/images/valid/openexr/MultiView/Fog.exr"),
|
||||
Path::new("tests/images/valid/openexr/TestImages/GrayRampsDiagonal.exr"),
|
||||
Path::new("tests/images/valid/openexr/TestImages/GrayRampsHorizontal.exr"),
|
||||
Path::new("tests/images/valid/openexr/TestImages/WideFloatRange.exr"),
|
||||
Path::new("tests/images/valid/openexr/IlmfmlmflmTest/v1.7.test.tiled.exr")
|
||||
];
|
||||
|
||||
if blacklist.contains(&path) { return Ok(()) }
|
||||
|
||||
let image_reader = read()
|
||||
.no_deep_data()
|
||||
.largest_resolution_level() // TODO all levels
|
||||
.rgba_channels(PixelVec::<(f32,f32,f32,f32)>::constructor, PixelVec::set_pixel)
|
||||
.first_valid_layer()
|
||||
.all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image = image_reader.clone().from_buffered(Cursor::new(file))?;
|
||||
|
||||
let mut tmp_bytes = Vec::with_capacity(file.len());
|
||||
|
||||
image.write().non_parallel()
|
||||
.to_buffered(&mut Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image2 = image_reader.from_buffered(Cursor::new(&tmp_bytes))?;
|
||||
|
||||
image.assert_equals_result(&image2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO compare rgba vs rgb images for color content, and rgb vs rgb(a?)
|
||||
|
||||
|
||||
fn round_trip_parallel_file(file: &[u8]) -> Result<()> {
|
||||
let image = read()
|
||||
.no_deep_data().all_resolution_levels().all_channels().all_layers().all_attributes()
|
||||
.from_buffered(Cursor::new(file))?;
|
||||
|
||||
let mut tmp_bytes = Vec::with_capacity(file.len());
|
||||
image.write().to_buffered(Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image2 = read()
|
||||
.no_deep_data().all_resolution_levels().all_channels().all_layers().all_attributes()
|
||||
.pedantic()
|
||||
.from_buffered(Cursor::new(tmp_bytes.as_slice()))?;
|
||||
|
||||
image.assert_equals_result(&image2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// read all images in a directory.
|
||||
/// does not check any content, just checks whether a read error or panic happened.
|
||||
fn check_all_files_in_repo<T>(
|
||||
operation: impl Sync + std::panic::RefUnwindSafe + Fn(&Path) -> exr::error::Result<T>
|
||||
) {
|
||||
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
enum Result { Ok, Unsupported(String), Error(String) }
|
||||
|
||||
let files: Vec<PathBuf> = all_exr_files_in_repo().collect();
|
||||
let mut results: Vec<(PathBuf, Result)> = files.into_par_iter()
|
||||
.map(|file| {
|
||||
let result = catch_unwind(||{
|
||||
let prev_hook = panic::take_hook();
|
||||
panic::set_hook(Box::new(|_| (/* do not println panics */)));
|
||||
let result = operation(&file);
|
||||
panic::set_hook(prev_hook);
|
||||
|
||||
result
|
||||
});
|
||||
|
||||
let result = match result {
|
||||
Ok(Ok(_)) => Result::Ok,
|
||||
Ok(Err(Error::NotSupported(message))) => Result::Unsupported(message.to_string()),
|
||||
|
||||
Ok(Err(Error::Io(io))) => Result::Error(format!("IoError: {:?}", io)),
|
||||
Ok(Err(Error::Invalid(message))) => Result::Error(format!("Invalid: {:?}", message)),
|
||||
Ok(Err(Error::Aborted)) => panic!("a test produced `Error::Abort`"),
|
||||
|
||||
Err(_) => Result::Error("Panic".to_owned()),
|
||||
};
|
||||
|
||||
match &result {
|
||||
Result::Error(_) => println!("✗ Error when processing {:?}", file),
|
||||
_ => println!("✓ No error when processing {:?}", file)
|
||||
};
|
||||
|
||||
(file, result)
|
||||
})
|
||||
.collect();
|
||||
|
||||
results.sort_by(|(_, a), (_, b)| a.cmp(b));
|
||||
|
||||
println!("{:#?}", results.iter().map(|(path, result)| {
|
||||
format!("{:?}: {}", result, path.to_str().unwrap())
|
||||
}).collect::<Vec<_>>());
|
||||
|
||||
assert!(results.len() > 80, "Not enough files were tested!");
|
||||
|
||||
if let Result::Error(_) = results.last().unwrap().1 {
|
||||
panic!("A file triggered a panic");
|
||||
}
|
||||
}
|
||||
|
||||
fn all_exr_files_in_repo() -> impl Iterator<Item=PathBuf> {
|
||||
walkdir::WalkDir::new("tests/images/valid").into_iter().map(std::result::Result::unwrap)
|
||||
.filter(|entry| entry.path().extension() == Some(OsStr::new("exr")))
|
||||
.map(walkdir::DirEntry::into_path)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_unusual_2() -> UnitResult {
|
||||
let random_pixels: Vec<(f16, u32)> = vec![
|
||||
( f16::from_f32(-5.0), 4),
|
||||
( f16::from_f32(4.0), 9),
|
||||
( f16::from_f32(2.0), 6),
|
||||
( f16::from_f32(21.0), 8),
|
||||
( f16::from_f32(64.0), 7),
|
||||
];
|
||||
|
||||
let size = Vec2(3, 2);
|
||||
let pixels = (0..size.area())
|
||||
.zip(random_pixels.into_iter().cycle())
|
||||
.map(|(_index, color)| color).collect::<Vec<_>>();
|
||||
|
||||
let pixels = PixelVec { resolution: size, pixels };
|
||||
|
||||
let channels = SpecificChannels::build()
|
||||
.with_channel("N")
|
||||
.with_channel("Ploppalori Taranos")
|
||||
.with_pixels(pixels.clone()
|
||||
);
|
||||
|
||||
let image = Image::from_channels(size, channels);
|
||||
|
||||
let mut tmp_bytes = Vec::new();
|
||||
image.write().non_parallel().to_buffered(&mut Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image_reader = read()
|
||||
.no_deep_data()
|
||||
.largest_resolution_level() // TODO all levels
|
||||
.specific_channels().required("N").required("Ploppalori Taranos")
|
||||
.collect_pixels(PixelVec::<(f16,u32)>::constructor, PixelVec::set_pixel)
|
||||
.first_valid_layer()
|
||||
.all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image2 = image_reader.from_buffered(Cursor::new(&tmp_bytes))?;
|
||||
|
||||
// custom compare function: considers nan equal to nan
|
||||
assert_eq!(image.layer_data.size, size, "test is buggy");
|
||||
let pixels1 = &image.layer_data.channel_data.pixels;
|
||||
let pixels2 = &image2.layer_data.channel_data.pixels;
|
||||
|
||||
assert_eq!(pixels1.pixels, pixels2.pixels);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// TODO test optional reader
|
||||
// TODO dedup
|
||||
#[test]
|
||||
fn roundtrip_unusual_7() -> UnitResult {
|
||||
|
||||
let random_pixels: Vec<(f16, u32, f32,f32,f32,f32,f32)> = vec![
|
||||
( f16::from_f32(-5.0), 4, 1.0,2.0,3.0,4.0,5.0),
|
||||
( f16::from_f32(4.0), 8, 2.0,3.0,4.0,5.0,1.0),
|
||||
( f16::from_f32(2.0), 9, 3.0,4.0,5.0,1.0,2.0),
|
||||
( f16::from_f32(21.0), 6, 4.0,5.0,1.0,2.0,3.0),
|
||||
( f16::from_f32(64.0), 5, 5.0,1.0,2.0,3.0,4.0),
|
||||
];
|
||||
|
||||
let size = Vec2(3, 2);
|
||||
let pixels = (0..size.area())
|
||||
.zip(random_pixels.into_iter().cycle())
|
||||
.map(|(_index, color)| color).collect::<Vec<_>>();
|
||||
|
||||
let pixels = PixelVec { resolution: size, pixels };
|
||||
|
||||
let channels = SpecificChannels::build()
|
||||
.with_channel("N")
|
||||
.with_channel("Ploppalori Taranos")
|
||||
.with_channel("4")
|
||||
.with_channel(".")
|
||||
.with_channel("____")
|
||||
.with_channel(" ")
|
||||
.with_channel(" ")
|
||||
.with_pixels(pixels.clone()
|
||||
);
|
||||
|
||||
let image = Image::from_channels(size, channels);
|
||||
|
||||
let mut tmp_bytes = Vec::new();
|
||||
image.write().non_parallel().to_buffered(&mut Cursor::new(&mut tmp_bytes))?;
|
||||
|
||||
let image_reader = read()
|
||||
.no_deep_data()
|
||||
.largest_resolution_level() // TODO all levels
|
||||
.specific_channels()
|
||||
.required("N")
|
||||
.required("Ploppalori Taranos")
|
||||
.required("4")
|
||||
.required(".")
|
||||
.required("____")
|
||||
.required(" ")
|
||||
.required(" ")
|
||||
.collect_pixels(PixelVec::<(f16, u32, f32,f32,f32,f32,f32)>::constructor, PixelVec::set_pixel)
|
||||
.first_valid_layer()
|
||||
.all_attributes()
|
||||
.non_parallel();
|
||||
|
||||
let image2 = image_reader.from_buffered(Cursor::new(&tmp_bytes))?;
|
||||
|
||||
// custom compare function: considers nan equal to nan
|
||||
assert_eq!(image.layer_data.size, size, "test is buggy");
|
||||
let pixels1 = &image.layer_data.channel_data.pixels;
|
||||
let pixels2 = &image2.layer_data.channel_data.pixels;
|
||||
|
||||
assert_eq!(pixels1.pixels, pixels2.pixels);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "big")] // TODO big endian pxr24
|
||||
fn pxr24_expect_error_on_big_endian(){
|
||||
let image = exr::prelude::read_all_data_from_file(
|
||||
"tests/images/valid/custom/compression_methods/f16/pxr24.exr"
|
||||
);
|
||||
|
||||
match image {
|
||||
Err(Error::NotSupported(_)) => {}
|
||||
_ => panic!("pxr24 should report an error on big endian architecture")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_endian = "little")] // TODO big endian pxr24
|
||||
fn roundtrip_pxr24() {
|
||||
test_mixed_roundtrip_with_compression(Compression::PXR24)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_rle() {
|
||||
test_mixed_roundtrip_with_compression(Compression::RLE)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_zip1() {
|
||||
test_mixed_roundtrip_with_compression(Compression::ZIP1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_zip16() {
|
||||
test_mixed_roundtrip_with_compression(Compression::ZIP16)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_b44() {
|
||||
test_mixed_roundtrip_with_compression(Compression::B44)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_b44a() {
|
||||
test_mixed_roundtrip_with_compression(Compression::B44A)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_piz() {
|
||||
test_mixed_roundtrip_with_compression(Compression::PIZ)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_uncompressed() {
|
||||
test_mixed_roundtrip_with_compression(Compression::Uncompressed)
|
||||
}
|
||||
|
||||
fn test_mixed_roundtrip_with_compression(compression: Compression) {
|
||||
|
||||
let original_pixels: [(f16,f32,f32); 4] = [
|
||||
(0.0.to_f16(), -1.1, std::f32::consts::PI),
|
||||
(9.1.to_f16(), -3.1, std::f32::consts::TAU),
|
||||
(-10.0.to_f16(), -11.1, f32::EPSILON),
|
||||
(half::f16::NAN, 10000.1, -1024.009),
|
||||
];
|
||||
|
||||
let mut file_bytes = Vec::new();
|
||||
let original_image = Image::from_encoded_channels(
|
||||
(2,2),
|
||||
Encoding {
|
||||
compression,
|
||||
.. Encoding::default()
|
||||
},
|
||||
SpecificChannels::rgb(
|
||||
PixelVec::new(Vec2(2,2), original_pixels.to_vec())
|
||||
)
|
||||
);
|
||||
|
||||
original_image.write().to_buffered(Cursor::new(&mut file_bytes)).unwrap();
|
||||
|
||||
let lossy_image = read().no_deep_data().largest_resolution_level()
|
||||
.rgb_channels(PixelVec::<(f16,f32,f32)>::constructor, PixelVec::set_pixel)
|
||||
.first_valid_layer().all_attributes().from_buffered(Cursor::new(&file_bytes)).unwrap();
|
||||
|
||||
// use automatic lossy detection by compression method
|
||||
original_image.assert_equals_result(&original_image);
|
||||
lossy_image.assert_equals_result(&lossy_image);
|
||||
original_image.assert_equals_result(&lossy_image);
|
||||
}
|
Reference in New Issue
Block a user