Have you ever wanted to build your own image editor app like Photoshop?
In this tutorial, I’ll show you how to create a Python-based image editing app with Tkinter for the graphical user interface (GUI) and Pillow for image manipulation. I love this project, as it's a fun and relatable way to combine practicality with programming.
By the end, you’ll have a functional app that can load, edit, and save images with various filters like blur, sharpen, and more. Let’s dive in!
Why Build a Python Image Editor?
An image editor is a fun and practical Python project that can enhance your skills. Here’s what you’ll learn:
- Using Pillow to apply various image filters and process images.
- Leveraging Tkinter to create a user-friendly graphical user interface.
- Understanding Object-Oriented Programming (OOP) to structure your application.
This project is not only educational but also practical, providing a real-world tool you can expand and improve. It's also a great addition to your portfolio, as it shows you can build something truly useful.
Let’s get started!
Project Prerequisites
Before we begin coding, let’s review the skills and tools needed for this tutorial.
Don’t worry if you’re not a Python expert just yet! Having a few basics under your belt will make this journey smoother and more enjoyable.
Basic Python Knowledge
You should be familiar with:
- Variables, functions, and loops.
- Basic file handling and exception handling.
Required Libraries
We’ll use the following Python libraries:
- Pillow (PIL) for image processing.
- Tkinter for creating the GUI (this comes pre-installed with Python).
If you don’t have Pillow installed, you can install it using this command:
pip install pillow
A Curious and Experimental Mind
For me, a willingness to experiment and make small adjustments is key to learning. Be ready to explore and debug as you go along!
Step 1: Set Up Your Project
Before I jump into coding, let’s set up the project:
1. Make sure Python is installed on your computer. If not, download it from the official Python website.
2. Open your favorite code editor or IDE.
3. Create a new Python file, for example, image_editor.py.
Step 2: Import Required Libraries
Let’s begin by importing the libraries we’ll use in this project:
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk, ImageFilter
Tkinter: For creating the graphical interface.
Pillow (PIL): For working with images and applying filters.
Step 3: Structuring the App with OOP
We’ll use Object-Oriented Programming (OOP) to build our app. Let’s start by creating the ImageEditorApp class and initializing it:
class ImageEditorApp:
def __init__(self, root):
self.root = root
self.root.title("Image Editing App")
self.root.geometry("1000x600")
self.root.configure(bg="#e6f7ff")
self.original_image = None
self.image = None
self.image_tk = None
self.create_widgets()
__init__: This special method initializes the app, setting up the main window and defining attributes for the images.
Attributes: self.original_image stores the original image, while self.image holds the current edited version.
Step 4: Adding Core Functionality
First, let's figure out how to load and display images:
def load_image(self):
file_path = filedialog.askopenfilename(
filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.gif")]
)
if file_path:
self.original_image = Image.open(file_path)
self.image = self.original_image.copy()
self.display_image()
def display_image(self):
if self.image:
aspect_ratio = self.image.width / self.image.height
new_width = 600
new_height = int(new_width / aspect_ratio)
self.image_tk = ImageTk.PhotoImage(self.image.resize((new_width, new_height), Image.LANCZOS))
self.image_label.config(image=self.image_tk)
load_image: Opens a file dialog to allow a user to select an image.
display_image: Resizes and displays the image in the app, including logic to ensure the image is shown at the correct aspect ratio.
Next, let's code in a method for applying filters:
def apply_filter(self, filter_type):
if self.image:
self.image = self.image.filter(filter_type)
self.display_image()
This method applies a selected filter to the current image and refreshes the display.
Now, let's add functionality to reset and save images after making changes:
def reset_image(self):
if self.original_image:
self.image = self.original_image.copy()
self.display_image()
def save_image(self):
if self.image:
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg"), ("All files", "*.*")],
)
if file_path:
self.image.save(file_path)
messagebox.showinfo("Success", "Image saved successfully!")
reset_image: Restores the original image to remove any previously applied filter effects.
save_image: Opens a save dialog and writes the image to the chosen file.
Step 5: Designing the GUI
Now let’s create the buttons and layout for the app using Tkinter.
I'd also encourage you to experiment with the design and layout, as it's an excellent way to enhance your understanding of UX/UI.
def create_widgets(self):
# Load Image Button
self.load_button = tk.Button(
self.root, text="Load Image", command=self.load_image, bg="#007bff", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.load_button.pack(pady=10)
# Image Display
self.image_label = tk.Label(self.root, bg="#e6f7ff")
self.image_label.pack(pady=10)
# Filters Section
self.filters_frame = tk.Frame(self.root, bg="#e6f7ff")
self.filters_frame.pack(pady=20)
filters = [
("Blur", ImageFilter.BLUR),
("Contour", ImageFilter.CONTOUR),
("Edge Enhance", ImageFilter.EDGE_ENHANCE),
("Emboss", ImageFilter.EMBOSS),
("Sharpen", ImageFilter.SHARPEN),
("Smooth", ImageFilter.SMOOTH),
]
for filter_name, filter_type in filters:
tk.Button(
self.filters_frame, text=filter_name, command=lambda ft=filter_type: self.apply_filter(ft),
bg="#007bff", fg="white", font=("Arial", 10), padx=10, pady=5
).pack(side="left", padx=10, pady=5)
# Reset and Save Buttons
self.buttons_frame = tk.Frame(self.root, bg="#e6f7ff")
self.buttons_frame.pack(pady=20)
self.reset_button = tk.Button(
self.buttons_frame, text="Reset Image", command=self.reset_image, bg="#28a745", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.reset_button.pack(side="left", padx=10)
self.save_button = tk.Button(
self.buttons_frame, text="Save Image", command=self.save_image, bg="#17a2b8", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.save_button.pack(side="left", padx=10)
Step 6: Running the App
Finally, let's initialize and run the image editor app:
if __name__ == "__main__":
root = tk.Tk()
app = ImageEditorApp(root)
root.mainloop()
With this block, we create the Tkinter root window, instantiate an instance of the ImageEditorApp class, and then start the Tkinter event loop with root.mainloop().
Full Program Source Code
Here’s the complete code for the Python image editor app:
'''
Hackr.io Python Tutorial: Image Editor App
'''
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk, ImageFilter
class ImageEditorApp:
def __init__(self, root):
self.root = root
self.root.title("Image Editing App")
# Adjusted window size to accommodate image and buttons
self.root.geometry("1000x600")
self.root.configure(bg="#e6f7ff")
self.original_image = None
self.image = None
self.image_tk = None
# UI Elements
self.create_widgets()
def create_widgets(self):
# Load Image Button
self.load_button = tk.Button(
self.root, text="Load Image", command=self.load_image, bg="#007bff", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.load_button.pack(pady=10)
# Image Display
self.image_label = tk.Label(self.root, bg="#e6f7ff")
self.image_label.pack(pady=10)
# Filters Section
self.filters_frame = tk.Frame(self.root, bg="#e6f7ff")
self.filters_frame.pack(pady=20)
filters = [
("Blur", ImageFilter.BLUR),
("Contour", ImageFilter.CONTOUR),
("Edge Enhance", ImageFilter.EDGE_ENHANCE),
("Emboss", ImageFilter.EMBOSS),
("Sharpen", ImageFilter.SHARPEN),
("Smooth", ImageFilter.SMOOTH),
]
for filter_name, filter_type in filters:
tk.Button(
self.filters_frame, text=filter_name, command=lambda ft=filter_type: self.apply_filter(
ft),
bg="#007bff", fg="white", font=("Arial", 10), padx=10, pady=5
).pack(side="left", padx=10, pady=5)
# Buttons Section
self.buttons_frame = tk.Frame(self.root, bg="#e6f7ff")
self.buttons_frame.pack(pady=20)
# Reset Button
self.reset_button = tk.Button(
self.buttons_frame, text="Reset Image", command=self.reset_image, bg="#28a745", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.reset_button.pack(side="left", padx=10)
# Save Image Button
self.save_button = tk.Button(
self.buttons_frame, text="Save Image", command=self.save_image, bg="#17a2b8", fg="white", font=("Arial", 12), padx=10, pady=5
)
self.save_button.pack(side="left", padx=10)
def load_image(self):
file_path = filedialog.askopenfilename(
filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.gif")]
)
if file_path:
self.original_image = Image.open(file_path)
self.image = self.original_image.copy()
self.display_image()
def display_image(self):
if self.image:
aspect_ratio = self.image.width / self.image.height
new_width = 600
new_height = int(new_width / aspect_ratio)
self.image_tk = ImageTk.PhotoImage(
self.image.resize((new_width, new_height), Image.LANCZOS))
self.image_label.config(image=self.image_tk)
def apply_filter(self, filter_type):
if self.image:
self.image = self.image.filter(filter_type)
self.display_image()
def reset_image(self):
if self.original_image:
self.image = self.original_image.copy()
self.display_image()
def save_image(self):
if self.image:
file_path = filedialog.asksaveasfilename(
defaultextension=".png",
filetypes=[("PNG files", "*.png"),
("JPEG files", "*.jpg"), ("All files", "*.*")],
)
if file_path:
self.image.save(file_path)
messagebox.showinfo("Success", "Image saved successfully!")
if __name__ == "__main__":
root = tk.Tk()
app = ImageEditorApp(root)
root.mainloop()
Wrapping Up
You’ve just built your own image editing app with Python while also sharpening your OOP skills, that's very cool indeed!
Hopefully, this project has shown you how Python can leverage libraries like pillow and tkinter to create practical applications.
Feel free to expand this project by:
- Adding more filters or editing options.
- Improving the GUI design with advanced styling.
- Supporting additional image file formats.
Happy coding!