Why are these images disappearing and how can I fix it (python)? - python

I'm currently working on Tkinter and image stuff in a program. I want to display 9 images on the screen at the same time, but only one image(the last one)will appear on screen at one time. I've isolated the problem in this code so this is the fraction of my code that is causing this problem. The function "download" receives the images from the internet, and then "ext" takes the downloaded images and is supposed to put them on the screen, but not all of them go on.
import tkinter as tk
from tkinter.ttk import *
from threading import *
import random
from io import BytesIO
import urllib
import urllib.request
from PIL import Image, ImageTk
class CardClass:
def __init__(self):
self.master = tk.Tk()
self.master.attributes('-zoomed', True)
self.frame = Frame(self.master)
self.frame.pack()
self.state = False
self.master.attributes("-fullscreen", True)
self.but = Button(self.master, text="Print Images", command=self.Hand, pad = 150)
self.but.pack(pady = 12)
self.cardsList = ["https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg", "https://post.medicalnewstoday.com/wp-content/uploads/sites/3/2020/02/322868_1100-800x825.jpg", "https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg", "https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg", "https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg", "https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg", "https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://post.medicalnewstoday.com/wp-content/uploads/sites/3/2020/02/322868_1100-800x825.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://post.medicalnewstoday.com/wp-content/uploads/sites/3/2020/02/322868_1100-800x825.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://post.medicalnewstoday.com/wp-content/uploads/sites/3/2020/02/322868_1100-800x825.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://post.medicalnewstoday.com/wp-content/uploads/sites/3/2020/02/322868_1100-800x825.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg","https://www.thoughtco.com/thmb/O8fvqeXnAtOZ_L4eQ-aCRFKou_I=/768x0/filters:no_upscale():max_bytes(150000):strip_icc()/atlantic-bottlenose-dolphin--jumping-high-during-a-dolphin-training-demonstration-154724035-59ce93949abed50011352530.jpg"]
def Hand(self):
self.but.destroy()
self.newCard = random.sample(self.cardsList, k=9)
self.slot1 = self.cardsList[0]
self.slot2 = self.cardsList[1]
self.slot3 = self.cardsList[2]
self.slot4 = self.cardsList[3]
self.slot5 = self.cardsList[4]
self.slot6 = self.cardsList[5]
self.slot7 = self.cardsList[6]
self.slot8 = self.cardsList[7]
self.slot9 = self.cardsList[8]
self.ext()
def download(self, url, ex, ey):
print("here1")
with urllib.request.urlopen(url) as u:
raw_data = u.read()
img = Image.open(BytesIO(raw_data))
self.iimage = ImageTk.PhotoImage(img.resize((50,50), Image.ANTIALIAS))
lala = tk.Label(image=self.iimage)
lala.place(x=ex, y=ey)
return self.iimage
def ext(self):
self.download(self.newCard[0], 50, 150)
self.download(self.newCard[1], 100, 150)
self.download(self.newCard[2], 150, 150)
self.download(self.newCard[3], 200, 150)
self.download(self.newCard[4], 150, 150)
self.download(self.newCard[5], 300, 150)
self.download(self.newCard[6], 350, 150)
self.download(self.newCard[7], 400, 150)
self.download(self.newCard[8], 450, 150)
if __name__ == '__main__':
w = CardClass()
w.master.mainloop()
Does anybody know why this is happening? Thank you!

I don't think I understand why this should be, but the problem is, in fact, that the ImageTk.PhotoImage instances evaporate when the function ends. That shouldn't be the case. The Label widget should be holding a reference that keeps it alive, but if you store those PhotoImage objects in a list, as below, the code works:
def Hand(self):
self.but.destroy()
self.newCard = random.sample(self.cardsList, k=9)
self.keep = []
self.ext()
def download(self, url, ex, ey):
with urllib.request.urlopen(url) as u:
raw_data = u.read()
img = Image.open(BytesIO(raw_data)).resize((50,50),Image.ANTIALIAS)
iimage = ImageTk.PhotoImage(img)
Label(self.master, image=iimage).place(x=ex,y=ey)
self.keep.append(iimage)

Related

Rotating tkinter canvas by a particular angle

I am trying to use the code at Python Tkinter rotate image animation with the following change:
Instead of rotating the canvas endlessly, I want a rotation of "turn" degrees which is randomly decided using randint() function. However, after turning by this angle, the tkinter window disappears and an error is raised. How can I make the following code work.
From my intermediate level knowledge of Python, I can see that the "yield" statement is putting a generator to work.
You can use any image in place of "0.png" in my code. I am using Python 3.9.6. Thanks in advance. The following is the code I am trying to get to work.
from tkinter import *
from PIL import ImageTk, Image
from time import sleep
from random import randint
class SimpleApp(object):
def __init__(self, master, filename):
self.master = master
self.filename = filename
self.canvas = Canvas(master, bg="black", width=500, height=500)
self.canvas.pack()
self.update = self.draw().__next__
master.after(100, self.update)
def draw(self):
image = Image.open(self.filename)
angle = 0
turn = randint(30, 390)
for i in range(turn):
tkimage = ImageTk.PhotoImage(image.rotate(angle))
canvas_obj = self.canvas.create_image(250, 250, image=tkimage)
self.master.after_idle(self.update)
yield
self.canvas.delete(canvas_obj)
angle = (angle - 1) % 360
sleep(.01)
win = Tk()
app = SimpleApp(win, '0.png')
win.mainloop()
After last yield it exits function draw in normal way and then __next__() can't run it again and it raises StopIteration and this makes problem. Normally when it is used in for-loop then it catchs StopIteration. Or if you run it with next() then you can also catch StopIteration but in this example it is problem.
I would do it without yield. I would split it in two functions: draw() to set default values at start, and rotate() to update image.
import tkinter as tk
from PIL import ImageTk, Image
from time import sleep
from random import randint
class SimpleApp(object):
def __init__(self, master, filename):
self.master = master
self.filename = filename
self.canvas = tk.Canvas(master, bg="black", width=500, height=500)
self.canvas.pack()
self.draw()
def draw(self):
self.image = Image.open(self.filename)
self.angle = 0
self.turn = randint(30, 360)
self.canvas_obj = None
self.master.after(100, self.rotate)
def rotate(self):
# it will remove image after last move
#if self.canvas_obj:
# self.canvas.delete(self.canvas_obj)
if self.turn > 0:
# it will NOT remove image after last move
if self.canvas_obj:
self.canvas.delete(self.canvas_obj)
self.tkimage = ImageTk.PhotoImage(self.image.rotate(self.angle))
self.canvas_obj = self.canvas.create_image(250, 250, image=self.tkimage)
self.angle = (self.angle - 1) % 360
self.turn -= 1
self.master.after_idle(self.rotate)
win = tk.Tk()
app = SimpleApp(win, 'lenna.png')
win.mainloop()
lenna.png - (Wikipedia Lenna)

Resize PIL image: ValueError: Unknown resampling filter

So I am trying to make a desktop-like interface in python with Tkinter, and I am trying to set the wallpaper but I have no idea how to resize it. Here is the code:
from tkinter import *
import tkinter.messagebox as box
import webbrowser
from PIL import Image, ImageTk
window=Tk()
window.title('Label Example')
window.configure(background = 'gray44')
#---=Main_Frame=---#
main_frame = Frame(window)
main_frame.pack(padx = 600, pady=350)
#---=Wallpaper=---#
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10)) # the one-liner I used in my app
label_w = Label(window, image=img_wallpaper)
label_w.image = img_wallpaper # this feels redundant but the image didn't show up without it in my app
label_w.pack()
##wallpaper_image = PhotoImage(file = 'minecraft main picture.gif')
##wallpaper = Label(window, image= wallpaper_image, width=400, height = 400)
##wallpaper_image_big = PhotoImage.subsample(wallpaper_image, x=1, y=1)
##can_wallpaper = \
##Canvas(window, width = 1200, height = 700)
##can_wallpaper.create_image((100, 100), image = wallpaper_image)
##can_wallpaper.place(x=0, y =0)
window.mainloop() #Main loop
I have tried used someone else's code to resize it with PIL pillow but it does not work.
Here is the error:
Traceback (most recent call last):
File "/Users/edwardandreilucaciu/Desktop/Desktop Interface Project/Desktop Interface.py", line 16, in <module>
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10)) # the one-liner I used in my app
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/Image.py", line 1865, in resize
message + " Use " + ", ".join(filters[:-1]) + " or " + filters[-1]
ValueError: Unknown resampling filter (10). Use Image.NEAREST (0), Image.LANCZOS (1), Image.BILINEAR (2), Image.BICUBIC (3), Image.BOX (4) or Image.HAMMING (5)
Question: how to resize images in Tkinter
import kinter as tk
from PIL import Image, ImageTk
class ImageLabel(tk.Label):
def __init__(self, parent, **kwargs):
path = kwargs.pop('path', None)
if path is not None:
image = Image.open(path)
resize = kwargs.pop('resize', None)
if resize is not None:
image = image.resize(resize, Image.LANCZOS)
# Keep a reference to prevent garbage collection
self.photo = ImageTk.PhotoImage(image)
kwargs['image'] = self.photo
super().__init__(parent, **kwargs)
Usage:
class App(tk.Tk):
def __init__(self):
super().__init__()
lab=ImageLabel(self,
path="minecraft main picture.gif",
resize=(400, 400))
lab.grid()
if __name__ == '__main__':
App().mainloop()
It's actually quite easy
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10))
you see .resize is not availble for ImageTk image object also .resize takes a tuple of width and height
Try this
img_wallpaper = Image.open('minecraft main picture.gif').resize((10,10))
img_wallpaper = ImageTk.PhotoImage(img_wallpaper)

Run Images in Loop Tkinter

I am creating an app that will allow users to scan a ticket and a message will be displayed. I have created a short GIF animation to play when the app starts to show users where to scan their ticket.
I am having trouble understanding how to play a GIF image using tkinter in Python 3. I have tried many solutions and I came across a piece of code where you select the folder and the images in that folder will play in a loop but it's not working.
I think I'm not understanding the code. Here is my code for my app:
from tkinter import *
from tkinter import messagebox
import tkinter.filedialog
from tkinter.filedialog import askdirectory
import requests
import simplejson as json
import os
#from json import JSONEncoder
#class MyEncoder(JSONEncoder):
#def default(self, o):
#return o.__dict__
#Connect to API function
def apiconnect(statusvar):
ticektid = e1.get()
def to_serializable(ticketid):
return str(ticketid)
url = "https://staging3.activitar.com/ticket_api/tickets"
data = {'ticket_id':e1.get(),'direction': 'up'}
headers = {'Content-Type': 'application/json','Authorization' :'J0XDvDqVRy9hMF9Fo7j5'}
r = requests.post(url,data=json.dumps(data), headers=headers)
requestpost = requests.post(url, headers=headers, json=data)
response_data = requestpost.json()
statusvar = (response_data["status"])
messagevar = (response_data["message"])
json.dumps(url,data)
# MyEncoder().encode(ticketid)
#'{"ticekt_id": "/foo/bar"}'
#19 February 2018
#def from_json(json_object):
# if 'ticket_id' in json_object:
# return FileItem(json_object['ticket_id'])
# ticketid = JSONDecoder(object_hook = from_json).decode('{"ticket_id": "/foo/bar"}')
#Including GPIO config
if statusvar == "failed":
messagebox.showinfo("Cape Point", messagevar)
else: statusvar == "successful"
#Run at full screen automatically:
#---------------Function & Class--------------------------------#
class FullScreenApp(object):
def __init__(self, master, **kwargs):
self.master=master
pad=3
self._geom='200x200+0+0'
master.geometry("{0}x{1}+0+0".format(
master.winfo_screenwidth()-pad, master.winfo_screenheight()-pad))
master.bind('<Escape>',self.toggle_geom)
def toggle_geom(self,event):
geom=self.master.winfo_geometry()
print(geom,self._geom)
self.master.geometry(self._geom)
self._geom=geom
#--------------------------------------------------------------------#
def next_img():
img_label.img = PhotoImage(file=next(imgs))
img_label.config(image=img_label.img)
#create a textbox on a form
root = Tk()
#-----Full Screen-------#
app = FullScreenApp(root)
root.title("Cape Point")
root.configure(background = 'White')
#________ this code below was the original that displayed a static image _____#
#titlepic = PhotoImage(file = "ScanPlease.gif")
#shownpic = titlepic
#filename = shownpic
#Label(root, image = filename).grid(row=0, sticky=W)
img_dir = askdirectory(parent=root, initialdir= "C:/Users/Nickitaes/Desktop", title='Where To Scan')
os.chdir(img_dir)
imgs = iter(os.listdir(img_dir))
img_label = Label(root)
img_label.bind("<Return>",next_img())
next_img()
e1 = Entry(root)
e1.grid(row=1, column=0)
e1.focus_set() #set cursor focus to textbox
e1.bind("<Return>", apiconnect) #Return function
root.mainloop( )
Thanks for the help!
Well..., it was not hard to find other questions about this on StackOverflow. Here are some: Play Animations in GIF with Tkinter and Play an Animated GIF in python with tkinter.
I have combined the answers to take care of different number of subpictures an also commented the code a bit more.
from tkinter import *
import time
root = Tk()
framelist = [] # List to hold all the frames
for ix in range(1000): # range > frames in largest GIF
part = 'gif -index {}'.format(ix)
try: frame = PhotoImage(file='giphy.gif', format=part)
except:
last = len(framelist) - 1 # Save index for last frame
break # Will break when GIF index is reached
framelist.append(frame)
def update(ix):
if ix > last: ix = 0 # Reset frame counter if too big
label.configure(image=framelist[ix]) # Display frame on label
ix += 1 # Increase framecounter
root.after(100, update, ix) # Run again after 100 ms.
label = Label(root)
label.pack()
root.after(0, update, 0) # Start update(0) after 0 ms.
root.mainloop()
Adjust the for-loop for the GIF size you use, or rewrite as a while-loop.
I don't know how to read the frame delay from the GIF. You'll have to try different values in after() until it looks good.

How to use transform from PIL in Python

That's my code and I get the error message:
... return getattr(self.tk, attr)
AttributeError: temp_pic"...
I need to program two buttons: [zoom in] and [zoom out].
If you have any better ideas for doing that, please, just say it.
I'm going to use this image to develop maps through graphs (structure)
from Tkinter import *
from PIL import Image, ImageTk, ImageDraw, ImageOps, ImageEnhance
bairro = "botafogo.jpg"
class Painel(Tk):
def __init__(self):
Tk.__init__(self) #create ui
self.zoom = Frame(self)
self.zoom.pack()
self.zin = Button(self.zoom, command = self.zoom_in, text = "Zoom In")
self.zin.pack()
self.zout = Button(self.zoom, command = self.zoom_out, text = "Zoom Out")
self.zout.pack()
self.c = Canvas(self, bd=0, highlightthickness=0, width=100, height=100)
self.c.pack(fill='both', expand=1)
self.main_pic = Image.open(bairro) #load image
self.main_pic.thumbnail((800, 600))
self.tkphoto = ImageTk.PhotoImage(self.main_pic)
self.canvasItem = self.c.create_image(0, 0, anchor='nw', image = self.tkphoto)
self.c.config(width = self.main_pic.size[0], height = self.main_pic.size[1])
self.temp = self.main_pic.copy() # 'working' image
def update_painel(self):
self.tkphoto = ImageTk.PhotoImage(self.temp_pic)
self.c.itemconfigure(self.canvasItem, image = self.tkphoto)
def zoom_in(self):
self.temp_pic = self.temp_pic.transform( ( self.temp_pic.size[0]/2,
self.temp_pic.size[0]/2
),
Image.EXTEND,
( 0, 0, self.temp_pic[0], self.temp_pic[1]
)
)
self.update_painel()
def zoom_out(self):
self.temp_pic = self.main_pic
self.update_painel()
app = Painel()
app.mainloop()
a deep-copy instruction shall read
self.temp_pic = self.main_pic.copy() # 'working' image
instead of
self.temp = self.main_pic.copy() # 'working' image**

Image display issue

When I load a transparent image with:
def load_image(path):
img = Image.open(path)
return ImageTk.PhotoImage(img)
class Home_Screen(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.home = Tk()
self.home.resizable(width = False,height = False)
self.home.geometry("700x500+300+100")
self.start()
def run(self):
self.images()
Label(self.home, image = self.background).pack() # Put it in the display window
button_instructions = Label(self.home,image = self.b_instructions).place(x = 300,y = 200)
self.home.mainloop()
def images(self):
self.background = load_image("Images/night-sky.jpg")
self.b_instructions = load_image("button_instructions.png")
def start_game(self):
self.home.destroy()
Home = Home_Screen()
I get an image with a white border around it. Does anyone know why the original transparency was not retained? If so could you please offer a solution.
Use a Canvas instead of Label widgets. The transparency isn't getting lost, because what you see is the background of the widget.
def run(self):
img_sky = ImageTk.PhotoImage(file="Images/night-sky.jpg")
img_button = ImageTk.PhotoImage(file="button_instructions.png")
self.canvas = Canvas(self.home, width=700, height=500)
self.canvas.create_image(0, 0, image=img_sky)
self.canvas.create_image(300, 200, image=img_button)
self.canvas.pack()
self.home.mainloop()

Categories