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.
This commit is contained in:
1 parent
26c32431fa
commit
a4cbf7bbaf
30 files changed
+892
No files matched your search
@@ -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_i8, I8, i64);
|
||||||
test_image_sum!(test_image_sum_u16, U16, u64);
|
test_image_sum!(test_image_sum_u16, U16, u64);
|
||||||
test_image_sum!(test_image_sum_i16, I16, i64);
|
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_u32, U32, u64);
|
||||||
test_image_sum!(test_image_sum_u64, U64, u64);
|
test_image_sum!(test_image_sum_u64, U64, u64);
|
||||||
test_image_sum!(test_image_sum_f32, F32, f32);
|
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() {
|
fn test_seq_3c_24b_planar() {
|
||||||
test_image_sum_u32("seq-3c-24b-planar.tiff", ColorType::RGB(24), 32640);
|
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);
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define W 16
|
#define W 16
|
||||||
#define H 16
|
#define H 16
|
||||||
@@ -175,6 +176,554 @@ static int write_rgb_planar(const char *path, int bits)
|
|||||||
return 0;
|
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)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (argc < 2) {
|
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; }
|
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!");
|
printf("\nDone. %s\n", ok ? "All succeeded." : "Some failed!");
|
||||||
return ok ? 0 : 1;
|
return ok ? 0 : 1;
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user