Python 3 tkinter | Image from URL not displaying [duplicate] - python

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 3 years ago.
First of all, my code is based on this StackOverflow answer.
Due to circumstance, I am trying to have most of the code packed into a function that I call ImgFromUrl()
import io
import tkinter as tk
import urllib.request
from PIL import Image, ImageTk
def ImgFromUrl(root, url):
with urllib.request.urlopen(url) as connection:
raw_data = connection.read()
im = Image.open(io.BytesIO(raw_data))
image = ImageTk.PhotoImage(im)
return tk.Label(root, image=image)
root = tk.Tk()
url = "http://imgs.xkcd.com/comics/python.png"
widget = ImgFromUrl(root,url)
widget.grid(row=0,column=0)
root.mainloop()
And for some reason, the image does not show up (though the Tkinter window was automatically resized to the size of the image).
However, this works:
# same imports
root = tk.Tk()
url = "http://imgs.xkcd.com/comics/python.png"
with urllib.request.urlopen(url) as connection:
raw_data = connection.read()
im = Image.open(io.BytesIO(raw_data))
image = ImageTk.PhotoImage(im)
widget = tk.Label(root, image=image)
widget.grid(row=0,column=0)
root.mainloop()

So your issue is because image is deleted as soon as the function end and tkinter needs the image to be saved for a reference somewhere.
We can do this with global or by returning the image to a variable defined in the global.
Option 1 global:
import tkinter as tk
import urllib.request
from PIL import Image, ImageTk
import io
def ImgFromUrl(url):
global image
with urllib.request.urlopen(url) as connection:
raw_data = connection.read()
im = Image.open(io.BytesIO(raw_data))
image = ImageTk.PhotoImage(im)
return image
root = tk.Tk()
url = "http://imgs.xkcd.com/comics/python.png"
widget = tk.Label(root, image=ImgFromUrl(url))
widget.grid(row=0, column=0)
root.mainloop()
Option 2 returning the image object to a variable defined in the global namespace:
import tkinter as tk
import urllib.request
from PIL import Image, ImageTk
import io
def ImgFromUrl(url):
with urllib.request.urlopen(url) as connection:
raw_data = connection.read()
im = Image.open(io.BytesIO(raw_data))
image = ImageTk.PhotoImage(im)
return image
root = tk.Tk()
url = "http://imgs.xkcd.com/comics/python.png"
image = ImgFromUrl(url)
widget = tk.Label(root, image=image)
widget.grid(row=0, column=0)
root.mainloop()

Related

How to get the image name of a label in python tkinter?

Suppose I have below codes:
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
my_img = ImageTk.PhotoImage(Image.open("./Images/img.jpg"))
my_img1 = ImageTk.PhotoImage(Image.open("./Images/img1.jpg"))
my_img2 = ImageTk.PhotoImage(Image.open("./Images/img2.jpg"))
image_list = [my_img, my_img1, my_img2]
label1 = tk.Label(root, image=image_list[0])
print(label1.cget('image'))
I want to get the name of the image that is currently assigned to label1, in this example, the result I want to get is "my_img", how to do it? Thank you.

displaying an Image in python within a function [duplicate]

This question already has answers here:
Why does Tkinter image not show up if created in a function?
(5 answers)
Closed 2 years ago.
I'm trying to display the image from the link the code below works and shows image as intended
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_link =Label(root, image = my_img)
image_link.grid(row = 0, column = 0 )
root.mainloop()
but now i have to update my code a little bit and have to put this in a function
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
def image_func():
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label =Label(root, image = my_img)
image_label.grid(row = 0, column = 0 )
image_func()
root.mainloop()
the above doesn't shows the image so I tried to to put the image label inside a frame but that just shows the frame with nothing inside also the powershell or cmd doesn't show any error
All the objects you create inside the function are local. So these object are deleted when the function exits. You need a way to keep these object existing. For example by using global variables
from tkinter import *
from PIL import ImageTk,Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
my_img = None
image_label = None
def image_func():
global my_img, image_label
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label = Label(root, image = my_img)
image_label.grid(row = 0, column = 0 )
image_func()
root.mainloop()
Another way could be returning the objects from the function and keep the returned values
from tkinter import *
from PIL import ImageTk, Image
import requests
from io import BytesIO
root = Tk()
root.title('Weather')
root.iconbitmap('icon.ico')
root.geometry("450x300")
def image_func():
image_link = requests.get('https://assets.weatherstack.com/images/wsymbols01_png_64/wsymbol_0006_mist.png')
my_img = ImageTk.PhotoImage(Image.open(BytesIO(image_link.content)))
image_label = Label(root, image=my_img)
image_label.grid(row=0, column=0)
return my_img, image_label
my_img, image_label = image_func()
root.mainloop()

how to save images with the save button on the tkinter in python

I tried to make the 'save as' button to save the image in a certain location directory using tkinter but I got a problem
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
from PIL import ImageTk, Image, ImageDraw
import cv2
import numpy as np
img = cv2.imread('face_person1.jpg')
# convert the images to PIL format...
edged = Image.fromarray(img)
edged = ImageTk.PhotoImage(edged)
def savefile():
hsl = Image.open(edged)
hsl = filedialog.asksaveasfile(mode='w', defaultextension=".jpg")
if hsl is None:
return
sv = edged.save()
sv.close()
button = Button(text="save as", command=savefile)
button.pack()
The error message is:
Exception in Tkinter callback fp = io.BytesIO(fp.read())
AttributeError: 'numpy.ndarray' object has no attribute 'read'
To save image you have to use PIL.Image so don't assign PhotoImage to variable which you use to keep PIL.Image
edge = Image.fromarray(img)
tk_edge = ImageTk.PhotoImage(edge)
and you have to use filename to save it
edge.save(filename)
Full working example
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from PIL import ImageTk, Image, ImageDraw
import cv2
import numpy as np
# --- functions ---
def savefile():
filename = filedialog.asksaveasfile(mode='w', defaultextension=".jpg")
if not filename:
return
edge.save(filename)
# --- main ---
root = tk.Tk()
img = cv2.imread('face_person1.jpg')
edge = Image.fromarray(img)
tk_edge = ImageTk.PhotoImage(edge)
label = tk.Label(root, image=tk_edge)
label.pack()
button = tk.Button(root, text="save as", command=savefile)
button.pack()
root.mainloop()

Tkinter being fickle with pictures, some are blank, others are not

NOTE: The main problem hasn't been solved, but the code does work on a Windows PC, the problem has something to with the computer I'm using.
As the title suggests, in my code, one image works perfectly fine, yet the other doesn't display correctly.
I feel like I'm overlooking something very obvious, regardless, this is the segment of code that I'm having trouble with.
from Tkinter import *
from StringIO import StringIO
from PIL import Image,ImageTk
from urllib import urlopen
url1 = 'https://lh3.googleusercontent.com/-bnh6_0GlqbA/VUKUsl1Pp9I/AAAAAAACGoM/Vx9yu1QGIKQ/s650/Sunset.png'
url2 = 'https://lh3.googleusercontent.com/-_J57qf7Y9yI/VUPaEaMbp9I/AAAAAAACGuM/3f4551Kcd0I/s650/UpsideDawn.png'
window = Tk()
imagebytes = urlopen(url1).read()
imagedata = StringIO(imagebytes)
imagePIL = Image.open(imagedata)
imageready = ImageTk.PhotoImage(imagePIL)
imagelabel = Label(window, image = imageready)
imagelabel.image = imageready
imagelabel.pack()
window.mainloop()
If you were to run this code, you'll find that url1 will display a blank window, but url2 will display the image.
The following code works for me in Python 3, displaying either image just fine.
from tkinter import *
from PIL import Image,ImageTk
import urllib.request
import io
url1 = 'https://lh3.googleusercontent.com/-bnh6_0GlqbA/VUKUsl1Pp9I/AAAAAAACGoM/Vx9yu1QGIKQ/s650/Sunset.png'
url2 = 'https://lh3.googleusercontent.com/-_J57qf7Y9yI/VUPaEaMbp9I/AAAAAAACGuM/3f4551Kcd0I/s650/UpsideDawn.png'
window = Tk()
imagebytes = urllib.request.urlopen(url1).read()
imagedata = io.BytesIO(imagebytes)
imagePIL = Image.open(imagedata)
imageready = ImageTk.PhotoImage(imagePIL)
imagelabel = Label(window, image = imageready)
imagelabel.image = imageready
imagelabel.pack()
window.mainloop()
The following is my best guess at a Python 2 version of the above:
from Tkinter import *
from PIL import Image,ImageTk
from urllib import urlopen
import io # try this
url1 = 'https://lh3.googleusercontent.com/-bnh6_0GlqbA/VUKUsl1Pp9I/AAAAAAACGoM/Vx9yu1QGIKQ/s650/Sunset.png'
url2 = 'https://lh3.googleusercontent.com/-_J57qf7Y9yI/VUPaEaMbp9I/AAAAAAACGuM/3f4551Kcd0I/s650/UpsideDawn.png'
window = Tk()
imagebytes = urlopen(url1).read()
imagedata = io.BytesIO(imagebytes) # use bytesio instead of stringio
imagePIL = Image.open(imagedata)
imageready = ImageTk.PhotoImage(imagePIL)
imagelabel = Label(window, image = imageready)
imagelabel.image = imageready
imagelabel.pack()
window.mainloop()

why can not see images in a similar code?

please help to understand the cause of the phenomenon.
This script does not work (can not see images).
import os, sys
from tkinter import *
from PIL.ImageTk import PhotoImage
DIR_IMGS = 'imgs'
imgfiles = os.listdir(DIR_IMGS)
main = Tk()
for imgfile in imgfiles:
win = Toplevel()
imgpath = os.path.join(DIR_IMGS, imgfile)
objImg = PhotoImage(file=imgpath)
Label(win, image=objImg).pack()
main.mainloop()
and this script works (see images).
import os, sys
from tkinter import *
from PIL.ImageTk import PhotoImage
imgdir = 'images'
imgfiles = os.listdir(imgdir)
main = Tk()
savephotos = [] #?????????????????????
for imgfile in imgfiles:
imgpath = os.path.join(imgdir, imgfile)
win = Toplevel()
win.title(imgfile)
imgobj = PhotoImage(file=imgpath)
Button(win, image=imgobj).pack()
savephotos.append(imgobj) #?????????????????????
main.mainloop()
they differ only in two rows. it is unclear why such great importance "savephotos"
As FabienAndre writes in the second comment. The garbage collector deletes the image object. The image must be retained for the duration of the display.
I tried a simple code modification:
import os, sys
from tkinter import *
from PIL.ImageTk import PhotoImage
DIR_IMGS = 'imgs'
imgfiles = os.listdir(DIR_IMGS)
main = Tk()
objImgList = []
for imgfile in imgfiles:
win = Toplevel()
imgpath = os.path.join(DIR_IMGS, imgfile)
objImg = PhotoImage(file=imgpath)
Label(win, image=objImg).pack()
objImgList.append(objImg)
main.mainloop()
All pictures are now displayed.

Categories