Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d7cfe13

Browse files
Merge pull request #1089 from vivekthedev/main
Add New Project : GUI PDF Utility Tool
2 parents 929022b + 1207acf commit d7cfe13

File tree

5 files changed

+386
-0
lines changed

5 files changed

+386
-0
lines changed
31 KB
Loading[フレーム]
25.4 KB
Loading[フレーム]
33.7 KB
Loading[フレーム]

‎GUIScripts/PDF Utility Tool/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# PDF Utility Tool
2+
3+
## Aim
4+
5+
Work with PDFs offline and make changes to the pdfs in a GUI.
6+
7+
## Purpose
8+
9+
This tool makes it easy to perform the following operations:
10+
11+
- PDF Splitting
12+
- Merge two PDFs
13+
- Encrypt a PDF
14+
- Add Watermark
15+
- Rotate PDF
16+
17+
## Short description of package/script
18+
19+
- This PDF tool utilizes `PyPDF` module to work with PDF
20+
- The GUI is made with the `tkinter`.
21+
- The script shows a window with button for every action that is available to perform
22+
- The script uses `askfilename` in `tkinter` to get the file from the user while staying in the GUI.
23+
- Program also has an information label which is responsible of showing the process success messages
24+
25+
## Setup instructions
26+
27+
To install the dependencies
28+
`pip install PyPDF2`
29+
30+
To run the script
31+
`python main.py`
32+
33+
- A GUI will open up, select the option and follow the instruction
34+
- The Output PDF will be generated in the current working directory.
35+
36+
## Output
37+
38+
![](./Images/screen1.png)
39+
<br/>
40+
![](./Images/screen2.png)
41+
<br/>
42+
![](./Images/screen3.png)
43+
44+
## Author(s)
45+
46+
[Vivek](https://github.com/vivekthedev)
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
import tkinter as tk
2+
import tkinter.font as tkFont
3+
from tkinter.filedialog import askopenfilename
4+
import os
5+
from PyPDF2 import PdfFileReader, PdfFileWriter
6+
7+
## Helper Functions
8+
9+
### Get PDF details in the window
10+
def extract_information(pdf_path):
11+
new_window = tk.Toplevel(root)
12+
new_window.title(pdf_path)
13+
new_window.geometry("400x200")
14+
with open(pdf_path, "rb") as f:
15+
pdf = PdfFileReader(f, strict=False)
16+
information = pdf.getDocumentInfo()
17+
number_of_pages = pdf.getNumPages()
18+
txt = f"""
19+
Information about {pdf_path}:
20+
21+
Author: {information.author}
22+
Creator: {information.creator}
23+
Producer: {information.producer}
24+
Subject: {information.subject}
25+
Title: {information.title}
26+
Number of pages: {number_of_pages}
27+
"""
28+
29+
new_label = tk.Label(new_window, text=txt)
30+
new_label.place(x=10, y=10)
31+
32+
# Read a pdf then create a new pdf with each page rotated
33+
def rotate_pages(pdf_path):
34+
35+
# Output file object
36+
pdf_writer = PdfFileWriter()
37+
pdf_reader = PdfFileReader(pdf_path)
38+
39+
# Copy each page to the output file object
40+
for i in range(pdf_reader.getNumPages()):
41+
pdf_writer.addPage(pdf_reader.getPage(i).rotateClockwise(90))
42+
43+
# Export the object in a pdf file
44+
with open("./rotate_pages.pdf", "wb") as fh:
45+
pdf_writer.write(fh)
46+
47+
# Read two pdfs and merge them into one
48+
def merge_pdfs(pdfA, pdfB):
49+
50+
# Reading file objects of both pdfs
51+
pdfA_obj = PdfFileReader(pdfA, strict=False)
52+
pdfB_obj = PdfFileReader(pdfB, strict=False)
53+
54+
# Object to store merged pdf
55+
pdf_merge = PdfFileWriter()
56+
57+
# Get all the pages from pdfA to writer object
58+
for pgNum in range(pdfA_obj.numPages):
59+
pg = pdfA_obj.getPage(pgNum)
60+
pdf_merge.addPage(pg)
61+
62+
# Get all the pages from pdfB to writer object
63+
for pgNum in range(pdfB_obj.numPages):
64+
pg = pdfB_obj.getPage(pgNum)
65+
pdf_merge.addPage(pg)
66+
67+
# Write out the merged PDF
68+
fileObj = open(".\merged_pdf.pdf", "wb")
69+
pdf_merge.write(fileObj)
70+
71+
#Display confirmation message
72+
info_label.configure(text=f"File Saved at : {os.getcwd()}\merged_pdf.pdf")
73+
74+
75+
# Split one pdf in two different pdfs
76+
def pdf_split(path, ranges):
77+
78+
# Read original pdf
79+
pdf = PdfFileReader(path, strict=False)
80+
81+
# Writer obeject for pdf
82+
pdf_writer = PdfFileWriter()
83+
84+
# Get all the pages upto the provided page number
85+
for page in range(int(ranges)):
86+
pdf_writer.addPage(pdf.getPage(page))
87+
88+
# Export the object to pdf file for the first part of the splitted pdf
89+
with open("./SplitA.pdf", "wb") as output_pdf:
90+
pdf_writer.write(output_pdf)
91+
92+
# Same steps for the second part of the pdf.
93+
pdf_writer = PdfFileWriter()
94+
for page in range(int(ranges), pdf.getNumPages()):
95+
pdf_writer.addPage(pdf.getPage(page))
96+
with open("./SplitB.pdf", "wb") as output_pdf:
97+
pdf_writer.write(output_pdf)
98+
99+
# Overlay water mark on a pdf (watermark should also be a pdf)
100+
def create_watermark(input_pdf, watermark):
101+
102+
# Get watermark page after reading the pdf
103+
watermark_obj = PdfFileReader(watermark, strict=False)
104+
watermark_page = watermark_obj.getPage(0)
105+
106+
pdf_reader = PdfFileReader(input_pdf, strict=False)
107+
pdf_writer = PdfFileWriter()
108+
109+
# Watermark all the pages
110+
for page in range(pdf_reader.getNumPages()):
111+
page = pdf_reader.getPage(page)
112+
page.mergePage(watermark_page)
113+
pdf_writer.addPage(page)
114+
115+
# Export the writer object to a pdf
116+
with open("./Watermarked.pdf", "wb") as out:
117+
pdf_writer.write(out)
118+
info_label.configure(text=f"Watermark set\nCheck : {os.getcwd()}")
119+
120+
# Make a pdf password protected
121+
def add_encryption(input_pdf, password):
122+
123+
# Reader and writer objects
124+
pdf_writer = PdfFileWriter()
125+
pdf_reader = PdfFileReader(input_pdf, strict=False)
126+
127+
# Copy all the pages from the pdf to the writer object
128+
for page in range(pdf_reader.getNumPages()):
129+
pdf_writer.addPage(pdf_reader.getPage(page))
130+
131+
# add encryption to a writer object
132+
pdf_writer.encrypt(user_pwd=password, owner_pwd=None, use_128bit=True)
133+
134+
# export the encrypted pdf
135+
f = open("./Encrypted.pdf", "wb")
136+
pdf_writer.write(f)
137+
info_label.configure(text=f"Password Set\nCheck : {os.getcwd()}")
138+
139+
140+
## Selection Functions
141+
142+
# Select file and call extract_information()
143+
def info():
144+
path = askopenfilename(title="Select File", filetypes=[("PDF Document", "*pdf")])
145+
if path:
146+
extract_information(path)
147+
148+
149+
# Select file and call rotate_pages()
150+
def rotate():
151+
path = askopenfilename(title="Select File", filetypes=[("PDF Document", "*pdf")])
152+
if path:
153+
rotate_pages(path)
154+
155+
# Select two files and call merge_pdfs()
156+
def merge():
157+
path_A = askopenfilename(
158+
title="Select First File", filetypes=[("PDF Document", "*pdf")]
159+
)
160+
path_B = askopenfilename(
161+
title="Select Second File", filetypes=[("PDF Document", "*pdf")]
162+
)
163+
if all(path_A, path_B):
164+
merge_pdfs(path_A, path_B)
165+
166+
#Select file and get range and then call pdf_split
167+
def split():
168+
path = askopenfilename(title="Select File", filetypes=[("PDF Document", "*pdf")])
169+
170+
def assign():
171+
ranges = Range.get()
172+
pdf_split(path, ranges)
173+
newWindow.destroy()
174+
175+
if path:
176+
# Small windo basic tkinter setup
177+
# this window is responsible of creating a popup and ask user the required informationn
178+
newWindow = tk.Toplevel(root)
179+
newWindow.title("Enter Split Ranges")
180+
newWindow.geometry("400x200")
181+
newWindow.rowconfigure([0, 1, 2], minsize=50)
182+
newWindow.columnconfigure([0], minsize=400)
183+
labelh = tk.Label(newWindow, text="Enter Split Range middle point and Press GO")
184+
labelE = tk.Label(newWindow, text="Eg: 1-23 and 24-36 can be written as 23")
185+
labelh.grid(row=0, column=0)
186+
labelE.grid(row=1, column=0)
187+
container = tk.Frame(newWindow)
188+
container.columnconfigure([0, 1], minsize=200)
189+
container.rowconfigure([0], minsize=50)
190+
Range = tk.Entry(container)
191+
submit = tk.Button(container, text="GO", command=assign)
192+
Range.grid(row=0, column=0)
193+
submit.grid(row=0, column=1, padx=10, pady=10)
194+
container.grid(row=2, column=0)
195+
196+
197+
# Select two files and call creat_watermark()
198+
def watermark():
199+
path = askopenfilename(title="Select File", filetypes=[("PDF Document", "*pdf")])
200+
pathW = askopenfilename(
201+
title="Select Watermark File", filetypes=[("PDF Document", "*pdf")]
202+
)
203+
if all(path, pathW):
204+
create_watermark(path, pathW)
205+
206+
207+
def encrypt():
208+
path = askopenfilename(title="Select File", filetypes=[("PDF Document", "*pdf")])
209+
210+
def assign():
211+
passwordText = password.get()
212+
add_encryption(path, passwordText)
213+
newWindow.destroy()
214+
215+
if path:
216+
217+
# Small windo basic tkinter setup
218+
# this window is responsible of creating a popup and ask user the required informationn
219+
newWindow = tk.Toplevel(root)
220+
newWindow.title("Create Password")
221+
newWindow.geometry("400x200")
222+
223+
newWindow.rowconfigure([0, 1], minsize=100)
224+
newWindow.columnconfigure([0], minsize=400)
225+
label1 = tk.Label(newWindow, text="Create a Strong password to encrypt PDF")
226+
label1.grid(row=0, column=0)
227+
228+
container = tk.Frame(newWindow)
229+
container.rowconfigure([0], minsize=100)
230+
container.columnconfigure([0, 1], minsize=200)
231+
password = tk.Entry(container)
232+
submit = tk.Button(container, text="Encrypt", command=assign)
233+
password.grid(row=0, column=0)
234+
submit.grid(row=0, column=1)
235+
container.grid(row=1, column=0)
236+
237+
238+
# Basic root tkinter setup, geometry, title
239+
root = tk.Tk()
240+
root.geometry("800x600")
241+
root.wm_title("PDF Utility Tool")
242+
root.resizable(False, False)
243+
fontStyle = tkFont.Font(size=42)
244+
btnText = tkFont.Font(size=12)
245+
246+
# Creating two rows and one column in the window
247+
root.columnconfigure(0, minsize=800)
248+
root.rowconfigure(0, minsize=200)
249+
root.rowconfigure(2, minsize=400)
250+
251+
# Title label
252+
label1 = tk.Label(
253+
text="PDF Utility Tool", font=fontStyle, borderwidth=2, relief="groove"
254+
)
255+
256+
# Information label shows the confirmation messages
257+
info_label = tk.Label(text="", font=btnText)
258+
label1.grid(row=0, column=0)
259+
info_label.place(x=200, y=150)
260+
261+
# Container to store all the function buttons
262+
container = tk.Frame(root)
263+
264+
container.columnconfigure([0, 1], minsize=300)
265+
container.rowconfigure([0, 1, 2], minsize=100)
266+
267+
# Button for evry function and custom command attribute to call the functions
268+
btn_merge = tk.Button(
269+
container,
270+
text="Merge",
271+
bg="#FFE882",
272+
padx=15,
273+
pady=15,
274+
width=9,
275+
height=2,
276+
command=merge,
277+
)
278+
btn_rotate = tk.Button(
279+
container,
280+
text="Rotate",
281+
bg="#FFE882",
282+
padx=15,
283+
pady=15,
284+
width=9,
285+
height=2,
286+
command=rotate,
287+
)
288+
btn_split = tk.Button(
289+
container,
290+
text="Split",
291+
bg="#FFE882",
292+
padx=15,
293+
pady=15,
294+
width=9,
295+
height=2,
296+
command=split,
297+
)
298+
btn_watermark = tk.Button(
299+
container,
300+
text="Watermark",
301+
bg="#FFE882",
302+
padx=15,
303+
pady=15,
304+
width=9,
305+
height=2,
306+
command=watermark,
307+
)
308+
btn_encrypt = tk.Button(
309+
container,
310+
text="Encrypt",
311+
bg="#FFE882",
312+
padx=15,
313+
pady=15,
314+
width=9,
315+
height=2,
316+
command=encrypt,
317+
)
318+
btn_extract = tk.Button(
319+
container,
320+
text="Extract Info",
321+
bg="#FFE882",
322+
padx=15,
323+
pady=15,
324+
width=9,
325+
height=2,
326+
command=info,
327+
)
328+
329+
330+
# Placing all the buttons in the grid setup
331+
btn_merge.grid(row=0, column=0)
332+
btn_rotate.grid(row=0, column=1)
333+
btn_split.grid(row=1, column=0)
334+
btn_watermark.grid(row=1, column=1)
335+
btn_encrypt.grid(row=2, column=0)
336+
btn_extract.grid(row=2, column=1)
337+
338+
container.grid(row=1, column=0)
339+
340+
root.mainloop()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /