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
Post a Comment