How to Create an Image Editor Project in Python Using Tkinter
In this Python tutorial, we will see how to create a simple photo editor application using Tkinter for the GUI and the Pillow library for image manipulation.
This photo editor application allows users to open an image and apply various editing effects such as blur, grayscale, brightness enhancement, rotation, color inversion, edge detection, and mirroring.
Users can also crop the image interactively.
What We Are Gonna Use In This Project:
- Python Programming Language.- Tkinter for GUI.
- VS Code Editor.
- VS Code Editor.
Project Source Code:
import tkinter as tk
from tkinter import filedialog, simpledialog
# pip install Pillow
from PIL import Image, ImageTk, ImageFilter, ImageEnhance, ImageOps, ImageChops
class PhotoEditorApp:
def __init__(self, root):
self.root = root
self.root.title("Photo Editor")
self.root.geometry("750x450")
self.canvas = tk.Canvas(self.root, bg="white")
self.canvas.pack(fill=tk.BOTH, expand=True)
# Create menu bar
self.menubar = tk.Menu(self.root)
self.root.config(menu = self.menubar)
# Create File menu with Open and Exit options
self.file_menu = tk.Menu(self.menubar, tearoff=0)
self.menubar.add_cascade(label="File", menu = self.file_menu)
self.file_menu.add_command(label = "Open", command = self.open_image)
self.file_menu.add_separator()
self.file_menu.add_command(label = "Exit", command = self.root.quit)
# Create Edit menu with various image manipulation options
self.edit_manu = tk.Menu(self.menubar, tearoff = 0)
self.menubar.add_cascade(label = "Edit", menu=self.edit_manu)
self.edit_manu.add_command(label = "Blur", command = self.apply_blur)
self.edit_manu.add_command(label = "Grayscale", command = self.apply_grayscale)
self.edit_manu.add_command(label = "Enhance Brightness",
command = self.enhance_brightness)
self.edit_manu.add_command(label = "Rotate", command = self.rotate_image)
self.edit_manu.add_command(label = "Crop", command = self.crop_image)
self.edit_manu.add_command(label = "Invert Colors",
command = self.inver_colors)
self.edit_manu.add_command(label = "Edge Detection",
command = self.edge_detection)
self.edit_manu.add_command(label = "Mirror", command = self.mirror_image)
self.edit_manu.add_command(label = "Original State",
command = self.display_original_state)
# Variables for cropping
self.crop_start_x = None
self.crop_start_y = None
self.crop_rect = None
# Bind events for cropping
self.canvas.bind("<Button-1>", self.start_crop)
self.canvas.bind("<B1-Motion>", self.update_crop)
self.canvas.bind("<ButtonRelease-1>", self.crop_image)
def open_image(self):
# Open a file dialog to select an image file
file_path = filedialog.askopenfilename(filetypes = [("Image Files" ,
"*.png *.jpg *.jpeg *.bmp *.gif")])
if file_path:
# Open the selected image file using PIL
self.image = Image.open(file_path)
# Save a copy of the original image
self.original_image = self.image.copy()
self.image_tk = ImageTk.PhotoImage(self.image)
# Display the image on the canvas
self.canvas.create_image(0,0, anchor = tk.NW, image=self.image_tk)
def apply_blur(self):
# Apply a blur filter to the image
if self.image:
blurred_image = self.image.filter(ImageFilter.BLUR)
self.display_image(blurred_image)
def apply_grayscale(self):
# Convert the image to grayscale
if self.image:
grayscale_image = self.image.convert("L")
self.display_image(grayscale_image)
def enhance_brightness(self):
# Enhance the brightness of the image
if self.image:
enhancer = ImageEnhance.Brightness(self.image)
enhanced_image = enhancer.enhance(1.5)
self.display_image(enhanced_image)
def rotate_image(self):
# Rotate the image based on user input
if self.image:
degrees = simpledialog.askinteger("Rotate Image",
"Enter rotation angle(degrees):", parent = self.root)
if degrees:
rotated_image = self.image.rotate(degrees, expand=True)
self.display_image(rotated_image)
def inver_colors(self):
# Invert the colors of the image
if self.image:
inverted_image = ImageOps.invert(self.image)
self.display_image(inverted_image)
def edge_detection(self):
# Apply edge detection filter to the image
if self.image:
edge_detection = self.image.filter(ImageFilter.FIND_EDGES)
self.display_image(edge_detection)
def mirror_image(self):
# Mirror the image horizontally
if self.image:
mirrored_image = ImageOps.mirror(self.image)
self.display_image(mirrored_image)
def start_crop(self, event):
# Record the starting position of the crop
self.crop_start_x = self.canvas.canvasx(event.x)
self.crop_start_y = self.canvas.canvasy(event.y)
def update_crop(self, event):
"""
Update the crop rectangle during mouse motion.
Args:
event: Mouse event containing information about the current mouse position.
"""
# Get current mouse position relative to the canvas
cur_x = self.canvas.canvasx(event.x)
cur_y = self.canvas.canvasy(event.y)
# Delete previous crop rectangle if it exists
if self.crop_rect:
self.canvas.delete(self.crop_rect)
# Create a new crop rectangle based on the starting position
# and current position
self.crop_rect = self.canvas.create_rectangle(self.crop_start_x,
self.crop_start_y, cur_x, cur_y, outline="red")
def crop_image(self, event=None):
"""
Crop the image based on the crop rectangle.
Args:
event: Mouse event triggering the crop action (optional).
"""
if self.crop_rect:
# Get current mouse position relative to the canvas
if event:
cur_x = self.canvas.canvasx(event.x)
cur_y = self.canvas.canvasy(event.y)
# Determine the coordinates of the crop rectangle
x1, y1 = min(self.crop_start_x, cur_x), min(self.crop_start_y, cur_y)
x2, y2 = max(self.crop_start_x, cur_x), max(self.crop_start_y, cur_y)
# Crop the image using the determined coordinates
cropped_image = self.image.crop((x1, y1, x2, y2))
self.display_image(cropped_image)
# Delete the crop rectangle
self.canvas.delete(self.crop_rect)
self.crop_rect = None
def display_original_state(self):
# Display the image in its original state
if self.image:
self.display_image(self.original_image)
def display_image(self, img):
# Display the given image on the canvas
self.image = img
self.image_tk = ImageTk.PhotoImage(self.image)
self.canvas.create_image(0, 0, anchor = tk.NW, image = self.image_tk)
if __name__ == "__main__":
root = tk.Tk()
app = PhotoEditorApp(root)
root.mainloop()
The Final Result:
![]() |
Edge Detection |
![]() |
GrayScale |
![]() |
rotate (180 degree) |
![]() |
brightness enhancement |
![]() |
grayscale |
![]() |
blur |
![]() |
invert colors |
![]() |
edge detection |
![]() |
crop image |
![]() |
mirror |