diff --git a/Tests/test_file_apng.py b/Tests/test_file_apng.py index 36110e891fc..b48995ab636 100644 --- a/Tests/test_file_apng.py +++ b/Tests/test_file_apng.py @@ -12,7 +12,8 @@ class TestFilePng(PillowTestCase): # (referenced from https://wiki.mozilla.org/APNG_Specification) def test_apng_basic(self): 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.assertIsNone(im.info.get("default_image")) self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255)) @@ -20,6 +21,7 @@ def test_apng_basic(self): with Image.open("Tests/images/apng/single_frame_default.png") as im: self.assertTrue(im.is_animated) + self.assertEqual(im.n_frames, 2) self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertTrue(im.info.get("default_image")) self.assertEqual(im.getpixel((0, 0)), (255, 0, 0, 255)) @@ -311,7 +313,8 @@ def test_apng_save(self): with Image.open(test_file) as im: 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.assertIsNone(im.info.get("default_image")) self.assertEqual(im.getpixel((0, 0)), (0, 255, 0, 255)) @@ -328,6 +331,7 @@ def test_apng_save(self): with Image.open(test_file) as im: im.load() self.assertTrue(im.is_animated) + self.assertEqual(im.n_frames, 2) self.assertEqual(im.get_format_mimetype(), "image/apng") self.assertTrue(im.info.get("default_image")) im.seek(1) diff --git a/docs/handbook/image-file-formats.rst b/docs/handbook/image-file-formats.rst index a6b87407dd5..5d882eb768f 100644 --- a/docs/handbook/image-file-formats.rst +++ b/docs/handbook/image-file-formats.rst @@ -559,8 +559,11 @@ APNG sequences The PNG loader includes limited support for reading and writing Animated Portable Network Graphics (APNG) files. 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 be ``True`` (even for single frame APNG files). +will return ``"image/apng"``. The value of the :py:attr:`~PIL.Image.Image.is_animated` +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 are supported. diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 398eade3cb2..dd3673b53b4 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -717,7 +717,7 @@ def n_frames(self): @property 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): """Verify PNG file"""