mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 18:06:18 +03:00
Merge pull request #1988 from wiredfool/iccprofile
Binary Tiff Metadata/ICC profile.
This commit is contained in:
commit
ffcc067038
|
@ -544,8 +544,7 @@ class ImageFileDirectory_v2(collections.MutableMapping):
|
||||||
self.tagtype[tag] = 2
|
self.tagtype[tag] = 2
|
||||||
|
|
||||||
if self.tagtype[tag] == 7 and bytes is not str:
|
if self.tagtype[tag] == 7 and bytes is not str:
|
||||||
values = [value.encode("ascii", 'replace') if isinstance(value, str) else value
|
values = [value.encode("ascii", 'replace') if isinstance(value, str) else value]
|
||||||
for value in values]
|
|
||||||
|
|
||||||
values = tuple(info.cvt_enum(value) for value in values)
|
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.
|
@_register_loader(1, 1) # Basic type, except for the legacy API.
|
||||||
def load_byte(self, data, legacy_api=True):
|
def load_byte(self, data, legacy_api=True):
|
||||||
return (data if legacy_api else
|
return data
|
||||||
tuple(map(ord, data) if bytes is str else data))
|
|
||||||
|
|
||||||
@_register_writer(1) # Basic type, except for the legacy API.
|
@_register_writer(1) # Basic type, except for the legacy API.
|
||||||
def write_byte(self, data):
|
def write_byte(self, data):
|
||||||
|
|
|
@ -48,11 +48,21 @@ def lookup(tag):
|
||||||
#
|
#
|
||||||
# id: (Name, Type, Length, enum_values)
|
# 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
|
ASCII = 2
|
||||||
SHORT = 3
|
SHORT = 3
|
||||||
LONG = 4
|
LONG = 4
|
||||||
RATIONAL = 5
|
RATIONAL = 5
|
||||||
|
UNDEFINED = 7
|
||||||
|
SIGNED_RATIONAL = 10
|
||||||
|
DOUBLE = 12
|
||||||
|
|
||||||
TAGS_V2 = {
|
TAGS_V2 = {
|
||||||
|
|
||||||
|
@ -128,8 +138,8 @@ TAGS_V2 = {
|
||||||
338: ("ExtraSamples", SHORT, 0),
|
338: ("ExtraSamples", SHORT, 0),
|
||||||
339: ("SampleFormat", SHORT, 0),
|
339: ("SampleFormat", SHORT, 0),
|
||||||
|
|
||||||
340: ("SMinSampleValue", 12, 0),
|
340: ("SMinSampleValue", DOUBLE, 0),
|
||||||
341: ("SMaxSampleValue", 12, 0),
|
341: ("SMaxSampleValue", DOUBLE, 0),
|
||||||
342: ("TransferRange", SHORT, 6),
|
342: ("TransferRange", SHORT, 6),
|
||||||
|
|
||||||
# obsolete JPEG tags
|
# obsolete JPEG tags
|
||||||
|
@ -152,34 +162,34 @@ TAGS_V2 = {
|
||||||
|
|
||||||
# FIXME add more tags here
|
# FIXME add more tags here
|
||||||
34665: ("ExifIFD", SHORT, 1),
|
34665: ("ExifIFD", SHORT, 1),
|
||||||
34675: ('ICCProfile', 7, 0),
|
34675: ('ICCProfile', UNDEFINED, 1),
|
||||||
34853: ('GPSInfoIFD', 1, 1),
|
34853: ('GPSInfoIFD', BYTE, 1),
|
||||||
|
|
||||||
# MPInfo
|
# MPInfo
|
||||||
45056: ("MPFVersion", 7, 1),
|
45056: ("MPFVersion", UNDEFINED, 1),
|
||||||
45057: ("NumberOfImages", LONG, 1),
|
45057: ("NumberOfImages", LONG, 1),
|
||||||
45058: ("MPEntry", 7, 1),
|
45058: ("MPEntry", UNDEFINED, 1),
|
||||||
45059: ("ImageUIDList", 7, 0),
|
45059: ("ImageUIDList", UNDEFINED, 0), # UNDONE, check
|
||||||
45060: ("TotalFrames", LONG, 1),
|
45060: ("TotalFrames", LONG, 1),
|
||||||
45313: ("MPIndividualNum", LONG, 1),
|
45313: ("MPIndividualNum", LONG, 1),
|
||||||
45569: ("PanOrientation", LONG, 1),
|
45569: ("PanOrientation", LONG, 1),
|
||||||
45570: ("PanOverlap_H", RATIONAL, 1),
|
45570: ("PanOverlap_H", RATIONAL, 1),
|
||||||
45571: ("PanOverlap_V", RATIONAL, 1),
|
45571: ("PanOverlap_V", RATIONAL, 1),
|
||||||
45572: ("BaseViewpointNum", LONG, 1),
|
45572: ("BaseViewpointNum", LONG, 1),
|
||||||
45573: ("ConvergenceAngle", 10, 1),
|
45573: ("ConvergenceAngle", SIGNED_RATIONAL, 1),
|
||||||
45574: ("BaselineLength", RATIONAL, 1),
|
45574: ("BaselineLength", RATIONAL, 1),
|
||||||
45575: ("VerticalDivergence", 10, 1),
|
45575: ("VerticalDivergence", SIGNED_RATIONAL, 1),
|
||||||
45576: ("AxisDistance_X", 10, 1),
|
45576: ("AxisDistance_X", SIGNED_RATIONAL, 1),
|
||||||
45577: ("AxisDistance_Y", 10, 1),
|
45577: ("AxisDistance_Y", SIGNED_RATIONAL, 1),
|
||||||
45578: ("AxisDistance_Z", 10, 1),
|
45578: ("AxisDistance_Z", SIGNED_RATIONAL, 1),
|
||||||
45579: ("YawAngle", 10, 1),
|
45579: ("YawAngle", SIGNED_RATIONAL, 1),
|
||||||
45580: ("PitchAngle", 10, 1),
|
45580: ("PitchAngle", SIGNED_RATIONAL, 1),
|
||||||
45581: ("RollAngle", 10, 1),
|
45581: ("RollAngle", SIGNED_RATIONAL, 1),
|
||||||
|
|
||||||
50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
|
50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
|
||||||
50780: ("BestQualityScale", RATIONAL, 1),
|
50780: ("BestQualityScale", RATIONAL, 1),
|
||||||
50838: ("ImageJMetaDataByteCounts", LONG, 1),
|
50838: ("ImageJMetaDataByteCounts", LONG, 1),
|
||||||
50839: ("ImageJMetaData", 7, 1)
|
50839: ("ImageJMetaData", UNDEFINED, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Legacy Tags structure
|
# Legacy Tags structure
|
||||||
|
|
|
@ -287,7 +287,7 @@ class TestFileTiff(PillowTestCase):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
data = b"abc"
|
data = b"abc"
|
||||||
ret = ifd.load_byte(data, legacy_api)
|
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):
|
def test_load_string(self):
|
||||||
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
ifd = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
|
|
|
@ -175,7 +175,7 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
|
|
||||||
im.save(out)
|
im.save(out)
|
||||||
reloaded = Image.open(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'])
|
self.assertEqual(im.info['icc_profile'], reloaded.info['icc_profile'])
|
||||||
|
|
||||||
def test_iccprofile_binary(self):
|
def test_iccprofile_binary(self):
|
||||||
|
@ -186,6 +186,16 @@ class TestFileTiffMetadata(PillowTestCase):
|
||||||
self.assertEqual(im.tag_v2.tagtype[34675], 1)
|
self.assertEqual(im.tag_v2.tagtype[34675], 1)
|
||||||
self.assertTrue(im.info['icc_profile'])
|
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):
|
def test_exif_div_zero(self):
|
||||||
im = hopper()
|
im = hopper()
|
||||||
info = TiffImagePlugin.ImageFileDirectory_v2()
|
info = TiffImagePlugin.ImageFileDirectory_v2()
|
||||||
|
|
|
@ -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
|
that are checked for libraries and headers for build systems or
|
||||||
cross compilers that specify that information in via environment
|
cross compilers that specify that information in via environment
|
||||||
variables.
|
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``.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user