diff --git a/Tests/test_imagesequence.py b/Tests/test_imagesequence.py index 38645f133..5d90dc4c5 100644 --- a/Tests/test_imagesequence.py +++ b/Tests/test_imagesequence.py @@ -74,3 +74,25 @@ class TestImageSequence(PillowTestCase): im.seek(0) color2 = im.getpalette()[0:3] self.assertEqual(color1, color2) + + def test_all_frames(self): + # Test a single image + im = Image.open("Tests/images/iss634.gif") + ims = ImageSequence.all_frames(im) + + self.assertEqual(len(ims), 42) + for i, im_frame in enumerate(ims): + self.assertFalse(im_frame is im) + + im.seek(i) + self.assert_image_equal(im, im_frame) + + # Test a series of images + ims = ImageSequence.all_frames([im, hopper(), im]) + self.assertEqual(len(ims), 85) + + # Test an operation + ims = ImageSequence.all_frames(im, lambda im_frame: im_frame.rotate(90)) + for i, im_frame in enumerate(ims): + im.seek(i) + self.assert_image_equal(im.rotate(90), im_frame) diff --git a/src/PIL/ImageSequence.py b/src/PIL/ImageSequence.py index 84199fe27..f9be92d48 100644 --- a/src/PIL/ImageSequence.py +++ b/src/PIL/ImageSequence.py @@ -54,3 +54,25 @@ class Iterator(object): def next(self): return self.__next__() + + +def all_frames(im, func=None): + """ + Applies a given function to all frames in an image or a list of images. + The frames are returned as a list of separate images. + + :param im: An image, or a list of images. + :param func: The function to apply to all of the image frames. + :returns: A list of images. + """ + if not isinstance(im, list): + im = [im] + + ims = [] + for imSequence in im: + current = imSequence.tell() + + ims += [im_frame.copy() for im_frame in Iterator(imSequence)] + + imSequence.seek(current) + return [func(im) for im in ims] if func else ims