Title: Display an image at different scales in Python
This example shows how you can let the user load images and display them at various scales.
Opening Images
When you select the File menu's Open command, the following code executes.
def mnu_open_image(self):
'''Open an image file.'''
self.pil_image = self.get_image_file('Load Image')
# Display the image at the desired scale.
self.show_image()
This code first calls the get_image_file method shown in the following code to let you open an image file. It then calls show_image (we'll get to that a bit later) to display the image.
def get_image_file(self, title):
'''
Let the user pick an image file.
Then load and return it in an RGB PIL Image.
'''
filetypes = (
('Image Files', '*.png;*.jpg;*.bmp;*.gif;*.tif'),
('All files', '*.*')
)
filename = fd.askopenfilename(title=title, filetypes=filetypes)
if not filename: return None
try:
return Image.open(filename)
except Exception as e:
messagebox.showinfo('Open Error', f'Error loading image file.\n{e}')
return None
This code makes a tuple holding tuples giving file type names and their extensions. For example, the Image Files file type includes the file extensions *.png, *.jpg, *.bmp, *.gif, and *.tif. The program then uses tkinter's askopenfilename method to display a file selection dialog.
If you cancel the dialog, the method returns None.
If you select a file and click Open, the program calls Image.open to open the selected file and it returns the resulting PIL image object. If that fails (probably because you tried to open a file that isn't an image file), the method displays an error message and returns None.
Making Menus
This program's Scale menu lets the user scale the current image. Here's the code that builds the Scale menu.
def build_scale_menu(self, menu_bar):
'''Build the Scale menu.'''
scale_menu = tk.Menu(menu_bar, tearoff=False)
menu_bar.add_cascade(label='Scale (100%)', menu=scale_menu,
state=tk.DISABLED)
self.scale_var = tk.DoubleVar(value=1.0)
scale_menu.add_radiobutton(label='100%', variable=self.scale_var,
value=1.00, command=self.mnu_scale)
scale_menu.add_radiobutton(label='75%', variable=self.scale_var,
value=0.75, command=self.mnu_scale)
scale_menu.add_radiobutton(label='50%', variable=self.scale_var,
value=0.50, command=self.mnu_scale)
scale_menu.add_radiobutton(label='25%', variable=self.scale_var,
value=0.25, command=self.mnu_scale)
scale_menu.add_radiobutton(label='20%', variable=self.scale_var,
value=0.20, command=self.mnu_scale)
scale_menu.add_radiobutton(label='15%', variable=self.scale_var,
value=0.15, command=self.mnu_scale)
This code adds the Scale cascade item to the main menu bar. Notice that this menu is initially disabled so it's grayed out and the user cannot select it.
The method then creates a DoubleVar named self.scale_var to hold the current scale factor.
Next, the code adds several radio buttons to the Scale menu. Each is uses self.scale_var as its variable. Each radio button's value gives its scale factor. For example, the 50% menu item has value set to 0.50 so, when you select that option, the value 0.50 is dropped into self.scale_var.
Whenever you select any of the radio buttons, tkinter automatically checks that button and unchecks the others that share the same variable. The program then calls the self.mnu_scale method described in the following section.
Scale Selections
When you select one of the Scale menu's radio buttons, the following code executes.
def mnu_scale(self):
'''Show the image at the desired scale.'''
# Display the scale in the Scale menu.
scale = int(self.scale_var.get() * 100)
self.menu_bar.entryconfig(2, label=f'Scale ({scale}%)')
# Display the image at the desired scale.
self.show_image()
This method calls the self.scale_var variable's get method to get its value. It multiples the scale factor (which is something like 0.75) by 100 and multiplies it by 100 to get a percentage (like 75). It then configures the Scale menu's caption so it shows the selected scale factor as in "Scale (75%)."
The code then calls the show_image method described next to do the actual resizing work.
Scaling Images
The following show_image method displays the currently loaded image at the selected scale. (I told you earlier that we would get to show_image.)
def show_image(self):
'''Display the image at the desired scale.'''
if self.pil_image is None:
# No image. Hide the canvas.
self.photo_image = None
self.menu_bar.entryconfig(2, state=tk.DISABLED)
self.canvas.pack_forget()
else:
# Make a scaled version of the image.
wid = int(self.pil_image.width * self.scale_var.get())
hgt = int(self.pil_image.height * self.scale_var.get())
scaled_image = self.pil_image.resize((wid, hgt))
# Convert into a PhotoImage.
self.photo_image = ImageTk.PhotoImage(scaled_image)
# Display it.
self.canvas.delete(tk.ALL)
self.canvas.create_image(0, 0, anchor=tk.NW,
image=self.photo_image)
wid = self.photo_image.width()
hgt = self.photo_image.height()
self.canvas.config(width=wid, height=hgt)
self.menu_bar.entryconfig(2, state=tk.NORMAL)
self.canvas.pack(side=tk.TOP, fill=tk.NONE, expand=False,
anchor=tk.NW, padx=10, pady=10)
This code first checks whether self.photo_image is None. If it is None, no image is loaded so the method disables the Scale and hides the program's Canvas widget.
If self.photo_image is not None, the code multiplies the image's width and height by the scale factor stored in self.scale_var to get the image's scaled dimensions. It then uses the image's resize method to make a scaled copy.
Next, the code converts the resized PIL image into a PhotoImage that tkinter can understand. Note that you must save the PhotoImage in a persistent variable so Python's garbage collector doesn't become overzealous and throw it away.
The method then deletes any previous image from the program's Canvas widget, displays the new PhotoImage there, and resizes that widget to fit the scaled image.
Finally, the method enables the Scale menu and uses pack to make the Canvas widget visible.
Conclusion
That's all this example does. It just lets you open an image and view it at different scales. Later posts will enhance this example by letting you scroll over the scaled image and process events on the resized picture, for example, letting to draw on the image.
Meanwhile, download the example to experiment with it and to see additional details.
|