[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky] [Facebook]
[Build Your Own Python Action Arcade!]

[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Interactively crop scaled images in Python and tkinter

[This program lets you Interactively crop scaled images in Python and tkinter]

My earlier post Interactively crop images in Python and tkinter lets you use the mouse to crop images. This example expands that one to let you scale the image first. That lets you see all of a really large image or zoom in on part of an image to get greater precision.

Building the Scale Menu

When the program starts, it uses the following code to create its Scale menu.

self.selected_scale = tk.DoubleVar(value=1) scales = [3, 2, 1, 0.5, 0.25, 0.1] for scale in scales: text = f'{scale:.0%}' self.scale_menu.add_radiobutton(label=text, variable=self.selected_scale, value=scale, command=self.set_scale)

This code creates a DoubleVar named self.selected_scale to hold the scale. It then makes a list of the scales that it will allow and loops through them.

For each scale, the code adds a radio button to the Scale menu. The text displayed on the button is the scale factor formatted as a percentage. For example, 3 becomes 300% and 0.5 becomes 50%.

The radio button is attached to self.selected_scale so it will update that variable when it is selected. The button's value is the scale so it sets the variable to that value. For example, when you click the 50% radio button, it sets self.selected_scale to 0.5.

The radio button's command is set_scale, so it calls that method (described shortly) when it is clicked.

Scaling and Scrolling

When you select a new scale from the Scale menu and when you open a new file, the program calls the following set_scale method to scale the image.

def set_scale(self): '''Scale the current image.''' if not self.image: return # Get the scale. scale = self.selected_scale.get() # Scale the image. wid = int(self.image.width * scale) hgt = int(self.image.height * scale) self.scaled_image = self.image.resize((wid, hgt), Image.Resampling.LANCZOS) # Remove any previous selection rectangle. self.selection_rectangle = None # Display the image. self.photo_image = ImageTk.PhotoImage(self.scaled_image) self.display_image() # Size the canvas to fit the image. self.canvas.config(width=wid, height=hgt) self.scrolled_frame.configure_frame()

The code first returns if no image is loaded.

Next, the method gets the currently selected scale value. It then gets the original image's width and height, multiplies those values by the scale factor, and resizes the image, saving the result in self.scaled_image.

The code then removes any previous selection rectangle. Alternatively you could scale the rectangle's coordinates, but this program doesn't let you adjust those coordinates (it makes you draw a new rectangle from scratch) so there's little point.

The program then converts the scaled image into a PhotoImage and calls self.display_image to display the image on the program's canvas.

Next, the code resizes the canvas to fit the image.

The canvas is inside a scrolled frame (see my post Make a scrolled frame that responds to the mouse wheel in tkinter and Python) which automatically displays the canvas and allows scrolling if the canvas is too large. To make that work, however, the code must call the frame's configure_frame method, so the program does that.

Saving

When you save the selected area, the program calls get_crop_rectangle to get the coordinates of the area you selected. The following code shows that method with the modified code shown in blue.

def get_crop_rectangle(self): '''Return the selection rectangle with x1 < x2 and y1 < y2.''' # Put the values in order. x1 = min(self.selection_rectangle[0], self.selection_rectangle[2]) y1 = min(self.selection_rectangle[1], self.selection_rectangle[3]) x2 = max(self.selection_rectangle[0], self.selection_rectangle[2]) y2 = max(self.selection_rectangle[1], self.selection_rectangle[3]) # Scale. scale = self.selected_scale.get() x1 = int(x1 / scale) y1 = int(y1 / scale) x2 = int(x2 / scale) y2 = int(y2 / scale) return [x1, y1, x2, y2]

The code gets the selected area's coordinates in order as before. It then gets the current scale factor and divides each coordinate by that factor. For example, if the scale factor is 2 (meaning 200%), then every pixel in the scaled image is moved 2 times as far from the origin as it was in the original image. This code divides by 2 to get the selected area's coordinates in the original image's coordinate system.

Conclusion

Those are the only changes to the previous example. Download the example to see additional details and to experiment with it.
© 2024 - 2026 Rocky Mountain Computer Consulting, Inc. All rights reserved.