Displaying Animated Gifs In Tkinter Using Pil
Solution 1:
For one, you are creating a new canvas object for every frame. Eventually you will have thousands of images stacked on top of one another. This is highly inefficient; the canvas widget has performance issues when you start to have thousands of objects.
Instead of creating new image objects on the canvas, just reconfigure the existing object with the itemconfig method of the canvas.
Second, you don't need the complexities of threading for such a simple task. There is a well known pattern in tkinter for doing animations: draw a frame, then have that function use after
to call itself in the future.
Something like this:
defanimate(self):
if self._image_id isNone:
self._image_id = self.display.create_image(...)
else:
self.itemconfig(self._image_id, image= the_new_image)
self.display.after(self.gif["delay"], self.animate)
Finally, unless there's a strict reason to use a canvas, you can lower the complexity a little more by using a Label widget.
Solution 2:
Your problem has nothing to do with Tkinter. (For all I know, you may also have Tk problems, but your images are already bad before you get to Tk.)
The way I tested this was to modify your anim_gif
function to write out the frames as separate image file, by changing the for item in pics[1:]
loop like this:
for i, item in enumerate(pics[1:]):
temp.paste(item)
temp.save('temp{}.png'.format(i))
gif['frames'].append(ImageTk.PhotoImage(temp.convert('RGBA')))
The very first file, temp0.png
, is already screwed up, with no Tk-related code being called.
In fact, you can test the same thing even more easily:
from PIL import Image
im = Image.open('test.gif')
temp = im.copy()
im.seek(1)
temp.paste(im.copy())
temp.save('test.png')
The problem is that you're pasting the pixels from frame #1 over top of the pixels from frame #0, but leaving the color palette from frame #0.
There are two easy ways to solve this.
First, use the RGBA-converted frames instead of the palette-color frames:
temp = pics[0].convert('RGBA')
gif['frames'] = [ImageTk.PhotoImage(temp)]
for item in pics[1:]:
frame = item.convert('RGBA')
temp.paste(frame)
gif['frames'].append(ImageTk.PhotoImage(temp))
Second, don't use copy and paste at all; just copy over each frame as an independent image:
gif['frames'] = [ImageTk.PhotoImage(frame.convert('RGBA')) forframein pics]
Post a Comment for "Displaying Animated Gifs In Tkinter Using Pil"