Merge pull request #3506 from radarhere/png

Read textual chunks located after IDAT chunks for PNG
This commit is contained in:
Hugo 2018-12-26 13:34:50 +02:00 committed by GitHub
commit a43b8bac1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 2 deletions

View File

@ -557,6 +557,28 @@ class TestFilePng(PillowTestCase):
chunks = PngImagePlugin.getchunks(im)
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")
class TestTruncatedPngPLeaks(PillowLeakTestCase):

View File

@ -482,7 +482,7 @@ The :py:meth:`~PIL.Image.Image.open` method sets the following
This key is omitted if the image is not a transparent palette image.
``Open`` also sets ``Image.text`` to a list of the values of the
``Open`` also sets ``Image.text`` to a dictionary of the values of the
``tEXt``, ``zTXt``, and ``iTXt`` chunks of the PNG image. Individual
compressed chunks are limited to a decompressed size of
``PngImagePlugin.MAX_TEXT_CHUNK``, by default 1MB, to prevent

View File

@ -579,7 +579,7 @@ class PngImageFile(ImageFile.ImageFile):
self.mode = self.png.im_mode
self._size = self.png.im_size
self.info = self.png.im_info
self.text = self.png.im_text # experimental
self._text = None
self.tile = self.png.im_tile
if self.png.im_palette:
@ -588,6 +588,15 @@ class PngImageFile(ImageFile.ImageFile):
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):
"Verify PNG file"
@ -640,7 +649,22 @@ class PngImageFile(ImageFile.ImageFile):
def load_end(self):
"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 = None