mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-10-30 23:47:27 +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 | ||||
| 
 | ||||
|         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): | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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() | ||||
|  |  | |||
|  | @ -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``. | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user