From e1110b5a9c5d601aab4f947eb70de82aff71aa0a Mon Sep 17 00:00:00 2001 From: wiredfool Date: Wed, 14 Dec 2016 03:50:06 -0800 Subject: [PATCH] Whitepoint, Primary Chromaticities working --- PIL/TiffTags.py | 18 +++++----- Tests/test_file_libtiff.py | 10 ++++++ docs/reference/tiff_metadata.rst | 4 +-- encode.c | 57 +++++++++++++++++++++++--------- libImaging/TiffDecode.c | 7 ++++ libImaging/TiffDecode.h | 1 + 6 files changed, 72 insertions(+), 25 deletions(-) diff --git a/PIL/TiffTags.py b/PIL/TiffTags.py index 3bcf9b383..c5c301e97 100644 --- a/PIL/TiffTags.py +++ b/PIL/TiffTags.py @@ -95,8 +95,8 @@ TAGS_V2 = { 278: ("RowsPerStrip", LONG, 1), 279: ("StripByteCounts", LONG, 0), - 280: ("MinSampleValue", LONG, 0), - 281: ("MaxSampleValue", SHORT, 0), + 280: ("MinSampleValue", LONG, 1), + 281: ("MaxSampleValue", SHORT, 1), 282: ("XResolution", RATIONAL, 1), 283: ("YResolution", RATIONAL, 1), 284: ("PlanarConfiguration", SHORT, 1, {"Contiguous": 1, "Separate": 2}), @@ -121,7 +121,7 @@ TAGS_V2 = { 316: ("HostComputer", ASCII, 1), 317: ("Predictor", SHORT, 1, {"none": 1, "Horizontal Differencing": 2}), 318: ("WhitePoint", RATIONAL, 2), - 319: ("PrimaryChromaticities", SHORT, 6), + 319: ("PrimaryChromaticities", RATIONAL, 6), 320: ("ColorMap", SHORT, 0), 321: ("HalftoneHints", SHORT, 2), @@ -137,10 +137,10 @@ TAGS_V2 = { 336: ("DotRange", SHORT, 0), 337: ("TargetPrinter", ASCII, 1), 338: ("ExtraSamples", SHORT, 0), - 339: ("SampleFormat", SHORT, 0), + 339: ("SampleFormat", SHORT, 1), - 340: ("SMinSampleValue", DOUBLE, 0), - 341: ("SMaxSampleValue", DOUBLE, 0), + 340: ("SMinSampleValue", DOUBLE, 1), + 341: ("SMaxSampleValue", DOUBLE, 1), 342: ("TransferRange", SHORT, 6), # obsolete JPEG tags @@ -161,7 +161,7 @@ TAGS_V2 = { # sgi, in core 32995:("Matteing", SHORT, 1), - 32996:("DataType", SHORT, 0), + 32996:("DataType", SHORT, 1), 32997:("ImageDepth", LONG, 1), 32998:("TileDepth", LONG, 1), @@ -431,7 +431,9 @@ LIBTIFF_CORE = {255, 256, 257, 258, 259, 262, 263, 266, 274, 277, 296, 297, 321, 320, 338, 32995, 322, 323, 32998, 32996, 339, 32997, 330, 531, 530, 301, 532, 333, # as above - 269 # this has been in our tests forever, and works + 269, # this has been in our tests forever, and works + 318, # Whitepoint, Specific test for it + 319, # Primary Chromaticities } LIBTIFF_CORE.remove(330) # subifd, requires extra support for uint64 payload diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index d74ce1420..1c4b67624 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -517,6 +517,16 @@ class TestFileLibTiff(LibTiffTestCase): im.save(out, format='TIFF') TiffImagePlugin.WRITE_LIBTIFF = False + reloaded = Image.open(out) + + self.assert_image_equal(im, reloaded) + for tag in (318, 319): + for ix in range(len(im.tag_v2[tag])): + self.assertAlmostEqual(float(im.tag_v2[tag][ix]), + float(reloaded.tag_v2[tag][ix]), + places=5) + + def test_page_number_x_0(self): # Issue 973 # Test TIFF with tag 297 (Page Number) having value of 0 0. diff --git a/docs/reference/tiff_metadata.rst b/docs/reference/tiff_metadata.rst index daf1227f0..5f420d96c 100644 --- a/docs/reference/tiff_metadata.rst +++ b/docs/reference/tiff_metadata.rst @@ -54,8 +54,8 @@ them) of built in items that regular. These have one of three call signatures: * Individual: ``TIFFVSetField(tiff, tag, item)`` -* Multiple: ``TIFFVSetField(tiff, tag, ct, items* )`` -* Alternate Multiple: ``TIFFVSetField(tiff, tag, items* )`` +* Multiple, passcount=1: ``TIFFVSetField(tiff, tag, ct, items* )`` +* Multiple, passcount=0: ``TIFFVSetField(tiff, tag, items* )`` In libtiff4, the individual integer like numeric items are passed as 32 bit ints (signed or unsigned as appropriate) even if the actual diff --git a/encode.c b/encode.c index 8baa002bf..e0f05917e 100644 --- a/encode.c +++ b/encode.c @@ -754,11 +754,17 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args) if (arrav) {\ for (i=0;istate,\ - tag,\ - len, arrav);\ - free(arrav);\ + } \ + if (fi->field_passcount) { \ + status = ImagingLibTiffSetField(&encoder->state, \ + tag, \ + len, arrav); \ + } else { \ + status = ImagingLibTiffSetField(&encoder->state, \ + tag, \ + arrav); \ + } \ + free(arrav); \ } @@ -783,6 +789,7 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) Py_ssize_t d_size; PyObject *keys, *values; + const TIFFFieldInfo* fi; if (! PyArg_ParseTuple(args, "sssisO", &mode, &rawmode, &compname, &fp, &filename, &dir)) { return NULL; @@ -834,6 +841,13 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) length = PyInt_AsLong(PyTuple_GetItem(valuetuple,2)); value = PyTuple_GetItem(valuetuple,3); + fi = ImagingLibTiffGetFieldInfo(&encoder->state, tag); + if (!fi) { + /* undone, custom */ + PyErr_SetString(PyExc_ValueError, "Couldn't find field info for tag."); + return NULL; + } + if (flarray == 0) { if (length != 1) { PyErr_SetString(PyExc_ValueError, "Expected length == 1 for non-array item"); @@ -969,21 +983,31 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) PyErr_SetString(PyExc_ValueError, "Requiring 6 items for for ReferenceBlackWhite"); return NULL; } - arrav = calloc(len, sizeof(float)); - if (arrav) { - for (i=0;istate, - tag, - arrav); - free(arrav); - } + PUSHMETAARRAY(float, PyFloat_AsDouble); break; case TIFFTAG_INKNAMES: /* int length, char * names */ break; default: + // Check for the right length for default case items + if (len > INT_MAX) { + PyErr_SetString(PyExc_MemoryError, "Metadata size error - int overflow"); + return NULL; + } + + if (fi->field_writecount == TIFF_VARIABLE || + fi->field_writecount == TIFF_VARIABLE2) { + if (len != 1) { + PyErr_SetString(PyExc_ValueError, "Expected 1 item for tag"); + return NULL; + } + } else if (fi->field_writecount == TIFF_SPP) { + /* need to check for samples per pixel here */ + } else if (len != fi->field_writecount) { + PyErr_SetString(PyExc_ValueError, "Incorrect number of items for tag"); + return NULL; + } + if ((int)len == length) { switch (type) { case 3: @@ -997,6 +1021,9 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args) case 5: case 10: case 11: + TRACE((" %d elements, setting as float \n", (int)len)); + PUSHMETAARRAY(float, PyFloat_AsDouble); + break; case 12: TRACE((" %d elements, setting as double \n", (int)len)); PUSHMETAARRAY(double, PyFloat_AsDouble); diff --git a/libImaging/TiffDecode.c b/libImaging/TiffDecode.c index f292da388..afdf99b14 100644 --- a/libImaging/TiffDecode.c +++ b/libImaging/TiffDecode.c @@ -336,6 +336,13 @@ int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) { } + +const TIFFFieldInfo* +ImagingLibTiffGetFieldInfo(ImagingCodecState state, ttag_t tag) { + TIFFSTATE *clientstate = (TIFFSTATE *)state->context; + return TIFFFieldWithTag(clientstate->tiff, tag); +} + int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...){ // after tif_dir.c->TIFFSetField. TIFFSTATE *clientstate = (TIFFSTATE *)state->context; diff --git a/libImaging/TiffDecode.h b/libImaging/TiffDecode.h index e14a09329..8c0f39dd8 100644 --- a/libImaging/TiffDecode.h +++ b/libImaging/TiffDecode.h @@ -46,6 +46,7 @@ typedef struct { extern int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset); extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp); extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); +extern const TIFFFieldInfo* ImagingLibTiffGetFieldInfo(ImagingCodecState state, ttag_t tag); /*