mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 09:14:27 +03:00
Merge pull request #2719 from wiredfool/issue_2278
Fixes for Issues #2278 and #2006, value error in exif/tiff ifd
This commit is contained in:
commit
a0ce5740d5
|
@ -550,11 +550,28 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
|||
|
||||
dest = self._tags_v1 if legacy_api else self._tags_v2
|
||||
|
||||
if info.length == 1:
|
||||
if legacy_api and self.tagtype[tag] in [5, 10]:
|
||||
# Three branches:
|
||||
# Spec'd length == 1, Actual length 1, store as element
|
||||
# Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
|
||||
# No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
|
||||
# Don't mess with the legacy api, since it's frozen.
|
||||
if ((info.length == 1) or
|
||||
(info.length is None and len(values) == 1 and not legacy_api)):
|
||||
# Don't mess with the legacy api, since it's frozen.
|
||||
if legacy_api and self.tagtype[tag] in [5, 10]: # rationals
|
||||
values = values,
|
||||
dest[tag], = values
|
||||
try:
|
||||
dest[tag], = values
|
||||
except ValueError:
|
||||
# We've got a builtin tag with 1 expected entry
|
||||
warnings.warn(
|
||||
"Metadata Warning, tag %s had too many entries: %s, expected 1" % (
|
||||
tag, len(values)))
|
||||
dest[tag] = values[0]
|
||||
|
||||
else:
|
||||
# Spec'd length > 1 or undefined
|
||||
# Unspec'd, and length > 1
|
||||
dest[tag] = values
|
||||
|
||||
def __delitem__(self, tag):
|
||||
|
@ -1011,8 +1028,10 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
args = rawmode, ""
|
||||
if JPEGTABLES in self.tag_v2:
|
||||
# Hack to handle abbreviated JPEG headers
|
||||
# FIXME This will fail with more than one value
|
||||
self.tile_prefix, = self.tag_v2[JPEGTABLES]
|
||||
# Definition of JPEGTABLES is that the count
|
||||
# is the number of bytes in the tables datastream
|
||||
# so, it should always be 1 in our tag info
|
||||
self.tile_prefix = self.tag_v2[JPEGTABLES]
|
||||
elif compression == "packbits":
|
||||
args = rawmode
|
||||
elif compression == "tiff_lzw":
|
||||
|
|
|
@ -23,7 +23,7 @@ from collections import namedtuple
|
|||
class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
|
||||
__slots__ = []
|
||||
|
||||
def __new__(cls, value=None, name="unknown", type=None, length=0, enum=None):
|
||||
def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None):
|
||||
return super(TagInfo, cls).__new__(
|
||||
cls, value, name, type, length, enum or {})
|
||||
|
||||
|
@ -142,6 +142,8 @@ TAGS_V2 = {
|
|||
341: ("SMaxSampleValue", DOUBLE, 0),
|
||||
342: ("TransferRange", SHORT, 6),
|
||||
|
||||
347: ("JPEGTables", UNDEFINED, 1),
|
||||
|
||||
# obsolete JPEG tags
|
||||
512: ("JPEGProc", SHORT, 1),
|
||||
513: ("JPEGInterchangeFormat", LONG, 1),
|
||||
|
@ -158,7 +160,10 @@ TAGS_V2 = {
|
|||
531: ("YCbCrPositioning", SHORT, 1),
|
||||
532: ("ReferenceBlackWhite", LONG, 0),
|
||||
|
||||
700: ('XMP', BYTE, 1),
|
||||
|
||||
33432: ("Copyright", ASCII, 1),
|
||||
34377: ('PhotoshopInfo', BYTE, 1),
|
||||
|
||||
# FIXME add more tags here
|
||||
34665: ("ExifIFD", SHORT, 1),
|
||||
|
@ -188,8 +193,8 @@ TAGS_V2 = {
|
|||
|
||||
50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
|
||||
50780: ("BestQualityScale", RATIONAL, 1),
|
||||
50838: ("ImageJMetaDataByteCounts", LONG, 1),
|
||||
50839: ("ImageJMetaData", UNDEFINED, 1)
|
||||
50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
|
||||
50839: ("ImageJMetaData", UNDEFINED, 1) # see Issue #2006
|
||||
}
|
||||
|
||||
# Legacy Tags structure
|
||||
|
|
BIN
Tests/images/issue_2278.tif
Normal file
BIN
Tests/images/issue_2278.tif
Normal file
Binary file not shown.
|
@ -56,7 +56,7 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
loaded = Image.open(f)
|
||||
|
||||
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
|
||||
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], len(bindata))
|
||||
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (len(bindata),))
|
||||
|
||||
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
|
||||
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
|
||||
|
@ -69,6 +69,16 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
loaded_double = loaded.tag[tag_ids['YawAngle']][0]
|
||||
self.assertAlmostEqual(loaded_double, doubledata)
|
||||
|
||||
# check with 2 element ImageJMetaDataByteCounts, issue #2006
|
||||
|
||||
info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
|
||||
img.save(f, tiffinfo=info)
|
||||
loaded = Image.open(f)
|
||||
|
||||
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
|
||||
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], (8, len(bindata) - 8))
|
||||
|
||||
|
||||
def test_read_metadata(self):
|
||||
img = Image.open('Tests/images/hopper_g4.tif')
|
||||
|
||||
|
@ -202,8 +212,8 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
im.save(out, tiffinfo=info, compression='raw')
|
||||
|
||||
reloaded = Image.open(out)
|
||||
self.assertEqual(0, reloaded.tag_v2[41988][0].numerator)
|
||||
self.assertEqual(0, reloaded.tag_v2[41988][0].denominator)
|
||||
self.assertEqual(0, reloaded.tag_v2[41988].numerator)
|
||||
self.assertEqual(0, reloaded.tag_v2[41988].denominator)
|
||||
|
||||
def test_expty_values(self):
|
||||
data = io.BytesIO(
|
||||
|
@ -220,6 +230,27 @@ class TestFileTiffMetadata(PillowTestCase):
|
|||
self.fail("Should not be struct value error there.")
|
||||
self.assertIn(33432, info)
|
||||
|
||||
def test_PhotoshopInfo(self):
|
||||
im = Image.open('Tests/images/issue_2278.tif')
|
||||
|
||||
self.assertIsInstance(im.tag_v2[34377], bytes)
|
||||
out = self.tempfile('temp.tiff')
|
||||
im.save(out)
|
||||
reloaded = Image.open(out)
|
||||
self.assertIsInstance(reloaded.tag_v2[34377], bytes)
|
||||
|
||||
def test_too_many_entries(self):
|
||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||
|
||||
# 277: ("SamplesPerPixel", SHORT, 1),
|
||||
ifd._tagdata[277] = struct.pack('hh', 4,4)
|
||||
ifd.tagtype[277] = TiffTags.SHORT
|
||||
|
||||
try:
|
||||
self.assert_warning(UserWarning, lambda: ifd[277])
|
||||
except ValueError:
|
||||
self.fail("Invalid Metadata count should not cause a Value Error.")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -46,6 +46,22 @@ This release contains several performance improvements:
|
|||
using a recent version of libjpeg-turbo.
|
||||
|
||||
|
||||
TIFF Metadata Changes
|
||||
=====================
|
||||
|
||||
* TIFF tags with unknown type/quantity now default to being bare
|
||||
values if they are 1 element, where previously they would be a
|
||||
single element tuple. This is only with the new api, not the legacy
|
||||
api. This normalizes the handling of fields, so that the metadata
|
||||
with inferred or image specified counts are handled the same as
|
||||
metadata with count specified in the TIFF spec.
|
||||
* The ``PhotoshopInfo``, ``XMP``, and ``JPEGTables`` tags now have a
|
||||
defined type (bytes) and a count of 1.
|
||||
* The ``ImageJMetaDataByteCounts`` tag now has an arbitrary number of
|
||||
items, as there can be multiple items, one for UTF-8, and one for
|
||||
UTF-16.
|
||||
|
||||
|
||||
Core Image API Changes
|
||||
======================
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user