GUI application to merge PDF files

INTRODUCTION

This program is a user-friendly PDF merger application built using Python’s tkinter library for the GUI and PyPDF2 for managing PDF files. It allows users to seamlessly select multiple PDF files, reorder them as needed, and merge them into a single document. The interface provides intuitive buttons for adding, removing, and reordering files, ensuring a smooth and efficient workflow. Once the desired order is set, the application merges the selected files and saves the output as a new PDF. It is designed for simplicity, making it accessible even to users with minimal technical experience.

PROGRAM

HERE IS THE FULL PROGRAM TO MERGE PDF FILES
import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
from PyPDF2 import PdfWriter, PdfReader

class PDFMergerApp:
    def init(self, master):
        self.master = master
        self.master.title("PDF Merger")
        self.master.geometry("600x700")
        self.master.configure(bg="#f0f0f0")

        self.file_list = []

        self.title_label = tk.Label(master, text="PDF Merger Application", font=("Arial", 14, "bold"), bg="#f0f0f0")
        self.title_label.pack(pady=10)

        self.button_frame = tk.Frame(master, bg="#f0f0f0")
        self.button_frame.pack(pady=5)

        self.add_button = tk.Button(self.button_frame, text="Add PDF Files", command=self.add_files, bg="#4CAF50", fg="white", padx=10, pady=5)
        self.add_button.pack(side=tk.LEFT, padx=5)

        self.remove_button = tk.Button(self.button_frame, text="Remove Selected Files", command=self.remove_file, bg="#f44336", fg="white", padx=10, pady=5)
        self.remove_button.pack(side=tk.LEFT, padx=5)

        self.reorder_button = tk.Button(self.button_frame, text="Reorder Files", command=self.reorder_files, bg="#2196F3", fg="white", padx=10, pady=5)
        self.reorder_button.pack(side=tk.LEFT, padx=5)

        self.merge_button = tk.Button(self.button_frame, text="Merge PDFs", command=self.merge_pdfs, bg="#FF9800", fg="white", padx=10, pady=5)
        self.merge_button.pack(side=tk.LEFT, padx=5)

        self.file_listbox = tk.Listbox(master, width=60, height=15, selectmode=tk.MULTIPLE, bg="#ffffff", fg="#333333", selectbackground="#e0e0e0")
        self.file_listbox.pack(pady=10)

    def add_files(self):
        files = filedialog.askopenfilenames(title="Select PDF Files", filetypes=[("PDF Files", "*.pdf")])
        for file in files:
            if file not in self.file_list:
                self.file_list.append(file)
                self.update_file_display()
            else:
                messagebox.showwarning("Duplicate File", f"{file} is already in the list.")

    def remove_file(self):
        selected_indices = self.file_listbox.curselection()
        if not selected_indices:
            messagebox.showwarning("Selection Error", "Please select at least one file to remove.")
            return
        for index in reversed(selected_indices):
            self.file_listbox.delete(index)
            del self.file_list[index]

    def reorder_files(self):
        try:
            selected_index = self.file_listbox.curselection()[0]
            new_position = simpledialog.askinteger("Reorder File", "Enter new position (1-based):", minvalue=1, maxvalue=len(self.file_list))
            if new_position is not None:
                new_position -= 1
                if 0 <= new_position < len(self.file_list):
                    self.file_list.insert(new_position, self.file_list.pop(selected_index))
                    self.update_file_display()
        except IndexError:
            messagebox.showwarning("Selection Error", "Please select a file to reorder.")

    def update_file_display(self):
        self.file_listbox.delete(0, tk.END)
        for index, file in enumerate(self.file_list, start=1):
            filename = file.split("/")[-1] 
            self.file_listbox.insert(tk.END, f"File {index}: {filename}")

    def merge_pdfs(self):
        if not self.file_list:
            messagebox.showwarning("No Files", "Please add some PDF files to merge.")
            return

        output_file = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF Files", "*.pdf")])
        if not output_file:
            return

        pdf_writer = PdfWriter()

        for file in self.file_list:
            try:
                pdf_reader = PdfReader(file)
                for page in range(len(pdf_reader.pages)):
                    pdf_writer.add_page(pdf_reader.pages[page])
            except Exception as e:
                messagebox.showerror("Error", f"Failed to read {file}. Error: {e}")
                return

        with open(output_file, "wb") as out_file:
            pdf_writer.write(out_file)

        messagebox.showinfo("Success", "PDFs merged successfully!")
        self.file_list.clear()
        self.file_listbox.delete(0, tk.END)

if name == "main":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()

EXPLANATION OF THE PROGRAM

1. Import Statements

import tkinter as tk
from tkinter import filedialog, messagebox, simpledialog
from PyPDF2 import PdfWriter, PdfReader

 

2.PDFMerge class

 

The PDF merge class encapsulates all functionalities of the PDF merger application.it manages the GUI components and the logic for adding,removing,reordering and merging PDF files
class PDFMergerApp:
    def __init__(self, master):
        ...
a.intilization(_init_)
def __init__(self, master):
    self.master = master
    self.master.title("PDF Merger")
    self.master.geometry("600x700")
    self.master.configure(bg="#f0f0f0")

    self.file_list = []

The constructor sets up the main window and initializes all GUI components and variables

b.title label

 

self.title_label = tk.Label(master, text="PDF Merger Application", font=("Arial", 14, "bold"), bg="#f0f0f0")
self.title_label.pack(pady=10)
c.button frames and buttons

 

self.button_frame = tk.Frame(master, bg="#f0f0f0")
self.button_frame.pack(pady=5)

self.add_button = tk.Button(self.button_frame, text="Add PDF Files", command=self.add_files, bg="#4CAF50", fg="white", padx=10, pady=5)
self.add_button.pack(side=tk.LEFT, padx=5)

self.remove_button = tk.Button(self.button_frame, text="Remove Selected Files", command=self.remove_file, bg="#f44336", fg="white", padx=10, pady=5)
self.remove_button.pack(side=tk.LEFT, padx=5)

self.reorder_button = tk.Button(self.button_frame, text="Reorder Files", command=self.reorder_files, bg="#2196F3", fg="white", padx=10, pady=5)
self.reorder_button.pack(side=tk.LEFT, padx=5)

self.merge_button = tk.Button(self.button_frame, text="Merge PDFs", command=self.merge_pdfs, bg="#FF9800", fg="white", padx=10, pady=5)
self.merge_button.pack(side=tk.LEFT, padx=5)
3.Methods of PDF merge class

 

a.adding files

opens a dialog for users to select multiple PDF files.check for duplicates and ensures the same file isn’t added multiple times. Adds the unique file path.

def add_files(self):
    files = filedialog.askopenfilenames(title="Select PDF Files", filetypes=[("PDF Files", "*.pdf")])
    for file in files:
        if file not in self.file_list:
            self.file_list.append(file)
            self.update_file_display()
        else:
            messagebox.showwarning("Duplicate File", f"{file} is already in the list.")
b.Removing files

Retrieves the indices of selected items in the listbox. removes the item from the listbox. Deletes the corresponding file path from the internal.

def remove_file(self):
    selected_indices = self.file_listbox.curselection()
    if not selected_indices:
        messagebox.showwarning("Selection Error", "Please select at least one file to remove.")
        return
    for index in reversed(selected_indices):
        self.file_listbox.delete(index)
        del self.file_list[index]
c.Recording files

Retrieves the index of the first selected file. removes the file from is current position. Inserts the file at the new position. updates the listbox to reflect the new order.handles the error and cathes cases where no file is selected and prompts the user accordingly.

the fidef reorder_files(self):
    try:
        selected_index = self.file_listbox.curselection()[0]
        new_position = simpledialog.askinteger("Reorder File", "Enter new position (1-based):", minvalue=1, maxvalue=len(self.file_list))
        if new_position is not None:
            new_position -= 1
            if 0 <= new_position < len(self.file_list):
                self.file_list.insert(new_position, self.file_list.pop(selected_index))
                self.update_file_display()
    except IndexError:
        messagebox.showwarning("Selection Error", "Please select a file to reorder.")
d.Updating files

Remove all current entries in the listbox.Extracts the filename from the full file path.adds each file with its index and filename to the listbox.

def update_file_display(self):
    self.file_listbox.delete(0, tk.END)
    for index, file in enumerate(self.file_list, start=1):
        filename = file.split("/")[-1] 
        self.file_listbox.insert(tk.END, f"File {index}: {filename}")
e.Merging files

opens a dialog for the user to specify the save location and filename. ensures the file is saved. filters to display only PDF files.intilizes a object to compile the merged PDF. opens,reads and iterates through each page of PDF.

def merge_pdfs(self):
    if not self.file_list:
        messagebox.showwarning("No Files", "Please add some PDF files to merge.")
        return

    output_file = filedialog.asksaveasfilename(defaultextension=".pdf", filetypes=[("PDF Files", "*.pdf")])
    if not output_file:
        return

    pdf_writer = PdfWriter()

    for file in self.file_list:
        try:
            pdf_reader = PdfReader(file)
            for page in range(len(pdf_reader.pages)):
                pdf_writer.add_page(pdf_reader.pages[page])
        except Exception as e:
            messagebox.showerror("Error", f"Failed to read {file}. Error: {e}")
            return

    with open(output_file, "wb") as out_file:
        pdf_writer.write(out_file)

    messagebox.showinfo("Success", "PDFs merged successfully!")
    self.file_list.clear()
    self.file_listbox.delete(0, tk.END)
4.Running the application

Ensures the following code runs only if the script is executed directly,not when imported as a module.intilizes the main tkinter window. starts the tkinter event loop which waits for user interactions

if __name__ == "__main__":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()   

Important Correction: In your provided code, the main block is written as: 

if name == "main":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()

This should be corrected:

if __name__ == "__main__":
    root = tk.Tk()
    app = PDFMergerApp(root)
    root.mainloop()

OUTPUT

               

 

CONCLUSION

The PDF Merger Application is a straightforward and user-friendly tool for combining multiple PDF files into one. By leveraging Python’s tkinter for the GUI and PyPDF2 for PDF operations, it provides essential functionalities with a clean interface. Understanding each component and its role enhances the ability to maintain, customize, and extend the application’s capabilities.

 

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top