Robert Johns | 23 Jan, 2025
Fact checked by Jim Markus

How To Create Your Own Image Editor App with Python

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!

By Robert Johns

Technical Editor for Hackr.io | 15+ Years in Python, Java, SQL, C++, C#, JavaScript, Ruby, PHP, .NET, MATLAB, HTML & CSS, and more... 10+ Years in Networking, Cloud, APIs, Linux | 5+ Years in Data Science | 2x PhDs in Structural & Blast Engineering

View all post by the author

Subscribe to our Newsletter for Articles, News, & Jobs.

I accept the Terms and Conditions.

Disclosure: Hackr.io is supported by its audience. When you purchase through links on our site, we may earn an affiliate commission.

In this article

Learn More

Please login to leave comments