Read textual chunks located after IDAT chunks

This commit is contained in:
Andrew Murray 2018-12-24 23:58:19 +11:00
parent 95d80a7e5d
commit 22837c37e2
2 changed files with 47 additions and 1 deletions

View File

@ -557,6 +557,28 @@ class TestFilePng(PillowTestCase):
chunks = PngImagePlugin.getchunks(im) chunks = PngImagePlugin.getchunks(im)
self.assertEqual(len(chunks), 3) self.assertEqual(len(chunks), 3)
def test_textual_chunks_after_idat(self):
im = Image.open("Tests/images/hopper.png")
self.assertIn('comment', im.text.keys())
for k, v in {
'date:create': '2014-09-04T09:37:08+03:00',
'date:modify': '2014-09-04T09:37:08+03:00',
}.items():
self.assertEqual(im.text[k], v)
# Raises a SyntaxError in load_end
im = Image.open("Tests/images/broken_data_stream.png")
with self.assertRaises(IOError):
self.assertIsInstance(im.text, dict)
# Raises a UnicodeDecodeError in load_end
im = Image.open("Tests/images/truncated_image.png")
# The file is truncated
self.assertRaises(IOError, lambda: im.text)
ImageFile.LOAD_TRUNCATED_IMAGES = True
self.assertIsInstance(im.text, dict)
ImageFile.LOAD_TRUNCATED_IMAGES = False
@unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS") @unittest.skipIf(sys.platform.startswith('win32'), "requires Unix or macOS")
class TestTruncatedPngPLeaks(PillowLeakTestCase): class TestTruncatedPngPLeaks(PillowLeakTestCase):

View File

@ -579,7 +579,7 @@ class PngImageFile(ImageFile.ImageFile):
self.mode = self.png.im_mode self.mode = self.png.im_mode
self._size = self.png.im_size self._size = self.png.im_size
self.info = self.png.im_info self.info = self.png.im_info
self.text = self.png.im_text # experimental self._text = None
self.tile = self.png.im_tile self.tile = self.png.im_tile
if self.png.im_palette: if self.png.im_palette:
@ -588,6 +588,15 @@ class PngImageFile(ImageFile.ImageFile):
self.__idat = length # used by load_read() self.__idat = length # used by load_read()
@property
def text(self):
# experimental
if self._text is None:
# iTxt, tEXt and zTXt chunks may appear at the end of the file
# So load the file to ensure that they are read
self.load()
return self._text
def verify(self): def verify(self):
"Verify PNG file" "Verify PNG file"
@ -640,7 +649,22 @@ class PngImageFile(ImageFile.ImageFile):
def load_end(self): def load_end(self):
"internal: finished reading image data" "internal: finished reading image data"
while True:
self.fp.read(4) # CRC
try:
cid, pos, length = self.png.read()
except (struct.error, SyntaxError):
break
if cid == b"IEND":
break
try:
self.png.call(cid, pos, length)
except UnicodeDecodeError:
break
self._text = self.png.im_text
self.png.close() self.png.close()
self.png = None self.png = None