How can I resize image without stretching it in Tkinter? - python-3.x

I am currently working on a project which requires displaying Images of different sizes. So I wanted to use tkinter for that purpose.
Here is my Code for displaying image
from tkinter import Tk, Label
from PIL import Image, ImageTk
root = Tk()
root.title("Display Images")
root.geometry('550x550')
root.maxsize(550, 550)
root.iconbitmap('icon.ico')
root.configure(background='#333')
image = Image.open('./image.jpg')
resized_image = image.resize((540, 540), Image.ANTIALIAS)
disp_image = ImageTk.PhotoImage(resized_image)
label = Label(image=disp_image) #.pack(padx=10, pady=10)
label.configure(border=0)
label.pack(padx=10, pady=10)
root.mainloop()
which works perfectly fine but
I wanted to display different sizes of images without stretching them.
Like, If image size exceeds the window size, it should take the size of the window, and If image size is less than the size of the window then there should be no change in image size.
Example:
I have two images of width and height [200x300, 400x500]
and my display size(windows width and height) is 350x350
When I display an image of size 200x300, it should display as it is without change in size and when I display another image it should change its size to 350x350
So, is there a way to pull that off?

Here is a solution:
from tkinter import Tk, Label
from PIL import Image, ImageTk
root = Tk()
root.title("Display Images")
root.geometry('550x550')
root.maxsize(550, 550)
root.configure(background='#333')
image = Image.open('./image.jpg')
# main part -----------------------------------------
if image.width > 540 and image.height > 540:
resized_image = image.resize((540, 540), Image.ANTIALIAS)
elif image.width > 540:
resized_image = image.resize((540, image.height), Image.ANTIALIAS)
elif image.height > 540:
resized_image = image.resize((image.width, 540), Image.ANTIALIAS)
else:
resized_image = image
# end main part ----------------------------------------
disp_image = ImageTk.PhotoImage(resized_image)
label = Label(image=disp_image, border=0)
label.pack(padx=10, pady=10)
root.mainloop()
Simple use of if statements.

Related

I am using tkinter ,I want to clear the canvas using a button(close_button) but the camera is always on and the button not doing anything

I am using Tkinter, I want to clear the canvas using a button(close_button) but the camera is always on and the button not doing anything I want the button to close the camera feed and reset the canvas so that the canvas becomes as it was before I opened the cam
from tkinter import*
import tkinter as tk
from PIL import Image, ImageTk
import cv2
# new window function which will be called when button pressed
class OpenCam():
def __init__(self, window, cap):
self.window = window
self.cap = cap
self.width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
self.height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
self.interval = 20 # Interval in ms to get the latest frame
# Create canvas for image
self.canvas = tk.Canvas(self.window, width=self.width, height=self.height)
self.canvas.place(x=100,y=100)
# close Button need to close cam and reset canvas
close_button = tk.Button(root, text="close", bg='black', fg='white', command=self.canvas.delete() )
close_button.place(x=610,y=0)
# Update image on canvas
self.update_image()
def update_image(self):
# Get the latest frame and convert image format
self.image = cv2.cvtColor(self.cap.read()[1], cv2.COLOR_BGR2RGB) # to RGB
self.image = Image.fromarray(self.image) # to PIL format
self.image = ImageTk.PhotoImage(self.image) # to ImageTk format
# Update image
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.image)
# Repeat every 'interval' ms
self.window.after(self.interval, self.update_image)
def new_window():
OpenCam(root, cv2.VideoCapture(0))
#create original window
root = tk.Tk()
root.title("ADD CAM: ")
canvas = tk.Canvas(root, height=1000, width=1000)
canvas.pack()
#create button that will be placed
button = tk.Button(root, text="ADD CAM", bg='black', fg='white', command=new_window )
button.place(x=0,y=0)
root.mainloop()

Tkinter resizing images in labels arranged in a grid

To start, I'm totally new to Tkinter and am trying to make a Raspberry Pi Media Player of sorts...
I grab the directories of all .mp4 files on a USB drive, and use PIL to put the thumbnails of the videos into a 3x3 grid of labels, with the grid inside of a frame (frame2 in the code).
Right now, with the thumbnails of varying sizes, the labels are also inconsistently sized. Also, only the top-right portion of larger thumbnails are displayed, rather than the entire image.
How can I to scale and fit the thumbnails into consistently sized labels, in grid form?
Here is part of my code (It's quite large so I try to include only the relevant parts):
import tkinter as tk
from subprocess import Popen
from time import sleep
import os
from random import randint
import imageio
from PIL import ImageTk, Image
from pathlib import Path
#putting 100th frame of video with 'path' into the label
def pack_thumbnail(path, label):
#this is probably not a good way to do this
video = imageio.get_reader(path)
for i in range(100):
try:
image = video.get_next_data()
except:
video.close()
break
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
window = tk.Tk()
window.attributes("-fullscreen", True)
frame1 = tk.Frame(master=window, width=200, height=100, bg="white")
frame1.pack(fill=tk.Y, side=tk.LEFT)
#frame2 contains the grid of labels
frame2 = tk.Frame()
for i in range(3):
frame2.columnconfigure(i, weight=1, minsize=75)
frame2.rowconfigure(i, weight=1, minsize=50)
for j in range(0, 3):
frame = tk.Frame(master=frame2, relief=tk.RAISED, borderwidth=1)
frame.grid(row=i, column=j, padx=5, pady=5)
#path to video to get thumbnail (i only have 3 videos so i randomize it)
vid_path=f"/media/pi/{os.listdir('/media/pi/')[0]}/{folder_name}/{videos[randint(0, 2)]}"
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
pack_thumbnail(vid_path, label)
label.pack(padx=5, pady=5)
frame2.pack()
window.bind("<Escape>", lambda x: window.destroy())
window.mainloop()
You can use Image.thumbnail() to resize the image:
# putting 100th frame of video with 'path' into the label
def pack_thumbnail(path, label):
with imageio.get_reader(path) as video:
image = video.get_data(100) # use get_date() instead of get_next_data()
w, h = 200, 200 # thumbnail size
image = Image.fromarray(image)
image.thumbnail((w, h)) # resize the image
frame_image = ImageTk.PhotoImage(image)
label.config(image=frame_image, width=w, height=h)
label.image = frame_image

How to convert ImageTk to Image?

Let's say I have some ImageTk.PhotoImage image stored in the variable imgtk. How can I convert it back to an Image.Image?
The reason is that I want to resize it, but it seems that .resize() only works for Image.Images.
I know it is awfully late, but I just came across the same issue and I just discovered that there is a getimage(imagetk) function in the ImageTk interface.
So, to get your imgtk back as an PIL Image you can do:
img = ImageTk.getimage( imgtk )
I just did a quick test on Windows (Python 3.8.5/Pillow 8.1.2/Tkinter 8.6) and it seems to work fine:
# imgtk is an ImageTk.PhotoImage object
img = ImageTk.getimage( imgtk )
img.show()
img.close()
Ok, that was not easy but I think I have a solution though you need to go into some private methods of label.image. Maybe there is a better way if so I would love to see.
import tkinter as tk
from tkinter import Label
import numpy as np
from PIL import Image, ImageTk
root = tk.Tk()
# create label1 with an image
image = Image.open('pic1.jpg')
image = image.resize((500, 750), Image.ANTIALIAS)
picture = ImageTk.PhotoImage(image=image)
label1 = Label(root, image=picture)
label1.image = picture
# extract rgb from image of label1
width, height = label1.image._PhotoImage__size
rgb = np.empty((height, width, 3))
for j in range(height):
for i in range(width):
rgb[j, i, :] = label1.image._PhotoImage__photo.get(x=i, y=j)
# create new image from rgb, resize and use for label2
new_image = Image.fromarray(rgb.astype('uint8'))
new_image = new_image.resize((250, 300), Image.ANTIALIAS)
picture2 = ImageTk.PhotoImage(image=new_image)
label2 = Label(root, image=picture2)
label2.image = picture2
# grid the two labels
label1.grid(row=0, column=0)
label2.grid(row=0, column=1)
root.mainloop()
Actually you can zoom and reduce the original picture by using the methods zoom to enlarge the picture (zoom(2) doubles the size) and subsample to reduce the size (subsample(2) halves the picture size).
for example
picture2 = label1.image._PhotoImage__photo.subsample(4)
reduces the size of the picture to a quarter and you can skip all the conversion to an Image.
According to label1.image._PhotoImage__photo.subsample.__doc__:
Return a new PhotoImage based on the same image as this widget but use only every Xth or Yth pixel. If y is not given, the default value is the same as x
and label1.image._PhotoImage__photo.zoom.__doc__:
Return a new PhotoImage with the same image as this widget but zoom it with a factor of x in the X direction and y in the Y direction. If y is not given, the default value is the same as x.

Is there any way to resize a tkinter button?

Is there any way to resize button size in python tkinter?
I have tried to resize button size in python 3.7.2 tkinter by using button.config(width = 100, hight = 100), but it didn't work properly. Is there any way to resize button?
I use Python 3.7.2 and Windows 10.
import tkinter as tk
win = tk.Tk()
#*** Settings ***#
win.title("Project_title")
win.geometry("660x450")
win.resizable(False, False)
wall = tk.PhotoImage(file = "pictures_gui.gif")
wall_label = tk.Label(image = wall)
#*** Settings ***#
#*** Test code ***#
def click_me():
button.configure(text="** I have been clicked")
button = tk.Button(win,text = "Click me!",command=click_me)
button.grid(column=1, row=0)
button.config(width = 100,hight = 100)
#*** Test code ***#
win.mainloop()
I'm guessing you want to set the button size in pixels. The button size defaults to characters when the button displays text but no image. To get the size to be pixels you have to display an image in the button. See the example below:
import tkinter as tk
win = tk.Tk()
win.geometry("660x450")
win.resizable(False, False)
def click_me():
button.configure(text="** I have been clicked")
# Create a transparent image to allow Button size in pixels
pixel = tk.PhotoImage(file='images/pixel.png')
button = tk.Button(win, text="Click me!", command=click_me,
image=pixel, compound='center')
button.grid(column=1, row=0)
button.config(width=100, height=100) # Config size in pixels
win.mainloop()
The pixel.png image is 1x1 pixel and has transparent color.

Removing background from a label in Tkinter

from tkinter import *
from tkinter import messagebox
import tkinter
import hashlib
from PIL import Image, ImageTk
from win32api import GetSystemMetrics
#===========================================================================================
#functions to center windows
def center_window_x(width):
x_coordinate = (GetSystemMetrics(0)/2) - (width/2)
return x_coordinate
def center_window_y(height):
y_coordinate = (GetSystemMetrics(1)/2) - (height/2)
return y_coordinate
#===========================================================================================
#function to create setup page
def first_time_setup(width, height):
setup_window = Tk()
#===========================================================================================
#remove window border and position in center
setup_window.overrideredirect(1)
setup_frame = Frame(setup_window)
setup_frame.pack_propagate(False)
setup_window.geometry('%dx%d+%d+%d' % (width, height, center_window_x(width), center_window_y(height)))
#===========================================================================================
#background image for setup window
canvas = Canvas(setup_window, width=width, height=height)
canvas.grid(columnspan=2)
image = Image.open("setup_background.jpg")
canvas.image = ImageTk.PhotoImage(image)
canvas.create_image(0, 0, image=canvas.image, anchor="nw")
#===================================================================================================
#add username label
start_title = Label(setup_window, text="Username")
start_title.place(x=430,y=225)
#===================================================================================================
#add admin user entry box
admin_user_ent = Entry(setup_window)
admin_user_ent.place(x=500,y=225)
first_time_setup(650, 300)
Is there a way to remove the white background behind the username label? I know how to change the colour of it, but how do I remove it all together.
Is there a way to remove the white background behind the username label? I know how to change the colour of it, but how do I remove it all together.
sorry for posting twice, apparently there wasn't enough text and too much code.
It sounds like you are asking how to make your Label have a transparent background. From my understanding at the moment tkinter does not have this feature for widgets like labels and buttons. However it is still possible to create your own see-through label with Canvas
Here is an example of using Canvas to achieve something similar to what you are looking to do.
import tkinter as tk
root = tk.Tk()
mycanvas = tk.Canvas(root, width = 200, height = 25)
mycanvas.create_rectangle(0, 0, 100, 40, fill = "green")
mycanvas.pack(side = "top", fill = "both", expand = True)
text_canvas = mycanvas.create_text(10, 10, anchor = "nw")
mycanvas.itemconfig(text_canvas, text="Look no background! Thats new!")
root.mainloop()

Resources