是否可以在图像上提供动画? -Tkinter
Is it possible to provide animation on image ? - Tkinter
我正在 Tkinter 中开发 GUI,并希望在图像出现时在下面的 GIF 中应用动画。
这是我的代码,
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=300, height=300, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
background = PhotoImage(file="background.png")
canvas.create_image(300,300,image=background)
my_pic = PhotoImage(file="start000-befored.png")
frame.after(1000, lambda: (canvas.create_image(50,50,image=my_pic, anchor=NW))) #and on this image, I want to give the effect.
root.mainloop()
图像应该像这个动画一样在 1 秒后自动出现并停留在屏幕上,而不是点击 GIF 中显示的播放按钮。 (没有关闭选项)。
我不是 100% 确定我理解了这个问题,但我将描述如何为图像设置动画。
Tkinter 不包含用于动画图像的函数,因此您必须自己编写它们。您将必须提取所有子图像、子图像持续时间,然后构建一个序列器以在您的显示器上交换子图像。
Pillow 可以提取图像序列。 WEBP 图像似乎只支持一个帧持续时间,而 GIF 图像可能每个子图像具有不同的帧持续时间。我将只使用 GIF 图片的第一个持续时间,即使有很多。据我所知,Pillow 不支持从 WEBP 图像获取帧持续时间,但您可以从文件中读取它,请参阅 WebP Container Specification。
示例实现:
import tkinter as tk
from PIL import Image, ImageTk, ImageSequence
import itertools
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
filename = 'images/animated-nyan-cat.webp'
pil_image = Image.open(filename)
no_of_frames = pil_image.n_frames
# Get frame duration, assuming all frame durations are the same
duration = pil_image.info.get('duration', None) # None for WEBP
if duration is None:
with open(filename, 'rb') as binfile:
data = binfile.read()
pos = data.find(b'ANMF') # Extract duration for WEBP sequences
duration = int.from_bytes(data[pos+12:pos+15], byteorder='big')
# Create an infinite cycle of PIL ImageTk images for display on label
frame_list = []
for frame in ImageSequence.Iterator(pil_image):
cp = frame.copy()
frame_list.append(cp)
tkframe_list = [ImageTk.PhotoImage(image=fr) for fr in frame_list]
tkframe_sequence = itertools.cycle(tkframe_list)
tkframe_iterator = iter(tkframe_list)
def show_animation():
global after_id
after_id = root.after(duration, show_animation)
img = next(tkframe_sequence)
display.config(image=img)
def stop_animation(*event):
root.after_cancel(after_id)
def run_animation_once():
global after_id
after_id = root.after(duration, run_animation_once)
try:
img = next(tkframe_iterator)
except StopIteration:
stop_animation()
else:
display.config(image=img)
root.bind('<space>', stop_animation)
# Now you can run show_animation() or run_animation_once() at your pleasure
root.after(1000, run_animation_once)
root.mainloop()
有些库,例如 imgpy,支持 GIF 动画,但我没有使用任何此类库的经验。
加法
duration
变量设置动画速率。要减慢速率,只需增加持续时间。
将动画放在 canvas 上的最简单方法就是将标签放在 canvas 上,请参见下面的示例:
# Replace this code
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
# with this code
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500)
canvas.pack(padx=10, pady=10)
display = tk.Label(canvas)
window = canvas.create_window(250, 250, anchor='center', window=display)
那么您不必更改程序中的任何其他内容。
我正在 Tkinter 中开发 GUI,并希望在图像出现时在下面的 GIF 中应用动画。
这是我的代码,
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=300, height=300, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
background = PhotoImage(file="background.png")
canvas.create_image(300,300,image=background)
my_pic = PhotoImage(file="start000-befored.png")
frame.after(1000, lambda: (canvas.create_image(50,50,image=my_pic, anchor=NW))) #and on this image, I want to give the effect.
root.mainloop()
图像应该像这个动画一样在 1 秒后自动出现并停留在屏幕上,而不是点击 GIF 中显示的播放按钮。 (没有关闭选项)。
我不是 100% 确定我理解了这个问题,但我将描述如何为图像设置动画。
Tkinter 不包含用于动画图像的函数,因此您必须自己编写它们。您将必须提取所有子图像、子图像持续时间,然后构建一个序列器以在您的显示器上交换子图像。
Pillow 可以提取图像序列。 WEBP 图像似乎只支持一个帧持续时间,而 GIF 图像可能每个子图像具有不同的帧持续时间。我将只使用 GIF 图片的第一个持续时间,即使有很多。据我所知,Pillow 不支持从 WEBP 图像获取帧持续时间,但您可以从文件中读取它,请参阅 WebP Container Specification。
示例实现:
import tkinter as tk
from PIL import Image, ImageTk, ImageSequence
import itertools
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
filename = 'images/animated-nyan-cat.webp'
pil_image = Image.open(filename)
no_of_frames = pil_image.n_frames
# Get frame duration, assuming all frame durations are the same
duration = pil_image.info.get('duration', None) # None for WEBP
if duration is None:
with open(filename, 'rb') as binfile:
data = binfile.read()
pos = data.find(b'ANMF') # Extract duration for WEBP sequences
duration = int.from_bytes(data[pos+12:pos+15], byteorder='big')
# Create an infinite cycle of PIL ImageTk images for display on label
frame_list = []
for frame in ImageSequence.Iterator(pil_image):
cp = frame.copy()
frame_list.append(cp)
tkframe_list = [ImageTk.PhotoImage(image=fr) for fr in frame_list]
tkframe_sequence = itertools.cycle(tkframe_list)
tkframe_iterator = iter(tkframe_list)
def show_animation():
global after_id
after_id = root.after(duration, show_animation)
img = next(tkframe_sequence)
display.config(image=img)
def stop_animation(*event):
root.after_cancel(after_id)
def run_animation_once():
global after_id
after_id = root.after(duration, run_animation_once)
try:
img = next(tkframe_iterator)
except StopIteration:
stop_animation()
else:
display.config(image=img)
root.bind('<space>', stop_animation)
# Now you can run show_animation() or run_animation_once() at your pleasure
root.after(1000, run_animation_once)
root.mainloop()
有些库,例如 imgpy,支持 GIF 动画,但我没有使用任何此类库的经验。
加法
duration
变量设置动画速率。要减慢速率,只需增加持续时间。
将动画放在 canvas 上的最简单方法就是将标签放在 canvas 上,请参见下面的示例:
# Replace this code
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
# with this code
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500)
canvas.pack(padx=10, pady=10)
display = tk.Label(canvas)
window = canvas.create_window(250, 250, anchor='center', window=display)
那么您不必更改程序中的任何其他内容。