Learn how to build Pro Image Cropper Plus, a lightweight Python image cropping app using Tkinter, Pillow, and ttkbootstrap. This tutorial is beginner-friendly, with each section broken into small steps and explained clearly.
GitHub repo: ProImageCropperPlus
Step 1: Setup Your Environment
Make sure you have Python installed (preferably 3.8+). You’ll also need the following packages:
pip install pillow ttkbootstrap
Pillow – For image handling.
ttkbootstrap – For modern themed Tkinter widgets.
Step 2: Import Required Modules
At the top of your Python file, import all required modules:
import sys
from pathlib import Path
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import ttkbootstrap as tb
Explanation:
sys and Path handle file paths and packaging.
tkinter is for GUI elements.
Pillow is for image opening, cropping, and displaying.
ttkbootstrap gives modern-looking widgets.
Step 3: App Configuration
Define some basic app information:
APP_NAME = "Pro Image Cropper Plus"
APP_VERSION = "2.1.0"
APP_AUTHOR = "Mate Technologies"
APP_WEBSITE = "https://matetools.gumroad.com"
Create a helper function for resource paths:
def resource_path(name):
base = getattr(sys, "_MEIPASS", Path(__file__).parent)
return Path(base) / name
This ensures your app works even when bundled with PyInstaller.
Step 4: Create the Main Window
app = tk.Tk()
style_obj = tb.Style(theme="superhero") # Using ttkbootstrap theme
app.title(f"{APP_NAME} {APP_VERSION}")
app.geometry("1200x680")
try:
app.iconbitmap(str(resource_path("logo.ico")))
except Exception as e:
print("Icon error:", e)
Explanation:
tk.Tk() initializes the main window.
ttkbootstrap.Style applies a modern theme.
iconbitmap sets the app icon (optional).
Step 5: Define Variables
image_paths = [] # Stores all selected images
current_index = 0 # Tracks current image
img = None # PIL Image object
tk_img = None # Tkinter-compatible image
rect_id = None # Crop rectangle ID on canvas
# Crop properties
crop_x = tk.IntVar(master=app, value=0)
crop_y = tk.IntVar(master=app, value=0)
crop_width = tk.IntVar(master=app, value=100)
crop_height = tk.IntVar(master=app, value=100)
constrain_aspect = tk.BooleanVar(master=app, value=False)
aspect_ratio_value = tk.DoubleVar(master=app, value=1.0)
crop_status = tk.StringVar(master=app, value="Idle")
crop_output_path = tk.StringVar(master=app, value="")
Explanation:
These variables will control:
The current image being edited
Crop rectangle position and size
Crop constraints (aspect ratio, status, output path)
Step 6: Load and Display Images
def load_image(path):
global img, tk_img
img = Image.open(path)
update_canvas_image()
reset_crop()
def update_canvas_image():
global tk_img
if img is None: return
scale = zoom_scale.get()
w, h = int(img.width*scale), int(img.height*scale)
tk_img = ImageTk.PhotoImage(img.resize((w,h), Image.Resampling.LANCZOS), master=app)
canvas.config(scrollregion=(0,0,w,h))
canvas.delete("all")
canvas.create_image(0,0,anchor="nw",image=tk_img)
Explanation:
load_image opens the selected image.
update_canvas_image applies zoom and updates the Tkinter canvas.
Image.Resampling.LANCZOS ensures smooth scaling.
Step 7: Crop Rectangle and Handles
def draw_rectangle():
global rect_id, handles
if img is None: return
x, y, w, hgt = crop_x.get(), crop_y.get(), crop_width.get(), crop_height.get()
scale = zoom_scale.get()
x1, y1, x2, y2 = x*scale, y*scale, (x+w)*scale, (y+hgt)*scale
rect_id = canvas.create_rectangle(x1, y1, x2, y2, outline="red", width=2, tag="rect")
Explanation:
This draws a red rectangle for cropping.
Later, you’ll add corner and edge handles for resizing.
Step 8: Cropping and Saving Images
def crop_image():
if img is None or not crop_output_path.get():
messagebox.showwarning("Save first", "Please choose save location.")
return
x, y, w, h = crop_x.get(), crop_y.get(), crop_width.get(), crop_height.get()
cropped = img.crop((x, y, x+w, y+h))
cropped.save(crop_output_path.get())
messagebox.showinfo("Success", f"Cropped image saved:\n{crop_output_path.get()}")
Explanation:
Uses Pillow’s crop() to select the rectangle.
Saves the cropped image to the chosen path.
Step 9: Zoom and Aspect Ratio Controls
zoom_scale = tk.DoubleVar(master=app, value=1.0)
def set_aspect(ratio):
if img is None: return
# Calculate crop size based on aspect ratio
new_w = img.width
new_h = int(new_w / ratio)
if new_h > img.height:
new_h = img.height
new_w = int(new_h * ratio)
crop_x.set((img.width-new_w)//2)
crop_y.set((img.height-new_h)//2)
crop_width.set(new_w)
crop_height.set(new_h)
aspect_ratio_value.set(ratio)
draw_rectangle()
Explanation:
Zooming changes how the image is displayed, not the actual image.
Aspect ratio buttons (1:1, 16:9, etc.) adjust crop rectangle proportionally.
Step 10: UI Layout
# Left Frame: Canvas
canvas_frame = tb.Frame(app)
canvas_frame.pack(side="left", fill="both", expand=True)
canvas = tk.Canvas(canvas_frame, width=600, height=600, bg="#222222")
canvas.pack(fill="both", expand=True)
# Right Frame: Controls
control_frame = tb.Frame(app)
control_frame.pack(side="right", fill="y", padx=5, pady=5)
tb.Label(control_frame, text="Zoom:").pack(anchor="w")
zoom_slider = tb.Scale(control_frame, from_=0.1, to=3.0, orient="horizontal", variable=zoom_scale, command=lambda v: update_canvas_image())
zoom_slider.pack(fill="x", pady=5)
Explanation:
Left side contains the canvas for images.
Right side contains sliders, aspect buttons, preview, and save buttons.
Step 11: Event Handling (Drag & Resize)
canvas.bind("<ButtonPress-1>", start_drag)
canvas.bind("<B1-Motion>", drag_motion)
canvas.bind("<ButtonRelease-1>", end_drag)
canvas.tag_bind("handle","<ButtonPress-1>", start_drag_handle)
canvas.tag_bind("handle","<B1-Motion>", drag_handle)
canvas.tag_bind("handle","<ButtonRelease-1>", end_drag_handle)
Explanation:
Allows dragging and resizing the crop rectangle.
Handles are interactive corner and edge points.
Step 12: Run the App
Finally, run the main loop:
app.mainloop()
Explanation:
This keeps the GUI running until the user closes it.
Step 13: Try It Out
Open one or more images with Open Images.
Drag or resize the crop rectangle.
Adjust zoom and aspect ratio.
Click Save Cropped to export.
✅ This tutorial covers the core features of Pro Image Cropper Plus. For full code and extras like undo/redo, batch navigation, and live preview, check the GitHub repo:
ProImageCropperPlus

Top comments (0)