Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pr 2388 #2902

Merged
merged 7 commits into from Dec 27, 2017
Merged

Pr 2388 #2902

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 10 additions & 3 deletions PIL/GifImagePlugin.py
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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))
Expand Down
34 changes: 34 additions & 0 deletions Tests/test_file_gif.py
Expand Up @@ -259,6 +259,40 @@ def test_dispose_previous(self):
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
Expand Down
11 changes: 11 additions & 0 deletions docs/handbook/image-file-formats.rst
Expand Up @@ -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
~~~~~~~~~~~~~~~~~~~~

Expand Down