test: self-verifying seq images with CRC32 hash in filenames
Move 74 seq-*.tiff test images to tests/images/seq/ and embed a CRC32 hash of the full decoded output (dimensions, color type, sample data) as the last filename segment. Replace 75 individual test functions with one generic verify_all_seq_images test that decodes each file and validates its hash against the filename. This catches byte-order, bit-alignment, stride, padding, and value errors that sum-based tests would miss (e.g., swapped pixels preserve the sum but change the hash). Adding new test images only requires dropping a correctly-named file in seq/ — no test code changes needed.
This commit is contained in:
1 parent
c3977c4513
commit
43cfc5bc3a
75 files changed
+231
-441
No files matched your search
+231
-441
@@ -8,6 +8,7 @@ use std::io::{Read, Seek};
|
||||
use std::path::PathBuf;
|
||||
|
||||
const TEST_IMAGE_DIR: &str = "./tests/images/";
|
||||
const SEQ_IMAGE_DIR: &str = "./tests/images/seq/";
|
||||
const LIBTIFFPIC_DEPTH_DIR: &str = "./tests/libtiffpic/depth/";
|
||||
|
||||
macro_rules! test_image_sum {
|
||||
@@ -36,7 +37,6 @@ test_image_sum!(test_image_sum_u8, U8, u64);
|
||||
test_image_sum!(test_image_sum_i8, I8, i64);
|
||||
test_image_sum!(test_image_sum_u16, U16, u64);
|
||||
test_image_sum!(test_image_sum_i16, I16, i64);
|
||||
test_image_sum!(test_image_sum_i32, I32, i64);
|
||||
test_image_sum!(test_image_sum_u32, U32, u64);
|
||||
test_image_sum!(test_image_sum_u64, U64, u64);
|
||||
test_image_sum!(test_image_sum_f32, F32, f32);
|
||||
@@ -68,6 +68,236 @@ macro_rules! test_image_sum_in {
|
||||
test_image_sum_in!(test_depth_sum_u16, U16, u64);
|
||||
test_image_sum_in!(test_depth_sum_u32, U32, u64);
|
||||
|
||||
/// Compute a CRC32 hash of the full decoded TIFF output including metadata.
|
||||
///
|
||||
/// Hashes: page count, and for each page: dimensions, color type, and decoded
|
||||
/// sample data (in little-endian byte order for multi-byte types). This catches
|
||||
/// wrong dimensions, wrong color type, byte-order errors, bit-alignment errors,
|
||||
/// stride/padding errors, and pixel value errors.
|
||||
fn compute_tiff_hash<R: Read + Seek>(reader: R) -> u32 {
|
||||
let mut decoder = Decoder::open(reader).expect("Cannot create decoder");
|
||||
let mut hasher = crc32fast::Hasher::new();
|
||||
|
||||
let mut page = 0u32;
|
||||
loop {
|
||||
decoder.next_image().expect("Cannot read image IFD");
|
||||
let (width, height) = decoder.dimensions().unwrap();
|
||||
let color_type = decoder.colortype().unwrap();
|
||||
let result = decoder.read_image().unwrap();
|
||||
|
||||
// Hash page index + dimensions
|
||||
hasher.update(&page.to_le_bytes());
|
||||
hasher.update(&width.to_le_bytes());
|
||||
hasher.update(&height.to_le_bytes());
|
||||
|
||||
// Hash color type (discriminant + fields)
|
||||
match color_type {
|
||||
ColorType::Gray(n) => hasher.update(&[0, n]),
|
||||
ColorType::RGB(n) => hasher.update(&[1, n]),
|
||||
ColorType::Palette(n) => hasher.update(&[2, n]),
|
||||
ColorType::GrayA(n) => hasher.update(&[3, n]),
|
||||
ColorType::RGBA(n) => hasher.update(&[4, n]),
|
||||
ColorType::CMYK(n) => hasher.update(&[5, n]),
|
||||
ColorType::CMYKA(n) => hasher.update(&[6, n]),
|
||||
ColorType::YCbCr(n) => hasher.update(&[7, n]),
|
||||
ColorType::Lab(n) => hasher.update(&[8, n]),
|
||||
ColorType::Multiband {
|
||||
bit_depth,
|
||||
num_samples,
|
||||
} => {
|
||||
hasher.update(&[9, bit_depth]);
|
||||
hasher.update(&num_samples.to_le_bytes());
|
||||
}
|
||||
_ => hasher.update(&[255]),
|
||||
}
|
||||
|
||||
// Hash decoded data with type discriminant + LE sample bytes
|
||||
match result {
|
||||
DecodingResult::U8(ref data) => {
|
||||
hasher.update(&[0]);
|
||||
hasher.update(data);
|
||||
}
|
||||
DecodingResult::U16(ref data) => {
|
||||
hasher.update(&[1]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::U32(ref data) => {
|
||||
hasher.update(&[2]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::U64(ref data) => {
|
||||
hasher.update(&[3]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::F16(ref data) => {
|
||||
hasher.update(&[4]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::F32(ref data) => {
|
||||
hasher.update(&[5]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::F64(ref data) => {
|
||||
hasher.update(&[6]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::I8(ref data) => {
|
||||
hasher.update(&[7]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::I16(ref data) => {
|
||||
hasher.update(&[8]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::I32(ref data) => {
|
||||
hasher.update(&[9]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
DecodingResult::I64(ref data) => {
|
||||
hasher.update(&[10]);
|
||||
for v in data {
|
||||
hasher.update(&v.to_le_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
page += 1;
|
||||
if !decoder.more_images() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Hash total page count at the end
|
||||
hasher.update(&page.to_le_bytes());
|
||||
hasher.finalize()
|
||||
}
|
||||
|
||||
/// Verify all TIFF files in tests/images/seq/ against their filename-embedded CRC32 hash.
|
||||
///
|
||||
/// Each file is named `<description>-<8hex>.tiff` where the last segment before `.tiff`
|
||||
/// is the expected CRC32 hash of (dimensions, color type, decoded data) for all pages.
|
||||
#[test]
|
||||
fn verify_all_seq_images() {
|
||||
let seq_dir = std::path::Path::new(SEQ_IMAGE_DIR);
|
||||
if !seq_dir.is_dir() {
|
||||
panic!(
|
||||
"seq image directory not found: {}",
|
||||
seq_dir.display()
|
||||
);
|
||||
}
|
||||
|
||||
let mut files: Vec<_> = std::fs::read_dir(seq_dir)
|
||||
.expect("Cannot read seq image directory")
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| {
|
||||
e.path()
|
||||
.extension()
|
||||
.is_some_and(|ext| ext == "tiff" || ext == "tif")
|
||||
})
|
||||
.collect();
|
||||
files.sort_by_key(|e| e.file_name());
|
||||
|
||||
assert!(
|
||||
!files.is_empty(),
|
||||
"No .tiff files found in {}",
|
||||
seq_dir.display()
|
||||
);
|
||||
|
||||
let mut failures = Vec::new();
|
||||
for entry in &files {
|
||||
let path = entry.path();
|
||||
let stem = path.file_stem().unwrap().to_str().unwrap();
|
||||
|
||||
// Extract expected hash: last '-'-delimited segment
|
||||
let expected_hash = stem
|
||||
.rsplit('-')
|
||||
.next()
|
||||
.expect("filename must contain a '-' before the hash");
|
||||
|
||||
// Validate it looks like an 8-char hex string
|
||||
if expected_hash.len() != 8 || !expected_hash.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
failures.push(format!(
|
||||
"{}: filename does not end with 8-char hex hash (got '{}')",
|
||||
stem, expected_hash
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
let file = File::open(&path).expect("Cannot open test image");
|
||||
let actual_hash = format!("{:08x}", compute_tiff_hash(file));
|
||||
|
||||
if actual_hash != expected_hash {
|
||||
failures.push(format!(
|
||||
"{}: expected hash {} but got {}",
|
||||
stem, expected_hash, actual_hash
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if !failures.is_empty() {
|
||||
panic!(
|
||||
"{} of {} seq images failed hash verification:\n {}",
|
||||
failures.len(),
|
||||
files.len(),
|
||||
failures.join("\n ")
|
||||
);
|
||||
}
|
||||
|
||||
eprintln!("Verified {} seq images", files.len());
|
||||
}
|
||||
|
||||
/// Helper: print the correct hash-suffixed filename for every *.tiff in tests/images/seq/.
|
||||
/// Run with: cargo test print_seq_hashes -- --ignored --nocapture
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn print_seq_hashes() {
|
||||
let dir = std::path::Path::new(SEQ_IMAGE_DIR);
|
||||
let mut files: Vec<_> = std::fs::read_dir(dir)
|
||||
.expect("Cannot read image directory")
|
||||
.filter_map(|e| e.ok())
|
||||
.filter(|e| {
|
||||
e.file_name()
|
||||
.to_str()
|
||||
.is_some_and(|n| n.starts_with("seq-") && n.ends_with(".tiff"))
|
||||
})
|
||||
.collect();
|
||||
files.sort_by_key(|e| e.file_name());
|
||||
|
||||
for entry in &files {
|
||||
let path = entry.path();
|
||||
let name = path.file_name().unwrap().to_str().unwrap();
|
||||
let file = File::open(&path).expect("Cannot open test image");
|
||||
let hash = format!("{:08x}", compute_tiff_hash(file));
|
||||
// Strip the old hash (last -XXXXXXXX before .tiff) and print with new hash
|
||||
let stem = path.file_stem().unwrap().to_str().unwrap();
|
||||
let base = &stem[..stem.rfind('-').unwrap_or(stem.len())];
|
||||
let new_name = format!("{base}-{hash}.tiff");
|
||||
if new_name != name {
|
||||
eprintln!("RENAME: {name} -> {new_name}");
|
||||
} else {
|
||||
eprintln!("OK: {name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests that a decoder can be constructed for an image and the color type
|
||||
/// read from the IFD and is of the appropriate type, but the type is
|
||||
/// unsupported.
|
||||
@@ -1000,443 +1230,3 @@ fn test_gray_u12_hpredict() {
|
||||
test_image_sum_u16("hpredict-1c-12b.tiff", ColorType::Gray(12), 11000);
|
||||
}
|
||||
|
||||
// ===== Sequential-value test functions =====
|
||||
// Generated by gen_seq_images.py using manual TIFF writer
|
||||
// Each image has cycling 0..max values; any bit error changes the sum.
|
||||
// 16x16 images (256 pixels per channel).
|
||||
// Sub-byte checksums are sums of packed bytes (the decoder returns packed data).
|
||||
// Planar checksums are first-plane only (read_image() reads one plane).
|
||||
|
||||
// --- Sub-byte BlackIsZero ---
|
||||
#[test]
|
||||
fn test_seq_1c_3b() {
|
||||
test_image_sum_u8("seq-1c-3b.tiff", ColorType::Gray(3), 5792);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_5b() {
|
||||
test_image_sum_u8("seq-1c-5b.tiff", ColorType::Gray(5), 18944);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_7b() {
|
||||
test_image_sum_u8("seq-1c-7b.tiff", ColorType::Gray(7), 24992);
|
||||
}
|
||||
|
||||
// --- Sub-byte WhiteIsZero ---
|
||||
#[test]
|
||||
fn test_seq_1c_3b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-3b-miniswhite.tiff", ColorType::Gray(3), 5792);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_5b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-5b-miniswhite.tiff", ColorType::Gray(5), 18944);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_6b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-6b-miniswhite.tiff", ColorType::Gray(6), 25728);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_7b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-7b-miniswhite.tiff", ColorType::Gray(7), 24992);
|
||||
}
|
||||
|
||||
// --- Extended BlackIsZero ---
|
||||
#[test]
|
||||
fn test_seq_1c_10b() {
|
||||
test_image_sum_u16("seq-1c-10b.tiff", ColorType::Gray(10), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_12b() {
|
||||
test_image_sum_u16("seq-1c-12b.tiff", ColorType::Gray(12), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_14b() {
|
||||
test_image_sum_u16("seq-1c-14b.tiff", ColorType::Gray(14), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_24b() {
|
||||
test_image_sum_u32("seq-1c-24b.tiff", ColorType::Gray(24), 32640);
|
||||
}
|
||||
|
||||
// --- Extended WhiteIsZero ---
|
||||
#[test]
|
||||
fn test_seq_1c_10b_miniswhite() {
|
||||
test_image_sum_u16("seq-1c-10b-miniswhite.tiff", ColorType::Gray(10), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_12b_miniswhite() {
|
||||
test_image_sum_u16("seq-1c-12b-miniswhite.tiff", ColorType::Gray(12), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_14b_miniswhite() {
|
||||
test_image_sum_u16("seq-1c-14b-miniswhite.tiff", ColorType::Gray(14), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_24b_miniswhite() {
|
||||
test_image_sum_u32("seq-1c-24b-miniswhite.tiff", ColorType::Gray(24), 32640);
|
||||
}
|
||||
|
||||
// --- Extended HPredict ---
|
||||
#[test]
|
||||
fn test_seq_1c_10b_hpredict() {
|
||||
test_image_sum_u16("seq-1c-10b-hpredict.tiff", ColorType::Gray(10), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_12b_hpredict() {
|
||||
test_image_sum_u16("seq-1c-12b-hpredict.tiff", ColorType::Gray(12), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_14b_hpredict() {
|
||||
test_image_sum_u16("seq-1c-14b-hpredict.tiff", ColorType::Gray(14), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_24b_hpredict() {
|
||||
test_image_sum_u32("seq-1c-24b-hpredict.tiff", ColorType::Gray(24), 32640);
|
||||
}
|
||||
|
||||
// --- RGB Contiguous ---
|
||||
#[test]
|
||||
fn test_seq_3c_10b_contig() {
|
||||
test_image_sum_u16("seq-3c-10b-contig.tiff", ColorType::RGB(10), 294528);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_12b_contig() {
|
||||
test_image_sum_u16("seq-3c-12b-contig.tiff", ColorType::RGB(12), 294528);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_14b_contig() {
|
||||
test_image_sum_u16("seq-3c-14b-contig.tiff", ColorType::RGB(14), 294528);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_24b_contig() {
|
||||
test_image_sum_u32("seq-3c-24b-contig.tiff", ColorType::RGB(24), 294528);
|
||||
}
|
||||
|
||||
// --- RGB Planar (first plane only via read_image) ---
|
||||
#[test]
|
||||
fn test_seq_3c_10b_planar() {
|
||||
test_image_sum_u16("seq-3c-10b-planar.tiff", ColorType::RGB(10), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_12b_planar() {
|
||||
test_image_sum_u16("seq-3c-12b-planar.tiff", ColorType::RGB(12), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_14b_planar() {
|
||||
test_image_sum_u16("seq-3c-14b-planar.tiff", ColorType::RGB(14), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_24b_planar() {
|
||||
test_image_sum_u32("seq-3c-24b-planar.tiff", ColorType::RGB(24), 32640);
|
||||
}
|
||||
|
||||
// --- Compressed (LZW, Deflate, PackBits) ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_lzw() {
|
||||
test_image_sum_u8("seq-1c-8b-lzw.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_8b_deflate() {
|
||||
test_image_sum_u8("seq-1c-8b-deflate.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_8b_packbits() {
|
||||
test_image_sum_u8("seq-1c-8b-packbits.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_16b_lzw() {
|
||||
test_image_sum_u16("seq-1c-16b-lzw.tiff", ColorType::Gray(16), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_16b_deflate() {
|
||||
test_image_sum_u16("seq-1c-16b-deflate.tiff", ColorType::Gray(16), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_8b_lzw_hpredict() {
|
||||
test_image_sum_u8("seq-1c-8b-lzw-hpredict.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_8b_lzw() {
|
||||
test_image_sum_u8("seq-3c-8b-lzw.tiff", ColorType::RGB(8), 97920);
|
||||
}
|
||||
|
||||
// --- Tiled layout ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_tiled() {
|
||||
test_image_sum_u8("seq-1c-8b-tiled.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_16b_tiled() {
|
||||
test_image_sum_u16("seq-1c-16b-tiled.tiff", ColorType::Gray(16), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_8b_tiled() {
|
||||
test_image_sum_u8("seq-3c-8b-tiled.tiff", ColorType::RGB(8), 97920);
|
||||
}
|
||||
|
||||
// --- BigTIFF ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_bigtiff() {
|
||||
test_image_sum_u8("seq-1c-8b-bigtiff.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_16b_bigtiff() {
|
||||
test_image_sum_u16("seq-3c-16b-bigtiff.tiff", ColorType::RGB(16), 294528);
|
||||
}
|
||||
|
||||
// --- Float samples ---
|
||||
#[test]
|
||||
fn test_seq_1c_32f() {
|
||||
test_image_sum_f32("seq-1c-32f.tiff", ColorType::Gray(32), 128.00009);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_64f() {
|
||||
test_image_sum_f64("seq-1c-64f.tiff", ColorType::Gray(64), 127.99999999999986);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_32f() {
|
||||
test_image_sum_f32("seq-3c-32f.tiff", ColorType::RGB(32), 384.0);
|
||||
}
|
||||
|
||||
// --- Signed integer ---
|
||||
#[test]
|
||||
fn test_seq_1c_i8() {
|
||||
test_image_sum_i8("seq-1c-i8.tiff", ColorType::Gray(8), -128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_i16() {
|
||||
test_image_sum_i16("seq-1c-i16.tiff", ColorType::Gray(16), -128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_i32() {
|
||||
test_image_sum_i32("seq-1c-i32.tiff", ColorType::Gray(32), -128);
|
||||
}
|
||||
|
||||
// --- CMYK ---
|
||||
#[test]
|
||||
fn test_seq_4c_8b_cmyk() {
|
||||
test_image_sum_u8("seq-4c-8b-cmyk.tiff", ColorType::CMYK(8), 130560);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_4c_16b_cmyk() {
|
||||
test_image_sum_u16("seq-4c-16b-cmyk.tiff", ColorType::CMYK(16), 523776);
|
||||
}
|
||||
|
||||
// --- Palette (indexed) ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_palette() {
|
||||
test_image_sum_u8("seq-1c-8b-palette.tiff", ColorType::Palette(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_4b_palette() {
|
||||
test_image_sum_u8("seq-1c-4b-palette.tiff", ColorType::Palette(4), 15360);
|
||||
}
|
||||
|
||||
// --- RGBA (associated alpha) ---
|
||||
#[test]
|
||||
fn test_seq_4c_8b_rgba() {
|
||||
test_image_sum_u8("seq-4c-8b-rgba.tiff", ColorType::RGBA(8), 130560);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_4c_16b_rgba() {
|
||||
test_image_sum_u16("seq-4c-16b-rgba.tiff", ColorType::RGBA(16), 523776);
|
||||
}
|
||||
|
||||
// --- Multi-page (reads first page only via standard macro) ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_multipage() {
|
||||
test_image_sum_u8("seq-1c-8b-multipage.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_8b_multipage_all_pages() {
|
||||
let path = PathBuf::from(TEST_IMAGE_DIR).join("seq-1c-8b-multipage.tiff");
|
||||
let img_file = File::open(path).expect("Cannot find test image!");
|
||||
let mut decoder = Decoder::open(img_file).expect("Cannot create decoder");
|
||||
|
||||
let expected_sums: [u64; 3] = [32640, 32640, 32640];
|
||||
for (page, &expected) in expected_sums.iter().enumerate() {
|
||||
decoder.next_image().expect("Cannot read image IFD");
|
||||
assert_eq!(decoder.colortype().unwrap(), ColorType::Gray(8));
|
||||
match decoder.read_image().unwrap() {
|
||||
DecodingResult::U8(res) => {
|
||||
let sum: u64 = res.into_iter().map(u64::from).sum();
|
||||
assert_eq!(sum, expected, "Page {} sum mismatch", page);
|
||||
}
|
||||
_ => panic!("Wrong bit depth for page {}", page),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Big-endian byte order ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_bigendian() {
|
||||
test_image_sum_u8("seq-1c-8b-bigendian.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_16b_bigendian() {
|
||||
test_image_sum_u16("seq-1c-16b-bigendian.tiff", ColorType::Gray(16), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_8b_bigendian() {
|
||||
test_image_sum_u8("seq-3c-8b-bigendian.tiff", ColorType::RGB(8), 97920);
|
||||
}
|
||||
|
||||
// --- Standard sub-byte depths ---
|
||||
#[test]
|
||||
fn test_seq_1c_1b() {
|
||||
test_image_sum_u8("seq-1c-1b.tiff", ColorType::Gray(1), 2720);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_2b() {
|
||||
test_image_sum_u8("seq-1c-2b.tiff", ColorType::Gray(2), 1728);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_4b() {
|
||||
test_image_sum_u8("seq-1c-4b.tiff", ColorType::Gray(4), 15360);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_1b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-1b-miniswhite.tiff", ColorType::Gray(1), 2720);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_4b_miniswhite() {
|
||||
test_image_sum_u8("seq-1c-4b-miniswhite.tiff", ColorType::Gray(4), 15360);
|
||||
}
|
||||
|
||||
// --- Multi-strip (RowsPerStrip=4) ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_multistrip() {
|
||||
test_image_sum_u8("seq-1c-8b-multistrip.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_16b_multistrip() {
|
||||
test_image_sum_u16("seq-1c-16b-multistrip.tiff", ColorType::Gray(16), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_8b_multistrip() {
|
||||
test_image_sum_u8("seq-3c-8b-multistrip.tiff", ColorType::RGB(8), 97920);
|
||||
}
|
||||
|
||||
// --- Tiled + compressed ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_tiled_lzw() {
|
||||
test_image_sum_u8("seq-1c-8b-tiled-lzw.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_8b_tiled_deflate() {
|
||||
test_image_sum_u8("seq-1c-8b-tiled-deflate.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
|
||||
// --- Float + floating-point predictor ---
|
||||
#[test]
|
||||
fn test_seq_1c_32f_deflate_fpredict() {
|
||||
test_image_sum_f32("seq-1c-32f-deflate-fpredict.tiff", ColorType::Gray(32), 128.00009);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_1c_64f_deflate_fpredict() {
|
||||
test_image_sum_f64(
|
||||
"seq-1c-64f-deflate-fpredict.tiff",
|
||||
ColorType::Gray(64),
|
||||
127.99999999999986,
|
||||
);
|
||||
}
|
||||
|
||||
// --- Unassociated alpha ---
|
||||
#[test]
|
||||
fn test_seq_4c_8b_rgba_unassoc() {
|
||||
test_image_sum_u8("seq-4c-8b-rgba-unassoc.tiff", ColorType::RGBA(8), 130560);
|
||||
}
|
||||
|
||||
// --- Sub-byte RGB contiguous ---
|
||||
#[test]
|
||||
fn test_seq_3c_5b_contig() {
|
||||
test_image_sum_u8("seq-3c-5b-contig.tiff", ColorType::RGB(5), 56832);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_7b_contig() {
|
||||
test_image_sum_u8("seq-3c-7b-contig.tiff", ColorType::RGB(7), 74976);
|
||||
}
|
||||
|
||||
// --- Signed RGB (decoded as Multiband since PHOTOMETRIC_MINISBLACK) ---
|
||||
#[test]
|
||||
fn test_seq_3c_i8() {
|
||||
test_image_sum_i8(
|
||||
"seq-3c-i8.tiff",
|
||||
ColorType::Multiband {
|
||||
bit_depth: 8,
|
||||
num_samples: 3,
|
||||
},
|
||||
-384,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_seq_3c_i16() {
|
||||
test_image_sum_i16(
|
||||
"seq-3c-i16.tiff",
|
||||
ColorType::Multiband {
|
||||
bit_depth: 16,
|
||||
num_samples: 3,
|
||||
},
|
||||
-384,
|
||||
);
|
||||
}
|
||||
|
||||
// --- Float f64 RGB ---
|
||||
#[test]
|
||||
fn test_seq_3c_64f() {
|
||||
test_image_sum_f64("seq-3c-64f.tiff", ColorType::RGB(64), 383.99999999999994);
|
||||
}
|
||||
|
||||
// --- Tiled BigTIFF ---
|
||||
#[test]
|
||||
fn test_seq_1c_8b_tiled_bigtiff() {
|
||||
test_image_sum_u8("seq-1c-8b-tiled-bigtiff.tiff", ColorType::Gray(8), 32640);
|
||||
}
|
||||
Reference in new issue
Block a user