From 2e9f46fbefb73730fc5c02b8620ed5dc047b19cf Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Wed, 20 Aug 2014 17:24:28 -0500 Subject: [PATCH 1/9] multipage tiff for iterator testing --- Tests/images/test.tif | Bin 0 -> 816 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Tests/images/test.tif diff --git a/Tests/images/test.tif b/Tests/images/test.tif new file mode 100644 index 0000000000000000000000000000000000000000..7a7f5f89a05f35ebba3e8ff6ce7903c91a955965 GIT binary patch literal 816 zcmb_ayAHxI40IBxP$#H(NTnkSZ0rmSEd2p?29Q`7SXlc#d=?`kGg3JRCj==76=5m$ z)v=r0^~!Qa1;wLFqzox+rdTS#S}^aK04IVC>OIx6vmM|p=otifD41~6Nc#Ke&sE#b zUVz7fufRnxI|bIL;bt^f+TQVowJOT{O_Dk7&r0>?)puqGmPkbvcUJ9Pf{4p e>68J-bkbzJPC0s Date: Thu, 21 Aug 2014 13:02:01 -0500 Subject: [PATCH 2/9] added ifd offset to the tiff decoder args, call TIFFSetSubDirectory --- PIL/TiffImagePlugin.py | 11 +++++++---- decode.c | 5 +++-- libImaging/TiffDecode.c | 20 +++++++++++++++----- libImaging/TiffDecode.h | 8 ++------ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 9bef30ebefc..0e87c0c51c2 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -281,6 +281,7 @@ def reset(self): self.tagdata = {} self.tagtype = {} # added 2008-06-05 by Florian Hoech self.next = None + self.offset = None def __str__(self): return str(self.as_dict()) @@ -415,6 +416,7 @@ def load(self, fp): # load tag dictionary self.reset() + self.offset = fp.tell() i16 = self.i16 i32 = self.i32 @@ -706,6 +708,7 @@ def _load_libtiff(self): # (self._compression, (extents tuple), # 0, (rawmode, self._compression, fp)) ignored, extents, ignored_2, args = self.tile[0] + args = args + (self.ifd.offset,) decoder = Image._getdecoder(self.mode, 'libtiff', args, self.decoderconfig) try: @@ -743,9 +746,9 @@ def _load_libtiff(self): self.tile = [] self.readonly = 0 # libtiff closed the fp in a, we need to close self.fp, if possible - if hasattr(self.fp, 'close'): - self.fp.close() - self.fp = None # might be shared + #if hasattr(self.fp, 'close'): + # self.fp.close() + #self.fp = None # might be shared if err < 0: raise IOError(err) @@ -900,7 +903,7 @@ def _setup(self): self.tile.append( (self._compression, (0, 0, w, ysize), - 0, a)) + self.ifd.offset, a)) a = None else: diff --git a/decode.c b/decode.c index d5e32938444..e9aa6a387f9 100644 --- a/decode.c +++ b/decode.c @@ -442,8 +442,9 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args) char* rawmode; char* compname; int fp; + int ifdoffset; - if (! PyArg_ParseTuple(args, "sssi", &mode, &rawmode, &compname, &fp)) + if (! PyArg_ParseTuple(args, "sssii", &mode, &rawmode, &compname, &fp, &ifdoffset)) return NULL; TRACE(("new tiff decoder %s\n", compname)); @@ -455,7 +456,7 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args) if (get_unpacker(decoder, mode, rawmode) < 0) return NULL; - if (! ImagingLibTiffInit(&decoder->state, fp)) { + if (! ImagingLibTiffInit(&decoder->state, fp, ifdoffset)) { Py_DECREF(decoder); PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed"); return NULL; diff --git a/libImaging/TiffDecode.c b/libImaging/TiffDecode.c index 787cd4506a9..40fca19d8c7 100644 --- a/libImaging/TiffDecode.c +++ b/libImaging/TiffDecode.c @@ -21,8 +21,8 @@ #include "TiffDecode.h" void dump_state(const TIFFSTATE *state){ - TRACE(("State: Location %u size %d eof %d data: %p \n", (uint)state->loc, - (int)state->size, (uint)state->eof, state->data)); + TRACE(("State: Location %u size %d eof %d data: %p ifd: %d\n", (uint)state->loc, + (int)state->size, (uint)state->eof, state->data, state->ifd)); } /* @@ -142,7 +142,7 @@ void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) { (void) hdata; (void) base; (void) size; } -int ImagingLibTiffInit(ImagingCodecState state, int fp) { +int ImagingLibTiffInit(ImagingCodecState state, int fp, int offset) { TIFFSTATE *clientstate = (TIFFSTATE *)state->context; TRACE(("initing libtiff\n")); @@ -158,6 +158,7 @@ int ImagingLibTiffInit(ImagingCodecState state, int fp) { clientstate->size = 0; clientstate->data = 0; clientstate->fp = fp; + clientstate->ifd = offset; clientstate->eof = 0; return 1; @@ -192,10 +193,9 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int dump_state(clientstate); clientstate->size = bytes; clientstate->eof = clientstate->size; - clientstate->loc = 0; + //clientstate->loc = 0; clientstate->data = (tdata_t)buffer; clientstate->flrealloc = 0; - dump_state(clientstate); TIFFSetWarningHandler(NULL); @@ -220,6 +220,16 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int return -1; } + if (clientstate->ifd){ + unsigned int ifdoffset = clientstate->ifd; + TRACE(("reading tiff ifd %d\n", ifdoffset)); + int rv = TIFFSetSubDirectory(tiff, ifdoffset); + if (!rv){ + TRACE(("error in TIFFSetSubDirectory")); + return -1; + } + } + size = TIFFScanlineSize(tiff); TRACE(("ScanlineSize: %d \n", size)); if (size > state->bytes) { diff --git a/libImaging/TiffDecode.h b/libImaging/TiffDecode.h index 46c940d1b3d..3f8a6ed7d41 100644 --- a/libImaging/TiffDecode.h +++ b/libImaging/TiffDecode.h @@ -26,6 +26,7 @@ typedef struct { toff_t loc; /* toff_t == uint32 */ tsize_t size; /* tsize_t == int32 */ int fp; + int ifd; TIFF *tiff; /* Used in write */ toff_t eof; int flrealloc; /* may we realloc */ @@ -33,7 +34,7 @@ typedef struct { -extern int ImagingLibTiffInit(ImagingCodecState state, int fp); +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, ...); @@ -43,12 +44,7 @@ extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); legacy, don't enable for python 3.x, unicode issues. */ -/* #define VA_ARGS(...) __VA_ARGS__ #define TRACE(args) fprintf(stderr, VA_ARGS args) -*/ - -#define TRACE(args) - #endif From 051398c3e9043fdf639fbfb109a879c14b53f043 Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Thu, 21 Aug 2014 13:50:19 -0500 Subject: [PATCH 3/9] disabled cpp trace --- libImaging/TiffDecode.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libImaging/TiffDecode.h b/libImaging/TiffDecode.h index 3f8a6ed7d41..4167acd8937 100644 --- a/libImaging/TiffDecode.h +++ b/libImaging/TiffDecode.h @@ -44,7 +44,11 @@ extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); legacy, don't enable for python 3.x, unicode issues. */ +/* #define VA_ARGS(...) __VA_ARGS__ #define TRACE(args) fprintf(stderr, VA_ARGS args) +*/ + +#define TRACE(args) #endif From c7862f57c2a7c39516cab697d780a8c68aaea3c4 Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Thu, 21 Aug 2014 14:33:12 -0500 Subject: [PATCH 4/9] ignore vendor defined tags in python parsing --- PIL/TiffImagePlugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 0e87c0c51c2..d5362dee82a 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -1122,7 +1122,7 @@ def _save(im, fp, filename): # save(load('')) == original file. for k, v in itertools.chain(ifd.items(), getattr(im, 'ifd', {}).items()): - if k not in atts and k not in blocklist: + if k not in atts and k not in blocklist and k < 1024: if type(v[0]) == tuple and len(v) > 1: # A tuple of more than one rational tuples # flatten to floats, From 7158894042a9907cdedfda9dedd8107ded16b50c Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Thu, 21 Aug 2014 15:52:09 -0500 Subject: [PATCH 5/9] added test for multi.tif --- Tests/images/{test.tif => multi.tif} | Bin Tests/test_sequence_tiff.py | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+) rename Tests/images/{test.tif => multi.tif} (100%) create mode 100644 Tests/test_sequence_tiff.py diff --git a/Tests/images/test.tif b/Tests/images/multi.tif similarity index 100% rename from Tests/images/test.tif rename to Tests/images/multi.tif diff --git a/Tests/test_sequence_tiff.py b/Tests/test_sequence_tiff.py new file mode 100644 index 00000000000..448d9605b45 --- /dev/null +++ b/Tests/test_sequence_tiff.py @@ -0,0 +1,20 @@ +from helper import unittest, PillowTestCase + +from PIL import Image, ImageSequence, TiffImagePlugin + +TiffImagePlugin.READ_LIBTIFF = True + +class TestFileTiff(PillowTestCase): + + def testSequence(self): + try: + im = Image.open('multi.tif') + index = 0 + for frame in ImageSequence.Iterator(im): + frame.load() + self.assertEqual(index, im.tell()) + index = index+1 + except Exception as e: + self.assertTrue(False, str(e)) + + From 398b1174b1b9d510d9183c8d29e9fb608a28b6dd Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Thu, 21 Aug 2014 15:58:01 -0500 Subject: [PATCH 6/9] fix crash by checking len(v) before accessing v[0] --- PIL/TiffImagePlugin.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index d5362dee82a..8e283e0283d 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -1122,14 +1122,16 @@ def _save(im, fp, filename): # save(load('')) == original file. for k, v in itertools.chain(ifd.items(), getattr(im, 'ifd', {}).items()): + # all adobe defined tags are < 1024 if k not in atts and k not in blocklist and k < 1024: - if type(v[0]) == tuple and len(v) > 1: + # check len(v) before accessing elements + if len(v) > 1 and type(v[0]) == tuple: # A tuple of more than one rational tuples # flatten to floats, # following tiffcp.c->cpTag->TIFF_RATIONAL atts[k] = [float(elt[0])/float(elt[1]) for elt in v] continue - if type(v[0]) == tuple and len(v) == 1: + if len(v) == 1 and type(v[0]) == tuple: # A tuple of one rational tuples # flatten to floats, # following tiffcp.c->cpTag->TIFF_RATIONAL From d0e51650e36713bfb453f14d5e06be392a968c28 Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Tue, 26 Aug 2014 10:09:23 -0500 Subject: [PATCH 7/9] removed some deadend attempts that should have been rolled back once the ifd offset was passed in args.\nThere should be no changes to Tile or clientstate->loc for this code. --- PIL/TiffImagePlugin.py | 2 +- libImaging/TiffDecode.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/PIL/TiffImagePlugin.py b/PIL/TiffImagePlugin.py index 8e283e0283d..44b9f3c791e 100644 --- a/PIL/TiffImagePlugin.py +++ b/PIL/TiffImagePlugin.py @@ -903,7 +903,7 @@ def _setup(self): self.tile.append( (self._compression, (0, 0, w, ysize), - self.ifd.offset, a)) + 0, a)) a = None else: diff --git a/libImaging/TiffDecode.c b/libImaging/TiffDecode.c index 40fca19d8c7..1d320e9bdc6 100644 --- a/libImaging/TiffDecode.c +++ b/libImaging/TiffDecode.c @@ -193,7 +193,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int dump_state(clientstate); clientstate->size = bytes; clientstate->eof = clientstate->size; - //clientstate->loc = 0; + clientstate->loc = 0; clientstate->data = (tdata_t)buffer; clientstate->flrealloc = 0; dump_state(clientstate); From 6891989274a103c994d960d73b70c1c6e631286b Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Tue, 26 Aug 2014 10:26:25 -0500 Subject: [PATCH 8/9] print version numbers on mismatch --- PIL/Image.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 480410eff1a..e365f26c94a 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -59,9 +59,11 @@ def __getattr__(self, id): # them. Note that other modules should not refer to _imaging # directly; import Image and use the Image.core variable instead. from PIL import _imaging as core - if PILLOW_VERSION != getattr(core, 'PILLOW_VERSION', None): + pillow_version_imported = getattr(core, 'PILLOW_VERSION', None) + if PILLOW_VERSION != pillow_version_imported: raise ImportError("The _imaging extension was built for another " - " version of Pillow or PIL") + " version of Pillow or PIL - " + " expected %s actual %s" % (PILLOW_VERSION, pillow_version_imported)) except ImportError as v: core = _imaging_not_installed() From e6ad472c3b5739c48c497f1b51dfeeb51aa4ea46 Mon Sep 17 00:00:00 2001 From: Kenny Ostrom Date: Tue, 26 Aug 2014 10:46:44 -0500 Subject: [PATCH 9/9] test_sequence_tiff fixed (was not run by selftest.py) --- Tests/test_sequence_tiff.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Tests/test_sequence_tiff.py b/Tests/test_sequence_tiff.py index 448d9605b45..2dbbe16021a 100644 --- a/Tests/test_sequence_tiff.py +++ b/Tests/test_sequence_tiff.py @@ -6,9 +6,15 @@ class TestFileTiff(PillowTestCase): + def setUp(self): + codecs = dir(Image.core) + + if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs: + self.skipTest("tiff support not available") + def testSequence(self): try: - im = Image.open('multi.tif') + im = Image.open('Tests/images/multi.tif') index = 0 for frame in ImageSequence.Iterator(im): frame.load() @@ -17,4 +23,8 @@ def testSequence(self): except Exception as e: self.assertTrue(False, str(e)) +if __name__ == '__main__': + unittest.main() + +# End of file