mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-08-18 19:24:47 +03:00
Merge c02b25720c
into 4c932e0661
This commit is contained in:
commit
2486f48d40
|
@ -298,7 +298,7 @@ except ImportError:
|
|||
RAWMODE = {
|
||||
"1": "L",
|
||||
"L": "L",
|
||||
"P": "P",
|
||||
"P": "P"
|
||||
}
|
||||
|
||||
|
||||
|
@ -321,7 +321,6 @@ def _save_all(im, fp, filename):
|
|||
|
||||
|
||||
def _save(im, fp, filename, save_all=False):
|
||||
|
||||
im.encoderinfo.update(im.info)
|
||||
if _imaging_gif:
|
||||
# call external driver
|
||||
|
@ -344,62 +343,68 @@ def _save(im, fp, filename, save_all=False):
|
|||
im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
|
||||
|
||||
if save_all:
|
||||
previous = None
|
||||
|
||||
first_frame = None
|
||||
append_images = im.encoderinfo.get("append_images", [])
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im_frame, duration=1000)
|
||||
if "duration" in im.encoderinfo:
|
||||
duration = im.encoderinfo["duration"]
|
||||
else:
|
||||
duration = None
|
||||
im_frames = []
|
||||
append_images = im.encoderinfo.get("append_images", [])
|
||||
frame_count = 0
|
||||
for imSequence in [im]+append_images:
|
||||
for im_frame in ImageSequence.Iterator(imSequence):
|
||||
encoderinfo = im.encoderinfo.copy()
|
||||
im_frame = _convert_mode(im_frame)
|
||||
|
||||
encoderinfo = im.encoderinfo.copy()
|
||||
if isinstance(duration, (list, tuple)):
|
||||
encoderinfo["duration"] = duration[frame_count]
|
||||
encoderinfo['duration'] = duration[frame_count]
|
||||
frame_count += 1
|
||||
|
||||
# To specify duration, add the time in milliseconds to getdata(),
|
||||
# e.g. getdata(im_frame, duration=1000)
|
||||
if not previous:
|
||||
# global header
|
||||
first_frame = getheader(im_frame, palette, encoderinfo)[0]
|
||||
first_frame += getdata(im_frame, (0, 0), **encoderinfo)
|
||||
else:
|
||||
if first_frame:
|
||||
for s in first_frame:
|
||||
fp.write(s)
|
||||
first_frame = None
|
||||
|
||||
if im_frames:
|
||||
# delta frame
|
||||
delta = ImageChops.subtract_modulo(im_frame, previous.copy())
|
||||
previous = im_frames[-1]
|
||||
delta = ImageChops.subtract_modulo(im_frame,
|
||||
previous['im'])
|
||||
bbox = delta.getbbox()
|
||||
|
||||
if bbox:
|
||||
# compress difference
|
||||
encoderinfo['include_color_table'] = True
|
||||
for s in getdata(im_frame.crop(bbox),
|
||||
bbox[:2], **encoderinfo):
|
||||
fp.write(s)
|
||||
if not bbox:
|
||||
# This frame is identical to the previous frame
|
||||
if duration:
|
||||
previous['encoderinfo']['duration'] += encoderinfo['duration']
|
||||
continue
|
||||
else:
|
||||
# FIXME: what should we do in this case?
|
||||
pass
|
||||
previous = im_frame
|
||||
if first_frame:
|
||||
bbox = None
|
||||
im_frames.append({
|
||||
'im':im_frame,
|
||||
'bbox':bbox,
|
||||
'encoderinfo':encoderinfo
|
||||
})
|
||||
if len(im_frames) < 2:
|
||||
save_all = False
|
||||
if not save_all:
|
||||
header = getheader(im_out, palette, im.encoderinfo)[0]
|
||||
for s in header:
|
||||
else:
|
||||
for frame_data in im_frames:
|
||||
im_frame = frame_data['im']
|
||||
if not frame_data['bbox']:
|
||||
# global header
|
||||
for s in getheader(im_frame, palette, frame_data['encoderinfo'])[0]:
|
||||
fp.write(s)
|
||||
offset = (0, 0)
|
||||
else:
|
||||
# compress difference
|
||||
frame_data['encoderinfo']['include_color_table'] = True
|
||||
|
||||
flags = 0
|
||||
|
||||
if get_interlace(im):
|
||||
flags = flags | 64
|
||||
im_frame = im_frame.crop(frame_data['bbox'])
|
||||
offset = frame_data['bbox'][:2]
|
||||
for s in getdata(im_frame, offset, **frame_data['encoderinfo']):
|
||||
fp.write(s)
|
||||
if not save_all:
|
||||
for s in getheader(im_out, palette, im.encoderinfo)[0]:
|
||||
fp.write(s)
|
||||
|
||||
# local image header
|
||||
flags = 0
|
||||
if get_interlace(im):
|
||||
flags = flags | 64
|
||||
_get_local_header(fp, im, (0, 0), flags)
|
||||
|
||||
im_out.encoderconfig = (8, get_interlace(im))
|
||||
|
|
|
@ -287,7 +287,7 @@ class TestFileGif(PillowTestCase):
|
|||
im_list = [
|
||||
Image.new('L', (100, 100), '#000'),
|
||||
Image.new('L', (100, 100), '#111'),
|
||||
Image.new('L', (100, 100), '#222'),
|
||||
Image.new('L', (100, 100), '#222')
|
||||
]
|
||||
|
||||
#duration as list
|
||||
|
@ -322,7 +322,31 @@ class TestFileGif(PillowTestCase):
|
|||
except EOFError:
|
||||
pass
|
||||
|
||||
def test_identical_frames(self):
|
||||
duration_list = [1000, 1500, 2000, 4000]
|
||||
|
||||
out = self.tempfile('temp.gif')
|
||||
im_list = [
|
||||
Image.new('L', (100, 100), '#000'),
|
||||
Image.new('L', (100, 100), '#000'),
|
||||
Image.new('L', (100, 100), '#000'),
|
||||
Image.new('L', (100, 100), '#111')
|
||||
]
|
||||
|
||||
#duration as list
|
||||
im_list[0].save(
|
||||
out,
|
||||
save_all=True,
|
||||
append_images=im_list[1:],
|
||||
duration=duration_list
|
||||
)
|
||||
reread = Image.open(out)
|
||||
|
||||
# Assert that the first three frames were combined
|
||||
self.assertEqual(reread.n_frames, 2)
|
||||
|
||||
# Assert that the new duration is the total of the identical frames
|
||||
self.assertEqual(reread.info['duration'], 4500)
|
||||
|
||||
def test_number_of_loops(self):
|
||||
number_of_loops = 2
|
||||
|
|
Loading…
Reference in New Issue
Block a user