how to resize an image to fit the label size? (python)
Solution 1
If you don't have PIL installed, first you need to install
pip install pillow
Once installed you can now import from PIL:
from PIL import Image, ImageTk
Tk's PhotoImage can only display .gif's, whereas PIL's ImageTk will let us display various image formats in tkinter and PIL's Image class has a resize
method we can use to resize the image.
I trimmed your code down some.
You can resize the image and then just configure the label, the label will expand to be the size of the image. If you gave the label a specific height and width, lets say height=1
and width=1
and you resized the image to be 500x500 and then configured the widget. It would still display a 1x1 label since you've set these attributes explicitly.
In the below code, modifiying the dict, it is not okay to modify a dict while iterating over it. dict.items() returns a copy of the dict.
There's various ways to do this, I just though a dict was convenient here.
Link to an image that's over the height / width limit - kitty.gif
from tkinter import *
import random
from PIL import Image, ImageTk
WIDTH, HEIGHT = 150, 150
flags = {
'England': 'england.gif',
'Wales': 'wales.gif',
'Kitty': 'kitty.gif'
}
def batch_resize():
for k, v in flags.items():
v = Image.open(v).resize((WIDTH, HEIGHT), Image.ANTIALIAS)
flags[k] = ImageTk.PhotoImage(v)
def newcountry():
country = random.choice(list(flags.keys()))
image = flags[country]
flagLabel['text'] = country
flagpicture.config(image=image)
if __name__ == '__main__':
root = Tk()
root.configure(bg='black')
batch_resize()
flagLabel = Label(root, text="", bg='black', fg='cyan', font=('Helvetica',40))
flagLabel.pack()
flagpicture = Label(root)
flagpicture.pack()
newflagButton = Button(root, text="Next Country", command=newcountry)
newflagButton.pack()
root.mainloop()
Solution 2
Instead of randomly selecting a country to display its flag, we loop through the flags dictionary that is key-sorted. Unlike the random choice which will inevitably repeat the flags, this scheme runs through the countries in alphabetical order. Meanwhile, we resize all the images to a fixed pixel size based on the width and height of the root window multiplied by a scale factor. Below is the code:
import tkinter as tk
from PIL import Image, ImageTk
class Flags:
def __init__(self, flags):
self.flags = flags
self.keyList = sorted(self.flags.keys()) # sorted(flags)
self.length = len(self.keyList)
self.index = 0
def resize(self, xy, scale):
xy = [int(x * y) for (x, y) in zip(xy, scale)]
for k, v in self.flags.items():
v = Image.open(r'C:/Users/user/Downloads/' + v)
v = v.resize((xy[0], xy[1]), Image.ANTIALIAS)
self.flags[k] = ImageTk.PhotoImage(v)
def newCountry(self, lbl_flag, lbl_pic):
country = self.keyList[self.index]
lbl_flag["text"] = country
img = self.flags[country]
lbl_pic.config(image = img)
self.index = (self.index + 1) % self.length # loop around the flags dictionary
def rootSize(root):
# Find the size of the root window
root.update_idletasks()
width = int(root.winfo_width() * 1.5) # 200 * m
height = int(root.winfo_height() * 1.0) # 200 * m
return width, height
def centerWsize(root, wh):
root.title("Grids layout manager")
width, height = wh
# Find the (x,y) to position it in the center of the screen
x = int((root.winfo_screenwidth() / 2) - width/2)
y = int((root.winfo_screenheight() / 2) - height/2)
root.geometry("{}x{}+{}+{}".format(width, height, x, y))
if __name__ == "__main__":
flags = {
"Republic of China": "taiwan_flag.png",
"United States of America": "america_flag.gif",
"America": "america_flag.png",
}
root = tk.Tk()
wh = rootSize(root)
centerWsize(root, wh)
frame = tk.Frame(root, borderwidth=5, relief=tk.GROOVE)
frame.grid(column=0, row=0, rowspan=3)
flag = Flags(flags)
zoom = (0.7, 0.6) # Resizing all the flags to a fixed size of wh * zoom
flag.resize(wh, zoom)
lbl_flag = tk.Label(frame, text = "Country name here", bg = 'white', fg = 'magenta', font = ('Helvetica', 12), width = 30)
lbl_flag.grid(column = 0, row = 0)
pic_flag = tk.Label(frame, text = "Country flag will display here")
pic_flag.grid(column = 0, row = 1)
btn_flag = tk.Button(frame, text = "Click for next Country Flag",
bg = "white", fg = "green", command = lambda : flag.newCountry(lbl_flag, pic_flag))
btn_flag.grid(column = 0, row = 2)
root.mainloop()
Minch
Updated on June 04, 2022Comments
-
Minch almost 2 years
My aim is to create a random country generator, and the flag of the country that is picked will appear. However, if the image file is bigger than the predetermined size of the label, then only part of the image is displayed. Is there a way of resizing the image to fit the label? (All other questions like this which I have seen have been answered, mentioning the PIL or Image modules. I tested them both, and they both came up with this error:
Traceback (most recent call last): File "C:\python\country.py", line 6, in import PIL ImportError: No module named 'PIL'
This is my code, if it helps:
import tkinter from tkinter import * import random flags = ['England','Wales','Scotland','Northern Ireland','Republic of Ireland'] def newcountry(): country = random.choice(flags) flagLabel.config(text=country) if country == "England": flagpicture.config(image=England) elif country == "Wales": flagpicture.config(image=Wales) elif country == "Scotland": flagpicture.config(image=Scotland) elif country == "Northern Ireland": flagpicture.config(image=NorthernIreland) else: flagpicture.config(image=Ireland) root = tkinter.Tk() root.title("Country Generator") England = tkinter.PhotoImage(file="england.gif") Wales = tkinter.PhotoImage(file="wales.gif") Scotland = tkinter.PhotoImage(file="scotland.gif") NorthernIreland = tkinter.PhotoImage(file="northern ireland.gif") Ireland = tkinter.PhotoImage(file="republic of ireland.gif") blackscreen = tkinter.PhotoImage(file="black screen.gif") flagLabel = tkinter.Label(root, text="",font=('Helvetica',40)) flagLabel.pack() flagpicture = tkinter.Label(root,image=blackscreen,height=150,width=150) flagpicture.pack() newflagButton = tkinter.Button(text="Next Country",command=newcountry) newflagButton.pack()
The code works perfectly fine apart from only showing part of the image. Is there a way to resize the images within the code itself?(I am using Python 3.5.1)