I want to display images that are send to a specific folder in a sort of slideshow - python-3.x

I have a piece of code right now that when i start it up it creates a black canvas and displays a image on it (With Tkinter) that i randomly grab from a folder i have selected with photos in it.
But right now i have to press esc to go to the next image. I would like it to be on a timer.
It also won't go to the next image. It says pyimage2 does not exist.
It would be great if someone can help me. I am incredibly new to python and don't know that much.
from PIL import Image
import os, random
import time
import sys
if sys.version_info[0] == 2:
import Tkinter
tkinter = Tkinter
else:
import tkinter
from PIL import Image, ImageTk
i = True
def showPIL(pilImage):
root = tkinter.Tk()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set()
root.bind("<Escape>", lambda e: (e.widget.withdraw(), e.widget.quit()))
canvas = tkinter.Canvas(root,width=w,height=h)
canvas.pack()
canvas.configure(background='black')
imgWidth, imgHeight = pilImage.size
if imgWidth > w or imgHeight > h:
ratio = min(w/imgWidth, h/imgHeight)
imgWidth = int(imgWidth*ratio)
imgHeight = int(imgHeight*ratio)
pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS)
image = ImageTk.PhotoImage(pilImage)
imagesprite = canvas.create_image(w/2,h/2,image=image)
root.mainloop()
while i == True:
timer = 0
while timer < 5:
path = "C:/Users/thymen.hummel/PycharmProjects/HelloWorld/Images"
random_filename = random.choice([x
for x in os.listdir(path)
if os.path.isfile(os.path.join(path, x))
])
pilImage = Image.open(f'C:/Users/thymen.hummel/PycharmProjects/HelloWorld/Images/{random_filename}')
showPIL(pilImage)
print(random_filename)
timer += 1
time.sleep(5)

check https://www.geeksforgeeks.org/python-convert-speech-to-text-and-text-to-speech/. Instead of typing, you can name the name of the image and the program will open it.

To do it by timer, you can do it using pygame.time.wait(). It takes input in milliseconds. see https://www.pygame.org/docs/ref/time.html for more information.

Related

Tkinter program displays blank screen on linux, works on windows

I've been writing this code for a slideshow program in Linux. The problem I'm having is that when run from a windows environment it works perfectly (Full-screen resized images), however when run from a virtual Linux (Ubuntu x64) environment a blank white canvas appears with no images being displayed.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
self.w = self.winfo_screenwidth()
self.h = self.winfo_screenheight()
self.overrideredirect(1)
self.geometry("%dx%d+0+0" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex +=1
original_image = Image.open(x)
resized = original_image.resize((self.w, self.h),Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
delay = 5000
playlist = glob.glob(r'\mnt\hgfs\E\Images\*.*')
random.shuffle(playlist)
image_files = playlist
app = App(image_files, delay)
app.show_slides()
app.mainloop()
Any help would be appreciated!
winfo_screenwidth() and winfo_screenheight() give not correct display size on Linux. Use full-screen mode to fix it.
The code:
from PIL import Image, ImageTk
import tkinter as tk
import os
import glob
import random
class App(tk.Tk):
def __init__(self, image_files, delay):
tk.Tk.__init__(self)
# start window size (any)
self.w = 500
self.h = 500
self.attributes("-fullscreen", True) # Activate full-screen mode
# Change full-screen mode bind
self.bind("<F11>", lambda event: self.attributes("-fullscreen",
not self.attributes("-fullscreen")))
# Bind full-screen mode exit
self.bind("<Escape>", lambda event: self.attributes("-fullscreen", False))
self.geometry("%dx%d+100+100" % (self.w, self.h))
self.delay = delay
self.pictures = []
self.track_img_ndex = 0
for img in image_files:
self.pictures.append(img)
self.picture_display = tk.Label(self)
self.picture_display.pack(expand=True, fill="both")
def show_slides(self):
if self.track_img_ndex < len(self.pictures):
x = self.pictures[self.track_img_ndex]
self.track_img_ndex += 1
original_image = Image.open(x)
window_size_now = (self.winfo_width(), self.winfo_height()) # Getting current window size :
resized = original_image.resize(window_size_now, Image.ANTIALIAS)
new_img = ImageTk.PhotoImage(resized)
self.picture_display.config(image=new_img)
self.picture_display.image = new_img
self.title(os.path.basename(x))
self.after(self.delay, self.show_slides)
else:
print("End of list!")
_delay = 5000
playlist = glob.glob(r'/home/yaroslav_admin/PycharmProjects/LearnPython_01/imgs/*.*')
random.shuffle(playlist)
_image_files = playlist
app = App(_image_files, _delay)
app.after(100, app.show_slides) # delayed start,
# because tkinter need some time to count full-screen window size in main loop !
app.mainloop()

about Python canvas moving object

I want to move a rectangle from left to right with a step of 50,but the canvas doesn't draw the rectangle until it arrive right side.
import tkinter as tk
import time
root=tk.Tk()
c_width,c_height=500,250
cv = tk.Canvas(root,bg = 'white',width=c_width,height=c_height)
l_x=0
l_y=0
r_x=50
r_y=50
step=50
r1=cv.create_rectangle(l_x,l_y,r_x,r_y,fill='red')
while l_x<c_width-50:
cv.delete(r1)
l_x=l_x+step
r_x=r_x+step
r1=cv.create_rectangle(l_x,l_y,r_x,r_y,fill='red')
print(c_width,l_x)
time.sleep(1)
cv.pack()
root.mainloop()
It is not recommended to use while/for loop in tkinter application because it will block the tkinter mainloop() from handling pending events and updates. Use .after() instead.
Also you don't need to delete and recreate the rectangle item, just move the rectangle item using cv.move().
Below is the update code:
import tkinter as tk
root = tk.Tk()
c_width, c_height = 500, 250
cv = tk.Canvas(root, bg='white', width=c_width, height=c_height)
cv.pack()
l_x = 0
l_y = 0
r_x = 50
r_y = 50
step = 50
r1 = cv.create_rectangle(l_x, l_y, r_x, r_y, fill='red')
def move_rect(x):
# move the rectangle by "step" pixels horizontally
cv.move(r1, step, 0)
x += step
if x < c_width:
cv.after(1000, move_rect, x)
cv.after(1000, move_rect, r_x)
root.mainloop()

Display video size on label tkinter

The below code displays video on the label. But, problem is that, it is displayed in a very zoom (large) manner. I want to resize it to display correctly on label. When I use the option image=image.resize(), I get an error
ValueError: cannot resize this array: it does not own its data
import tkinter as tk, threading
import imageio
from PIL import Image, ImageTk
video_name = "e.mp4"
video = imageio.get_reader(video_name)
#video = video.resize(20,20)
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
root = tk.Tk()
my_label = tk.Label(root, width=500,height=500)
my_label.place(x=0,y=0)
thread = threading.Thread(target=stream, args=(my_label,))
thread.daemon = 1
thread.start()
root.mainloop()
You can call resize() on the return image of Image.fromarray(image):
frame_image = ImageTk.PhotoImage(Image.fromarray(image).resize((100,100)))

How to enhance window size selection on a tkinter project including button-image as label?

I'm currently working on a little project on python-3.x including some tkinter ressources. My program is made to display on a screen a list of pictures included in a directory, each picture is put on a button that is a sixth of the original image, and if we click on it, it display the image on his original size on a new window. The original window is set by the amount of pictures i put in the columns (i can choose in the code) and i ve made a scrollbar because i have to work with a lot of pictures.
But here is my problem, it's works fine except that if i change the window size, like reduce it for example, the buttons don't follow, they just vanish behind the window, and with the scrollbar.
I'm not particularly good in python so i was wondering that maybe by doing like a threading we could get the window size in live and then if the window size is inferior/superior of our columns of buttons, we could resize it and change the amount of columns then reload the page, but i will have to work with multiple image so it will take a lot of time.
from tkinter import *
from tkinter.filedialog import *
from tkinter.messagebox import *
from PIL import Image, ImageTk
import tkinter as tk
import glob
import os
import cv2
import copy
import _thread
import time
folder = 'X:/users/Robin/data/dataset-valid/visu/*.jpg'
a=glob.glob(folder)
fic = "../data/list.txt"
fichObj=open(fic,"w")
p = []
for f in a:
fichObj.write(f+"\n")
fichObj.close()
class SuperPhoto(object):
def __init__(self, photo , image):
self.photo = photo
temp = cv2.resize(image, (int((self.photo.width())/6) , int((self.photo.height())/6)))
red = temp[:,:,2].copy()
blue = temp[:,:,0].copy()
temp[:,:,0] = red
temp[:,:,2] = blue
temp = Image.fromarray(temp)
self.miniature = ImageTk.PhotoImage(temp)
def agrandir(self):
Newfen=Toplevel()
Newfen.geometry("+60+60")
#self.photo.resize((500,500))
print(type(self.photo))
label = Label(Newfen, image=self.photo, width=self.photo.width(), height=self.photo.height())
label.image = self.photo # keep a reference!
label.pack()
if os.path.exists (fic): #os.path utile
count = len(open(fic).readlines())
print(count)
#lin = open(fic).readlines()
#print(lin)
class ScrollableCanvas(Frame):
def __init__(self, parent, *args, **kw):
Frame.__init__(self, parent, *args, **kw)
canvas=Canvas(self,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500))
canvas.update_idletasks()
vbar=Scrollbar(self,orient=VERTICAL)
vbar.pack(side=RIGHT, fill=Y)
vbar.config(command=canvas.yview)
canvas.config(width=1200,height=700)
canvas.config(yscrollcommand=vbar.set)
canvas.pack(side=LEFT,expand=True,fill=BOTH)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior, anchor=NW )
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas's width to fit the inner frame
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the inner frame's width to fill the canvas
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
class Main_frame(Frame):
# Init
def __init__(self, fenetre_principale=None):
Frame.__init__(self, fenetre_principale)
self.grid()
self.scrollable_canvas = ScrollableCanvas(self)
self.scrollable_canvas.grid(row=1,column=1)
nbCol = 4
for file in a:
image = Image.open(file)
photo = ImageTk.PhotoImage(image)
w = photo.width()
L.append(int(w/6))
#print(L)
sumL = int(sum(L)/nbCol)
print(sumL)
p.append(SuperPhoto(photo, cv2.imread(file)))
for ligne in range(int(count/nbCol)):
for colonne in range(nbCol):
photo = p[ligne * nbCol + colonne]
button = Button(self.scrollable_canvas.interior, image=photo.miniature, command=photo.agrandir)
button.grid(row=ligne, column=colonne)
if __name__ == "__main__":
root = Tk()
root.title("VISU")
root.geometry("+0+0")
L= []
interface = Main_frame(fenetre_principale=root)
root.update_idletasks()
print(root.winfo_width())
print(root.geometry())
interface.mainloop()
So, I except this program to work like a classic directory display, with the columns that change automatically when we resize the window and with the scrollbar that follow it.
If you have any solutions it will really help me ..
You can try it, just put some jpeg pictures in a directory and change the folder variable with the link of your directory.
Thanks in advance for your help, if you have any questions to understand more clearly what i've said don't hesitate.
Each time the root window is resized, a <Configure> event is triggered. Catch it as follows:
def resize(event):
root.update_idletasks()
#update all image sizes here if needed
#all widgets can be 're-grided' here based on new width and height of root window
root.bind('<Configure>', resize)
If you want to ensure that your window cannot be resized, use the following:
root.resizable(False, False)

I want to display image dynamically in Tkinter using Pillow

I want to be able to display photos dynamically in Tkinter I have one button that will find the paths to the photos I want to display and as I add photos I want them to be displayed at the top of the canvas
I have already tried going through a for loop of the array after I upload the photos but that doesn't seem to do what I want, and now I am trying to iterate with a while loop but that doesn't work. I am kind of at a loss now. Below is my code
import tkinter as tk
from tkinter import filedialog as tkfd
from PIL import ImageTk, Image
import time
photo_name_list = []
def find_photos():
photo = tkfd.askopenfile()
photo_name_list.append(photo.name)
window = tk.Tk()
#creates the canvas
canvas = tk.Canvas(window, width = WINDOW_WIDTH,
height = WINDOW_HEIGHT, bg="green")
canvas.pack()
b1 = tk.Button(canvas, text="Click me to add 5 photos of yourself",
height = 5, width = 30, command = find_photos)
canvas.create_window(WINDOW_WIDTH//3, WINDOW_HEIGHT//3, window = b1)
while True:
if len(photo_name_list) > 0:
for image in photo_name_list:
img = Image.open(image)
tkimage = ImageTk.PhotoImage(img)
tk.Label(window, image=tkimage).pack()
canvas.update()
time.sleep(1/60)
window.mainloop()
So as you can see in the code I have one button that does that takes the path to an image as a string and appends it to the list. I want to display photos as they are appended.
This should work
import tkinter as tk
from tkinter import filedialog as tkfd
from PIL import ImageTk, Image
import time
WINDOW_WIDTH = 500
WINDOW_HEIGHT = 500
phat_list = []
images_reference_list = []
def find_photos():
photo = tkfd.askopenfile()
file_path = photo.name
img = Image.open(file_path)
photo_image = ImageTk.PhotoImage(img)
tk.Label(window, image=photo_image).pack(side=tk.TOP)
images_reference_list.append(photo_image)
phat_list.append(file_path)
window = tk.Tk()
#creates the canvas
canvas = tk.Canvas(window, width = WINDOW_WIDTH,
height = WINDOW_HEIGHT, bg="green")
canvas.pack(side=tk.BOTTOM)
b1 = tk.Button(canvas, text="Click me to add 5 photos of yourself",
height = 5, width = 30, command = find_photos)
canvas.create_window(WINDOW_WIDTH//3, WINDOW_HEIGHT//3, window = b1)
window.mainloop()
I've added the code lines that display the photo inside the function find_photos().
The while statement was causing some troubles i assume, you have always to check if the while will ever end for have a working code
and if you want to display an image you have always to keep a solid reference of it , the best way is to add it into a list

Resources