Creating a GUI-Based Image to PDF Converter in Python and Compiling It to an Executable

yahia almarafi
5 min readMar 20, 2024

--

Introduction

In a fast-paced digital environment, the conversion of images to PDFs is a common necessity for professionals and casual users alike. While numerous online services offer this functionality, they often come with strings attached — be it the addition of watermarks, limitations on the number of images, or concerns about uploading sensitive data to a third-party server. It’s not uncommon to find yourself constrained by these limitations just when you need functionality the most. That’s why we are embarking on a journey to build our bespoke program — a tool that allows us to convert an unlimited number of images to PDF format, free of charge and without any restrictive caveats. It’s time to create a solution that works on your terms, ensuring your documents are handled with the privacy and flexibility you deserve.

The Framework: Python and Tkinter

Our journey begins by setting up our workspace. Python offers Tkinter as a built-in library, so no extra installation is needed for it. However, we’ll need to ensure the Pillow library, a fork of Python Imaging Library (PIL), is available since it provides us with the image processing capabilities we require.

First things first, let’s install Pillow via pip:

pip install Pillow

With the installation out of the way, we turn our attention to crafting the user interface.

Designing the Interface

A good application is like a story; it should have a beginning, a middle, and an end. The beginning is where the user starts: selecting the images. The middle is the process: arranging and possibly removing images. The end is the grand finale: the creation of the PDF.

Let’s start by writing the script for our GUI:

import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image

def select_images():
file_types = [
('Image files', '*.jpeg *.jpg *.png *.gif *.bmp'),
('All files', '*.*')
]
file_paths = filedialog.askopenfilenames(title='Select Images', filetypes=file_types)
# Display the selected files to the user
for path in file_paths:
listbox.insert(tk.END, path)

def remove_selected_images():
selected_indices = listbox.curselection()
# Must delete from the end towards the beginning to maintain correct indices
for i in reversed(selected_indices):
listbox.delete(i)

def convert_to_pdf():
paths = listbox.get(0, tk.END)
if not paths:
messagebox.showwarning('No Images Selected', 'Please select one or more images to convert.')
return
try:
images = [Image.open(path).convert('RGB') for path in paths]
if not images:
messagebox.showerror('Error', 'No images to convert.')
return
output_pdf_path = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF files", "*.pdf")])
if not output_pdf_path:
return # User cancelled save
images[0].save(output_pdf_path, save_all=True, append_images=images[1:])
messagebox.showinfo('Success', 'The images have been successfully converted to PDF!')
except Exception as e:
messagebox.showerror('Error', f'An error occurred: {e}')

root = tk.Tk()
root.title('Image to PDF Converter')
root.geometry('400x300')

listbox = tk.Listbox(root, selectmode=tk.EXTENDED)
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

scrollbar = tk.Scrollbar(root)
scrollbar.pack(side=tk.LEFT, fill=tk.Y)

listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)

select_button = tk.Button(root, text='Select Images', command=select_images)
select_button.pack(fill=tk.X)

remove_button = tk.Button(root, text='Remove Selected Images', command=remove_selected_images)
remove_button.pack(fill=tk.X)

convert_button = tk.Button(root, text='Convert to PDF', command=convert_to_pdf)
convert_button.pack(fill=tk.X)

root.mainloop()

In this segment of code, we lay the foundation of our application by assembling the main window, which serves as the canvas for our GUI elements. Within this window, we place:

  • A List Box for showcasing the paths of selected images, allowing users to see and review their choices at a glance.
  • Buttons that act as the interactive components:
  • The Select Images button is linked to the select_images function, enabling users to browse and choose images they wish to include in the PDF.
  • The Remove Selected Images button connects to the remove_selected_images function, giving users the flexibility to deselect any images before the final conversion.
  • The Convert to PDF button triggers the convert_to_pdf function, initiating the conversion process of the selected images into a single PDF file.

Each element is meticulously crafted and bound to its respective function, ensuring a seamless and user-friendly experience as we navigate through the process of transforming images into a PDF document.

Adding Life to the Interface: Selecting and Managing Images

The journey begins with the act of selecting images. Through the select_images function, we introduce a file dialog that filters for image files, allowing users the freedom to choose multiple files at once. As these files are selected, their paths are displayed within the list box, granting users a transparent overview of their selections.

Recognizing that decisiveness can evolve, we’ve integrated the remove_selected_images function. This feature grants users the autonomy to reconsider their choices, deselecting any images that no longer align with their vision. By pinpointing the selected images in the list box and removing them, this function ensures the resulting PDF will encapsulate only the images deemed perfect by the user.

The Alchemical Process: Converting Images to a PDF

At the heart of our application lies the convert_to_pdf function — the catalyst for transformation. This pivotal function engages each selected image, converting it to the RGB color space to guarantee its authentic representation in the PDF.

We don’t merely aim for conversion; we strive for excellence. By setting the PDF’s DPI to 300, we ensure our output meets the high-resolution demands of professional contexts. The fruition of this process is marked by a congratulatory message box, celebrating the creation of the new PDF.

Error Handling: Ensuring a Smooth Experience

In our quest for perfection, we prepare for the inevitable: errors. Our approach is not to avoid but to address them with grace. Encapsulating the convert_to_pdf function within a try-except block, we capture exceptions and present them to the user through an error message box. This meticulous attention to error handling cultivates a bond of trust and reliability with our users.

The Final Step: Compiling to an Executable

To extend our reach beyond the Python-savvy, we embrace PyInstaller for its prowess in transforming our script into an executable file. This transformation is as straightforward as executing a single command:

pyinstaller --onefile --windowed --icon=icon.ico ImageToPDFConverter.py

This bundles our application into a single file with a windowed application, without a console window, and even allows us to set an icon for our executable, giving it a professional appearance.

This command not only signifies the culmination of our development journey but also marks the beginning of wider accessibility, allowing users without Python installed to benefit from our application.

Closing Thoughts: The Joy of Creation

What we’ve created here is more than just a utility; it’s a testament to the power of Python, the versatility of Tkinter, and the capabilities of Pillow. It represents the potential within each developer to create tools that make life a little easier and workflows a little smoother.

We encourage you to take this foundation and build upon it. Maybe add a feature to rearrange the images within the list box, or include image editing capabilities before the conversion. The possibilities are limited only by your imagination.

--

--

yahia almarafi

Data Analyst passionate about automation & web scraping. Here to share insights on making data work smarter. Let's explore data together