Partial fix for #1597

Haven't excercized all of the metadata that we're allowing yet,
and there's clearly still something up with Arrays, as one
of them is still crashing and making it impossible to save a
palette with a libtiff image.
This commit is contained in:
wiredfool 2015-12-30 07:54:14 -08:00
parent 80ab12bdc0
commit 9fa6634f4d
4 changed files with 81 additions and 9 deletions

View File

@ -1400,8 +1400,7 @@ def _save(im, fp, filename):
# STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
# based on the data in the strip.
# ICCPROFILE crashes.
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ICCPROFILE]
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS]
atts = {}
# bits per sample is a single short in the tiff directory, not a list.
atts[BITSPERSAMPLE] = bits[0]
@ -1411,16 +1410,22 @@ def _save(im, fp, filename):
legacy_ifd = {}
if hasattr(im, 'tag'):
legacy_ifd = im.tag.to_v2()
for k, v in itertools.chain(ifd.items(),
for tag, value in itertools.chain(ifd.items(),
getattr(im, 'tag_v2', {}).items(),
legacy_ifd.items()):
if k not in atts and k not in blocklist:
if isinstance(v, unicode if bytes is str else str):
atts[k] = v.encode('ascii', 'replace') + b"\0"
elif isinstance(v, IFDRational):
atts[k] = float(v)
# Libtiff can only process certain core items without adding
# them to the custom dictionary. It will segfault if it attempts
# to add a custom tag without the dictionary entry
#
# UNDONE -- add code for the custom dictionary
if tag not in TiffTags.LIBTIFF_CORE: continue
if tag not in atts and tag not in blocklist:
if isinstance(value, unicode if bytes is str else str):
atts[tag] = value.encode('ascii', 'replace') + b"\0"
elif isinstance(value, IFDRational):
atts[tag] = float(value)
else:
atts[k] = v
atts[tag] = value
if DEBUG:
print("Converted items: %s" % sorted(atts.items()))

View File

@ -331,3 +331,59 @@ TYPES = {}
# 11: "float",
# 12: "double",
# }
#
# These tags are handled by default in libtiff, without
# adding to the custom dictionary. From tif_dir.c, searching for
# case TIFFTAG in the _TIFFVSetField function:
# Line: item.
# 148: case TIFFTAG_SUBFILETYPE:
# 151: case TIFFTAG_IMAGEWIDTH:
# 154: case TIFFTAG_IMAGELENGTH:
# 157: case TIFFTAG_BITSPERSAMPLE:
# 181: case TIFFTAG_COMPRESSION:
# 202: case TIFFTAG_PHOTOMETRIC:
# 205: case TIFFTAG_THRESHHOLDING:
# 208: case TIFFTAG_FILLORDER:
# 214: case TIFFTAG_ORIENTATION:
# 221: case TIFFTAG_SAMPLESPERPIXEL:
# 228: case TIFFTAG_ROWSPERSTRIP:
# 238: case TIFFTAG_MINSAMPLEVALUE:
# 241: case TIFFTAG_MAXSAMPLEVALUE:
# 244: case TIFFTAG_SMINSAMPLEVALUE:
# 247: case TIFFTAG_SMAXSAMPLEVALUE:
# 250: case TIFFTAG_XRESOLUTION:
# 256: case TIFFTAG_YRESOLUTION:
# 262: case TIFFTAG_PLANARCONFIG:
# 268: case TIFFTAG_XPOSITION:
# 271: case TIFFTAG_YPOSITION:
# 274: case TIFFTAG_RESOLUTIONUNIT:
# 280: case TIFFTAG_PAGENUMBER:
# 284: case TIFFTAG_HALFTONEHINTS:
# 288: case TIFFTAG_COLORMAP:
# 294: case TIFFTAG_EXTRASAMPLES:
# 298: case TIFFTAG_MATTEING:
# 305: case TIFFTAG_TILEWIDTH:
# 316: case TIFFTAG_TILELENGTH:
# 327: case TIFFTAG_TILEDEPTH:
# 333: case TIFFTAG_DATATYPE:
# 344: case TIFFTAG_SAMPLEFORMAT:
# 361: case TIFFTAG_IMAGEDEPTH:
# 364: case TIFFTAG_SUBIFD:
# 376: case TIFFTAG_YCBCRPOSITIONING:
# 379: case TIFFTAG_YCBCRSUBSAMPLING:
# 383: case TIFFTAG_TRANSFERFUNCTION:
# 389: case TIFFTAG_REFERENCEBLACKWHITE:
# 393: case TIFFTAG_INKNAMES:
# some of these are not in our TAGS_V2 dict and were included from tiff.h
LIBTIFF_CORE = set ([255, 256, 257, 258, 259, 262, 263, 266, 274, 277,
278, 280, 281, 340, 341, 282, 283, 284, 286, 287,
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
])
LIBTIFF_CORE.remove(320) # Arrays error?

BIN
Tests/images/rdf.tif Normal file

Binary file not shown.

View File

@ -395,6 +395,17 @@ class TestFileLibTiff(LibTiffTestCase):
TiffImagePlugin.WRITE_LIBTIFF = False
TiffImagePlugin.READ_LIBTIFF = False
def test_crashing_metadata(self):
# issue 1597
im = Image.open('Tests/images/rdf.tif')
out = self.tempfile('temp.tif')
TiffImagePlugin.WRITE_LIBTIFF = True
# this shouldn't crash
im.save(out, format='TIFF')
TiffImagePlugin.WRITE_LIBTIFF = False
if __name__ == '__main__':
unittest.main()