我正在試圖製作一個程序來顯示使用Tkinter的動畫GIF。下面是代碼,我最初使用:在Tkinter中使用PIL顯示動畫GIF
from __future__ import division # Just because division doesn't work right in 2.7.4
from Tkinter import *
from PIL import Image,ImageTk
import threading
from time import sleep
def anim_gif(name):
## Returns { 'frames', 'delay', 'loc', 'len' }
im = Image.open(name)
gif = { 'frames': [],
'delay': 100,
'loc' : 0,
'len' : 0 }
pics = []
try:
while True:
pics.append(im.copy())
im.seek(len(pics))
except EOFError: pass
temp = pics[0].convert('RGBA')
gif['frames'] = [ImageTk.PhotoImage(temp)]
temp = pics[0]
for item in pics[1:]:
temp.paste(item)
gif['frames'].append(ImageTk.PhotoImage(temp.convert('RGBA')))
try: gif['delay'] = im.info['duration']
except: pass
gif['len'] = len(gif['frames'])
return gif
def ratio(a,b):
if b < a: d,c = a,b
else: c,d = a,b
if b == a: return 1,1
for i in reversed(xrange(2,int(round(a/2)))):
if a % i == 0 and b % i == 0:
a /= i
b /= i
return (int(a),int(b))
class App(Frame):
def show(self,image=None,event=None):
self.display.create_image((0,0),anchor=NW,image=image)
def animate(self,event=None):
self.show(image=self.gif['frames'][self.gif['loc']])
self.gif['loc'] += 1
if self.gif['loc'] == self.gif['len']:
self.gif['loc'] = 0
if self.cont:
threading.Timer((self.gif['delay']/1000),self.animate).start()
def kill(self,event=None):
self.cont = False
sleep(0.1)
self.quit()
def __init__(self,master):
Frame.__init__(self,master)
self.grid(row=0,sticky=N+E+S+W)
self.rowconfigure(1,weight=2)
self.rowconfigure(3,weight=1)
self.columnconfigure(0,weight=1)
self.title = Label(self,text='No title')
self.title.grid(row=0,sticky=E+W)
self.display = Canvas(self)
self.display.grid(row=1,sticky=N+E+S+W)
self.user = Label(self,text='Posted by No Username')
self.user.grid(row=2,sticky=E+W)
self.comment = Text(self,height=4,width=40,state=DISABLED)
self.comment.grid(row=3,sticky=N+E+S+W)
self.cont = True
self.gif = anim_gif('test.gif')
self.animate()
root.protocol("WM_DELETE_WINDOW",self.kill)
root = Tk()
root.rowconfigure(0,weight=1)
root.columnconfigure(0,weight=1)
app = App(root)
app.mainloop()
try: root.destroy()
except: pass
test.gif如下GIF:
這工作得很好,但GIF質量是可怕的。我嘗試將其更改爲以下內容:
def anim_gif(name):
## Returns { 'frames', 'delay', 'loc', 'len' }
im = Image.open(name)
gif = { 'frames': [],
'delay': 100,
'loc' : 0,
'len' : 0 }
pics = []
try:
while True:
gif['frames'].append(im.copy())
im.seek(len(gif['frames']))
except EOFError: pass
try: gif['delay'] = im.info['duration']
except: pass
gif['len'] = len(gif['frames'])
return gif
class App(Frame):
def show(self,image=None,event=None):
can_w = self.display['width']
can_h = self.display['height']
pic_w,pic_h = image.size
rat_w,rat_h = ratio(pic_w,pic_h)
while pic_w > int(can_w) or pic_h > int(can_h):
pic_w -= rat_w
pic_h -= rat_h
resized = image.resize((pic_w,pic_h))
resized = ImageTk.PhotoImage(resized)
self.display.create_image((0,0),anchor=NW,image=resized)
但是,這會偶爾閃爍一張圖片。雖然這張照片看起來不錯,但作爲一個程序來說它是無用的。我究竟做錯了什麼?
要做的第一件事就是找出問題所在。嘗試每次通過循環將'temp'保存到新的.PNG文件中。他們已經搞砸了嗎?如果是這樣,Tkinter與這個問題無關,這意味着你可以寫一個更小的[SSCCE](http://sscce.org)。 – abarnert
更仔細地查看了代碼,併爲您完成了建議的測試:問題完全在於您的PIL代碼中;試圖解決Tkinter的問題就是在錯誤的樹上追逐一隻野鵝。 – abarnert
相關:[用tkinter播放動畫GIF](https://stackoverflow.com/q/43770847/190597) – unutbu