I have been trying to put a GIF in tkinter.
[GIF THAT I NEED HELP WITH]: https://i.stack.imgur.com/64SG8.gif
But for some reason, it is not coming properly and some pixel at a time only. Could someone help me with it?
from tkinter import *
import tkinter as tk
from PIL import Image
root=Tk()
file="preview.gif"
info = Image.open(file)
frames = info.n_frames # gives total number of frames that gif contains
# creating list of PhotoImage objects for each frames
im = [tk.PhotoImage(file=file,format=f"gif -index {i}") for i in range(frames)]
count = 0
anim = None
def animation(count):
global anim
im2 = im[count]
gif_label.configure(image=im2)
count += 1
if count == frames:
count = 0
anim = root.after(50,lambda :animation(count))
def stop_animation():
root.after_cancel(anim)
gif_label = tk.Label(root,image="")
gif_label.pack()
start = tk.Button(root,text="start",command=lambda :animation(count))
start.pack()
stop = tk.Button(root,text="stop",command=stop_animation)
stop.pack()
root.mainloop()
When I try to run this program it hangs on the list comprehension creating the frame list im.
Pillow has a neat function for getting frames of an animated gif. Example below, using slightly different object names but nonetheless:
from PIL import Image, ImageTk, ImageSequence
...
file = "preview.gif"
animated_gif = Image.open(file)
image_frame_list = []
for frame in ImageSequence.Iterator(animated_gif):
image_frame_list.append(ImageTk.PhotoImage(image=frame))
im = image_frame_list
Related
I am dealing with tkinter and opencv to display frames of video in tkinter canvas. my code is as following :
import tkinter as tk
from PIL import ImageTk as itk
from PIL import Image
from tkinter import filedialog as fd
import cv2
window = tk.Tk()
class window_tk():
def __init__(self,main):
self.canvas = tk.Canvas(main, bg='white' )
self.img = itk.PhotoImage(file=self.init_img_route)
self.bg= self.canvas.create_image(0,0,anchor = tk.NW,image=self.img)
self.vid = None
def load_video(self):
self.foldername = fd.askopenfilename(parent=window,initialdir="C:/",title='Select a video file to load.',filetypes=[('video files','*.wmv *.mp4 *.mov *.avi')])
self.label_foldername.config(text='Video Load : '+self.foldername)
self.current_pic_num=0
try:
self.vid = cv2.VideoCapture(self.foldername)
frame_number =0
print(self.vid,self.vid.isOpened())
self.frame_count = 0
if self.vid.isOpened():
vid_w = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
vid_h = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)
vid_f = self.vid.get(cv2.CAP_PROP_FPS)
ret,frame = self.vid.read()
#cv2.imshow('frame',frame)
frame_convert = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
#print(self.frame_count, vid_w,vid_h,vid_f,frame.shape)
imgg = itk.PhotoImage(Image.fromarray(frame_convert))
self.canvas.itemconfig(self.bg, image = imgg)
self.canvas.pack(fill='both',expand=1)
# frame_number+=1
except IndexError:
pass
I confirmed that frame has successfully loaded by checking it as cv2.imshow(), but The canvas only shows the white empty image. Is there anything I missed ?
I found answer and leave the solution for my study.
I changed imgg to self.img and let it globally used in class.
I don't know why it solved the problem so if anyone can explain the reason thank you very much.
I am wanting to create a virtual pet style game using python3 and tkinter. So far I have the main window and have started putting labels in, but the issue I am having is playing an animated gif. I have searched on here and have found some answers, but they keep throwing errors. The result I found has the index position of the gif using PhotoImage continue through a certain range.
# Loop through the index of the animated gif
frame2 = [PhotoImage(file='images/ball-1.gif', format = 'gif -index %i' %i) for i in range(100)]
def update(ind):
frame = frame2[ind]
ind += 1
img.configure(image=frame)
ms.after(100, update, ind)
img = Label(ms)
img.place(x=250, y=250, anchor="center")
ms.after(0, update, 0)
ms.mainloop()
When I run this in terminal with "pyhton3 main.py" I get the following error:
_tkinter.TclError: no image data for this index
What am I overlooking or completely leaving out?
Here is the link to the GitHub repository to see the full project:VirtPet_Python
Thanks in advance!
The error means that you tried to load 100 frames, but the gif has less than that.
Animated gifs in tkinter are notoriously bad. I wrote this code an age ago that you can steal from, but will get laggy with anything but small gifs:
import tkinter as tk
from PIL import Image, ImageTk
from itertools import count
class ImageLabel(tk.Label):
"""a label that displays images, and plays them if they are gifs"""
def load(self, im):
if isinstance(im, str):
im = Image.open(im)
self.loc = 0
self.frames = []
try:
for i in count(1):
self.frames.append(ImageTk.PhotoImage(im.copy()))
im.seek(i)
except EOFError:
pass
try:
self.delay = im.info['duration']
except:
self.delay = 100
if len(self.frames) == 1:
self.config(image=self.frames[0])
else:
self.next_frame()
def unload(self):
self.config(image="")
self.frames = None
def next_frame(self):
if self.frames:
self.loc += 1
self.loc %= len(self.frames)
self.config(image=self.frames[self.loc])
self.after(self.delay, self.next_frame)
root = tk.Tk()
lbl = ImageLabel(root)
lbl.pack()
lbl.load('ball-1.gif')
root.mainloop()
First of all, you need to know what is the last range of your GIF file. so by changing the different value of i, you will get it.For my condition is 31.
then just need to put the condition.So it will play gif infinitely.
from tkinter import *
import time
import os
root = Tk()
frames = [PhotoImage(file='./images/play.gif',format = 'gif -index %i' %(i)) for i in range(31)]
def update(ind):
frame = frames[ind]
ind += 1
print(ind)
if ind>30: #With this condition it will play gif infinitely
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
root.after(0, update, 0)
root.mainloop()
A very simple approach would be to use multithreading.
To run the GIF infinitely in a Tkinter window you should follow the following:
Create a function to run the GIF.
Put your code to run the GIF inside while True inside the function.
Create a thread to run the function.
Run root.mainloop() in the primary flow of the program.
Use time.sleep() to control the speed of your animation.
Refer to my code below:
i=0
ph = ImageTk.PhotoImage(Image.fromarray(imageframes[i]))
imglabel=Label(f2,image=ph)
imglabel.grid(row=0,column=0)
def runthegif(root,i):
while True:
i = i + 7
i= i % 150
ph=ImageTk.PhotoImage(PhotoImage(file='images/ball.gif',format='gif -index %i' %i))
imagelabel=Label(f2,image=ph)
imagelabel.grid(row=0,column=0)
time.sleep(0.1)
t1=threading.Thread(target=runthegif,args=(root,i))
t1.start()
root.mainloop()
I am trying to load 12 pictures from my directory of images by making a grid.
when I use this code, I get the same picture in each button.
I need a different photo in each button. Kinda brand new to Python.... sorry!
import Tkinter as tk
import glob
from PIL import Image, ImageTk
root = tk.Tk()
for pl in glob.glob("C:/Users/Tony/Pictures/*.jpg"):
im = Image.open(pl)
im.thumbnail((180, 140), Image.ANTIALIAS)
photo = ImageTk.PhotoImage(im)
for r in range(3):
for c in range(4):
tk.Button(root, image=photo).grid(row=r,column=c)
root.mainloop()
Thanks
Your loops aren't quite right, you probably end up with the last image on the all them? Heres what you are doing:
For each image
paste image in each grid point (repeat for next image)
I would just make an array of all the filenames:
pl = glob.glob("*.jpg")
i = 0
for r in range(3):
for c in range(4):
im = Image.open(pl[i])
i += 1
This lets you loop over your grid and use each photo only once
This question already has answers here:
Play an Animated GIF in python with tkinter
(3 answers)
Closed 5 years ago.
I've been trying to play an animated gif using Tkinter.PhotoImage, but haven't been seeing any success. It displays the image, but not the animation. The following is my code:
root = Tkinter.Tk()
photo = Tkinter.PhotoImage(file = "path/to/image.gif")
label = Tkinter.Label(image = photo)
label.pack()
root.mainloop()
It displays the image in a window, and that's it. I'm thinking that the issue has something to do with Tkinter.Label but I'm not sure. I've looked for solutions but they all tell me to use PIL (Python Imaging Library), and it's something that I don't want to use.
With the answer, I created some more code (which still doesn't work...), here it is:
from Tkinter import *
def run_animation():
while True:
try:
global photo
global frame
global label
photo = PhotoImage(
file = photo_path,
format = "gif - {}".format(frame)
)
label.configure(image = nextframe)
frame = frame + 1
except Exception:
frame = 1
break
root = Tk()
photo_path = "/users/zinedine/downloads/091.gif"
photo = PhotoImage(
file = photo_path,
)
label = Label(
image = photo
)
animate = Button(
root,
text = "animate",
command = run_animation
)
label.pack()
animate.pack()
root.mainloop()
Thanks for everything! :)
You have to drive the animation yourself in Tk. An animated gif consists of a number of frames in a single file. Tk loads the first frame but you can specify different frames by passing an index parameter when creating the image. For example:
frame2 = PhotoImage(file=imagefilename, format="gif -index 2")
If you load up all the frames into separate PhotoImages and then use timer events to switch the frame being shown (label.configure(image=nextframe)). The delay on the timer lets you control the animation speed. There is nothing provided to give you the number of frames in the image other than it failing to create a frame once you exceed the frame count.
See the photo Tk manual page for the official word.
Here's a simpler example without creating an object:
from tkinter import *
import time
import os
root = Tk()
frameCnt = 12
frames = [PhotoImage(file='mygif.gif',format = 'gif -index %i' %(i)) for i in range(frameCnt)]
def update(ind):
frame = frames[ind]
ind += 1
if ind == frameCnt:
ind = 0
label.configure(image=frame)
root.after(100, update, ind)
label = Label(root)
label.pack()
root.after(0, update, 0)
root.mainloop()
Is there any way to display an animated GIF in Tkinter using Python Image Library?
I thought the ImageSequence module would be the way to do it, but I don't know how to use it and if it's possible.
The first question is if there is any easy way. For example: load a GIF using PIL and the ImageSequence and just draw it on a Tkinter window using ImageTk.PhotoImage and it will be animated.
Or do I have to set up a function myself, using the after method or something like time.sleep to loop through the GIF frames and draw them on a tkinter window?
The second question: even if I have to make a function to loop through the GIF frames, is the ImageSequence module supposed to do this or PIL has another module for it?
I'm using Python 3.1 and a private port of PIL, indicated in this topic.
Newsgroups: comp.lang.python
From: "Fredrik Lundh"
Date: Mon, 1 May 2006
Daniel Nogradi wrote:
'The source distribution of the 1.1.4 version comes with a Scripts
directory where you can find player.py, gifmaker.py and explode.py
which all deal with animated gif.'
they're still shipped with 1.1.5 (and 1.1.6), and they should work.
if all you're missing is a few files from the script directory, you can get
them here:
http://svn.effbot.org/public/pil/Scripts/
player.py is run from the command line
see if this one works for you:
from Tkinter import *
from PIL import Image, ImageTk
class MyLabel(Label):
def __init__(self, master, filename):
im = Image.open(filename)
seq = []
try:
while 1:
seq.append(im.copy())
im.seek(len(seq)) # skip to next frame
except EOFError:
pass # we're done
try:
self.delay = im.info['duration']
except KeyError:
self.delay = 100
first = seq[0].convert('RGBA')
self.frames = [ImageTk.PhotoImage(first)]
Label.__init__(self, master, image=self.frames[0])
temp = seq[0]
for image in seq[1:]:
temp.paste(image)
frame = temp.convert('RGBA')
self.frames.append(ImageTk.PhotoImage(frame))
self.idx = 0
self.cancel = self.after(self.delay, self.play)
def play(self):
self.config(image=self.frames[self.idx])
self.idx += 1
if self.idx == len(self.frames):
self.idx = 0
self.cancel = self.after(self.delay, self.play)
root = Tk()
anim = MyLabel(root, 'animated.gif')
anim.pack()
def stop_it():
anim.after_cancel(anim.cancel)
Button(root, text='stop', command=stop_it).pack()
root.mainloop()
Simple PIL version:
canvas = Image.new("RGB",(Width,Height),"white")
gif = Image.open('text.gif', 'r')
frames = []
try:
while 1:
frames.append(gif.copy())
gif.seek(len(frames))
except EOFError:
pass
for frame in frames:
canvas.paste(frame)
canvas.show()