Introduction
In this project, we will create an image viewer application using Python and Tkinter. The image viewer will allow you to open an image file, display it, and perform actions such as zooming in, zooming out, and rotating the image. We will use the PIL (Python Imaging Library) library to handle image operations and Tkinter for creating the graphical user interface.
👀 Preview

🎯 Tasks
In this project, you will learn:
- How to create a GUI application using Tkinter.
- How to handle image loading and display using PIL.
- How to implement zoom in, zoom out, and rotate functionality for the displayed image.
🏆 Achievements
After completing this project, you will be able to:
- Develop a functional image viewer application using Python and Tkinter.
- Integrate image processing capabilities using the PIL library.
- Implement basic image manipulation features such as zooming and rotating.
Create the project files
First, create a new file named ~/project/image_viewer.py and open it in a text editor or an integrated development environment (IDE).
cd ~/project
touch image_viewer.py
Import the required libraries
In the image_viewer.py file, import the necessary libraries:
import tkinter as tk
from tkinter import filedialog
from tkinter import messagebox
from PIL import Image, ImageTk
import os
The tkinter library provides the functionality to create GUI elements, filedialog allows us to open a file dialog for selecting an image file, messagebox is used to display messages to the user, PIL is used for image processing, and os provides functions for interacting with the operating system.
Create the ImageViewer class
Define a new class named ImageViewer that will handle the image viewer application:
class ImageViewer:
def __init__(self, root):
self.root = root
self.root.title('LabEx Image Viewer')
self.root.geometry('800x600')
self.root.configure(background='white')
self.image_label = tk.Label(self.root)
self.image_label.pack()
self.control_frame = tk.Frame(self.root)
self.control_frame.pack()
self.open_button = tk.Button(self.control_frame, text='Open', command=self.open_image)
self.open_button.pack(side='left')
self.close_button = tk.Button(self.control_frame, text='Quit', command=self.root.quit)
self.close_button.pack(side='left')
self.zoom_in_button = tk.Button(self.control_frame, text='Zoom In', command=self.zoom_in)
self.zoom_in_button.pack(side='left')
self.zoom_out_button = tk.Button(self.control_frame, text='Zoom Out', command=self.zoom_out)
self.zoom_out_button.pack(side='left')
self.rotate_button = tk.Button(self.control_frame, text='Rotate', command=self.rotate)
self.rotate_button.pack(side='left')
self.current_image_path = ''
self.zoom_level = 1
In the __init__ method, we initialize the root window with a title, size, and background color. Then, we create a label to display the image and a frame to hold the control buttons (Open, Quit, Zoom In, Zoom Out, Rotate). We also define instance variables to keep track of the current image path and the zoom level.
Implement the open_image method
Add the open_image method to the ImageViewer class:
def open_image(self):
self.current_image_path = filedialog.askopenfilename(defaultextension=".jpg",
filetypes=[("All Files", "*.*"), ("JPEG", ".jpg"), ("PNG", ".png"), ("GIF", ".gif")])
if self.current_image_path:
self.load_image()
The open_image method opens a file dialog for selecting an image file. It sets the current_image_path variable to the selected file path and calls the load_image method to display the image.
Implement the load_image method
Implement the load_image method:
def load_image(self):
image = Image.open(self.current_image_path)
## Resize image for display
max_size = (600, 600)
image.thumbnail(max_size)
## Save a reference to the original image (for zooming/rotating)
self.original_image = image
## Create a Tkinter-compatible image
self.tk_image = ImageTk.PhotoImage(image)
self.image_label.configure(image=self.tk_image)
self.zoom_level = 1
The load_image method opens the selected image file using PIL's Image.open method. It resizes the image to fit within a maximum size of 600x600 pixels using the thumbnail method. Then, it saves a reference to the original image for zooming and rotating purposes. Next, it creates a Tkinter-compatible image using ImageTk.PhotoImage and updates the image label to display the loaded image. Finally, it sets the initial zoom level to 1.
Implement the zoom_in method
Implement the zoom_in method:
def zoom_in(self):
if not self.current_image_path: ## No image loaded
return
self.zoom_level *= 1.1 ## Increase zoom level by 10%
self.zoom_or_rotate_image()
The zoom_in method checks if an image is loaded. If no image is loaded, it returns. Otherwise, it increases the zoom level by 10% and calls the zoom_or_rotate_image method to update the displayed image.
Implement the zoom_out method
Implement the zoom_out method:
def zoom_out(self):
if not self.current_image_path: ## No image loaded
return
if self.zoom_level < 0.1: ## Limit outwards zoom
return
self.zoom_level *= 0.9 ## Decrease zoom level by 10%
self.zoom_or_rotate_image()
The zoom_out method checks if an image is loaded. If no image is loaded, it returns. If the zoom level is already below 0.1, meaning the image is zoomed out to the limit, it returns. Otherwise, it decreases the zoom level by 10% and calls the zoom_or_rotate_image method to update the displayed image.
Implement the rotate method
Implement the rotate method:
def rotate(self):
if not self.current_image_path: ## No image loaded
return
self.original_image = self.original_image.rotate(-90)
self.zoom_or_rotate_image()
The rotate method checks if an image is loaded. If no image is loaded, it returns. Otherwise, it rotates the original image by -90 degrees using the rotate method from PIL and calls the zoom_or_rotate_image method to update the displayed image.
Implement the zoom_or_rotate_image method
Implement the zoom_or_rotate_image method:
def zoom_or_rotate_image(self):
## Zoom and rotate original image, convert to Tk image, and display
new_image = self.original_image.resize((int(self.original_image.width * self.zoom_level),
int(self.original_image.height * self.zoom_level)))
self.tk_image = ImageTk.PhotoImage(new_image)
self.image_label.configure(image=self.tk_image)
The zoom_or_rotate_image method resizes the original image based on the current zoom level. It creates a new image with the updated size using the resize method from PIL. Then, it converts the new image to a Tkinter-compatible image using ImageTk.PhotoImage and updates the image label to display the updated image.
Create the main application loop
Add the following code at the end of the image_viewer.py file to create the main application loop:
if __name__ == '__main__':
root = tk.Tk()
app = ImageViewer(root)
root.mainloop()
This code creates a Tkinter root window, initializes an instance of the ImageViewer class, and starts the main application loop.
Switch to the Desktop and run the image_viewer.py file to test the application. You should see the following window:
python image_viewer.py

Summary
Congratulations! You have created an image viewer application using Python and Tkinter. The application allows you to open an image file, display it, and perform actions such as zooming in, zooming out, and rotating the image. You have learned how to use the PIL library for image processing and Tkinter for creating the graphical user interface. Feel free to customize the application further or explore additional features.



