How to Split an Image Into Pieces Using Python Tkinter
In this Python Tutorial, we will see how to create an Image Slicer application using python and tkinter.
When a user selects an image and specifies the number of slices, our Python script handles all the functionality including file reading, image processing, and dynamic grid generation.
Project Source Code:
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
class ImageSlicer(tk.Tk):
def __init__(self):
super().__init__()
# Set window properties
self.title("Image Slice")
self.geometry("900x500")
self.configure(bg="#fefefe")
# Create main container
self.main_container = tk.Frame(self, bg="#f7f7f7")
self.main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Create top frame for controls
self.control_frame = tk.Frame(self.main_container, bg="#f7f7f7")
self.control_frame.pack(fill=tk.X, pady=(0, 10))
# Create and place the upload button
self.upload_btn = tk.Button(self.control_frame, text="Upload Image",
bg="#2196F3", fg="white",
font=("Arial", 12, "bold"), padx=20, pady=8, bd=0,
command=self.upload_image,
cursor="hand2", activebackground="#1976D2")
self.upload_btn.pack(side=tk.LEFT, padx=5)
# Create spinboxes for rows and columns
self.rows_var = tk.StringVar(value="5")
self.cols_var = tk.StringVar(value="5")
row_frame = tk.Frame(self.control_frame, bg="#f7f7f7")
row_frame.pack(side=tk.LEFT, padx=20)
tk.Label(row_frame, text="Rows", bg="#f7f7f7",
font=("Arial", 12)).pack(side=tk.LEFT)
tk.Spinbox(row_frame, from_=2, to=20, width=5, textvariable=self.rows_var,
font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
col_frame = tk.Frame(self.control_frame, bg="#f7f7f7")
col_frame.pack(side=tk.LEFT)
tk.Label(col_frame, text="Columns", bg="#f7f7f7",
font=("Arial", 12)).pack(side=tk.LEFT)
tk.Spinbox(col_frame, from_=2, to=20, width=5, textvariable=self.cols_var,
font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
# Create frame for slices
self.slices_frame = tk.Frame(self.main_container, bg="#f7f7f7")
self.slices_frame.pack(fill=tk.BOTH, expand=True)
# Store the current image
self.current_image = None
def calculate_image_size(self):
"""Calculate the maximum size for the image to fit in the window"""
# Get window dimensions with padding
padding = 40 # Total padding (20px on each side)
max_width = self.winfo_width() - padding
max_height = self.winfo_height() - self.control_frame.winfo_height() - padding
if self.current_image:
# Get original image dimensions
img_width, img_height = self.current_image.size
# Calculate scaling factor to fit window
width_ratio = max_width / img_width
height_ratio = max_height / img_height
scale_factor = min(width_ratio, height_ratio)
# Calculate new dimensions
new_width = int(img_width * scale_factor)
new_height = int(img_height * scale_factor)
return new_width, new_height
return None
def upload_image(self):
"""Handle image upload and processing"""
file_path = filedialog.askopenfilename(filetypes=[
("Images Files", "*.jpg *.jpeg *.png")])
if file_path:
# Open and store the image
self.current_image = Image.open(file_path)
self.refresh_slices()
def refresh_slices(self):
"""Refresh the image slices with current settings"""
if not self.current_image:
return
# Clear previous slices
for widget in self.slices_frame.winfo_children():
widget.destroy()
# Get number of rows and columns
rows = int(self.rows_var.get())
cols = int(self.cols_var.get())
# Calculate new image size to fit window
new_size = self.calculate_image_size()
if not new_size:
return
# Resize the image
resized_image = self.current_image.resize(new_size, Image.Resampling.LANCZOS)
# Calculate slice dimensions
slice_width = new_size[0] // rows
slice_height = new_size[1] // cols
# Configure grid weights for even distribution
for i in range(rows):
self.slices_frame.grid_rowconfigure(i, weight=1)
for j in range(cols):
self.slices_frame.grid_columnconfigure(j, weight=1)
# Generate and display slices
for i in range(rows):
for j in range(cols):
# Calculate slice coordinates
left = j * slice_width
upper = i * slice_height
right = left + slice_width
lower = upper + slice_height
# Create the slice
slice_image = resized_image.crop((left, upper, right, lower))
tk_image = ImageTk.PhotoImage(slice_image)
# Create and place the label
slice_label = tk.Label(self.slices_frame, image=tk_image,
bg="#f7f7f7", relief="solid", borderwidth=0)
slice_label.image = tk_image
slice_label.grid(row=i, column=j, padx=0, pady=0, sticky="nsew")
if __name__ == "__main__":
app = ImageSlicer()
app.mainloop()
OUTPUT: