Merge pull request #1988 from wiredfool/iccprofile

Binary Tiff Metadata/ICC profile.
This commit is contained in:
wiredfool 2016-06-29 22:35:03 +01:00 committed by GitHub
commit ffcc067038
5 changed files with 49 additions and 22 deletions

View File

@ -544,8 +544,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
self.tagtype[tag] = 2
if self.tagtype[tag] == 7 and bytes is not str:
values = [value.encode("ascii", 'replace') if isinstance(value, str) else value
for value in values]
values = [value.encode("ascii", 'replace') if isinstance(value, str) else value]
values = tuple(info.cvt_enum(value) for value in values)
@ -604,8 +603,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
@_register_loader(1, 1) # Basic type, except for the legacy API.
def load_byte(self, data, legacy_api=True):
return (data if legacy_api else
tuple(map(ord, data) if bytes is str else data))
return data
@_register_writer(1) # Basic type, except for the legacy API.
def write_byte(self, data):

View File

@ -48,11 +48,21 @@ def lookup(tag):
#
# id: (Name, Type, Length, enum_values)
#
# The length here differs from the length in the tiff spec. For
# numbers, the tiff spec is for the number of fields returned. We
# agree here. For string-like types, the tiff spec uses the length of
# field in bytes. In Pillow, we are using the number of expected
# fields, in general 1 for string-like types.
BYTE = 1
ASCII = 2
SHORT = 3
LONG = 4
RATIONAL = 5
UNDEFINED = 7
SIGNED_RATIONAL = 10
DOUBLE = 12
TAGS_V2 = {
@ -128,8 +138,8 @@ TAGS_V2 = {
338: ("ExtraSamples", SHORT, 0),
339: ("SampleFormat", SHORT, 0),
340: ("SMinSampleValue", 12, 0),
341: ("SMaxSampleValue", 12, 0),
340: ("SMinSampleValue", DOUBLE, 0),
341: ("SMaxSampleValue", DOUBLE, 0),
342: ("TransferRange", SHORT, 6),
# obsolete JPEG tags
@ -152,34 +162,34 @@ TAGS_V2 = {
# FIXME add more tags here
34665: ("ExifIFD", SHORT, 1),
34675: ('ICCProfile', 7, 0),
34853: ('GPSInfoIFD', 1, 1),
34675: ('ICCProfile', UNDEFINED, 1),
34853: ('GPSInfoIFD', BYTE, 1),
# MPInfo
45056: ("MPFVersion", 7, 1),
45056: ("MPFVersion", UNDEFINED, 1),
45057: ("NumberOfImages", LONG, 1),
45058: ("MPEntry", 7, 1),
45059: ("ImageUIDList", 7, 0),
45058: ("MPEntry", UNDEFINED, 1),
45059: ("ImageUIDList", UNDEFINED, 0), # UNDONE, check
45060: ("TotalFrames", LONG, 1),
45313: ("MPIndividualNum", LONG, 1),
45569: ("PanOrientation", LONG, 1),
45570: ("PanOverlap_H", RATIONAL, 1),
45571: ("PanOverlap_V", RATIONAL, 1),
45572: ("BaseViewpointNum", LONG, 1),
45573: ("ConvergenceAngle", 10, 1),
45573: ("ConvergenceAngle", SIGNED_RATIONAL, 1),
45574: ("BaselineLength", RATIONAL, 1),
45575: ("VerticalDivergence", 10, 1),
45576: ("AxisDistance_X", 10, 1),
45577: ("AxisDistance_Y", 10, 1),
45578: ("AxisDistance_Z", 10, 1),
45579: ("YawAngle", 10, 1),
45580: ("PitchAngle", 10, 1),
45581: ("RollAngle", 10, 1),
45575: ("VerticalDivergence", SIGNED_RATIONAL, 1),
45576: ("AxisDistance_X", SIGNED_RATIONAL, 1),
45577: ("AxisDistance_Y", SIGNED_RATIONAL, 1),
45578: ("AxisDistance_Z", SIGNED_RATIONAL, 1),
45579: ("YawAngle", SIGNED_RATIONAL, 1),
45580: ("PitchAngle", SIGNED_RATIONAL, 1),
45581: ("RollAngle", SIGNED_RATIONAL, 1),
50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
50780: ("BestQualityScale", RATIONAL, 1),
50838: ("ImageJMetaDataByteCounts", LONG, 1),
50839: ("ImageJMetaData", 7, 1)
50839: ("ImageJMetaData", UNDEFINED, 1)
}
# Legacy Tags structure

View File

@ -287,7 +287,7 @@ class TestFileTiff(PillowTestCase):
ifd = TiffImagePlugin.ImageFileDirectory_v2()
data = b"abc"
ret = ifd.load_byte(data, legacy_api)
self.assertEqual(ret, b"abc" if legacy_api else (97, 98, 99))
self.assertEqual(ret, b"abc")
def test_load_string(self):
ifd = TiffImagePlugin.ImageFileDirectory_v2()

View File

@ -175,7 +175,7 @@ class TestFileTiffMetadata(PillowTestCase):
im.save(out)
reloaded = Image.open(out)
self.assert_(type(im.info['icc_profile']) is not type(tuple))
self.assert_(type(im.info['icc_profile']) is not tuple)
self.assertEqual(im.info['icc_profile'], reloaded.info['icc_profile'])
def test_iccprofile_binary(self):
@ -186,6 +186,16 @@ class TestFileTiffMetadata(PillowTestCase):
self.assertEqual(im.tag_v2.tagtype[34675], 1)
self.assertTrue(im.info['icc_profile'])
def test_iccprofile_save_png(self):
im = Image.open('Tests/images/hopper.iccprofile.tif')
outfile = self.tempfile('temp.png')
im.save(outfile)
def test_iccprofile_binary_save_png(self):
im = Image.open('Tests/images/hopper.iccprofile_binary.tif')
outfile = self.tempfile('temp.png')
im.save(outfile)
def test_exif_div_zero(self):
im = hopper()
info = TiffImagePlugin.ImageFileDirectory_v2()

View File

@ -22,3 +22,12 @@ There are two new options to control the ``build_ext`` task in ``setup.py``:
that are checked for libraries and headers for build systems or
cross compilers that specify that information in via environment
variables.
Image Metadata
==============
The return type for binary data in version 2 Exif and Tiff metadata
has been changed from a tuple of integers to bytes. This is a change
from the behavior since ``3.0.0``.