forked from python-pillow/Pillow
-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_file_tiff_metadata.py
225 lines (181 loc) · 8.81 KB
/
test_file_tiff_metadata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import io
import struct
from helper import unittest, PillowTestCase, hopper
from PIL import Image, TiffImagePlugin, TiffTags
from PIL.TiffImagePlugin import _limit_rational, IFDRational
tag_ids = {info.name: info.value for info in TiffTags.TAGS_V2.values()}
class TestFileTiffMetadata(PillowTestCase):
def test_rt_metadata(self):
""" Test writing arbitrary metadata into the tiff image directory
Use case is ImageJ private tags, one numeric, one arbitrary
data. https://github.com/python-pillow/Pillow/issues/291
"""
img = hopper()
# Behaviour change: re #1416
# Pre ifd rewrite, ImageJMetaData was being written as a string(2),
# Post ifd rewrite, it's defined as arbitrary bytes(7). It should
# roundtrip with the actual bytes, rather than stripped text
# of the premerge tests.
#
# For text items, we still have to decode('ascii','replace') because
# the tiff file format can't take 8 bit bytes in that field.
basetextdata = "This is some arbitrary metadata for a text field"
bindata = basetextdata.encode('ascii') + b" \xff"
textdata = basetextdata + " " + chr(255)
reloaded_textdata = basetextdata + " ?"
floatdata = 12.345
doubledata = 67.89
info = TiffImagePlugin.ImageFileDirectory()
ImageJMetaData = tag_ids['ImageJMetaData']
ImageJMetaDataByteCounts = tag_ids['ImageJMetaDataByteCounts']
ImageDescription = tag_ids['ImageDescription']
info[ImageJMetaDataByteCounts] = len(bindata)
info[ImageJMetaData] = bindata
info[tag_ids['RollAngle']] = floatdata
info.tagtype[tag_ids['RollAngle']] = 11
info[tag_ids['YawAngle']] = doubledata
info.tagtype[tag_ids['YawAngle']] = 12
info[ImageDescription] = textdata
f = self.tempfile("temp.tif")
img.save(f, tiffinfo=info)
loaded = Image.open(f)
self.assertEqual(loaded.tag[ImageJMetaDataByteCounts], (len(bindata),))
self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], len(bindata))
self.assertEqual(loaded.tag[ImageJMetaData], bindata)
self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)
self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata,))
self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)
loaded_float = loaded.tag[tag_ids['RollAngle']][0]
self.assertAlmostEqual(loaded_float, floatdata, places=5)
loaded_double = loaded.tag[tag_ids['YawAngle']][0]
self.assertAlmostEqual(loaded_double, doubledata)
def test_read_metadata(self):
img = Image.open('Tests/images/hopper_g4.tif')
self.assertEqual({'YResolution': IFDRational(4294967295, 113653537),
'PlanarConfiguration': 1,
'BitsPerSample': (1,),
'ImageLength': 128,
'Compression': 4,
'FillOrder': 1,
'RowsPerStrip': 128,
'ResolutionUnit': 3,
'PhotometricInterpretation': 0,
'PageNumber': (0, 1),
'XResolution': IFDRational(4294967295, 113653537),
'ImageWidth': 128,
'Orientation': 1,
'StripByteCounts': (1968,),
'SamplesPerPixel': 1,
'StripOffsets': (8,)
}, img.tag_v2.named())
self.assertEqual({'YResolution': ((4294967295, 113653537),),
'PlanarConfiguration': (1,),
'BitsPerSample': (1,),
'ImageLength': (128,),
'Compression': (4,),
'FillOrder': (1,),
'RowsPerStrip': (128,),
'ResolutionUnit': (3,),
'PhotometricInterpretation': (0,),
'PageNumber': (0, 1),
'XResolution': ((4294967295, 113653537),),
'ImageWidth': (128,),
'Orientation': (1,),
'StripByteCounts': (1968,),
'SamplesPerPixel': (1,),
'StripOffsets': (8,)
}, img.tag.named())
def test_write_metadata(self):
""" Test metadata writing through the python code """
img = Image.open('Tests/images/hopper.tif')
f = self.tempfile('temp.tiff')
img.save(f, tiffinfo=img.tag)
loaded = Image.open(f)
original = img.tag_v2.named()
reloaded = loaded.tag_v2.named()
for k, v in original.items():
if isinstance(v, IFDRational):
original[k] = IFDRational(*_limit_rational(v, 2**31))
if isinstance(v, tuple) and isinstance(v[0], IFDRational):
original[k] = tuple([IFDRational(
*_limit_rational(elt, 2**31)) for elt in v])
ignored = ['StripByteCounts', 'RowsPerStrip',
'PageNumber', 'StripOffsets']
for tag, value in reloaded.items():
if tag in ignored:
continue
if (isinstance(original[tag], tuple)
and isinstance(original[tag][0], IFDRational)):
# Need to compare element by element in the tuple,
# not comparing tuples of object references
self.assert_deep_equal(original[tag],
value,
"%s didn't roundtrip, %s, %s" %
(tag, original[tag], value))
else:
self.assertEqual(original[tag],
value,
"%s didn't roundtrip, %s, %s" %
(tag, original[tag], value))
for tag, value in original.items():
if tag not in ignored:
self.assertEqual(
value, reloaded[tag], "%s didn't roundtrip" % tag)
def test_no_duplicate_50741_tag(self):
self.assertEqual(tag_ids['MakerNoteSafety'], 50741)
self.assertEqual(tag_ids['BestQualityScale'], 50780)
def test_empty_metadata(self):
f = io.BytesIO(b'II*\x00\x08\x00\x00\x00')
head = f.read(8)
info = TiffImagePlugin.ImageFileDirectory(head)
try:
self.assert_warning(UserWarning, lambda: info.load(f))
except struct.error:
self.fail("Should not be struct errors there.")
def test_iccprofile(self):
# https://github.com/python-pillow/Pillow/issues/1462
im = Image.open('Tests/images/hopper.iccprofile.tif')
out = self.tempfile('temp.tiff')
im.save(out)
reloaded = Image.open(out)
self.assertNotIsInstance(im.info['icc_profile'], tuple)
self.assertEqual(im.info['icc_profile'], reloaded.info['icc_profile'])
def test_iccprofile_binary(self):
# https://github.com/python-pillow/Pillow/issues/1526
# We should be able to load this, but probably won't be able to save it.
im = Image.open('Tests/images/hopper.iccprofile_binary.tif')
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()
info[41988] = TiffImagePlugin.IFDRational(0, 0)
out = self.tempfile('temp.tiff')
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)
def test_expty_values(self):
data = io.BytesIO(
b'II*\x00\x08\x00\x00\x00\x03\x00\x1a\x01\x05\x00\x00\x00\x00\x00'
b'\x00\x00\x00\x00\x1b\x01\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00'
b'\x98\x82\x02\x00\x07\x00\x00\x002\x00\x00\x00\x00\x00\x00\x00a '
b'text\x00\x00')
head = data.read(8)
info = TiffImagePlugin.ImageFileDirectory_v2(head)
info.load(data)
try:
info = dict(info)
except ValueError:
self.fail("Should not be struct value error there.")
self.assertIn(33432, info)
if __name__ == '__main__':
unittest.main()