test: add CCITT Group 3 (Fax3) test images with libtiff cross-validation
Three 16x16 bilevel fax3 test images covering the key Group 3 variants: - seq-1c-1b-fax3: basic G3, no fill bits, MSB-first fill order - seq-1c-1b-fax3-fillbits: G3 with T4Options fill bits (byte-aligned EOLs) - seq-1c-1b-fax3-lsb: G3 with FillOrder=2 (LSB-first) All use MinIsWhite photometric with inverted sequential pattern, producing the same decoded CRC32 hash (71f6a21a) as the uncompressed 1-bit images. Cross-validated: libtiff writes the images, both libtiff and image-tiff read them back and agree on the decoded data.
This commit is contained in:
1 parent
ba7a290ff7
commit
6c8f8abc71
5 files changed
+75
No files matched your search
@@ -948,6 +948,52 @@ static int write_multipage(const char *path, int bits, const char *mode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a 1-bit bilevel TIFF with CCITT Group 3 (Fax3) compression.
|
||||
* Sequential pattern: pixel = (y*W+x) % 2, inverted for MinIsWhite. */
|
||||
static int write_bilevel_fax3(const char *path, uint32_t t4options, uint16_t fill_order)
|
||||
{
|
||||
TIFF *tif = TIFFOpen(path, "w");
|
||||
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, 1);
|
||||
TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
|
||||
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE);
|
||||
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX3);
|
||||
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||
TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, H);
|
||||
TIFFSetField(tif, TIFFTAG_GROUP3OPTIONS, t4options);
|
||||
TIFFSetField(tif, TIFFTAG_FILLORDER, fill_order);
|
||||
|
||||
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);
|
||||
int bit_offset = 0;
|
||||
for (int x = 0; x < W; x++) {
|
||||
uint32_t val = (y * W + x) % 2;
|
||||
/* MinIsWhite: store inverted so decoder inverts back to match
|
||||
* the canonical sequential pattern (same as seq-1c-1b.tiff). */
|
||||
val = 1 - val;
|
||||
pack_value(buf, &bit_offset, val, 1);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
@@ -1346,6 +1392,26 @@ int main(int argc, char **argv)
|
||||
printf(" OK seq-1c-8b-tiled-bigtiff.tiff\n");
|
||||
else { printf(" FAIL seq-1c-8b-tiled-bigtiff.tiff\n"); ok = 0; }
|
||||
|
||||
printf("\n--- CCITT Group 3 (Fax3) ---\n");
|
||||
|
||||
/* Fax3: basic (no fill bits, MSB-first) */
|
||||
snprintf(path, sizeof(path), "%s/seq-1c-1b-fax3.tiff", dir);
|
||||
if (write_bilevel_fax3(path, 0, FILLORDER_MSB2LSB) == 0)
|
||||
printf(" OK seq-1c-1b-fax3.tiff\n");
|
||||
else { printf(" FAIL seq-1c-1b-fax3.tiff\n"); ok = 0; }
|
||||
|
||||
/* Fax3: with fill bits (T4Options bit 2 = 4) */
|
||||
snprintf(path, sizeof(path), "%s/seq-1c-1b-fax3-fillbits.tiff", dir);
|
||||
if (write_bilevel_fax3(path, 4, FILLORDER_MSB2LSB) == 0)
|
||||
printf(" OK seq-1c-1b-fax3-fillbits.tiff\n");
|
||||
else { printf(" FAIL seq-1c-1b-fax3-fillbits.tiff\n"); ok = 0; }
|
||||
|
||||
/* Fax3: LSB-first fill order */
|
||||
snprintf(path, sizeof(path), "%s/seq-1c-1b-fax3-lsb.tiff", dir);
|
||||
if (write_bilevel_fax3(path, 0, FILLORDER_LSB2MSB) == 0)
|
||||
printf(" OK seq-1c-1b-fax3-lsb.tiff\n");
|
||||
else { printf(" FAIL seq-1c-1b-fax3-lsb.tiff\n"); ok = 0; }
|
||||
|
||||
printf("\nDone. %s\n", ok ? "All succeeded." : "Some failed!");
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -436,6 +436,15 @@ int main(int argc, char **argv)
|
||||
|
||||
/* --- Tiled BigTIFF --- */
|
||||
{"seq-1c-8b-tiled-bigtiff.tiff", SUM_U8, 8, 1, {.u = 32640}},
|
||||
|
||||
/* --- CCITT Group 3 (Fax3) ---
|
||||
* libtiff returns raw scanline data in MinIsWhite convention (0=white, 1=black).
|
||||
* The stored pattern is inverted sequential, so libtiff sum differs from
|
||||
* image-tiff's BlackIsZero sum. For 16x16 1-bit with inverted sequential pattern,
|
||||
* the raw packed byte sum is computed by verify run below. */
|
||||
{"seq-1c-1b-fax3.tiff", SUM_U8_PACKED, 1, 1, {.u = 5440}},
|
||||
{"seq-1c-1b-fax3-fillbits.tiff", SUM_U8_PACKED, 1, 1, {.u = 5440}},
|
||||
{"seq-1c-1b-fax3-lsb.tiff", SUM_U8_PACKED, 1, 1, {.u = 5440}},
|
||||
};
|
||||
|
||||
int ncases = sizeof(cases) / sizeof(cases[0]);
|
||||
|
||||
Reference in new issue
Block a user