I have an image that is saved in a file test.bmp and this file is overwritten 2 times per second
(I want to show 2 images per second).
Here is what I have so far:
import tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
img_path = 'test.bmp'
img = ImageTk.PhotoImage(Image.open(img_path), Image.ANTIALIAS))
canvas = tk.Canvas(root, height=400, width=400)
canvas.create_image(200, 200, image=img)
canvas.pack()
root.mainloop()
But I don't know how can I refresh the image every ½ second?
I'm using Python3 and Tkinter.
Gee, the code in your question looks very familiar...
Coming up with an answer comprised of tested code was complicated by the need to have the image file be updated by some mysterious unspecified process. This is done in the code below by creating a separate thread that periodically overwrites the image file independent of the main process. I tried to delineate this code from the rest with comments because I felt it was somewhat distracting and makes things seem more complex than they are really.
The main takeaway is that you'll need to use the universal tkinter widget after() method to schedule the image to be refreshed at some future time. Care also needs to be taken to first create a place-holder canvas image object so it can be updated in-place later. This is needed because there may be other canvas objects present, and otherwise the updated image could cover them up depending on relative placement if a place-holder had not been created (so the image object id that's returned can be saved and used later to change it).
from PIL import Image, ImageTk
import tkinter as tk
#------------------------------------------------------------------------------
# Code to simulate background process periodically updating the image file.
# Note:
# It's important that this code *not* interact directly with tkinter
# stuff in the main process since it doesn't support multi-threading.
import itertools
import os
import shutil
import threading
import time
def update_image_file(dst):
""" Overwrite (or create) destination file by copying successive image
files to the destination path. Runs indefinitely.
"""
TEST_IMAGES = 'test_image1.png', 'test_image2.png', 'test_image3.png'
for src in itertools.cycle(TEST_IMAGES):
shutil.copy(src, dst)
time.sleep(.5) # pause between updates
#------------------------------------------------------------------------------
def refresh_image(canvas, img, image_path, image_id):
try:
pil_img = Image.open(image_path).resize((400,400), Image.ANTIALIAS)
img = ImageTk.PhotoImage(pil_img)
canvas.itemconfigure(image_id, image=img)
except IOError: # missing or corrupt image file
img = None
# repeat every half sec
canvas.after(500, refresh_image, canvas, img, image_path, image_id)
root = tk.Tk()
image_path = 'test.png'
#------------------------------------------------------------------------------
# More code to simulate background process periodically updating the image file.
th = threading.Thread(target=update_image_file, args=(image_path,))
th.daemon = True # terminates whenever main thread does
th.start()
while not os.path.exists(image_path): # let it run until image file exists
time.sleep(.1)
#------------------------------------------------------------------------------
canvas = tk.Canvas(root, height=400, width=400)
img = None # initially only need a canvas image place-holder
image_id = canvas.create_image(200, 200, image=img)
canvas.pack()
refresh_image(canvas, img, image_path, image_id)
root.mainloop()
Related
from tkinter import *
from PIL import Image, ImageTk
import glob, os
root = Tk()
root.geometry("800x600")
# Function to display image
def displayImg(img):
image = Image.open(img)
photo = ImageTk.PhotoImage(image)
newPhoto_label = Label(image=photo)
newPhoto_label.pack()
# gta_images = []
os.chdir("gta")
for file in glob.glob("*.jpg"):
# gta_images.append(str(file))
displayImg(file)
print(file)
# print(gta_images)
root.mainloop()
I am trying to load images from a folder called "gta" and then display those game logos on my app. Program has no error but I think its a logical error. I am new to Python I don't know maybe there is some scoping logic problem in my displayImg funcion.
Note: When a PhotoImage object is garbage-collected by Python (e.g.
when you return from a function which stored an image in a local
variable), the image is cleared even if it’s being displayed by a
Tkinter widget.
For more.
from tkinter import *
from PIL import Image, ImageTk
import glob, os
root = Tk()
root.geometry("800x600")
photos = []
def displayImg(img):
image = Image.open(img)
photo = ImageTk.PhotoImage(image)
photos.append(photo)#keep references!
newPhoto_label = Label(image=photo)
newPhoto_label.pack()
for file in glob.glob("*.jpg"):
displayImg(file)
print(file)
root.mainloop()
Not sure if it will work but try using the path of the gta folder you are getting the images from, instead of its name simply - replace the name with the path.
I would like to add a looping video in a tkinter window. I have seen codes from here in stacksoverflow and online, and they seem to be about a Live Capture Video. in my case, I would like to import a video file to my existing Tkinter window, and if possible, keep it on loop. what modules do I need to import and how do I structure the code properly?
I am gonna add some codes that I have used.. I thankfully give the credits to the original creators whoever they are.
import imageio
from PIL import Image, ImageTk
video_name = "vid.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()
my_label = Label(root)
my_label.pack()
thread = threading.Thread(target = stream, args=(my_label))
thread.daemon = 1
thread.start()
root.mainloop()
I started a project a few days ago but unfortunately I'm stuck. I would like to make an image editor (a very simple one ;D) where a choose an image by using the filedialog then I would have the possibilty to make few modifications like rotations. My problem is that I can choose the image but once I did, I can't show the image on the canvas.
It says : "name 'image' is not define"
I think my problem is that the program want to show the image on the canvas but I haven't selected it yet.
from tkinter import *
from PIL import Image, ImageTk
from tkinter import filedialog
root = Tk()
#function to select my image by using the filedialog
def select_image():
file_path = filedialog.askopenfilename()
image = Image.open(file_path)
#button to press to open filedialog
select = Button(root, text="select an image", command=select_image)
select.pack()
#the canvas where the image will be display
canvas = Canvas(root, width= 100, height=100, bg="grey")
canvas.pack()
image_tk = ImageTk.PhotoImage(image)
canvas.create_image(0,0, image= image_tk)
root.mainloop()
It is possible to create an image object before you have an image file to display, but not in the way you're doing it. You simply need to create an empty image object and keep track of the image object id, and then reconfigure that object inside of select_image.
For example, don't define image_tk in the main program. Change the line that creates the image item on the canvas to this:
image_id = canvas.create_image(0,0, anchor="nw")
(note: without the anchor option, the center of the image will be at 0,0. I'm guessing you want the upper-left corner of the image to be at 0,0).
Next, in select_image is where you do all of the work of getting the image, saving a reference to it (to avoid it being deleted when the function returns), and showing it in the canvas. It would look something like this:
def select_image():
# ask the user for the filename
file_path = filedialog.askopenfilename()
# only show the image if they chose something
if file_path:
# open the file
image = Image.open(file_path)
# create the image object, and save it so that it
# won't get deleted by the garbage collector
canvas.image_tk = ImageTk.PhotoImage(image)
# configure the canvas item to use this image
canvas.itemconfigure(image_id, image=canvas.image_tk)
You’ve got a couple of problems here:
You are never calling your function! Your code ignores
select_image() after it is defined
The variable image is only defined inside your (uncalled) function, so when you try to use it via ImageTk.PhotoImage(), it is
undefined.
Try returning the image object this way:
from tkinter import *
from PIL import Image, ImageTk
from tkinter import filedialog
root = Tk()
#function to select my image by using the filedialog
def select_image():
file_path = filedialog.askopenfilename()
return Image.open(file_path)
#button to press to open filedialog
select = Button(root, text="select an image", command=select_image)
select.pack()
#the canvas where the image will be display
canvas = Canvas(root, width= 100, height=100, bg="grey")
canvas.pack()
image_tk = ImageTk.PhotoImage(select_image())
canvas.create_image(0,0, image= image_tk)
root.mainloop()
Note that you are not checking for errors or cancellation in your select_image() function. You’d be better off handling cancel or error inside the function too
I have loaded an image to tkinter label and that image is diplayed in that label.When i press the button i need to change that image.When the button is pressed older image is gone but the new image is not displayed
My code is
import Tkinter as tk
from PIL import Image, ImageTk
root = tk.Tk()
def change_pic(labelname):
photo1 = ImageTk.PhotoImage(Image.open("demo.jpg"))
labelname.configure(image=photo1)
print "updated"
vlabel=tk.Label(root)
photo = ImageTk.PhotoImage(Image.open('cardframe.jpg'))
vlabel.configure(image=photo)
vlabel.pack()
b2=tk.Button(root,text="Capture",command=lambda:change_pic(vlabel))
b2.pack()
root.mainloop()
In def change_pic(labelname), you need to add labelname.photo = photo1 to make sure photo1 not being garbage collected.
def change_pic(labelname):
photo1 = ImageTk.PhotoImage(Image.open("demo.jpg"))
labelname.configure(image=photo1)
labelname.photo = photo1
print "updated"
P.S. Looks like both labelname.photo = photo1 and labelname.image = photo1 work.
Check this out for more details: http://effbot.org/tkinterbook/label.htm
You can use the label to display PhotoImage and BitmapImage objects.
When doing this, make sure you keep a reference to the image object,
to prevent it from being garbage collected by Python’s memory
allocator. You can use a global variable or an instance attribute, or
easier, just add an attribute to the widget instance.
The following edits were made:
I have organised your code layout and simplified its
syntax where possible. These are to make your code easier to read.
Commonly we make the PIL objects a subset/children of tk.
So long it is a part of root (i.e. it is a child of the root
or any of its child widgets), your PIL objects will work.
Your working code is shown below:
import Tkinter as tk
from PIL import Image, ImageTk
def change_pic():
vlabel.configure(image=root.photo1)
print "updated"
root = tk.Tk()
photo = 'cardframe.jpg'
photo1 = "demo.jpg"
root.photo = ImageTk.PhotoImage(Image.open(photo))
root.photo1 = ImageTk.PhotoImage(Image.open(photo1))
vlabel=tk.Label(root,image=root.photo)
vlabel.pack()
b2=tk.Button(root,text="Capture",command=change_pic)
b2.pack()
root.mainloop()
I got it working with one more line of code:
import tkinter as tk # I am using python 3 on windows so the tkinter is lowercased
from PIL import Image, ImageTk
root = tk.Tk()
def change_pic(labelname):
global photo1 # This is the only new line you need, I believe
photo1 = ImageTk.PhotoImage(Image.open("demo.jpg"))
labelname.configure(image=photo1)
print("updated") # Again I'm using python 3 on windows so syntax may differ.
root.update() # You don't need this statement in this case, but it never hurts
vlabel=tk.Label(root)
photo = ImageTk.PhotoImage(Image.open('cardframe.jpg'))
vlabel.configure(image=photo)
vlabel.pack()
b2=tk.Button(root,text="Capture",command=lambda:change_pic(vlabel))
b2.pack()
root.mainloop()
I believe that the code changes the image locally, so the global statement will change it on the project scope.
I have added a image file to my code in tkinter but it basically fills my the whole frame so if its possible can you recommend a tutorial that shows or explains how to do this.... unless you can show me on here.
I havent added my full code but the code below should display a test image once you have it saved in the python directory.
I would like to create 'next' button which would open up a new frame with another image on it.
from Tkinter import *
root = Tk()
ButtonImage = PhotoImage(file='test.gif')
testButton = Button(root, image=ButtonImage)
testButton.pack()
root.mainloop()
You could try something like this:
from Tkinter import *
from glob import glob
class ImageFrame(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.images = glob("*.gif")
self.cur = 0
# label showing the image
self.image = PhotoImage()
imagelabel = Label(self, image=self.image)
imagelabel.grid(row=1, column=1)
# button cycling through the images
button = Button(self, text="NEXT", command=self.show_next)
button.grid(row=2, column=1)
# layout and show first image
self.grid()
self.show_next()
def show_next(self):
self.cur = (self.cur + 1) % len(self.images)
self.image.configure(file=self.images[self.cur])
ImageFrame().mainloop()
Some explanations:
glob is used to get a list of all files matching some pattern in the current directory
grid is a simple but quite flexible layout manager for Tkinter (see Tkinter reference)
the show_next method, which is bound to the button, cycles through the images and binds a new image to the PhotoImage using configure
The result is a simple frame showing a large image and a button, cycling though the gif images in the current directory.
There are numerous modules that would help you out with this. You can use the PIL module. Typically what I would do in a situation like yours is use the PIL module to load and paste the image onto the frame. This is how you do this.
from Tkinter import *
from PIL import Image, ImageTk
root = Tk()
Image = Image.open(path).resize((300, 300)), Image.ANTIALIAS
ButtonImage = ImageTk.PhotoImage(Image)
# If you are using image by itself. Without it being a button.
#Image_Label = Label(image = self.HomeImage, borderwidth=0, highlightthickness=0)
# Otherwise
testButton = Button(root, image=ButtonImage)
testButton.pack()
root.mainloop()
I believe that this would definitely help you with resizing the image and loading an image to the screen as a button. We used PIL to load the image onto the frame and resized the image. This is What you were also asking for earlier. I used the resize method on the Image.open() Function. This resizes the image to what you want. The standards are the actual sizes of that image.