From a4cbf7bbaf9dd3e716e5ec03981f3fd05d004426 Mon Sep 17 00:00:00 2001 From: Lilith River Date: Mon, 9 Mar 2026 23:35:50 -0600 Subject: [PATCH] test: add 28 format-variant test images covering compression, tiled, BigTIFF, float, signed, CMYK, palette, RGBA, multi-page, and big-endian Expand gen_seq_tiff.c with writers for standard-depth formats that exercise different decoder code paths. All 55 seq-* images are 16x16, libtiff-generated, and cross-validated against tifffile. New coverage: - Compression: LZW, Deflate, PackBits (gray 8/16-bit, RGB 8-bit) - LZW + horizontal predictor (8-bit gray) - Tiled layout: gray 8/16-bit, RGB 8-bit (16x16 tiles) - BigTIFF: gray 8-bit, RGB 16-bit - Float: gray f32/f64, RGB f32 - Signed integer: i8, i16, i32 - CMYK: 8-bit, 16-bit - Palette/indexed: 4-bit, 8-bit (with known colormap) - RGBA with associated alpha: 8-bit, 16-bit - Multi-page: 3-page gray 8-bit (all pages verified) - Big-endian byte order: gray 8/16-bit, RGB 8-bit Total: 298 tests, all passing. --- tests/decode_images.rs | 171 ++++++ tests/gen_seq_tiff.c | 721 +++++++++++++++++++++++ tests/images/seq-1c-16b-bigendian.tiff | Bin 0 -> 658 bytes tests/images/seq-1c-16b-deflate.tiff | Bin 0 -> 500 bytes tests/images/seq-1c-16b-lzw.tiff | Bin 0 -> 758 bytes tests/images/seq-1c-16b-tiled.tiff | Bin 0 -> 670 bytes tests/images/seq-1c-32f.tiff | Bin 0 -> 1170 bytes tests/images/seq-1c-4b-palette.tiff | Bin 0 -> 382 bytes tests/images/seq-1c-64f.tiff | Bin 0 -> 2194 bytes tests/images/seq-1c-8b-bigendian.tiff | Bin 0 -> 402 bytes tests/images/seq-1c-8b-bigtiff.tiff | Bin 0 -> 508 bytes tests/images/seq-1c-8b-deflate.tiff | Bin 0 -> 414 bytes tests/images/seq-1c-8b-lzw-hpredict.tiff | Bin 0 -> 212 bytes tests/images/seq-1c-8b-lzw.tiff | Bin 0 -> 438 bytes tests/images/seq-1c-8b-multipage.tiff | Bin 0 -> 1262 bytes tests/images/seq-1c-8b-packbits.tiff | Bin 0 -> 418 bytes tests/images/seq-1c-8b-palette.tiff | Bin 0 -> 1950 bytes tests/images/seq-1c-8b-tiled.tiff | Bin 0 -> 414 bytes tests/images/seq-1c-i16.tiff | Bin 0 -> 658 bytes tests/images/seq-1c-i32.tiff | Bin 0 -> 1170 bytes tests/images/seq-1c-i8.tiff | Bin 0 -> 402 bytes tests/images/seq-3c-16b-bigtiff.tiff | Bin 0 -> 1788 bytes tests/images/seq-3c-32f.tiff | Bin 0 -> 3230 bytes tests/images/seq-3c-8b-bigendian.tiff | Bin 0 -> 926 bytes tests/images/seq-3c-8b-lzw.tiff | Bin 0 -> 770 bytes tests/images/seq-3c-8b-tiled.tiff | Bin 0 -> 938 bytes tests/images/seq-4c-16b-cmyk.tiff | Bin 0 -> 2222 bytes tests/images/seq-4c-16b-rgba.tiff | Bin 0 -> 2222 bytes tests/images/seq-4c-8b-cmyk.tiff | Bin 0 -> 1198 bytes tests/images/seq-4c-8b-rgba.tiff | Bin 0 -> 1198 bytes 30 files changed, 892 insertions(+) create mode 100644 tests/images/seq-1c-16b-bigendian.tiff create mode 100644 tests/images/seq-1c-16b-deflate.tiff create mode 100644 tests/images/seq-1c-16b-lzw.tiff create mode 100644 tests/images/seq-1c-16b-tiled.tiff create mode 100644 tests/images/seq-1c-32f.tiff create mode 100644 tests/images/seq-1c-4b-palette.tiff create mode 100644 tests/images/seq-1c-64f.tiff create mode 100644 tests/images/seq-1c-8b-bigendian.tiff create mode 100644 tests/images/seq-1c-8b-bigtiff.tiff create mode 100644 tests/images/seq-1c-8b-deflate.tiff create mode 100644 tests/images/seq-1c-8b-lzw-hpredict.tiff create mode 100644 tests/images/seq-1c-8b-lzw.tiff create mode 100644 tests/images/seq-1c-8b-multipage.tiff create mode 100644 tests/images/seq-1c-8b-packbits.tiff create mode 100644 tests/images/seq-1c-8b-palette.tiff create mode 100644 tests/images/seq-1c-8b-tiled.tiff create mode 100644 tests/images/seq-1c-i16.tiff create mode 100644 tests/images/seq-1c-i32.tiff create mode 100644 tests/images/seq-1c-i8.tiff create mode 100644 tests/images/seq-3c-16b-bigtiff.tiff create mode 100644 tests/images/seq-3c-32f.tiff create mode 100644 tests/images/seq-3c-8b-bigendian.tiff create mode 100644 tests/images/seq-3c-8b-lzw.tiff create mode 100644 tests/images/seq-3c-8b-tiled.tiff create mode 100644 tests/images/seq-4c-16b-cmyk.tiff create mode 100644 tests/images/seq-4c-16b-rgba.tiff create mode 100644 tests/images/seq-4c-8b-cmyk.tiff create mode 100644 tests/images/seq-4c-8b-rgba.tiff diff --git a/tests/decode_images.rs b/tests/decode_images.rs index 8b0b067..1170f25 100644 --- a/tests/decode_images.rs +++ b/tests/decode_images.rs @@ -36,6 +36,7 @@ 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); @@ -1147,3 +1148,173 @@ fn test_seq_3c_14b_planar() { 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); +} diff --git a/tests/gen_seq_tiff.c b/tests/gen_seq_tiff.c index 614fb07..462f649 100644 --- a/tests/gen_seq_tiff.c +++ b/tests/gen_seq_tiff.c @@ -14,6 +14,7 @@ #include #include #include +#include #define W 16 #define H 16 @@ -175,6 +176,554 @@ static int write_rgb_planar(const char *path, int bits) return 0; } +/* Write a standard-depth grayscale TIFF with specified compression. + * Works for 8-bit and 16-bit depths using native sample storage. */ +static int write_gray_compressed(const char *path, int bits, + uint16_t compression, uint16_t predictor, + const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + if (predictor != PREDICTOR_NONE) + TIFFSetField(tif, TIFFTAG_PREDICTOR, predictor); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + uint32_t val = (y * W + x) % (max_val + 1); + if (bits == 8) { + buf[x] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)buf)[x] = (uint16_t)val; + } else if (bits == 32) { + ((uint32_t *)buf)[x] = val; + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a standard-depth RGB TIFF with specified compression. */ +static int write_rgb_compressed(const char *path, int bits, + uint16_t compression, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + for (int c = 0; c < 3; c++) { + uint32_t idx = (y * W + x) * 3 + c; + uint32_t val = idx % (max_val + 1); + if (bits == 8) { + buf[x * 3 + c] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)buf)[x * 3 + c] = (uint16_t)val; + } + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a tiled grayscale TIFF. Uses 8x8 tiles. */ +static int write_gray_tiled(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + int tw = 16, th = 16; + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_TILEWIDTH, tw); + TIFFSetField(tif, TIFFTAG_TILELENGTH, th); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t tile_size = TIFFTileSize(tif); + uint8_t *tile_buf = (uint8_t *)_TIFFmalloc(tile_size); + if (!tile_buf) { TIFFClose(tif); return -1; } + + for (int ty = 0; ty < H; ty += th) { + for (int tx = 0; tx < W; tx += tw) { + memset(tile_buf, 0, tile_size); + for (int row = 0; row < th; row++) { + for (int col = 0; col < tw; col++) { + int y = ty + row, x = tx + col; + uint32_t val = (y * W + x) % (max_val + 1); + if (bits == 8) { + tile_buf[row * tw + col] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)tile_buf)[row * tw + col] = (uint16_t)val; + } + } + } + if (TIFFWriteTile(tif, tile_buf, tx, ty, 0, 0) < 0) { + fprintf(stderr, "Error writing tile at (%d,%d) to %s\n", tx, ty, path); + _TIFFfree(tile_buf); TIFFClose(tif); return -1; + } + } + } + + _TIFFfree(tile_buf); + TIFFClose(tif); + return 0; +} + +/* Write a tiled RGB TIFF. Uses 8x8 tiles. */ +static int write_rgb_tiled(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + int tw = 16, th = 16; + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_TILEWIDTH, tw); + TIFFSetField(tif, TIFFTAG_TILELENGTH, th); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t tile_size = TIFFTileSize(tif); + uint8_t *tile_buf = (uint8_t *)_TIFFmalloc(tile_size); + if (!tile_buf) { TIFFClose(tif); return -1; } + + for (int ty = 0; ty < H; ty += th) { + for (int tx = 0; tx < W; tx += tw) { + memset(tile_buf, 0, tile_size); + for (int row = 0; row < th; row++) { + for (int col = 0; col < tw; col++) { + int y = ty + row, x = tx + col; + for (int c = 0; c < 3; c++) { + uint32_t idx = (y * W + x) * 3 + c; + uint32_t val = idx % (max_val + 1); + if (bits == 8) { + tile_buf[(row * tw + col) * 3 + c] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)tile_buf)[(row * tw + col) * 3 + c] = (uint16_t)val; + } + } + } + } + if (TIFFWriteTile(tif, tile_buf, tx, ty, 0, 0) < 0) { + fprintf(stderr, "Error writing tile at (%d,%d) to %s\n", tx, ty, path); + _TIFFfree(tile_buf); TIFFClose(tif); return -1; + } + } + } + + _TIFFfree(tile_buf); + TIFFClose(tif); + return 0; +} + +/* Write a grayscale float TIFF (32-bit or 64-bit). Values are (y*W+x)/255.0 */ +static int write_gray_float(const char *path, int float_bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, float_bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + double val = (double)(y * W + x) / 255.0; + if (float_bits == 32) { + ((float *)buf)[x] = (float)val; + } else { + ((double *)buf)[x] = val; + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write an RGB float TIFF (32-bit). Values are idx/767.0 where idx = (y*W+x)*3+c */ +static int write_rgb_float(const char *path, int float_bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, float_bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + for (int c = 0; c < 3; c++) { + double val = (double)((y * W + x) * 3 + c) / 767.0; + if (float_bits == 32) { + ((float *)buf)[x * 3 + c] = (float)val; + } else { + ((double *)buf)[x * 3 + c] = val; + } + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a signed integer grayscale TIFF. Values cycle -128..127 for 8-bit, + * -32768..32767 for 16-bit. */ +static int write_gray_signed(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + int32_t pixel_idx = y * W + x; + if (bits == 8) { + /* Cycle -128..127: signed_val = (pixel_idx % 256) - 128 */ + int8_t val = (int8_t)((pixel_idx % 256) - 128); + ((int8_t *)buf)[x] = val; + } else if (bits == 16) { + /* Same pattern but 16-bit signed: cycle through -128..127 for simplicity */ + int16_t val = (int16_t)((pixel_idx % 256) - 128); + ((int16_t *)buf)[x] = val; + } else if (bits == 32) { + int32_t val = (int32_t)((pixel_idx % 256) - 128); + ((int32_t *)buf)[x] = val; + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a 4-channel CMYK TIFF. Values cycle 0..max per channel. */ +static int write_cmyk(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED); + TIFFSetField(tif, TIFFTAG_INKSET, INKSET_CMYK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + for (int c = 0; c < 4; c++) { + uint32_t idx = (y * W + x) * 4 + c; + uint32_t val = idx % (max_val + 1); + if (bits == 8) { + buf[x * 4 + c] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)buf)[x * 4 + c] = (uint16_t)val; + } + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a palette (indexed color) TIFF with 8-bit indices and a known colormap. + * Colormap: R[i] = i*257, G[i] = (255-i)*257, B[i] = (i*37 % 256)*257 + * (multiplied by 257 for 16-bit colormap entries per TIFF spec). */ +static int write_palette(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + int ncolors = 1 << bits; + + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + /* Build colormap — 3 arrays of ncolors uint16 entries */ + uint16_t *r = (uint16_t *)calloc(ncolors, sizeof(uint16_t)); + uint16_t *g = (uint16_t *)calloc(ncolors, sizeof(uint16_t)); + uint16_t *b = (uint16_t *)calloc(ncolors, sizeof(uint16_t)); + if (!r || !g || !b) { + free(r); free(g); free(b); TIFFClose(tif); return -1; + } + for (int i = 0; i < ncolors; i++) { + r[i] = (uint16_t)((i % 256) * 257); + g[i] = (uint16_t)(((255 - (i % 256))) * 257); + b[i] = (uint16_t)(((i * 37) % 256) * 257); + } + TIFFSetField(tif, TIFFTAG_COLORMAP, r, g, b); + + /* Indices cycle 0..ncolors-1 */ + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { free(r); free(g); free(b); TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + if (bits == 8) { + for (int x = 0; x < W; x++) + buf[x] = (uint8_t)((y * W + x) % ncolors); + } else if (bits == 4) { + /* Pack two 4-bit indices per byte, MSB first */ + for (int x = 0; x < W; x++) { + uint8_t idx = (uint8_t)((y * W + x) % ncolors); + if (x % 2 == 0) + buf[x / 2] = (uint8_t)(idx << 4); + else + buf[x / 2] |= idx; + } + } else if (bits == 1) { + /* Pack 1-bit indices */ + int bit_offset = 0; + for (int x = 0; x < W; x++) { + uint32_t idx = (y * W + x) % ncolors; + pack_value(buf, &bit_offset, idx, 1); + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); free(r); free(g); free(b); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + free(r); free(g); free(b); + TIFFClose(tif); + return 0; +} + +/* Write an RGBA TIFF with associated alpha (pre-multiplied). */ +static int write_rgba(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + uint16_t extra_samples[] = { EXTRASAMPLE_ASSOCALPHA }; + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + for (int c = 0; c < 4; c++) { + uint32_t idx = (y * W + x) * 4 + c; + uint32_t val = idx % (max_val + 1); + if (bits == 8) { + buf[x * 4 + c] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)buf)[x * 4 + c] = (uint16_t)val; + } + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d to %s\n", y, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + + _TIFFfree(buf); + TIFFClose(tif); + return 0; +} + +/* Write a multi-page TIFF with 3 gray pages. Page n has values offset by n*50. */ +static int write_multipage(const char *path, int bits, const char *mode) +{ + TIFF *tif = TIFFOpen(path, mode); + if (!tif) { fprintf(stderr, "Cannot open %s\n", path); return -1; } + + uint32_t max_val = (bits < 32) ? ((1u << bits) - 1) : 0xFFFFFFFFu; + int npages = 3; + + for (int page = 0; page < npages; page++) { + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, W); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, H); + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bits); + TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); + TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H); + TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); + TIFFSetField(tif, TIFFTAG_PAGENUMBER, (uint16_t)page, (uint16_t)npages); + + tsize_t scanline_size = TIFFScanlineSize(tif); + uint8_t *buf = (uint8_t *)_TIFFmalloc(scanline_size); + if (!buf) { TIFFClose(tif); return -1; } + + for (int y = 0; y < H; y++) { + memset(buf, 0, scanline_size); + for (int x = 0; x < W; x++) { + uint32_t val = ((y * W + x) + page * 50) % (max_val + 1); + if (bits == 8) { + buf[x] = (uint8_t)val; + } else if (bits == 16) { + ((uint16_t *)buf)[x] = (uint16_t)val; + } + } + if (TIFFWriteScanline(tif, buf, y, 0) < 0) { + fprintf(stderr, "Error writing scanline %d page %d to %s\n", y, page, path); + _TIFFfree(buf); TIFFClose(tif); return -1; + } + } + _TIFFfree(buf); + + if (!TIFFWriteDirectory(tif)) { + fprintf(stderr, "Error writing directory page %d to %s\n", page, path); + TIFFClose(tif); return -1; + } + } + + TIFFClose(tif); + return 0; +} + int main(int argc, char **argv) { if (argc < 2) { @@ -255,6 +804,178 @@ int main(int argc, char **argv) else { printf(" FAIL seq-3c-%db-planar.tiff\n", b); ok = 0; } } + printf("\n--- Standard depths with compression ---\n"); + + /* Gray 8-bit: LZW, Deflate, PackBits */ + { + struct { const char *suffix; uint16_t comp; } comps[] = { + {"lzw", COMPRESSION_LZW}, + {"deflate", COMPRESSION_DEFLATE}, + {"packbits", COMPRESSION_PACKBITS}, + }; + for (int i = 0; i < 3; i++) { + snprintf(path, sizeof(path), "%s/seq-1c-8b-%s.tiff", dir, comps[i].suffix); + if (write_gray_compressed(path, 8, comps[i].comp, PREDICTOR_NONE, "w") == 0) + printf(" OK seq-1c-8b-%s.tiff\n", comps[i].suffix); + else { printf(" FAIL seq-1c-8b-%s.tiff\n", comps[i].suffix); ok = 0; } + } + } + + /* Gray 16-bit: LZW, Deflate */ + { + struct { const char *suffix; uint16_t comp; } comps[] = { + {"lzw", COMPRESSION_LZW}, + {"deflate", COMPRESSION_DEFLATE}, + }; + for (int i = 0; i < 2; i++) { + snprintf(path, sizeof(path), "%s/seq-1c-16b-%s.tiff", dir, comps[i].suffix); + if (write_gray_compressed(path, 16, comps[i].comp, PREDICTOR_NONE, "w") == 0) + printf(" OK seq-1c-16b-%s.tiff\n", comps[i].suffix); + else { printf(" FAIL seq-1c-16b-%s.tiff\n", comps[i].suffix); ok = 0; } + } + } + + /* Gray 8-bit LZW with horizontal predictor */ + snprintf(path, sizeof(path), "%s/seq-1c-8b-lzw-hpredict.tiff", dir); + if (write_gray_compressed(path, 8, COMPRESSION_LZW, PREDICTOR_HORIZONTAL, "w") == 0) + printf(" OK seq-1c-8b-lzw-hpredict.tiff\n"); + else { printf(" FAIL seq-1c-8b-lzw-hpredict.tiff\n"); ok = 0; } + + /* RGB 8-bit: LZW */ + snprintf(path, sizeof(path), "%s/seq-3c-8b-lzw.tiff", dir); + if (write_rgb_compressed(path, 8, COMPRESSION_LZW, "w") == 0) + printf(" OK seq-3c-8b-lzw.tiff\n"); + else { printf(" FAIL seq-3c-8b-lzw.tiff\n"); ok = 0; } + + printf("\n--- Tiled images ---\n"); + + /* Gray tiled: 8-bit and 16-bit */ + snprintf(path, sizeof(path), "%s/seq-1c-8b-tiled.tiff", dir); + if (write_gray_tiled(path, 8, "w") == 0) + printf(" OK seq-1c-8b-tiled.tiff\n"); + else { printf(" FAIL seq-1c-8b-tiled.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-16b-tiled.tiff", dir); + if (write_gray_tiled(path, 16, "w") == 0) + printf(" OK seq-1c-16b-tiled.tiff\n"); + else { printf(" FAIL seq-1c-16b-tiled.tiff\n"); ok = 0; } + + /* RGB tiled: 8-bit */ + snprintf(path, sizeof(path), "%s/seq-3c-8b-tiled.tiff", dir); + if (write_rgb_tiled(path, 8, "w") == 0) + printf(" OK seq-3c-8b-tiled.tiff\n"); + else { printf(" FAIL seq-3c-8b-tiled.tiff\n"); ok = 0; } + + printf("\n--- BigTIFF ---\n"); + + /* BigTIFF: gray 8-bit and RGB 16-bit */ + snprintf(path, sizeof(path), "%s/seq-1c-8b-bigtiff.tiff", dir); + if (write_gray_compressed(path, 8, COMPRESSION_NONE, PREDICTOR_NONE, "w8") == 0) + printf(" OK seq-1c-8b-bigtiff.tiff\n"); + else { printf(" FAIL seq-1c-8b-bigtiff.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-3c-16b-bigtiff.tiff", dir); + if (write_rgb_compressed(path, 16, COMPRESSION_NONE, "w8") == 0) + printf(" OK seq-3c-16b-bigtiff.tiff\n"); + else { printf(" FAIL seq-3c-16b-bigtiff.tiff\n"); ok = 0; } + + printf("\n--- Float samples ---\n"); + + /* Gray float: 32-bit and 64-bit */ + snprintf(path, sizeof(path), "%s/seq-1c-32f.tiff", dir); + if (write_gray_float(path, 32, "w") == 0) + printf(" OK seq-1c-32f.tiff\n"); + else { printf(" FAIL seq-1c-32f.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-64f.tiff", dir); + if (write_gray_float(path, 64, "w") == 0) + printf(" OK seq-1c-64f.tiff\n"); + else { printf(" FAIL seq-1c-64f.tiff\n"); ok = 0; } + + /* RGB float: 32-bit */ + snprintf(path, sizeof(path), "%s/seq-3c-32f.tiff", dir); + if (write_rgb_float(path, 32, "w") == 0) + printf(" OK seq-3c-32f.tiff\n"); + else { printf(" FAIL seq-3c-32f.tiff\n"); ok = 0; } + + printf("\n--- Signed integer ---\n"); + + /* Signed gray: 8-bit, 16-bit, 32-bit */ + snprintf(path, sizeof(path), "%s/seq-1c-i8.tiff", dir); + if (write_gray_signed(path, 8, "w") == 0) + printf(" OK seq-1c-i8.tiff\n"); + else { printf(" FAIL seq-1c-i8.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-i16.tiff", dir); + if (write_gray_signed(path, 16, "w") == 0) + printf(" OK seq-1c-i16.tiff\n"); + else { printf(" FAIL seq-1c-i16.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-i32.tiff", dir); + if (write_gray_signed(path, 32, "w") == 0) + printf(" OK seq-1c-i32.tiff\n"); + else { printf(" FAIL seq-1c-i32.tiff\n"); ok = 0; } + + printf("\n--- CMYK ---\n"); + + snprintf(path, sizeof(path), "%s/seq-4c-8b-cmyk.tiff", dir); + if (write_cmyk(path, 8, "w") == 0) + printf(" OK seq-4c-8b-cmyk.tiff\n"); + else { printf(" FAIL seq-4c-8b-cmyk.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-4c-16b-cmyk.tiff", dir); + if (write_cmyk(path, 16, "w") == 0) + printf(" OK seq-4c-16b-cmyk.tiff\n"); + else { printf(" FAIL seq-4c-16b-cmyk.tiff\n"); ok = 0; } + + printf("\n--- Palette (indexed) ---\n"); + + snprintf(path, sizeof(path), "%s/seq-1c-8b-palette.tiff", dir); + if (write_palette(path, 8, "w") == 0) + printf(" OK seq-1c-8b-palette.tiff\n"); + else { printf(" FAIL seq-1c-8b-palette.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-4b-palette.tiff", dir); + if (write_palette(path, 4, "w") == 0) + printf(" OK seq-1c-4b-palette.tiff\n"); + else { printf(" FAIL seq-1c-4b-palette.tiff\n"); ok = 0; } + + printf("\n--- RGBA (associated alpha) ---\n"); + + snprintf(path, sizeof(path), "%s/seq-4c-8b-rgba.tiff", dir); + if (write_rgba(path, 8, "w") == 0) + printf(" OK seq-4c-8b-rgba.tiff\n"); + else { printf(" FAIL seq-4c-8b-rgba.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-4c-16b-rgba.tiff", dir); + if (write_rgba(path, 16, "w") == 0) + printf(" OK seq-4c-16b-rgba.tiff\n"); + else { printf(" FAIL seq-4c-16b-rgba.tiff\n"); ok = 0; } + + printf("\n--- Multi-page ---\n"); + + snprintf(path, sizeof(path), "%s/seq-1c-8b-multipage.tiff", dir); + if (write_multipage(path, 8, "w") == 0) + printf(" OK seq-1c-8b-multipage.tiff\n"); + else { printf(" FAIL seq-1c-8b-multipage.tiff\n"); ok = 0; } + + printf("\n--- Big-endian ---\n"); + + snprintf(path, sizeof(path), "%s/seq-1c-8b-bigendian.tiff", dir); + if (write_gray_compressed(path, 8, COMPRESSION_NONE, PREDICTOR_NONE, "wb") == 0) + printf(" OK seq-1c-8b-bigendian.tiff\n"); + else { printf(" FAIL seq-1c-8b-bigendian.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-1c-16b-bigendian.tiff", dir); + if (write_gray_compressed(path, 16, COMPRESSION_NONE, PREDICTOR_NONE, "wb") == 0) + printf(" OK seq-1c-16b-bigendian.tiff\n"); + else { printf(" FAIL seq-1c-16b-bigendian.tiff\n"); ok = 0; } + + snprintf(path, sizeof(path), "%s/seq-3c-8b-bigendian.tiff", dir); + if (write_rgb_compressed(path, 8, COMPRESSION_NONE, "wb") == 0) + printf(" OK seq-3c-8b-bigendian.tiff\n"); + else { printf(" FAIL seq-3c-8b-bigendian.tiff\n"); ok = 0; } + printf("\nDone. %s\n", ok ? "All succeeded." : "Some failed!"); return ok ? 0 : 1; } diff --git a/tests/images/seq-1c-16b-bigendian.tiff b/tests/images/seq-1c-16b-bigendian.tiff new file mode 100644 index 0000000000000000000000000000000000000000..dfd127bb766af4f7ae9b111988893a2ee55f71bb GIT binary patch literal 658 zcmYk)WsnsF6o%pFF17U1-HkLzHz>KJbSPcYhzN+%C>V63G)N=eN;gU?3QB{DgrvmX z85r)LGw+;vzw_sOk&$u}7LI^0(L@(ROtFNEEsnV2i7$bKA|#Sn5=kYKTnZ_rl3E&R zrITI;8D)}L7FlJJT@E?r3SNFg9(m=HUjYRbQdkjhDyo>`N+_w6(#j~SoboEDsFKRw z^0q3fs;0UcYKl}#ZFSUDPkrxbprJ+@Yoe)Unroq@cfF^T*4k*Ro%TBDsFTjRcwblD zbk{>qz4X?{2m1O@KOgCDfPp?X$R|EE*bqYvGu#Lxjq;h#jW)&?zVwx^jWy1A6HGM8 zWK&Ev&2%%&G|M->HQO9>%`@Ku3oWwPca~UcndMekX_eK!x5irQthd2Nn{2klR@-d1 z!w-J6(=NO1vDZHP9dOVghaGX$F+cg)aVMN~%4uhu^^0Gf^PAtDcflY2bkQZ3U2)Yl z*WGZ_U;g%wTmE(19e3UHpZgwo=#j^s_}^2{JQp`0`2DCBL0C)2mklf_1lE4Gg#aYI-3+ zx!3e!i1FF27lO3cZoL?0{kHT%p!(d>i=pOszg`H|-~07qxcy&Vg9{4HyoOf{4)+>d z(pcPUc+KLmufau?$-ahHO)j4`xU94Jtl@Q=&$=5fD0S;@ykc~E?S@NQtJiM4X7xIE z!$q~(xf`#V-F~~_vfl2u8?W2_mMyrT*e+Xm#qjvtf=imq=N4YGd>&hHQFVH3;Z@V? zcMC4-ZogZ2-S)ffhYQO6wjZw;pWpl8lJ@$&AFo-zul;aQeSYo7tLFFrez>f^|L@1^ z_Wv29f7drMa5FG4GBW^!8XU@uNNgq~HZzpHseyrk4ax@T5oBZm>*WBlMUlkCko1Z} S)g%Hn$RMc+Mq&fCGXMZWv9%fi literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-16b-lzw.tiff b/tests/images/seq-1c-16b-lzw.tiff new file mode 100644 index 0000000000000000000000000000000000000000..c096523559196eac8e96a57a508a633af64f5a84 GIT binary patch literal 758 zcmYk4J4{qT6o$XqoyYpVs615EO)Ml@xQT@%7OtWK;^QhRC@QO{prEXxg5u*ZDQ`)+ zCFPcsl$5um+>(;g(utwiVlrR;oX3A=&hYR#<_aJnp+pe_DLn+Dn$gF;sFBmpAuJ|g zh$A>m$~fJ4OvVf+Vz|j!;&d!gNLb+vdnlx=a+bXmGS)aBD;09qxxjvk37cHx0L7Fo zE^&}z#x|E@lVZ+au0%67F(n4*z^0~$K@MXx)5l2cZ*$YnJ&xiMGsGyJxYUd@Mi(wK zGfYHlE;ma|#z}l)R+!=#J~gXMa~z+UHD;r0pPO~&=_Mp)lLbx^QnSS(rwEzZW;qTN zaufZ?LRB{5s%)8SvK0not6Y~&xglHQrfi)-SurG=F)Z8QmTZ#|*$r;X=G>8OaaVSS zdvcJknvri!4HKd%L*I(RLJ?I(Bikk4u4cC#sA0r v-!Bp(wsE12i@O{j2*1lFa)*iQ7w=L$oo#woTWVH-_LsR`6MUDi4GUMFySIZdO(zPqNVqshdk^N89XYZOft(Ns~C^T z=5g8OkW;K&a?9fhPs%Hwr{q__(+VmiPGLn9^^9VQE1{%PN-LwRa-LP*bDmeh3o5Fl zvMS;wNR*_iYN|{2q8e&?Ni8p{?G<&TsH>j(8fd7I#$MG#Q_VEjLQAh{rL{KNYUg$B zbUeTOWPB<6ZsqH^4xH3^v42!wfgVd*1hfkwzJ9jIqWU z??WG%V4_JTn_{YIru*0opZL^gX8PP0zVww@W}9QKdFESSp+y#3VyR`8TVbVDzV?l8 zt+vKm>wIUu4K~_jvn{^&gCA|R&2~HNw99UL?Ddm<_WRi{4mjwL!+!OfBaS-exD!q~ z<#&Jh(`kP>u$K|mfP;Q>tFZ$7wlPBL~sLwO$Q8dc!(p? noSGLE;+PP}hB!XWsXY@yoER2)e^zwxpOog{{G^1`1|k0gpmTzb literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-32f.tiff b/tests/images/seq-1c-32f.tiff new file mode 100644 index 0000000000000000000000000000000000000000..b77d2705d46c00505f8c8b19350e9220b68117f0 GIT binary patch literal 1170 zcmYk6cTf~}6vy|37!s4HNz@dRn4Xy4i?{Ea#5B?q(|hl|_n`?#5fBiLA{<4!fPiom z0Ria(0@8(}NEZ+gjw1TS;SY9ZXWstiz1`1u-e=a@dZS`xshqiNZEQB#+9=xnd5>sW zYeNkN)_K|vlZnrYy4`b?8fw^}?n$~+WsiEO`X#l)^r3ou^hcHbs@cZ05WoTOBOLS!X5N+|CnzOLq8N zEdKgSWM|NN;df4LrIFhxS(%w+&z9Vr9P;N$L4H0n6iRVX5p$GCd082=R7h22CG%8E zZA}d`)k#BrJ##fmOLH@`wMu(i8}pf@tFx0CyQR0MhdKLXaA1I0hh$`Un0ZHKd~A%F zCuC}JlDW+?J2S)Vb8>2ap7|Bn*=k^Kw+s&U7T_-6xb-YJIWC9J>1=Q>aB)5dt}f@o z&2RK*H|ZkeF~gk`nI#eL(V_yO5H6H&RpX0o_2_-usZAc0Y{i4}hK^Gvgs-Wj>7T ztWBUZ$l0eNH%E|{3(z0r?|&2p`H!KnU^D0viVi%1;-V)}Qv4L?70ODjQC{{8D$1V) z9Yf{8=TTMp0;;QC1bsuzp_frx^9t%}w}9@U{_tyPsDB-e4R3%RqPgiUv^2ks)|Pib zC((A~J+!yI4^#UGpr7dM_y}E{AEUeL6VO%k9Q_QvJ)fhm_Y2Tl4D^46!GW(aH24kZ zFoutPhmqm$F*@=C=rhKS|Ag_epD{813+Of`PyB|d$=_j~`UCVFGt+-zcII!)&He*A zkNK1T;ne*9P!t=iP!x@YqTzpF6>rUwdf8&Vf#(*B^+MnBCG~2J<(XM4p08PQzIL%* Xc;~vs9)*9K^-FrTEY=q6S-4IE_2D8o literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-4b-palette.tiff b/tests/images/seq-1c-4b-palette.tiff new file mode 100644 index 0000000000000000000000000000000000000000..f16f7fd342efb1de8fa0b9a84d44215d0ad78cdb GIT binary patch literal 382 zcmebD)MDshU|?WWc1`bGefIr8(L6vWFf%X$T_ON-4HBCP%4PwIGeg-Rb!<>JGmtIF z$O6{O0c49JsS$&+L1v0W)ieOvGDvD1fNTSxm>kg1U?g#%5D+jjGBGhTv#_wTvazwV zb8v8Sa&d8U^YHNU^6~NW|NsB*-`~G~{`~&^>(|epKYo1w{_We>uV21={`~3F$B!RA mFfgd9dU@sNPnoiF=e>K(%o-ZLzC}gTr|;SG@F5$Uwl)BxW^6tH literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-64f.tiff b/tests/images/seq-1c-64f.tiff new file mode 100644 index 0000000000000000000000000000000000000000..e8a96830d7f83715e56fd083e22b186328239144 GIT binary patch literal 2194 zcmYk;*N>EC7zOZI*BBCS00mUqy;q989&Wjl4i@|uP_co6mtIm9SYRnJh8RN#+k2sR z*y(-do8D*W9b}%fCuV=iX1|^N=9~9@-gC0MY}uQx88ck}n@Jln_5BaLMt|z(?Rb^i z^m;oMP=|hh1heTc-S;=<(ox<258j}E^}b_RM92016PQJvdQKN!p>92|2Xm-b&+WrJ z>eurJ@H!3ZbA~XVhV^+PSV*J#+%YVsaee*-c5F8jTE|K3++j{?J*Tj1r#Yo{okrU( zb6V>=gWYZBjMjM;dv=?%TJJgR-DA#a-RIH1*PPe-FJNE0xuAVq#QuHeqV{tM2lksw z+Sg@t959!)zbiP{VXkPOS8?c|xvKqM!{I~bn)ZDiM-H3o+W#cJph?YP67EUTJlt4L zZq3CFkDD|f4_1&zbMnCJA9pETb9 z)=)rm4j>pH%{z#-6x7^<2n9*=4`CgJbPgeeL!|QvV?Bj+E@4E%r1Od3ON!{6B8Wyv z=M}|Q6xF#!5sQ+}FNUuvrgMxT9wVJ+9N$n}=Nd;MPCDNNHc&$6oIo-`I`1UDrKHY1 z2`5Q9e+O@oqZ~NcNRIO0p!0-rlnVzpZx~1UNa1ZtDJLm>M=9kcg|1GMQf^YXb@m)v~rck?OP_Td}Z(sWt6iFexQuzCDL3uA=px+df`vM-^HwERth!3f#9u)Bl z71f6#1_w-0y(r@015;E#O8AIM>PZQ|Qb~O&VQA2l)SD6>Jv1ftr;LxOtR9uInab)@ z8N)-StX`Gz_>n2AUln{p74@uwEmTq8Di|3y74@!yCyz}<{j1_rs;Y-o{62Ut)z2C}qndhJ!|zm6Uuzf}H8u6NhG$PrP5rIobE>Pyb!?@&`dr8On5nDR zb^Q0t)Yb0>rZm*^2DVW{eQ#i5+%(kt2B!Y--@wZ*S4*p_rTOE`=2y$K>lbvrwE23g quI;{;rd`i!d6Dn6eMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;UhpC(4T&wt jzyj9Gz`(&MiX<)uWrNHVhpAy?V3a{p6O3R3&0qik`v-xh literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-8b-bigtiff.tiff b/tests/images/seq-1c-8b-bigtiff.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ee1555ff35a73293ff68fb0c5b35d172f845216a GIT binary patch literal 508 zcmebD)MnsdU|tEX>ZXk=_+YG!U>X=QC=YiIA^=;Z9;>gMj@>E-R?>*pU37!({58WtWA z85JE98yBCDn3SB7nwFlCnU$TBo0nfuSX5k6T2@|BSyf$ATUX!E*woz8+ScCD+11_C z+t)u~;-tw_rcRqaW9F>cbLP&QzhL2_#Y>hhTfSoDs?}@Ou3Nuh+#-&o7iNeIk~)~Z!C1r~u4G^U0CqnoxOvjle3Gfo4bdnm$#3vpMOALP;f|S zSa?KaRCG*iTzo=eQgTXaT6#uiR(4KqUVcGgQE^FWS$RceRdr2mU427iQ*%peTYE=m zS9ecuU;l)OlO|7@I&J!lnX_iknLBU(f`y9~FIl>5`HGdRRKIRx^4T8 zox67L*}HH5frEz*A31vL_=%IJPM z`HPpYUcY(!?)`_4pFV&2`tAFVpTBU|?uqU@)*y5#tePc1l>p5n__a+bWx|lkdXzf7o52ESDJ#ynkYy&_$F98a#)m39`3W2}s?2&Gzxv{v zAAZ%@FA&gBkrL!;b6zBUb?>o33k@mIb4 z3l0Wu1_nlE24G+@2mmo75}OIi<^YN_L)olAHXD=;(j&;o0@e#sBZ?$024#cH6o;x& Q25OK&QWK2C1}b9!00{VTiU0rr literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-8b-multipage.tiff b/tests/images/seq-1c-8b-multipage.tiff new file mode 100644 index 0000000000000000000000000000000000000000..20369b5f81ca8738158910afb8cf001d83a3e507 GIT binary patch literal 1262 zcmebD)MDUZWME)mWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;Uh5cj^+{)8{uZG%_|ZH8Z!cw6eCbwX^4UaCCBZadmU|@bvQb@%8iP4+snj4hanl zkBE$lj){$n=TAsXN=`{lOV7y6%FfBn%jYjBEGjN3Ei136tg5c5t*hs6Xl!b3X>Duo z=Fw+1pD=OKNRWEt>@pcant54 zTeofBv2)k%J$v`<=Ra`p(BUITj~zd8^3>@wXV0DIzi{!=o;%Tz32b%@zduoU%!3-@$=X3KY#!I=VoAFWM%*c41)j=Ga|8> ypllAHI5U*Z+Q7iT24#cv2r{yO^@7xhB8iJZ*&s8;p=tzx8f1{v1S7G5$`}B+s)I5B literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-8b-palette.tiff b/tests/images/seq-1c-8b-palette.tiff new file mode 100644 index 0000000000000000000000000000000000000000..735d5a242f5c278de2d033660f964720ac9c88e2 GIT binary patch literal 1950 zcmYk6LvSG47DZ#HW7~E*wr$($*tTukwr$&;j%{20lV3e}r|w|Yu66EU501DvB>)5< z0000W5HJWR7&rtZ6f_L%4>))PL?mPsR5Wx9Oe}01Ts(XNLLy=kQZjN1N-Am^S~_|L zMkeN;EUawo9GqO-JiL7T0)j%qBBEmA5|UEVGO}{=3W`d~DynMg8k$<#I=XuL28Kq) zCZ=ZQ7QZa5tZi)V>>V7PoLyYq+&w(KynTHA`~w1mfX!XqN1qGMv?;u8{+l2cOC z(lau%vU76t@(T)!ic3n%$}1|Xs%vWN>KhuHnp;}i+B-VCx_f&2`UeJwhDS!n#wRAH zre|j7<`)*1mRDAPul-ry*xcIQ+1=YeI6OK&IXyeSxV*Z)xxKr8czk+(d3}5T`1}j= z)c`QScMAphU}c2NG~p#J0UKhgd<-y-&Z9KJ6G z_1Ox&C1_l8E1qA~G2Zw-wgoJ{EhK7NGh5hjZ4h|k30Ra&a2?-e) z1qBrq4GkR~0|OHi3kw??2L~4y4-X%ofPj#Yh=`b&goKoojEtO|f`XEgii(<=hK81w zj*gz5fq{{ciHVu{=T80|EjAgMxyCLqbAB!@|PDBO)RrqoSgtV`5@s)6&w@GcqzWv$C?Yb8>QX^YZfZ3knJgi;9YiOG-*h%gV~jD=I20tE#H2Yieq1 z>+0(38yXrLo0^)NTUuIM+uGXOJ32Z$ySlo&dwP0%`}+F(2L=WQhlYlSM@B|R$HvCT zCnhE*r>3T-XJ%$+=jP_;7Zw&5mzI{7S5{V6fB#-v`}1dgePd&Db8BmRduL~NcW-Zh z|KQ;8@aX9H_~hjD^z7{X{Nm#B^6KjP`sU{L_U`Wf{^8;A@#*RL`Q_#H_3iEb{o~{F z^Y7PuetvwszrVe`zP`LXKR-P^K0Z9$-{0Nc-rn3?Ute8aUS3?BpP!wbo}Qc>A0HhZ z9v&R*@9*vH?(XbtZ*OgFZfumAb8w)Xq?>gvkM^77Ks;^M->{QTV9?Ci|U^z_u! zLizrUZKudk1f zx3`yBR9yStm4tE-EPv$K-5EBy-5fTy*;N#=r;o{=pU}IxpVPaxnprfOq zp`xOoAR{9oAtE9mz{A7A{rCY33j+fU4Fv@W2>}5P4h9Aa3IYNQ3sO03FoYK>KdiM7rA!%t96xeW|LLMkig<{lrhu=x0ljl;uhY8Dq?UT|>*1tIZw~^3hDJfb z#U(SdukY{>8k(M7S=rq^CueZ*CMGpCFR%Rkk&*Lr1OyfqO-*0lqN4Hft1Dz= zc6J?|fPm7{sj1srG&C+Qef{9zii+9UhX+hdUS1=ku(0atg@xy592@}wQ`5-Ey1M1% zw>NxzVPOl4n3%@K-@iXUiHO9+tgPbWTUyrF0Rc%#B_(Zblakuox3)k)C@5rP92`

j57GctO64-TN9=;)M`+}yIW2L_IhVPP2=RaHGb^YVs=&(7fCfBw|a z@bM`u92>j5L_%U?)7JL)FDaRvytzR|<>b`U3koVPpP9M8$H3s>F*FPft*V-ze|o~k r=I1vtiHNAJU0Qm5#lsU4GB=NoZfICt{rDgx6cx3!jEie-{`2R5EZ={$ literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-8b-tiled.tiff b/tests/images/seq-1c-8b-tiled.tiff new file mode 100644 index 0000000000000000000000000000000000000000..6da068836b0ecbc8ca585e9dec2d167dbf86cdf3 GIT binary patch literal 414 zcmebD)MDUZWME)mWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;UhNKbOgEO4z zEN45%xz2OG3tZ?T7rVrzE_1mnT{K=m^>M?)uxFK>NT%>!$17fzx>;O z{MY}y=`C-2$GiUTJ@5O#hd%PLPkib#pZmg>zVfwiR0tuIFrpBZXna68(TPD!V(}rd zi9=lC5uXGkBoT>8LQ;~EoD`%a6{$%>TGEl83}hq|naM&{vXPw}Q3Jl%*WysX#?45kY0D@F`WPMs;dXlUmfK4t1$VeHze^ zMl_}gO=(7RTF{bKwB|EDrwwgsM|(QZkxqO;XS&dpFZqhE=|*>Y(34*DrVoATM}Gz| zFtC)6u)qfdmIg40LxVUhlHcW`1#!HPDDS)B0Y6cYpE#(SBr+4YnUq19+L0Wv-|H=R CDgihE literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-i32.tiff b/tests/images/seq-1c-i32.tiff new file mode 100644 index 0000000000000000000000000000000000000000..4a2fcc1bd7ccc2c9f1d85d2204f22ae8b7df059d GIT binary patch literal 1170 zcmYk)WsntQ6b9gXcbAnC1=(G|l@I}0=~hZage65v1?lb(kOsj(8Wb@o36(Ad1yNGz z?od*cmXOlrxjXmAo|$LnoipeA{+yGTm=H)E6$lJXN=h2Wy9{Rp@9{n#@F64lh*6AY z3}YF`cqTBBNqo#FOy*Oj@EM=;1z$3iX-sDZGx>^H%w`UA`I>L|mU+x)0Sj5gVwSL! zWh`d}-|;;wS;Y_h$ZFQ`6KnaIUs%U_Hn5RRZ01*fV+&i^#&&kFlU?j)4}00iehzSu zLmcJ^M>)oEPH>Xn`GZrO<_u>!$9ewb0)O#07rDe`u5guWT<0HdaFbiy=3nk`mwVjj z0srwop$e!V5k%r70;!1R5mJ+ew4@_FkCK7Mc$|!6;t4VnLo9J*AuHK?N=t^Qz^kc(0^k-anCUjcyDQ4=0bA*{tJp^d=09yb6 literal 0 HcmV?d00001 diff --git a/tests/images/seq-1c-i8.tiff b/tests/images/seq-1c-i8.tiff new file mode 100644 index 0000000000000000000000000000000000000000..821c8d32a99d53d9f94cd352ac05c94f943536c5 GIT binary patch literal 402 zcmebD)MDUZWMF7$Y-(<4ZENr7?CS36?dzW~anj@|Q>RUzF>}`JIdkXDU$Ah|;w4L$ zEnl&6)#^2C*R9{Mant54TeofBv2)k%J$v`pllAHI5U(DQpbkG7Gz`r f>jkM1MG_Z-vO#8wL)Cy3${?u;hO(J}YCr%0@(zKY literal 0 HcmV?d00001 diff --git a/tests/images/seq-3c-16b-bigtiff.tiff b/tests/images/seq-3c-16b-bigtiff.tiff new file mode 100644 index 0000000000000000000000000000000000000000..71232bd25973ddc3f034f2d6e4a3c6ed2ef26438 GIT binary patch literal 1788 zcmZXVWz-Nv7lh{-kQ908PU-IM?(PO@>F(|Z>F)0C4(SF-rBS*YeD#Cxyytj-?A|jw zcV_?WPVwR?6-rV-h`{CFLRK&Z*LMn`kb!5R6-Ht8y~61Sg;#(gD54@MvZ5%eqA9v! zD5hd5w&EzR;wiooD4~8-A|+N5B~>ydR|=(6Dy3E$rBynmR|aKNCS_I@WmPt1R}SS= zF6CApX z)m1&!R|EZ|hH9k7YNDoUrsn!tE!0x2)LL!SR_)YY9n?{s)LC8BRo&EGJ=9aZ)LVVj zSN+sq12j;BG+0A4RKqk}BQ#Q@G+JXcR^#-G#%qEmYLX^vil%CsrfY^~YL;eej^=8f z=4*i#YLOOeiI!@amTQGpYL!-Njn-X3fbVI9#?9n*20&`F)rX`Rtoozr<;&_(^GOS-Hpx~glsuHW^CZs?|N>9+3ZuI}l+ z{?uQ3poe;-$9kftdZy=kp_h84*LtJ3dZ+jLppW{b&-x+(CK$o_ju3<-6rl-2SiUD5 zKMCL?#MRiAHo{5R+KMCJu3lM|={HkRM4zVv>-QWF#jADM>|Y(vX&Pq$dLz z$wX$dkd00k*TVTw?cViczYB`HN|%21Yal&1m}sYGR}P?c&_ zrv^2tMQ!R(mwMEv0YA}@Ml_}gO=(7Rex?O2X+>+=(3W-EM^HyS;lf!u##1*W({ju$9gufkxgu73tQR7c6P9nUF>ELd)dc+4seh|{K{dD zaFk;l=L9D?#c9rPmUEov0vGv>OI+p(SGmS@e&-KvaFbiy<_>qc$9?|fFCOraM?B^U zPkF|3UhtAvyygvWdB=M`@R3h^=1bt?$96CW_jeBAkPhY04&$)?-r@X%!#ltc9MO>+ z*-;$T(Hz||9MiEJ+i@J%@f_a?oX|fykrO+KlRBA`JB3p^l~X&7(>k5gJA*SilQTPu zvpSozJBM>RmvcLh^E#jNyMPP2kPEwri@KPLyM#-+luNse%etJ)yMimak}JE4tGb%2 zyM}AJmTS9?>$;xnyMcdlLpO3`H*r%pb94Xf7H;WQZtXU1>vnGM4({kq?(8n^>Td4t z9`5O0?(IJA>wfO<0Uqc<9_%3=>R}%45gzGL9_=w6>v8_Y<2}I>J;{?j#Zx`a(>=p8 zJ%GAny~&%s#aq42+r7g(z0143 z$9uic`+dL%eaOH1u#fntkNLPy_@qzyw9ojg&-uJB_@aOFC13UxU-dO#_wWA0H+<8# zeA{*4@JE00XMb_n|HnWu@wE^5 zy2F35z`r6eE&f*lf$8uMH&_tfH;oWMFn{GoAmBe9QG)Qk=|&BLeY;DvAhUr%^>4)v U!u#f1F%bKvL!jF?{GWlp0b$aF82|tP literal 0 HcmV?d00001 diff --git a/tests/images/seq-3c-32f.tiff b/tests/images/seq-3c-32f.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ab46c0c0f5a5d5892a302f3019b6d15f06c8383b GIT binary patch literal 3230 zcmYk9cU06@9>oVW#zZ3`QZZWiejO6QZ}1SvI(Lh zB4*tro6UyaK@mIBq_fu?|H#albKZIL=DqKE_cQl?e{OE;R7;kr{(KeoS2-5;uXFlw z-7Y7Nol=iBa;#FDBhYIUa zT$*BeMuHM#lFV~bmDu&C*sbfuNlvB<>v95DU*P&ln+i%MB(C@6T zQPFp8VU2ByO@1fq>{0y3`&jD*CE9C{^{HLb&H&Gc9rBDH=&NAx5-nw4tYuG4R4{QVtvFX;+>ojKI7( znY#WnIr~NGHvLN0ewCEN{~>R`iSN*FWbVJBx8-+o_q%i-`5)Q)L&|RcLH-&g(xr(E zHi>m^GdXOLnc)_)*ea)8+sI>^q~^7g$qw-w?I4$(V&L9IHoK%JzngsaNcmU~8SRxQ zk3MqRC$@$CWc9qvj-My57o^^EfXog^deKF4J17AYgJk!T81fH9e~{kdD`fbpR8C$c z$JbJUMm|PD_M%f729+kkEQSv<|tNq8x__*|!-y-J| zQZ+k4)+c3Wz!Z6(68p+&GCw1#`5AIQD`x}e$o`yUR?U-t6^wSNklU!jaw84Ui!j`% zfgqy=Xxg;^^dY*h` z5AL0Mps&ItSs(eG`p~j606i9CodyW8GDJ(VA?UZLv04q&l+`HcS`B(H;!@UNtZNOn zS>F%(Fx5rnY_ff30dkpk*jQ2iC?Kp1t1k5s? zKw;k#pwA;A<4KJ7J&92Jr$En#Xa7?;VZRP$nd?CRhqi+e5;Bc&tKSIB0<>is!}Gi` zPB@r=xqzbcCeU^?MZ#`VFe4D=XomLPX7IdV2Id9K_n4#Tf;m<>S%BGrTNf-4=46TX zJ(ggO;G~lk%=cQMXut~06eRAo#>9X%!qhfkzQF6E4Nj_UVUcAEW(`&;c1X;!!^A~9 zFn7?AWe=}Gdz@4pzzjn1paXQo5lQNfj<*^06uKj>}oN6Ha@FlQ0DB>>$=0^oZy z0L)xi9}Ps=%|Ph8Yz6Zd(>J#w(&cG%AAK6kVw`q)2G+UHpltXVFqe^<`z&ULpGBnW zb6`fpZ{#_gc6}Z;dC!A+4Sly4kec@bW=38Bvl~5mFT!v1MVxkf3CwYnkG=#0_m`2D z|1y~Ah;n}gJ^8P|f9w@7-(gemD$2)Rg@MOwVAf-H>@`GrypEoN*TLLJy~i7{EqntN z<8OdH0MZJBFgqTEXwP7v{qR>|o z1@;&?;}Z?L(r8ppMT7kYGD>$~ZfXa1`0fOI4+Ku{M1${}uq%5L>_f2H?=57My@mPd zx4@nRePwSWaOQ0^_`L)6C#afv2dn+xMMn9%V6TFm{_ml`{5=HDz6bU#u&;O@RkQD7 zO~40W4}S_6gwl_S&2~Pa$hnx8Jwt7OMUaB)dz= literal 0 HcmV?d00001 diff --git a/tests/images/seq-3c-8b-bigendian.tiff b/tests/images/seq-3c-8b-bigendian.tiff new file mode 100644 index 0000000000000000000000000000000000000000..be659fe324f609e9349ae90221cdddefafffe158 GIT binary patch literal 926 zcmebEWzb?^VCG<8WMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;Uhvy^I7|&Q1EUO*Il*8y$ov^VGk_+5AtTTw Fi~wOmf&u^l literal 0 HcmV?d00001 diff --git a/tests/images/seq-3c-8b-lzw.tiff b/tests/images/seq-3c-8b-lzw.tiff new file mode 100644 index 0000000000000000000000000000000000000000..2e98747db66a9a57d44dfd08521f0c393f1c398e GIT binary patch literal 770 zcmebD)MChCVqj=sU{Fwy5a42CZemne5Mdz2$KJxEs4ycyON_gXS#iOQ0xLQG4i+Uv zi3wh6!d52ESDJ#ynkYy&_$F98a#)m39`3W2}s?2&Gzxv{v zAAZ%@FA&gBkrL!;b6zBUb?>o33k@mIb4 z3n7kXMUEheb|sEU8r{kqmn`~KIE6eWt8xZKOjqNalrdYK^HRlp4KAUM#hP3}GnQ*{ zO|&mAO9T$gt(d)YD7u3FVdK$)xB8bmR0`}O)0O*OEsgSrZ3Z+l{I_0=B=vv zE3~A#7O&KbnzekD)~r>lS8LtcwSJAZ)TzyDwWDrrU#C6m)$aA$w|?#4pd-z7c%x3V z)bUL^v$ald*12tUev7WO*X6Cc(NWj8>CVo&yP63bzDsZRs@J>q zZtr@(M_>BX=e_#Tx4!SwpZ)6he*N3O{?C8G!NASHz{t$N$iToL0K|+)Y$hO^87TG* zm=c+x;;cYE8IFR$RHr# L07FKgd5jDInjHn{ literal 0 HcmV?d00001 diff --git a/tests/images/seq-3c-8b-tiled.tiff b/tests/images/seq-3c-8b-tiled.tiff new file mode 100644 index 0000000000000000000000000000000000000000..1fcbbe91264da167f3bcd5e9c8dba66b8615be23 GIT binary patch literal 938 zcmebD)MDUZW?*1oWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;Uhe!%cCLmiB$_A;EK~m!cWrNIgMq;}#vViU40E)Xp*&s`TfoeczECCTfzyXGgK(&kv E0FCp4_y7O^ literal 0 HcmV?d00001 diff --git a/tests/images/seq-4c-16b-cmyk.tiff b/tests/images/seq-4c-16b-cmyk.tiff new file mode 100644 index 0000000000000000000000000000000000000000..b3e2a08317bd9a058572c0d9029a6727758c09e4 GIT binary patch literal 2222 zcmYk8Q_vX55`_<9+qP|68{4*RZER~}+qP}nw$1xzZyt8~<*TmKT~jsaQ@nTz1Pg|M zMF>V91V#`9MKAMKUBu3Zz6Tq(&N~MLMKM24qAgWJVTbMK)wd4&+2Gf~u&7>ZpO5sD;|7gSx1P`e=ZLXoSXSf~IJO z=4gSIXoc2jgSKdg_UM3)=!DMbg0AR>?&yJ@=!M?sgTDA1{m>r+Fc5<<7(*}=!!R5p zFcPCM8e=dP<1ii*FcFh58B_2NreYeVV+Lko7G`4(=3*Y^V*wUo5f)u{6uDEX%PxE3hIfu`;W$Dyy+NYp^D3 zu{P_lF6*&A8?Yf8u`!#lDVwo5Td*Ztu{GPUE!(j@JFp`=u`|1{E4#5fd$1>au{Zm$ zFaKsg_U8Z&?yQj^_kUG!IfOa)m+21T*vj?z>VC*&D_GR+{W$P!JXX2-Q2^y+{gVq zz=J%*!#u*HJjUZZ!IM12(>%koJje6Az>B=Z%e=y?yvFOi!JE9r+q}cOyvO@|z=wRq z$9%%4e8%T|!Iyl+*L=gbe8>0vz>oaI&-}u#{KoJ6!JqsU@c1do3Z%daqM!<<;0mFT z3Z>8rqp%96@QR>_iloSjqNs|d=!&73ilx|!qqvHv_)4IJN~FX}qNGZu2>%B9@OqrA$e{3@V=Dx|_HqM|CM;wquPR8pl>T4hvL zltyce#%i3#Yl0?f zk|t}4{?SxT({#tMs3n& zZP8Y3({}C9PVLfe?a^NC(|#S$K^@Xz9nn!8({Y{9NuAPZozYpH(|KLcMP1TmUC~ut z({CCwq$j@l;RqbkFci&+=@~@m$aId@t}qFY;n9@lr4I za zpYmy+@mZhqd0+5FU-D&N@l{{*b>Hw!-|}tW@m=5ZeLwI+Kk{Qg@l!wZbHDIQzw&Fp z@ms(1dw=jpfAVL4@mGKIcmMED|8gjR4)6d7nDhbo9}bub0j>a;8Q>BEF3G=|-?|`w zIB)=mXP|%czl}uXKl$G^QU37no>Bj30;~mM{ijdK|8Ru>{$025Uq|wLFaHk)bpIXy E14=OnIRF3v literal 0 HcmV?d00001 diff --git a/tests/images/seq-4c-16b-rgba.tiff b/tests/images/seq-4c-16b-rgba.tiff new file mode 100644 index 0000000000000000000000000000000000000000..4f657fa88f7270f9290349d63c8ef9c501e2642f GIT binary patch literal 2222 zcmYk8Q_vX55`_<9+qP{d8{4*Rd&7-w+qP}nwr$-%d-JfAuxgLL@)G4AN0lF=!gCofPolk%peTPU<}R>49QRo%`gnha174~jL1lg%qWb? zXpGJnjLBGx%{Yw9c#O{kOvpq`%p^?8WK7N!OvzMC%`{BQbWG0-%*ag4%q+~xY|PFa z%*kBL%{h8VP1%gi*@7+Eimlm(ZP||P*?}F|iJjSnUD=J@*@HdVi@n*0 zefc;0u|EfJAO~?U|KSi0 zFs7G+g7WmgX6R4(OK9_3X&Zb1Mp`Plc-s+>i`dj_fUjsBygEUzGXo!Ytn1*YFMrxEsYmCNfoW^T{ zCTfxp5|+T7HW|eYl)U>nU-sXR%(@2YmL@woz`oEHfobL zYm2sOo3?9*c50V)YmfG7pZ4p34(gB&>xho(n2zg&PU@6S>x|CooX+clF6xpl>x!=G zny%}HZt9k9>yGZ~p6=^`9_o=E>xrJ~nV#!~Uh0)z>y6&(o!;w%KI)S`>x;hXo4)IZ ze(G1i*H6oKAP0632X!z9cL;}cD2H|!hjloIcLYatBu91>M|CtucMQjLEXQ^n$8|i% zcLFDLA}4kdCv`F>cM7L;DyMcDr*%4~cLry4CTDgQXLUAbcMj)tF6VY0=XE~kcLD$9 zf-dC3F5;pt=Hf2lk}l=aF5|K;=kl)Limv3!uHve$=IXBDny%&AuH(9{=lX8ohHm7> zZsMkH=H_nUmTu+NZsWFY=l1U4j_%~n?&7ZQ=I-v{p6=z|?&H4x+x^_%13b`!JlOwu zh=+QZhkJxadXz_djK_MM$9sY&dXgu5il=&-r+bEHdX{H!Z1kNbpA z`jk)mjL-U<&-;Qe`jRjEim&>bult5?`j&6|j_>-O@B4ut`jH>|iJ$tJpZkSh`jub% zjohaC;z)9${+sSGwL5rfVDuZ|MV&UAFdFqvg@<^REe?!V)I DN%aUk literal 0 HcmV?d00001 diff --git a/tests/images/seq-4c-8b-cmyk.tiff b/tests/images/seq-4c-8b-cmyk.tiff new file mode 100644 index 0000000000000000000000000000000000000000..ff64ee78fb67d88d25f22118c48501c6c5f3942c GIT binary patch literal 1198 zcmebD)MDUZVPIfjWMXDvWn<^yMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;UhC#>1%UvlFhF860okAeVjhrS zhKhsKu|e6aK(-(w3s^4)kSz)o2k8-mvO#8wL)Cx`lR+}a2ZMC+6cQE@6%&_`l#-T_m6KOcR8m$^Ra4i{ z)Y8_`)zddHG%_|ZH8Z!cw6eCbwX=6{baHlab#wRd^z!!c_45x13RUzF>}`JIdkXDU$Ah|;w4L$Enl&6)#^2C*R9{Mant54TeofBv2)k%J$v`< zKXCBS;UhC#>1%UvlFhF860okAeVjhrS zhKhsKu|e5PK(-(w3s^4)kSz)o2k8-mvO#8wL)Cx`lR+{k2#FmGWP|iA0}(*L0fme} H(?JjbI7$Kx literal 0 HcmV?d00001