When I work with scanned documents, screenshots, receipts, or batches of photos, converting each image manually into a PDF quickly becomes repetitive. A small Python desktop application solves that problem nicely.
For this project, I wanted more than a simple image-to-PDF script. The application needs a graphical user interface, multiple image selection, image ordering, validation, page-size options, portrait and landscape orientation, and reliable PDF creation.
The result is a practical Image-to-PDF Converter in Python that works well as a beginner-friendly desktop automation project.
What We Will Build
This is a GUI application, meaning users interact with buttons, lists, and controls instead of typing commands in a terminal.
The converter includes:
- Multiple image selection
- Up to 500 images
- Duplicate image prevention
- Image ordering
- Remove and Clear All options
- A4, Letter, Legal, and A3 page sizes
- Portrait and Landscape orientation
- Corrupted-image detection
- Unsupported-format validation
- File permission checks
- PDF filename validation
- Existing-file detection
- Conversion progress indicator
- Option to open the generated PDF
The project uses Python 3.10 or later. The supplied project uses Pillow, img2pdf, and ttkbootstrap for image processing, PDF conversion, and the graphical interface.
Set Up the Python Image-to-PDF Project
I recommend keeping the project separated into modules instead of putting everything inside one large Python file.
A clean structure looks like this:
Image-to-PDF-Converter/
│
├── main.py
├── requirements.txt
├── README.md
│
├── assets/
│
└── src/
├── __init__.py
├── app.py
├── image_manager.py
├── pdf_converter.py
├── theme.py
└── ui.py
This structure makes the application easier to maintain. For example, PDF-specific logic can stay inside pdf_converter.py, while image-list operations can remain inside image_manager.py.
If you are new to Python modules, separating functionality across files also gives you useful practice with organizing a Python Image-to-PDF project and importing a Python file from the same directory
Install the required packages
Create a requirements.txt file:
Pillow==11.0.0
img2pdf==0.5.1
ttkbootstrap==1.10.1
Then install the dependencies:
pip install -r requirements.txt
The project uses these specific package versions in its current setup.
Create the Image-to-PDF Converter GUI Using Python
For the interface, I use Tkinter, Python’s built-in GUI toolkit, together with ttkbootstrap for a cleaner appearance.
You can start with a root window:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Image to PDF Converter")
root.geometry("1000x650")
root.mainloop()
The root object represents the main application window.
From there, create separate areas for the selected images and PDF settings.

For more Tkinter layout techniques, the Python Tkinter frame tutorial is useful when organizing application sections.
Add Images to the Application
The first important feature in a Python Image-to-PDF application is selecting multiple images. Use askopenfilenames() so the user can select several files at once. Here is the code to add images to the application:
from tkinter import filedialog
files = filedialog.askopenfilenames(
title="Select Images",
filetypes=[
("Image Files", "*.png *.jpg *.jpeg *.bmp *.webp")
]
)
The dialog returns a collection of selected file paths.
I then add those paths to an internal list:
self.images = []
for file in files:
if file not in self.images:
self.images.append(file)

The duplicate check matters. Without it, selecting the same image twice could silently create duplicate pages in the PDF.
If you frequently work with file paths in Python, you may also find how to check if a file exists in Python useful.
Limit the number of images
Large batches can consume significant memory and processing time. For this application, I use a maximum of 500 images.
MAX_IMAGES = 500
warning_shown = False
for file in files:
if file in self.images:
continue
if len(self.images) < MAX_IMAGES:
self.images.append(file)
else:
if not warning_shown:
messagebox.showwarning(
"Maximum Images Reached",
"Only the first 500 images have been added.\n\n"
"The remaining images were skipped."
)
warning_shown = True

The warning_shown flag prevents the same warning from appearing repeatedly.
That small detail makes a big difference when someone accidentally selects 700 or 1,000 images while working with a Python Image-to-PDF application.
Display and Manage the Selected Images
After selecting images, the application should display them in a scrollable area.
Each image entry can contain:
- Thumbnail
- Filename
- Move Up button
- Move Down button
- Remove button
For example:
for img_path in self.images:
frame = ttk.Frame(self.image_frame)
frame.pack(fill="x", pady=5)
ttk.Label(
frame,
text=os.path.basename(img_path)
).pack(side="left", padx=10)
ttk.Button(
frame,
text="▲",
command=lambda p=img_path: self.move_up(p)
).pack(side="right")
ttk.Button(
frame,
text="▼",
command=lambda p=img_path: self.move_down(p)
).pack(side="right")

The important idea here is that the application doesn’t convert images in the order they were originally selected. It converts them according to the current self.images list.
That means moving an image up or down changes its page position in the final PDF, making the Python Image-to-PDF application more flexible and easier to use.
You can also use a Python Tkinter scrollbar when the selected-image list becomes longer than the available window space.
Validate the Images Before Conversion
Validation is one of the most important parts of this application.
Checking only the file extension isn’t enough.
For example, someone could rename:
report.xlsx
to:
report.png
The filename looks like an image, but the actual file isn’t a valid PNG image.
Use Pillow to verify the file:
from PIL import Image
for image_path in self.images:
try:
with Image.open(image_path) as img:
img.verify()
except Exception:
messagebox.showerror(
"Corrupted Image",
f"The following image is corrupted or cannot be opened:\n\n"
f"{os.path.basename(image_path)}"
)
return

The verify() method checks whether Pillow can validate the image structure.
I prefer this validation before PDF creation because discovering a bad image halfway through conversion creates a much worse user experience in a Python Image-to-PDF application.
Check supported formats
You can also check the actual format reported by Pillow:
supported_formats = {"JPEG", "PNG", "BMP", "TIFF", "WEBP"}
for image_path in self.images:
try:
with Image.open(image_path) as img:
if img.format not in supported_formats:
messagebox.showerror(
"Unsupported Image Format",
f"Unsupported format:\n\n"
f"{os.path.basename(image_path)}\n"
f"Format: {img.format}"
)
return
except Exception:
returnThis is stronger than trusting the filename extension.
Add PDF Page Size and Orientation
The PDF settings section contains two controls:
self.page_size = ttk.Combobox(
settings,
values=["A4", "Letter", "Legal", "A3"],
state="readonly"
)
self.orientation = ttk.Combobox(
settings,
values=["Portrait", "Landscape"],
state="readonly"
)
Using state="readonly" is important.
It prevents users from typing arbitrary values such as:
ABC12345Random
The user can select only one of the supported options.
For the interface, this makes the controls behave like a proper selection list rather than editable text boxes.
Convert the Images to PDF
Once the images pass validation, the application can create the PDF in the Python Image-to-PDF converter.
A simple conversion using img2pdf looks like this:
import img2pdf
with open(output_file, "wb") as pdf_file:
pdf_file.write(
img2pdf.convert(self.images)
)
The image list controls the order of pages.
So if the list contains:
1. cover.jpg
2. page1.jpg
3. page2.jpg
the PDF follows that same order.
For more PDF-related Python work, the URL list also includes resources covering saving multiple pages to PDF with Matplotlib.
Pro Tip: I’ve found that validation should happen before opening the output file. That prevents the application from creating an incomplete PDF when one selected image fails.
Validate the PDF Output
The Save dialog should also have validation.
First, handle cancellation:
output_file = filedialog.asksaveasfilename(
title="Save PDF",
defaultextension=".pdf",
filetypes=[
("PDF Files", "*.pdf")
]
)
if not output_file:
messagebox.showinfo(
"PDF Creation Cancelled",
"PDF creation has been cancelled."
)
return
Next, check whether the file already exists:
if os.path.exists(output_file):
overwrite = messagebox.askyesno(
"File Already Exists",
"A PDF with this name already exists.\n\n"
"Do you want to replace it?"
)
if not overwrite:
return
This prevents accidental overwriting.
You can also check the filename before conversion:
filename = os.path.basename(output_file)
if not filename or filename.strip() == ".pdf":
messagebox.showwarning(
"Invalid Filename",
"Please enter a valid PDF filename."
)
return
For file-management tasks, how to overwrite a file in Python provides useful background.
Add a Progress Indicator
PDF conversion can take time when the user selects many images.
A progress bar gives immediate visual feedback and lets the user see how the Python Image-to-PDF conversion is progressing. Here is the code to add the progress indicator.
self.progress = ttk.Progressbar(
self.root,
mode="indeterminate",
bootstyle="success-striped"
)
Before conversion:
self.progress.pack(
fill="x",
padx=15,
pady=(5, 10)
)
self.progress.start(10)
self.root.update_idletasks()
After conversion:
self.progress.stop()
self.progress.pack_forget()
This doesn’t calculate the exact percentage of work completed. Instead, the animated bar tells the user that processing continues.
For related Tkinter work, see the Python Tkinter progress bar tutorial.
Handle Conversion Errors
Never assume file conversion will always succeed.
A user might select a locked file, choose a protected folder, or encounter an unexpected image-processing problem. Proper error handling ensures the Python Image-to-PDF application can handle these situations gracefully instead of crashing.
Use exception handling:
try:
with open(output_file, "wb") as pdf_file:
pdf_file.write(
img2pdf.convert(self.images)
)
except PermissionError:
messagebox.showerror(
"Save Location Permission",
"The PDF could not be saved to this location."
)
except Exception as e:
messagebox.showerror(
"Unexpected Exception",
f"An unexpected error occurred.\n\n"
f"Error Details:\n{str(e)}"
)
Exception handling means catching runtime errors so the application can respond gracefully instead of crashing.
If you’re building larger Python applications, Python exception handling is an important concept to understand.
Open the PDF After Creation
After successful conversion, I like to give the user the option to open the generated PDF immediately.
On Windows:
open_pdf = messagebox.askyesno(
"PDF Created Successfully",
"Your PDF has been created successfully.\n\n"
"Would you like to open it now?"
)
if open_pdf:
os.startfile(output_file)
This avoids making users manually navigate to the output folder.
Things to Keep in Mind
- Validate actual image content: Don’t rely only on
.jpgor.pngextensions. A renamed or damaged file can still have an image-looking filename. - Limit large batches: Processing hundreds of images can require significant memory. A sensible maximum keeps the application responsive.
- Prevent duplicates: Always check the image list before adding a new file. Duplicate pages can otherwise appear unexpectedly.
- Use read-only settings: Page size and orientation should accept only supported values. Don’t allow arbitrary text input.
- Handle file permissions: The selected output folder might not allow writing. Catch
PermissionErrorand explain the problem clearly. - Keep the UI responsive: Large conversions can take time. A progress indicator helps users understand that the application is still working.
Frequently Asked Questions
How do I convert images to PDF using Python?
You can use Python libraries such as Pillow or img2pdf to create PDF documents from image files. For a desktop application, combine the conversion library with Tkinter or ttkbootstrap to create the user interface.
How many images can this Image-to-PDF Converter handle?
This implementation limits the selection to 500 images per conversion. Additional images are skipped instead of repeatedly displaying the maximum-limit warning.
Which image formats does the Python converter support?
The application supports JPG, JPEG, PNG, BMP, WEBP, and TIFF files. The application also validates the actual image content before conversion.
How can I detect a corrupted image in Python?
Use Pillow’s Image.open() together with img.verify(). This lets you detect files that Pillow cannot validate as proper images before starting PDF creation.
Can Python create both portrait and landscape PDFs?
Yes. The PDF conversion logic can apply the selected page dimensions and orientation before generating the document. This lets users create pages in either portrait or landscape format.
Can I change the order of images before creating the PDF?
Yes. Store the selected image paths in a Python list and provide Move Up and Move Down controls. The PDF converter then processes the list in its current order.
Building an Image-to-PDF Converter in Python is a practical project that brings together GUI development, image processing, file handling, validation, and PDF generation. By combining these concepts, you can create a useful desktop application that converts multiple images into a single PDF efficiently.
This project also provides a strong foundation for extending the application with features such as image reordering, page customization, file validation, progress indicators, and improved error handling. It is a great example of how Python can be used to turn individual programming concepts into a complete, real-world application.
You May Also Like
- Get the file extension from a file name in Python
- Save images to a file in Python
- Create a file in Python if it doesn’t exist
- Get the directory of a file in Python
- Create a Python file in the terminal

Bijay Kumar is an experienced Python and AI professional who enjoys helping developers learn modern technologies through practical tutorials and examples. His expertise includes Python development, Machine Learning, Artificial Intelligence, automation, and data analysis using libraries like Pandas, NumPy, TensorFlow, Matplotlib, SciPy, and Scikit-Learn. At PythonGuides.com, he shares in-depth guides designed for both beginners and experienced developers. More about us.