Create an AI-Powered PDF Editor Using Python (Tkinter + PyMuPDF + PIL) | Free Source Code 2025

 Demo :


Click Video πŸ‘‡πŸ‘‡πŸ‘‡

















πŸ“Œ Features :

  • ✅ Full source code (in formatted blocks or embedded from GitHub/Gist)

  • ✅ Live preview GIF or image of GUI

  • ✅ Download button for ZIP project

  • ✅ YouTube Shorts embed

  • ✅ SEO keywords in headings: Python PDF Editor, Tkinter Projects, AI PDF Tool


Code :


import tkinter as tk

from tkinter import filedialog, messagebox, simpledialog

from tkinter import ttk

import os

from PyPDF2 import PdfReader, PdfWriter

import fitz  # PyMuPDF

from PIL import Image, ImageTk



class PDFEditorApp:

    def __init__(self, root):

        self.root = root

        self.root.title("🧩 Advanced PDF Editor | FuzzuTech")

        self.root.geometry("1000x600")

        self.root.configure(bg="#1e1e2f")

        self.root.minsize(800, 600)

        self.tk_images = []  # Store references to images


        self.setup_ui()

        self.root.bind("<Configure>", self.on_resize)


    def setup_ui(self):

        style = ttk.Style()

        style.theme_use("default")

        style.configure("TButton",

                        font=("Segoe UI", 12),

                        padding=10,

                        foreground="#ffffff",

                        background="#000000",

                        borderwidth=0)

        style.map("TButton",

                  background=[("active", "#222222"), ("pressed", "#111111")],

                  foreground=[("disabled", "#888888")])


        self.title_label = tk.Label(self.root, text="Advanced PDF Editor", bg="#1e1e2f",

                                    fg="#ffffff", font=("Segoe UI", 24, "bold"))

        self.title_label.pack(pady=10)


        self.btn_frame = tk.Frame(self.root, bg="#1e1e2f")

        self.btn_frame.pack(pady=10, fill=tk.X)


        self.create_button(self.btn_frame, "Open PDF", self.open_pdf).pack(side=tk.LEFT, padx=10)

        self.create_button(self.btn_frame, "Merge PDFs", self.merge_pdfs).pack(side=tk.LEFT, padx=10)

        self.create_button(self.btn_frame, "Rotate Pages", self.rotate_pdf).pack(side=tk.LEFT, padx=10)

        self.create_button(self.btn_frame, "Extract Pages", self.extract_pages).pack(side=tk.LEFT, padx=10)


        self.status_label = tk.Label(self.root, text="", bg="#1e1e2f",

                                     fg="lightgreen", font=("Segoe UI", 12))

        self.status_label.pack(pady=5)


        # Scrollable canvas frame

        self.canvas_frame = tk.Frame(self.root, bg="#1e1e2f")

        self.canvas_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10)


        self.preview_canvas = tk.Canvas(self.canvas_frame, bg="#1e1e2f", highlightthickness=0)

        self.scroll_y = tk.Scrollbar(self.canvas_frame, orient=tk.VERTICAL, command=self.preview_canvas.yview)

        self.scrollable_frame = tk.Frame(self.preview_canvas, bg="#1e1e2f")


        self.scrollable_frame.bind("<Configure>", lambda e: self.preview_canvas.configure(

            scrollregion=self.preview_canvas.bbox("all")

        ))


        self.preview_canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        self.preview_canvas.configure(yscrollcommand=self.scroll_y.set)


        self.preview_canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        self.scroll_y.pack(side=tk.RIGHT, fill=tk.Y)


    def create_button(self, parent, text, command):

        return ttk.Button(parent, text=text, command=command, style="TButton")


    def open_pdf(self):

        path = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])

        if path:

            try:

                reader = PdfReader(path)

                pdf_info = f"Pages: {len(reader.pages)} | Encrypted: {reader.is_encrypted}"

                self.status_label.config(text=f"{os.path.basename(path)} → {pdf_info}", fg="lightblue")

                self.show_pdf_preview(path)

            except Exception as e:

                messagebox.showerror("Error", str(e))


    def show_pdf_preview(self, path):

        # Clear previous previews

        for widget in self.scrollable_frame.winfo_children():

            widget.destroy()

        self.tk_images.clear()


        try:

            doc = fitz.open(path)

            for i, page in enumerate(doc):

                pix = page.get_pixmap(matrix=fitz.Matrix(1.5, 1.5))

                img = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)


                try:

                    resample_filter = Image.Resampling.LANCZOS

                except AttributeError:

                    resample_filter = Image.ANTIALIAS


                width = self.root.winfo_width() - 100

                ratio = width / img.width

                height = int(img.height * ratio)

                img_resized = img.resize((width, height), resample_filter)


                tk_img = ImageTk.PhotoImage(img_resized)

                self.tk_images.append(tk_img)  # Store reference to avoid garbage collection


                img_label = tk.Label(self.scrollable_frame, image=tk_img, bg="#1e1e2f")

                img_label.pack(pady=5)

        except Exception as e:

            messagebox.showerror("Preview Error", str(e))


    def merge_pdfs(self):

        files = filedialog.askopenfilenames(filetypes=[("PDF files", "*.pdf")])

        if files:

            writer = PdfWriter()

            try:

                for file in files:

                    reader = PdfReader(file)

                    for page in reader.pages:

                        writer.add_page(page)

                output_path = filedialog.asksaveasfilename(defaultextension=".pdf")

                if output_path:

                    with open(output_path, "wb") as f:

                        writer.write(f)

                    self.status_label.config(text="PDFs Merged Successfully ✅")

            except Exception as e:

                messagebox.showerror("Error", str(e))


    def rotate_pdf(self):

        file = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])

        if file:

            try:

                reader = PdfReader(file)

                writer = PdfWriter()

                for page in reader.pages:

                    page.rotate(90)

                    writer.add_page(page)

                output = filedialog.asksaveasfilename(defaultextension=".pdf")

                if output:

                    with open(output, "wb") as f:

                        writer.write(f)

                    self.status_label.config(text="PDF Rotated Successfully πŸ”")

            except Exception as e:

                messagebox.showerror("Error", str(e))


    def extract_pages(self):

        file = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])

        if file:

            try:

                reader = PdfReader(file)

                total = len(reader.pages)

                start = simpledialog.askinteger("Start Page", f"Enter start page (1-{total}):")

                end = simpledialog.askinteger("End Page", f"Enter end page (1-{total}):")

                if start and end and start <= end:

                    writer = PdfWriter()

                    for i in range(start - 1, end):

                        writer.add_page(reader.pages[i])

                    output = filedialog.asksaveasfilename(defaultextension=".pdf")

                    if output:

                        with open(output, "wb") as f:

                            writer.write(f)

                        self.status_label.config(text="Pages Extracted πŸ“„")

            except Exception as e:

                messagebox.showerror("Error", str(e))


    def on_resize(self, event):

        self.preview_canvas.configure(width=event.width)

        self.show_pdf_preview_on_resize()


    def show_pdf_preview_on_resize(self):

        # Re-display the current images at new sizes

        if hasattr(self, "tk_images") and self.tk_images:

            # Simulate re-render of preview (heavy logic, optional)

            pass  # For full dynamic resizing, you can optimize here later



# ---------------- Run App ----------------

if __name__ == "__main__":

    root = tk.Tk()

    app = PDFEditorApp(root)

    root.mainloop()

Comments

Popular posts from this blog

πŸš€ Simple Login & Registration System in Python Tkinter πŸ“±

πŸš€ Create a Python Screen Recorder with Audio (Complete Code)

πŸ”₯ Advanced MP3 Music Player in Python | CustomTkinter + Pygame | Free Source Code