How to display created thumbnail image in tkinter without saving it first? - python

I'm trying to display a thumbnail image in tkinter by saving the image in memory using io.BytesIO(). I'm getting _tkinter.TclError: format error in bitmap data. The BitmapImage supports X11 bitmap image. So my question is how to convert my images to xbm before pass it to BitmapImage method?
from PIL import Image, ImageTk
import tkinter.scrolledtext as tkst
import tkinter as tk
import os, os.path
import io
class Example(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
img = Image.open("1.jpg")
image_size = 256, 256
img.thumbnail(image_size,Image.ANTIALIAS)
b = io.BytesIO()
img.save(b, 'gif')
p = b.getvalue()
photo = tk.BitmapImage(data=p)
self.photo = photo
self.imageview = tk.Label(self, image = self.photo, background="black")
self.imageview.grid(row=0, column=0, rowspan=2, sticky="nsew")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.geometry("800x400")
root.mainloop()
Last time, I solved the problem using this code but sometimes the height of the image will get cut off.
image = Image.open("1.jpg")
basewidth = 900
wpercent = (basewidth/float(image.size[0]))
hsize = int((float(image.size[1])*float(wpercent)))
image = image.resize((basewidth,hsize),Image.ANTIALIAS)
self.photo = ImageTk.PhotoImage(image)
self.imageview.configure(image=self.photo)

Related

I am getting an AttributeError when I try to resize an image I have inserted to a Tkinter window

I am trying to resize an image I inserted in my Tkinter window, but keep receiving this error message: "AttributeError: 'PhotoImage' object has no attribute 'resize'"
This is my code to resize the image:
self.path = 'S:/Öffentliche Ordner/Logos/Core Solution/Logo/CoreSolution_Logo_RGB.jpg'
self.img = ImageTk.PhotoImage(Image.open(self.path))
self.resized = self.img.resize(50,50)
self.new_img = ImageTk.PhotoImage(self.resized)
self.label = Label(master, image = self.new_img)
self.label.pack()
self.Main = Frame(self.master)
How can I resolve this error? All help is welcomed and appreciated.
As in this tutorial, it looks like it is easier to import the file as an image. Then resize it, then convert it to PhotoImage. Can you give it a try ?
# Import the required libraries
from tkinter import *
from PIL import Image, ImageTk
# Create an instance of tkinter frame or window
win=Tk()
# Set the size of the tkinter window
win.geometry("700x350")
# Load the image
image=Image.open('download.png')
# Resize the image in the given (width, height)
img=image.resize((450, 350))
# Conver the image in TkImage
my_img=ImageTk.PhotoImage(img)
# Display the image with label
label=Label(win, image=my_img)
label.pack()
win.mainloop()
https://www.tutorialspoint.com/resizing-images-with-imagetk-photoimage-with-tkinter
As far as I can see, the Pillow Image.PhotoImage class is meant for displaying in tkinter but does not have all the methods of the tkinter.PhotoImage class.
Easiest is to resize the Pillow.Image before converting to Pillow Image.PhotoImage.
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
path = 'images/cleese.png'
img = Image.open(path)
img.thumbnail((50,50)) # Resize Pillow Image
new_img = ImageTk.PhotoImage(img) # Convert
label = Label(master, image=new_img)
label.pack()
master.mainloop()
Try this. I did not test.
path = Image.open('S:/Öffentliche Ordner/Logos/Core Solution/Logo/CoreSolution_Logo_RGB.jpg'
self.resized = path.resize{(50,50),Image.ANTIALIAS)
self.img = ImageTk.PhotoImage(self.resized)
self.label = Label(master, image = self.new_img)
self.label.pack()
self.Main = Frame(self.master)

Need advice on submenus

So currently, I have to design some Menu bars with many options when clicked. But I have Menu bars part settled, what I'm lost about is I want to have 2 images. For instance if I click 'View', it'll drop down 'Original Image' & 'Scaled image' and if I clicked either one, it will show me respective images with the correct images.
import cv2
import numpy as np
img = cv2.imread('image.jpg')
scaled_img = cv2.resize(img, (400, 500))
cv2.imshow('Original image', img)
From my original code; and I'm not sure where to insert above codes(if correct), to below.
def showImg(self):
load = Image.open('image.jpg')
render = ImageTk.PhotoImage(load)
img = Label(self, image=render)
img.image = render
img.place(x=0,y=0)
You can use Pillow module to resize image instead of OpenCV. Below is an example:
from tkinter import *
from PIL import Image, ImageTk
class Window(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry('500x600')
# initialize the images
img = Image.open('image.jpg')
self.original_img = ImageTk.PhotoImage(image=img)
img = img.resize((400, 500))
self.scaled_img = ImageTk.PhotoImage(image=img)
# create the menu bar
menubar = Menu(self)
self.config(menu=menubar)
file = Menu(menubar, tearoff=0)
file.add_command(label='New')
file.add_command(label='Open')
file.add_command(label='Save')
file.add_command(label='Save As')
file.add_separator()
file.add_command(label='Exit', command=self.client_exit)
menubar.add_cascade(label='File', menu=file)
view = Menu(menubar, tearoff=0)
view.add_command(label='Original Image', command=lambda:self.showImg(self.original_img))
view.add_command(label='Scaled Image', command=lambda:self.showImg(self.scaled_img))
menubar.add_cascade(label='View', menu=view)
# create a label to show the image
self.imgbox = Label(self)
self.imgbox.place(x=0, y=0)
def showImg(self, img):
self.imgbox.config(image=img)
def client_exit(self):
self.destroy()
Window().mainloop()
from tkinter import *
import tkinter as tk
from PIL import Image, ImageTk
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
# Creation of init_window
def init_window(self):
img = Image.open("001.png")
img = img.resize((250, 250)) ## The (250, 250) is (height, width)
photo = ImageTk.PhotoImage(img)
quitBtn2 = Label(root, image=photo)
quitBtn2.image = photo
quitBtn2.pack()
Image Module
The Image module provides a class with the same name which is used to
represent a PIL image. The module also provides a number of factory
functions, including functions to load images from files, and to
create new images.
https://pillow.readthedocs.io/en/stable/reference/Image.html

convert coordinates into binary image python

I made a GUI in which I can load an image from disk and convert the mouse motion ( drawing the contours ) into coordinates. Now I need to convert the coordinates into a binary image and I don't know how.
Here is my code:
from Tkinter import *
from tkFileDialog import askopenfilename
from PIL import Image, ImageTk
import numpy as np
import cv2
class Browse_image :
def __init__ (self,master) :
frame = Frame(master)
frame.grid(sticky=W+E+N+S)
self.browse = Button(frame, text="Browse", command = lambda: browseim(self))
self.browse.grid(row=13, columnspan=1)
self.photo = PhotoImage(file="browse.png")
self.label = Label(frame, image=self.photo)
self.label.grid(row=1,rowspan=10)
self.label.bind('<B1-Motion>', self.mouseevent)
def mouseevent(self,event):
w=self.photo.width()
h=self.photo.height()
a = np.zeros(shape=(h,w))
#print event.x, event.y
a[event.x,event.y]=1
plt.imsave('binary.png', a, cmap=cm.gray)
def browseim(self):
path = askopenfilename(filetypes=(("png files","*.png"),("jpeg files",
"*.jpeg")) )
if path:
img = Image.open(path)
self.photo = ImageTk.PhotoImage(img)
self.label.configure(image = self.photo)
#self.label.image = self.photo
root= Tk()
b= Browse_image(root)
root.mainloop()
`
Your issue is that you are creating a new empty array at each mouse event with the line a = np.zeros(shape=(h,w)) in mouseevent. To fix that you should have a declared in the __init__ as an attribute (ie self.a = np.zeros(shape=(h,w))) so that you can acces and update it without overwriting it in your mouseevent function.

Python Tkinter show image acessed on a listbox

I'm trying to make a python script that shows a image that is acessed on a listbox. This code that I got on the internet works:
import Tkinter as tk
from PIL import ImageTk, Image
window = tk.Tk()
path = 'img\\2015722_univ_sqs_sm.jpg'
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(window, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
window.mainloop()
But when I tried to adapt it do the listbox it stopped working.
from Tkinter import *
from PIL import ImageTk, Image
import glob
files = glob.glob('img\\*.jpg')
class App:
def __init__(self, root):
self.l = Listbox(root, width = 50, height = 15)
self.l.pack()
self.l.bind('<<ListboxSelect>>', self.lol)
self.c = Label(root)
self.c.pack()
for f in files:
self.l.insert(END, f)
def lol(self, evt):
path = files[self.l.curselection()[0]]
img = ImageTk.PhotoImage(Image.open(path))
self.c.image = img
self.c.pack()
root = Tk()
App(root)
root.mainloop()
What am I missing?
You must use the configure method of the label, and store a reference to the image somewhere.
self.c.image = img # save reference
self.c.configure(image=img) # configure the label

How to update the image of a Tkinter Label widget?

I would like to be able to swap out an image on a Tkinter label, but I'm not sure how to do it, except for replacing the widget itself.
Currently, I can display an image like so:
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
root.mainloop()
However, when the user hits, say the ENTER key, I'd like to change the image.
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image = img)
panel.pack(side = "bottom", fill = "both", expand = "yes")
def callback(e):
# change image
root.bind("<Return>", callback)
root.mainloop()
Is this possible?
The method label.configure does work in panel.configure(image=img).
What I forgot to do was include the panel.image=img, to prevent garbage collection from deleting the image.
The following is the new version:
import Tkinter as tk
import ImageTk
root = tk.Tk()
img = ImageTk.PhotoImage(Image.open(path))
panel = tk.Label(root, image=img)
panel.pack(side="bottom", fill="both", expand="yes")
def callback(e):
img2 = ImageTk.PhotoImage(Image.open(path2))
panel.configure(image=img2)
panel.image = img2
root.bind("<Return>", callback)
root.mainloop()
The original code works because the image is stored in the global variable img.
Another option to do it.
Using object-oriented programming and with an interactive interface to update the image.
from Tkinter import *
import tkFileDialog
from tkFileDialog import askdirectory
from PIL import Image
class GUI(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
w,h = 650, 650
master.minsize(width=w, height=h)
master.maxsize(width=w, height=h)
self.pack()
self.file = Button(self, text='Browse', command=self.choose)
self.choose = Label(self, text="Choose file").pack()
self.image = PhotoImage(file='cualitativa.gif')
self.label = Label(image=self.image)
self.file.pack()
self.label.pack()
def choose(self):
ifile = tkFileDialog.askopenfile(parent=self,mode='rb',title='Choose a file')
path = ifile.name
self.image2 = PhotoImage(file=path)
self.label.configure(image=self.image2)
self.label.image=self.image2
root = Tk()
app = GUI(master=root)
app.mainloop()
root.destroy()
Replace 'cualitativa.jpg' for the default image you want to use.
Another solution that might be of help.
In my case, I had two tk.Tk() windows. When using ImageTk.PhotoImage(), the object defaults to setting its tk window to being the first one created. A simple fix to this is to pass the tk window that you want as such ImageTk.PhotoImage(img, master=your_window)
import tkinter as tk
from PIL import ImageTk, Image
if __name__ == '__main__':
main_window = tk.Tk()
second_window = tk.Tk()
main_canvas = Canvas(second_window)
main_canvas.pack()
filename = 'test.png'
img = Image.open(filename)
img = img.resize((300, 100), Image.ANTIALIAS)
logo = ImageTk.PhotoImage(img, master=second_window)
logo_label = Label(master=main_canvas, image=logo)
logo_label.image = logo
logo_label.pack()
main_window.mainloop()

Categories