Adjust is_animated behavior

- Make is_animated APNG behavior consistent with other Pillow formats
- is_animated will be true when n_frames is greater than 1 (for APNG
  this depends on animation frame count + presence or absence of a
  default image)
This commit is contained in:
Peter Rowlands 2020-01-23 09:49:39 +09:00 committed by Andrew Murray
parent dcc3f41fa1
commit 9b72f0513c
3 changed files with 12 additions and 5 deletions

View File

@ -12,7 +12,8 @@ class TestFilePng(PillowTestCase):
# (referenced from https://wiki.mozilla.org/APNG_Specification) # (referenced from https://wiki.mozilla.org/APNG_Specification)
def test_apng_basic(self): def test_apng_basic(self):
with Image.open("Tests/images/apng/single_frame.png") as im: with Image.open("Tests/images/apng/single_frame.png") as im:
self.assertTrue(im.is_animated) self.assertFalse(im.is_animated)
self.assertEqual(im.n_frames, 1)
self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertEqual(im.get_format_mimetype(), "image/apng")
self.assertIsNone(im.info.get("default_image")) self.assertIsNone(im.info.get("default_image"))
self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255)) self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255))
@ -20,6 +21,7 @@ class TestFilePng(PillowTestCase):
with Image.open("Tests/images/apng/single_frame_default.png") as im: with Image.open("Tests/images/apng/single_frame_default.png") as im:
self.assertTrue(im.is_animated) self.assertTrue(im.is_animated)
self.assertEqual(im.n_frames, 2)
self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertEqual(im.get_format_mimetype(), "image/apng")
self.assertTrue(im.info.get("default_image")) self.assertTrue(im.info.get("default_image"))
self.assertEqual(im.getpixel((0, 0)), (255, 0, 0, 255)) self.assertEqual(im.getpixel((0, 0)), (255, 0, 0, 255))
@ -311,7 +313,8 @@ class TestFilePng(PillowTestCase):
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
self.assertTrue(im.is_animated) self.assertFalse(im.is_animated)
self.assertEqual(im.n_frames, 1)
self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertEqual(im.get_format_mimetype(), "image/apng")
self.assertIsNone(im.info.get("default_image")) self.assertIsNone(im.info.get("default_image"))
self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255)) self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255))
@ -328,6 +331,7 @@ class TestFilePng(PillowTestCase):
with Image.open(test_file) as im: with Image.open(test_file) as im:
im.load() im.load()
self.assertTrue(im.is_animated) self.assertTrue(im.is_animated)
self.assertEqual(im.n_frames, 2)
self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertEqual(im.get_format_mimetype(), "image/apng")
self.assertTrue(im.info.get("default_image")) self.assertTrue(im.info.get("default_image"))
im.seek(1) im.seek(1)

View File

@ -559,8 +559,11 @@ APNG sequences
The PNG loader includes limited support for reading and writing Animated Portable The PNG loader includes limited support for reading and writing Animated Portable
Network Graphics (APNG) files. Network Graphics (APNG) files.
When an APNG file is loaded, :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype` When an APNG file is loaded, :py:meth:`~PIL.ImageFile.ImageFile.get_format_mimetype`
will return ``"image/apng"``, and the :py:attr:`~PIL.Image.Image.is_animated` property will return ``"image/apng"``. The value of the :py:attr:`~PIL.Image.Image.is_animated`
will be ``True`` (even for single frame APNG files). property will be ``True`` when the :py:attr:`~PIL.Image.Image.n_frames` property is
greater than 1. For APNG files, the ``n_frames`` property depends on both the animation
frame count as well as the presence or absence of a default image. See the
``default_image`` property documentation below for more details.
The :py:meth:`~PIL.Image.Image.seek` and :py:meth:`~PIL.Image.Image.tell` methods The :py:meth:`~PIL.Image.Image.seek` and :py:meth:`~PIL.Image.Image.tell` methods
are supported. are supported.

View File

@ -717,7 +717,7 @@ class PngImageFile(ImageFile.ImageFile):
@property @property
def is_animated(self): def is_animated(self):
return self._n_frames is not None return self._n_frames is not None and self._n_frames > 1
def verify(self): def verify(self):
"""Verify PNG file""" """Verify PNG file"""