Merge pull request #2902 from wiredfool/pr_2388

Add disposal option when saving GIFs
This commit is contained in:
wiredfool 2017-12-27 12:15:00 +00:00 committed by GitHub
commit ff13d184d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 3 deletions

View File

@ -392,6 +392,7 @@ def _write_single_frame(im, fp, palette):
def _write_multiple_frames(im, fp, palette):
duration = im.encoderinfo.get("duration", None)
disposal = im.encoderinfo.get('disposal', None)
im_frames = []
frame_count = 0
@ -404,6 +405,8 @@ def _write_multiple_frames(im, fp, palette):
encoderinfo = im.encoderinfo.copy()
if isinstance(duration, (list, tuple)):
encoderinfo['duration'] = duration[frame_count]
if isinstance(disposal, (list, tuple)):
encoderinfo["disposal"] = disposal[frame_count]
frame_count += 1
if im_frames:
@ -503,15 +506,19 @@ def _write_local_header(fp, im, offset, flags):
duration = int(im.encoderinfo["duration"] / 10)
else:
duration = 0
if transparent_color_exists or duration != 0:
transparency_flag = 1 if transparent_color_exists else 0
disposal = int(im.encoderinfo.get('disposal', 0))
if transparent_color_exists or duration != 0 or disposal:
packed_flag = 1 if transparent_color_exists else 0
packed_flag |= disposal << 2
if not transparent_color_exists:
transparency = 0
fp.write(b"!" +
o8(249) + # extension intro
o8(4) + # length
o8(transparency_flag) + # packed fields
o8(packed_flag) + # packed fields
o16(duration) + # duration
o8(transparency) + # transparency index
o8(0))

View File

@ -259,6 +259,40 @@ class TestFileGif(PillowTestCase):
except EOFError:
pass
def test_save_dispose(self):
out = self.tempfile('temp.gif')
im_list = [
Image.new('L', (100, 100), '#000'),
Image.new('L', (100, 100), '#111'),
Image.new('L', (100, 100), '#222'),
]
for method in range(0,4):
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
disposal=method
)
img = Image.open(out)
for _ in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, method)
# check per frame disposal
im_list[0].save(
out,
save_all=True,
append_images=im_list[1:],
disposal=tuple(range(len(im_list)))
)
img = Image.open(out)
for i in range(2):
img.seek(img.tell() + 1)
self.assertEqual(img.disposal_method, i+1)
def test_iss634(self):
img = Image.open("Tests/images/iss634.gif")
# seek to the second frame

View File

@ -132,6 +132,17 @@ are available::
the palette can be passed in as an
:py:class:`PIL.ImagePalette.ImagePalette` object.
**disposal**
Indicates the way in which the graphic is to be treated after being displayed.
* 0 - No disposal specified.
* 1 - Do not dispose.
* 2 - Restore to background color.
* 3 - Restore to previous content.
Pass a single integer for a constant disposal, or a list or tuple
to set the disposal for each frame separately.
Reading local images
~~~~~~~~~~~~~~~~~~~~