mirror of
https://gitlab.com/libtiff/libtiff.git
synced 2026-10-24 19:59:18 +03:00
* Add 'static' keyword to file-local functions that lack external visibility * Create header files for functions shared between test source files
401 lines
14 KiB
C
401 lines
14 KiB
C
/*
|
|
* TIFF Library
|
|
*
|
|
* The purpose of this test suite is to test the correctness of
|
|
* writing and reading transfer functions with TIFFTAG_TRANSFERFUNCTION.
|
|
*
|
|
* Depending on the SamplesPerPixel (and ExtraSamples) values,
|
|
* exactly one (1) or exactly three (3) transfer functions shall be written
|
|
* to file and are expected for reading from file.
|
|
* An exception is if all three transfer functions are equal.
|
|
* Then only one transfer function is written to file and
|
|
* at reading that transfer function is returned in three
|
|
* pointers to TIFFGetField().
|
|
* If only one array is returned, as for images with SamplesPerPixel=1,
|
|
* the other two are set to NULL.
|
|
*
|
|
* Each transfer function length is (1 << BitsPerSample) times uint16_t values.
|
|
*
|
|
*/
|
|
/* clang-format off */
|
|
|
|
#include "tif_config.h"
|
|
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "tiffio.h"
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h> /* for unlink() on linux */
|
|
#endif
|
|
|
|
/* Define basic TIFF file settings */
|
|
uint16_t spp = 3;
|
|
const uint16_t width = 4;
|
|
const uint16_t length = 6;
|
|
const uint16_t bps = 8;
|
|
const uint16_t photometric = PHOTOMETRIC_RGB;
|
|
const uint16_t rows_per_strip = 100; /* up to 2**32-1 */
|
|
const uint16_t planarconfig = PLANARCONFIG_CONTIG;
|
|
|
|
/* Data and pointer to three transfer functions. */
|
|
uint16_t *pTransferFunctionData;
|
|
uint32_t nSamplesPerTransferFunction;
|
|
/* Pointers into pTransferFunctionData for writing */
|
|
const uint16_t *ptf0;
|
|
const uint16_t *ptf1;
|
|
const uint16_t *ptf2;
|
|
/* Pointers for reading */
|
|
const uint16_t *ptfR0;
|
|
const uint16_t *ptfR1;
|
|
const uint16_t *ptfR2;
|
|
|
|
#define GOTOFAILURE(x) \
|
|
{ \
|
|
retval = x; \
|
|
goto failure; \
|
|
}
|
|
|
|
/*-- setup_transferfunctions() --
|
|
* Initializes the transfer function array pTransferFunctionData
|
|
* with three transfer functions.
|
|
* Pointer ptf0, ptf1, ptf2 are initialized to the first array element of
|
|
* each transfer function.
|
|
*/
|
|
static int setup_transfer_functions(void)
|
|
{
|
|
if (pTransferFunctionData)
|
|
_TIFFfree(pTransferFunctionData);
|
|
|
|
/* Setup array with some more values to shift start of the three arrays. */
|
|
nSamplesPerTransferFunction = ((uint32_t)1 << bps);
|
|
pTransferFunctionData = (uint16_t *)_TIFFmalloc(
|
|
3 * (tmsize_t)nSamplesPerTransferFunction * sizeof(uint16_t));
|
|
if (!pTransferFunctionData)
|
|
return 1;
|
|
|
|
for (uint32_t i = 0; i < 3 * nSamplesPerTransferFunction; i++)
|
|
pTransferFunctionData[i] = (uint16_t)(i + 1);
|
|
|
|
ptf0 = &pTransferFunctionData[0];
|
|
ptf1 = &pTransferFunctionData[nSamplesPerTransferFunction];
|
|
ptf2 = &pTransferFunctionData[2 * nSamplesPerTransferFunction];
|
|
|
|
return 0;
|
|
} /*-- setup_transferfunctions() --*/
|
|
|
|
/*--read_check_transferfunctions --
|
|
* The file is opened and the transfer functions are read.
|
|
* Then the read transfer functions are compared against the arrays provided
|
|
* with ptfx0, ptfx1, ptfx2.
|
|
* Depending on blnClose, the opened file is closed.
|
|
* TIFF **ptif returns the TIFF pointer.
|
|
* The function returns a bit-field with one bit set for each successfully read transfer function.
|
|
*/
|
|
static int read_check_transferfunctions(TIFF **ptif, const char *filename, int blnClose, const uint16_t *ptfx0,
|
|
const uint16_t *ptfx1, const uint16_t *ptfx2)
|
|
{
|
|
/* Test reading of transfer functions */
|
|
int retval = 0;
|
|
TIFF *tif = TIFFOpen(filename, "r");
|
|
*ptif = tif;
|
|
if (!tif)
|
|
{
|
|
fprintf(stderr, "read_check_transferfunctions(): Can't open %s for reading.\n", filename);
|
|
GOTOFAILURE(-1);
|
|
}
|
|
|
|
if (!TIFFGetField(tif, TIFFTAG_TRANSFERFUNCTION, &ptfR0, &ptfR1, &ptfR2))
|
|
{
|
|
fprintf(stderr, "read_check_transferfunctions(): TIFFGetField for TIFFTAG_TRANSFERFUNCTION failed.\n");
|
|
GOTOFAILURE(-1);
|
|
}
|
|
else
|
|
{
|
|
if (ptfR0 != NULL && !_TIFFmemcmp(ptfx0, ptfR0, nSamplesPerTransferFunction * sizeof(uint16_t)))
|
|
retval += 1;
|
|
if (ptfR1 != NULL && !_TIFFmemcmp(ptfx1, ptfR1, nSamplesPerTransferFunction * sizeof(uint16_t)))
|
|
retval += 2;
|
|
if (ptfR2 != NULL && !_TIFFmemcmp(ptfx2, ptfR2, nSamplesPerTransferFunction * sizeof(uint16_t)))
|
|
retval += 4;
|
|
}
|
|
|
|
failure:
|
|
if (blnClose)
|
|
{
|
|
TIFFClose(tif);
|
|
tif = NULL;
|
|
}
|
|
*ptif = tif;
|
|
|
|
return retval;
|
|
} /*-- read_check_transferfunctions() --*/
|
|
|
|
/*-- write_basic_IFD_data() --
|
|
* Opens a file for writing and initializes a basic TIFF image with the
|
|
* globally specified parameters.
|
|
*
|
|
* wrtTransferFunction: 0 = don't write TIFFTAG_TRANSFERFUNCTION tag
|
|
* 1 = write TIFFTAG_TRANSFERFUNCTION tag before and
|
|
* 2 = after ExtraSamples tag.
|
|
* blnExtraSamples=true writes ExtraSamples tag.
|
|
* Only if blnCloseFile is true, the file is closed.
|
|
* TIFF **ptif returns the pointer to the opened TIFF file.
|
|
*/
|
|
static int write_basic_IFD_data(TIFF **ptif, const char *filename, int wrtTransferFunction, int nExtraSamples,
|
|
int blnCloseFile)
|
|
{
|
|
unsigned char buf[3] = {0, 127, 255};
|
|
int retval = 0;
|
|
uint8_t *bufLine = NULL;
|
|
uint16_t extraSamples[4] = {EXTRASAMPLE_UNSPECIFIED, EXTRASAMPLE_UNSPECIFIED, EXTRASAMPLE_UNSPECIFIED,
|
|
EXTRASAMPLE_UNSPECIFIED};
|
|
size_t bufLen;
|
|
TIFF *tif = TIFFOpen(filename, "w");
|
|
*ptif = tif;
|
|
if (!tif)
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't create %s\n", filename);
|
|
GOTOFAILURE(1);
|
|
}
|
|
|
|
if (!TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set ImageWidth tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_IMAGELENGTH, length))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set ImageLength tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bps))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set BitsPerSample tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set SamplesPerPixel tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, rows_per_strip))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set SamplesPerPixel tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_PLANARCONFIG, planarconfig))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set PlanarConfiguration tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (!TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't set PhotometricInterpretation tag.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
|
|
/* Set transfer function before ExtraSamples*/
|
|
if (wrtTransferFunction == 1)
|
|
{
|
|
|
|
if (!TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, ptf1, ptf2))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): TIFFSetField for TIFFTAG_TRANSFERFUNCTION failed.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
}
|
|
|
|
/* Set ExtraSamples thus SamplesPerPixel for transfer functions is reduced by one. */
|
|
if (nExtraSamples > 0 && nExtraSamples < 4)
|
|
{
|
|
if (!TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, nExtraSamples, extraSamples))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Warning: Could not set TIFFTAG_EXTRASAMPLES tag.\n");
|
|
}
|
|
}
|
|
|
|
/* Set transfer function after ExtraSamples*/
|
|
if (wrtTransferFunction == 2)
|
|
{
|
|
|
|
if (!TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, ptf1, ptf2))
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): TIFFSetField for TIFFTAG_TRANSFERFUNCTION failed.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
}
|
|
|
|
/* Setup buffer for image line */
|
|
bufLen = (size_t)width * spp * (bps + 7) / 8;
|
|
bufLine = (uint8_t *)_TIFFmalloc(bufLen);
|
|
if (!bufLine)
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't allocate bufLine buffer.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
if (bufLen > sizeof(buf))
|
|
_TIFFmemcpy(bufLine, buf, sizeof(buf));
|
|
|
|
/* Write dummy pixel data. */
|
|
for (int i = 0; i < length; i++)
|
|
{
|
|
if (TIFFWriteScanline(tif, bufLine, i, 0) == -1)
|
|
{
|
|
fprintf(stderr, "write_basic_IFD_data(): Can't write image data.\n");
|
|
GOTOFAILURE(1);
|
|
}
|
|
size_t idx = (size_t)i * spp < bufLen ? (size_t)i * spp : bufLen - 2;
|
|
bufLine[idx] = (uint8_t)(i * 80);
|
|
}
|
|
|
|
failure:
|
|
if (bufLine)
|
|
_TIFFfree(bufLine);
|
|
if (blnCloseFile)
|
|
{
|
|
TIFFClose(tif);
|
|
tif = NULL;
|
|
}
|
|
*ptif = tif;
|
|
|
|
return retval;
|
|
} /*-- write_basic_IFD_data() --*/
|
|
|
|
/*==== main() ====*/
|
|
int main(void)
|
|
{
|
|
|
|
const char *filename = "test_transferfunction_write_read.tif";
|
|
|
|
if (setup_transfer_functions())
|
|
return 1;
|
|
|
|
int ret;
|
|
TIFF *tif = NULL;
|
|
|
|
fprintf(stderr,
|
|
"--- Testing TIFF_TRANSFERFUNCTION tag writing and reading. ---\n Expect 6 warning messages ...\n");
|
|
|
|
/* Test with RGB data */
|
|
spp = 3;
|
|
if (write_basic_IFD_data(&tif, filename, 2, 0, true))
|
|
return 1;
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != 7)
|
|
{
|
|
fprintf(stderr, "TRANSFERFUNCTION for RGB (SPP=3) could not be read correctly.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Test with Grayscale data */
|
|
spp = 1;
|
|
if (write_basic_IFD_data(&tif, filename, 2, 0, true))
|
|
return 1;
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != 1)
|
|
{
|
|
fprintf(stderr, "TRANSFERFUNCTION SPP=1 could not be read correctly.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Test with RGB and ExtraSample, thus only 2 SamplesPerPixel left.
|
|
* ExtraSample is written before transfer function.
|
|
* --> For v4.5.1: This gives an Error when reading the transfer functions!
|
|
*/
|
|
spp = 3;
|
|
if (write_basic_IFD_data(&tif, filename, 2, 1, true))
|
|
return 1;
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != 7)
|
|
{
|
|
fprintf(stderr, "One ExtraSample plus TRANSFERFUNCTION SPP=3 could not be read correctly.\n");
|
|
return 1;
|
|
}
|
|
/* Now write two ExtraSamples, thus only one transfer function is written to file and read. */
|
|
if (write_basic_IFD_data(&tif, filename, 2, 2, true))
|
|
return 1;
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != 1)
|
|
{
|
|
fprintf(stderr, "Two ExtraSamples plus TRANSFERFUNCTION SPP=3 could not be read correctly.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* Test with tree times the same transfer functions.
|
|
* Thus, only one should be written to file and when read copied three times.
|
|
*/
|
|
spp = 3;
|
|
if (write_basic_IFD_data(&tif, filename, 0, 0, false))
|
|
return 1;
|
|
ret = TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, ptf0, ptf0);
|
|
TIFFClose(tif);
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf0, ptf0);
|
|
if (ret != 7)
|
|
{
|
|
fprintf(stderr, "TRANSFERFUNCTIONs with same content could not be read correctly.\n");
|
|
return 1;
|
|
}
|
|
|
|
/*---- Test the setting of the transfer functions with different wrong calls of TIFFSetField(). ----*/
|
|
/* (ptf0, NULL, NULL) For v4.5.1: writes ptf0 to file and reads it back.
|
|
* Now, this should work for spp=1 but not for spp=3
|
|
*/
|
|
spp = 1;
|
|
if (write_basic_IFD_data(&tif, filename, 0, 0, false))
|
|
return 1;
|
|
ret = TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, NULL, NULL);
|
|
TIFFClose(tif);
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != 1)
|
|
{
|
|
fprintf(stderr, "Unexpected at %d.\n", __LINE__);
|
|
return 1;
|
|
}
|
|
spp = 3;
|
|
/* (ptf0, NULL, NULL) For v4.5.1: writes ptf0 to file and reads it back.*/
|
|
if (write_basic_IFD_data(&tif, filename, 0, 0, false))
|
|
return 1;
|
|
ret = TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, NULL, NULL);
|
|
TIFFClose(tif);
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != -1)
|
|
{
|
|
fprintf(stderr, "Unexpected at %d.\n", __LINE__);
|
|
return 1;
|
|
}
|
|
|
|
/* (ptf0, NULL, ptf2): For v4.5.1: Overflow error, when second ptf1 is copied in
|
|
* TIFFWriteDirectoryTagTransferfunction().*/
|
|
if (write_basic_IFD_data(&tif, filename, 0, 0, false))
|
|
return 1;
|
|
ret = TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, NULL, ptf2);
|
|
TIFFClose(tif);
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != -1)
|
|
{
|
|
fprintf(stderr, "Unexpected at %d.\n", __LINE__);
|
|
return 1;
|
|
}
|
|
|
|
/* (ptf0, ptf1, NULL) For v4.5.1: writes ptf0 and ptf1 to file but does not read it back, because only 2 but 3
|
|
* required.*/
|
|
if (write_basic_IFD_data(&tif, filename, 0, 0, false))
|
|
return 1;
|
|
ret = TIFFSetField(tif, TIFFTAG_TRANSFERFUNCTION, ptf0, ptf1, NULL);
|
|
TIFFClose(tif);
|
|
ret = read_check_transferfunctions(&tif, filename, true, ptf0, ptf1, ptf2);
|
|
if (ret != -1)
|
|
{
|
|
fprintf(stderr, "Unexpected at %d.\n", __LINE__);
|
|
return 1;
|
|
}
|
|
|
|
/* All tests passed; delete file and exit with success status. */
|
|
unlink(filename);
|
|
fprintf(stderr, "-------- Test finished OK ----------\n");
|
|
return 0;
|
|
}
|