Python Showing a gif as background using Tkinter and PIL - python

I'm trying to display an animated gif as background for my GUI but i can't do it, console shows this error:
Also i already tried every solution i found on this website and google, i read PIL and Tkinter documentation too but apparently nothing works for me
File "C:\Users\user\.spyder-py3\temporal.py", line 32, in <listcomp>
frames = [Image(file='079.gif',format = 'gif -index %i' %(i)) for i in range(79)]
TypeError: 'module' object is not callable
This is my code:
import tkinter as tk
import os
from PIL import Image
root= tk.Tk()
root.title("SCP-079")
root.resizable(0,0)
root.iconbitmap("079.ico")
root.geometry("540x360")
frames = [Image(file='079.gif',format = 'gif -index %i' %(i)) for i in range(79)]
def update(ind):
frame = frames[ind]
ind += 1
if ind>78: #With this condition it will play gif infinitely
ind = 0
gif.configure(image=frame)
root.after(100, update, ind)
gif = root.Label
gif.pack()
root.after(0, update, 0)
root.mainloop()
This is the gif i want to use
079.gif
i tried to do it in a different way but now i don't know how to display it
import tkinter as tk
import PIL.Image
root= tk.Tk()
root.title("SCP-079")
root.resizable(0,0)
root.iconbitmap("079.ico")
root.geometry("540x360")
gif=[PIL.Image.open(fp='079.gif', mode='r', formats=None)]
root.mainloop()

I got your code working.
Note that you haven't set everything on it. You must to "Image.open" in your file before.
"Image" is imported as PIM from PIL to prevent conflict.
import os, tkinter as tk
from PIL import Image as PIM, ImageTk
from tkinter import*
root= tk.Tk()
root.title("SCP-079")
root.resizable(0,0)
root.iconbitmap("079.ico")
root.geometry("540x360")
im = PIM.open("C:\\...\\CeEOy.gif")
ph = ImageTk.PhotoImage(im)
gif = Label(root, image = ph, bg="black", bd=3)
gif.image = ph
framnr = 79
frames = [PhotoImage(file="C:\\...\\CeEOy.gif",
format = 'gif -index %i' %(i)) for i in range(framnr)]
def update(ind):
frame = frames[ind]
ind += 1
if ind>78:
ind = 0
gif.configure(image = frame)
root.after(100, update, ind)
gif = Label(root)
gif.pack()
root.after(0, update, 0)
root.mainloop()

Related

Make gif transapernt on tkinter canvas

I have the below code to show my animated gif on a canvas but even though the gif has a transpert bg, it get in a white background. is there a way to remove it?
import tkinter as tk
from PIL import Image, ImageTk
from itertools import cycle
DELAY = 20
def animate():
canvas.itemconfig(img,image=next(frames_cycle))
root.after(DELAY,animate)
root = tk.Tk()
root.geometry('300x300')
root.config(background='red')
frames = []
im = Image.open('loading_circle.gif')
for frame in range(im.n_frames):
im.seek(frame)
frames.append(ImageTk.PhotoImage(im.convert('RGBA')))
frames_cycle=cycle(frames)
canvas = tk.Canvas(root,bg='red', width=300, height=300)
img = canvas.create_image(120,0,anchor='nw',image=next(frames_cycle))
canvas.pack()
animate()
root.resizable(False, False)
root.mainloop()

How to open another GUI window, once video is completed in GUI in python tkinter?

The purpose of the below code is to automatically open another window of GUI once video is completed (the length of video is 10 seconds)
I have tried to do this but some how its not working pl. have a look at below code.
import tkinter as tk, threading
import imageio
import tkinter as tk
from tkinter import *
from tkinter import ttk
import tkinter.font as font
import os
import re
from PIL import Image, ImageTk
global Image
global image
global Label
video_name = "C:\\Users\\Ray\\Desktop\\Duplicate.mp4"
video = imageio.get_reader(video_name)
def stream(label):
for image in video.iter_data():
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
if __name__ == "__main__":
root = tk.Tk()
my_label = tk.Label(root)
my_label.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
ima = Image.open('C:\\Users\\Ray\\Desktop\\July_bill.jpg')
ima = ima.resize((1920,1050), Image.ANTIALIAS)
my_img = ImageTk.PhotoImage(ima)
my_lbl = Label(Image = my_img)
my_lbl.pack()
root.mainloop()
In this code if I remove the image inserting code ( which is ima, my_img lines in code) the video plays smoothly but if i use this code then it does not works it shows the error of "unknown option "-Image"
Can anybody help me in getting this solved it would be great.
Regards,
Ray
Just change my_lbl = Label(Image = my_img) to my_lbl = Label(image = my_img)
You can see TK Label options here. As you can see "image" starts with lowercase, in your code, you had "Image" that caused the error.
Full code:
import tkinter as tk, threading
import imageio
from tkinter import *
from PIL import Image, ImageTk
from time import sleep
def stream(label):
video_name = "C:\\Users\\Ray\\Desktop\\Duplicate.mp4"
video = imageio.get_reader(video_name)
for image in video.iter_data():
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
if __name__ == "__main__":
root = tk.Tk()
my_label = tk.Label(root)
my_label.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
sleep(10)
ima = Image.open('C:\\Users\\Ray\\Desktop\\July_bill.jpg')
ima = ima.resize((1920,1050), Image.ANTIALIAS)
my_img = ImageTk.PhotoImage(ima)
my_lbl = Label(image = my_img)
my_lbl.pack()
root.mainloop()
I have not tested the video, but the image works well.

Is it possible to provide animation on image ? - Tkinter

I'm developing a GUI in Tkinter and want to apply animation in the below GIF on the image when it appears.
Here is my code,
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()
Instead of clicking on the play button as shown in GIF, the image should automatically appears after 1 second like this animation and stays on screen. (No closing option).
I'm not 100% sure I understood the problem, but I'll describe how to animate an image.
Tkinter does not contain functions for animating images so you'll have to write them yourself. You will have to extract all subimages, subimage duration and then build a sequencer to swap subimages on your display.
Pillow can extract image sequences. WEBP images seems to only support one frame duration whereas GIF images may have different frame duration for each subimage. I will use only the first duration for GIF images even if there is many. Pillow does not support getting frame duration from WEBP images as far as I have seen but you gan read it from the file, see WebP Container Specification.
Example implementation:
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()
There are libraries, like imgpy, which supports GIF animation but I have no experience in usig any such library.
Addition
The duration variable sets the animation rate. To slow the rate down just increase the duration.
The simplest way to put the animation on a canvas it simply to put the label on a canvas, see example below:
# 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)
Then you don't have to change anything else in the program.

unable to update image in tkinter using a function

I am trying to create a Tkinter to make a window that shows images using a label, then update the image using an update function, but the image that I am trying to show doesn't show up in the Tkinter window, instead, a black screen appears
I have two working code
one that shows an image on the Tkinter window
one what loops a GIF using an update function
I tried to combine them
the code I am working on that doesn't work
#import GUI
from tkinter import *
#change dir
import os
os.chdir("C:/Users/user/Desktop/test image folder/")
#add delay
import time
#import image
from PIL import Image, ImageTk
#set up the window
window = Tk()
#window.title("modify images")
#list of filename
filelist = []
#loop over all files in the working directory
for filename in os.listdir("."):
if not (filename.endswith('.png') or filename.endswith('.jpg')):
continue #skip non-image files and the logo file itself
filelist = filelist + [filename]
#list of filename
print(filelist)
#show first pic
imagefile = filelist[0]
photo = ImageTk.PhotoImage(Image.open(imagefile))
label1 = Label(window, image = photo)
label1.pack()
#update image
def update(ind):
imagefile = filelist[ind]
im = ImageTk.PhotoImage(Image.open(imagefile))
if ind < len(filelist):
ind += 1
else:
ind = 0
label1.configure(image=im)
window.after(2000, update, ind)
window.after(2000, update, 0)
#run the main loop
window.mainloop()
the other code I am trying to combine
1:the one that shows image
import tkinter as tk
from tkinter import *
from PIL import Image, ImageTk # Place this at the end (to avoid any conflicts/errors)
window = tk.Tk()
imagefile = "image.jpg"
img = ImageTk.PhotoImage(Image.open(imagefile))
lbl = tk.Label(window, image = img).pack()
window.mainloop()
print('hi')
2:updates gif
from tkinter import *
#change dir
import os
os.chdir("C:/Users/user/Desktop/Learn Python")
#add delay
import time
##### main:
window = Tk()
##### My Photo
photo1 = [PhotoImage(file="anime.gif", format="gif -index %i" %(i)) for i in range(85)]
#update image
def update(ind):
frame = photo1[ind]
if ind < 84:
ind += 1
else:
ind = 0
label.configure(image=frame)
window.after(80, update, ind)
label = Label(window, bg="black")
label.pack()
window.after(0, update, 0)
#####run the main loop
window.mainloop()
I expect it to show all images in the file one by one
it instead shows only the first image, then the window goes blank
You have problem because there is bug in PhotoImage. If you create it in function and assign to local variable then Garbage Collector removes image from memory and you see empty image. You have to create PhotoImages outside function or you have to assign it to some global variable.
Popular solution is to assign it to label which will display it.
label.im = im
Function:
def update(ind):
imagefile = filelist[ind]
im = ImageTk.PhotoImage(Image.open(imagefile))
if ind < len(filelist):
ind += 1
else:
ind = 0
label1.configure(image=im)
label1.im = im # <-- solution
window.after(2000, update, ind)
Doc: PhotoImage

How to show a frame of a video file (image) with tkinter in python

I am trying to show video frames (not from a stream) with tkinter. The next step are buttons which allow the user to get a frame backward or forward in the video. I have to say that I am quite new in programming with python.
So first I read the following articles:
Python snippets: Converting video to images http://srand.fr/blog/python%20import%20video.html
The Tkinter PhotoImage Class: http://effbot.org/tkinterbook/photoimage.htm
The problem is that I can’t use the image converted with imageio or VideoFileClip to show it with tkinter photoimage. I get the following error:
_tkinter.TclError: image "[[ …(some numbers)… ]]" doesn't exist
Here is my simple code. I hope you can help me :)
from moviepy.editor import VideoFileClip
from tkinter import *
import pylab
vid =VideoFileClip("example.mp4")
window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")
count =20
photo = vid.get_frame(count)
label =Label(window, image = photo)
label.pack()
Other Code, same problem:
import imageio
from tkinter import *
import pylab
filename = './example.mp4'
vid = imageio.get_reader(filename, 'ffmpeg')
window = Tk()
window.title("Choose Frame")
window.geometry ("900x600")
count =20
photo = vid.get_data(count)
label =Label(window, image = photo)
label.pack()
This is a bit late but better late than never.
Here is a working example I found and modify a little, this works with '.mp4', videos but not with '.flv', don't know why.
Note:
python 2.7 import Tkinter
python 3 import tkinter
import Tkinter as tk
import threading
import imageio
from PIL import Image, ImageTk
video_name = "test_video.mp4" #This is your video file path
video = imageio.get_reader(video_name)
def stream(label):
frame = 0
for image in video.iter_data():
frame += 1 #counter to save new frame number
image_frame = Image.fromarray(image)
image_frame.save('FRAMES/frame_%d.png' % frame) #if you need the frame you can save each frame to hd
frame_image = ImageTk.PhotoImage(image_frame)
label.config(image=frame_image)
label.image = frame_image
if frame == 40: break #after 40 frames stop, or remove this line for the entire video
if __name__ == "__main__":
root = tk.Tk()
my_label = tk.Label(root)
my_label.pack()
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
root.mainloop()
And here is another nice working example of a player that I was trying to make with Tkinter and some sample code with Opencv module.
This is a just an example idea, not finish code by any means.
import cv2
from Tkinter import *
from PIL import Image, ImageTk
import io
import threading
import os, sys
def resize(image):
im = image
new_siz = siz
im.thumbnail(new_siz, Image.ANTIALIAS)
return im
def size(event):
global siz
if siz == screenWH:
siz = (200, 200)
else:
siz = screenWH
win.state('zoomed')
print 'size is: ', siz
def view_frame_video():
vc = cv2.VideoCapture('test_video.flv')
if vc.isOpened():
rval , frame = vc.read()
else:
rval = False
while rval:
rval, frame = vc.read()
img =Image.fromarray(frame)
img = resize(img)
imgtk = ImageTk.PhotoImage(img)
lbl.config(image=imgtk)
lbl.img = imgtk
if stop == True:
vc.release()
break #stop the loop thus stops updating the label and reading imagge frames
cv2.waitKey(1)
vc.release()
def stop_():
global stop
stop = True
def play():
stop = False
t = threading.Thread(target=view_frame_video)
t.start()
win = Tk()
stop = None
screenWH = (win.winfo_screenwidth(), win.winfo_screenheight())
siz = (200, 200)
Label(text='Press Play Button').pack()
frm_ = Frame(bg='black')
frm_.pack()
lbl = Label(frm_, bg='black')
lbl.pack(expand=True)
lbl.bind('<Double-Button-1>', size)
frm = Frame()
frm.pack()
Button(text='Play', command = play).pack(side=LEFT)
Button(text='Stop', command = stop_).pack(side=LEFT)
win.mainloop()

Categories