-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
315 lines (263 loc) · 12.9 KB
/
main.py
File metadata and controls
315 lines (263 loc) · 12.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
import sys
import tools
import tkinter as tk
from tkinter import messagebox
from tkinter.scrolledtext import ScrolledText
import scrapper
import threading
import time
import queue
#command for conversion to executable: pyinstaller --onefile --windowed --icon=Logo.ico main.py
class RedirectOutput:
"""Class to redirect stdout and stderr to the text widget."""
def __init__(self, text_widget):
self.text_widget = text_widget
def write(self, message):
self.text_widget.insert(tk.END, message) # Inserts the message at the end of the widget
self.text_widget.see(tk.END) # Automatically scrolls to the end
self.text_widget.update_idletasks() # Immediately updates the GUI
def flush(self):
pass # Required for compatibility with sys.stdout and sys.stderr
def run_in_thread(func):
"""Decorator to run a function in a separate thread."""
def wrapper(*args, **kwargs):
thread = threading.Thread(target=func, args=args, kwargs=kwargs)
thread.start()
return wrapper
@run_in_thread
def text_extraction():
if not tools.check_pdfs(): # Check if tools.check_pdfs() returns False
print("Directory /pdfs is empty, please put a PDF file in it.")
return # Exit the function if the directory is empty
else:
print('Starting text extraction...\n')
time.sleep(1)
print('Opening PDF file...\n')
time.sleep(1)
tools.extractText()
print('Text extraction completed.\n')
messagebox.showinfo("Success", "Text extraction completed!")
@run_in_thread
def image_extraction():
if not tools.check_pdfs(): # Check if tools.check_pdfs() returns False
print("Directory /pdfs is empty, please put a PDF file in it.")
return # Exit the function if the directory is empty
else:
print('Starting image extraction...\n')
time.sleep(1)
print('Processing PDF pages...\n')
time.sleep(1)
tools.extractImage()
print('Image extraction completed.\n')
messagebox.showinfo("Success", "Image extraction completed!")
@run_in_thread
def pdf_merge():
if not tools.check_pdfs(): # Check if tools.check_pdfs() returns False
print("Directory /pdfs is empty, please put a PDF file in it.")
return # Exit the function if the directory is empty
else:
print('Starting PDF merge...\n')
time.sleep(1)
print('Reading PDF files...\n')
time.sleep(1)
tools.merge_pdfs()
print('PDF merge completed.\n')
messagebox.showinfo("Success", "PDFs merged successfully!")
@run_in_thread
def pdf_split_combine():
if not tools.check_pdfs(): # Check if tools.check_pdfs() returns False
print("Directory /pdfs is empty, please put a PDF file in it.")
return # Exit the function if the directory is empty
else:
print('Starting PDF split and combine...\n')
time.sleep(1)
print('Splitting selected pages...\n')
time.sleep(1)
tools.split_combine()
print('PDF split and combine completed.\n')
messagebox.showinfo("Success", "PDF split and combine completed!")
@run_in_thread
def pdf_requests():
if not tools.check_pdfs(): # Check if tools.check_pdfs() returns False
print("Directory /pdfs is empty, please put a PDF file in it.")
return # Exit the function if the directory is empty
else:
print('Starting PDF to PNG conversion and uploading to the website...\n')
time.sleep(1)
scrapper.Pen_to_Print(scrapper.activation())
print('PDF processing completed.\n')
messagebox.showinfo("Success", "PDF processing completed!")
def finish_program():
print("Closing the program...\n")
sys.exit(0)
def main_menu():
# Creates the main window
root = tk.Tk()
root.title("PDF Tools")
# Sets the window size
window_width = 600
window_height = 600
# Calculates the position to open the window on the right side and center vertically
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
position_x = screen_width - window_width - 50
position_y = (screen_height // 2) - (window_height // 2)
# Sets the window geometry
root.geometry(f"{window_width}x{window_height}+{position_x}+{position_y}")
root.configure(bg="#1e1e2f") # Dark blue-gray background
# Title
title_label = tk.Label(root, text="PDF Tools", font=("Helvetica", 20, "bold"), bg="#1e1e2f", fg="#ffffff")
title_label.pack(pady=20)
# Description label for hover effect
description_label = tk.Label(root, text="", font=("Helvetica", 12), bg="#1e1e2f", fg="#a9a9b3")
description_label.pack(pady=10)
# Function to update the description on hover
def on_hover(event, text, button):
description_label.config(text=text)
button.config(bg="#4a90e2", fg="#ffffff") # Highlight with blue
def on_leave(event, button):
description_label.config(text="")
button.config(bg="#2e2e3e", fg="#ffffff") # Reset to original colors
# Buttons for the options
btn_text_extraction = tk.Button(root, text="Text Extraction", command=text_extraction, width=30, bg="#2e2e3e", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_text_extraction.pack(pady=5)
btn_text_extraction.bind("<Enter>", lambda e: on_hover(e, "Extract text from PDF files.", btn_text_extraction))
btn_text_extraction.bind("<Leave>", lambda e: on_leave(e, btn_text_extraction))
btn_image_extraction = tk.Button(root, text="Image Extraction", command=image_extraction, width=30, bg="#2e2e3e", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_image_extraction.pack(pady=5)
btn_image_extraction.bind("<Enter>", lambda e: on_hover(e, "Extract images from PDF files.", btn_image_extraction))
btn_image_extraction.bind("<Leave>", lambda e: on_leave(e, btn_image_extraction))
btn_pdf_merge = tk.Button(root, text="PDF - Merge", command=pdf_merge, width=30, bg="#2e2e3e", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_pdf_merge.pack(pady=5)
btn_pdf_merge.bind("<Enter>", lambda e: on_hover(e, "Merge multiple PDF files into one.", btn_pdf_merge))
btn_pdf_merge.bind("<Leave>", lambda e: on_leave(e, btn_pdf_merge))
btn_pdf_split_combine = tk.Button(root, text="PDF - Split", command=pdf_split_combine, width=30, bg="#2e2e3e", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_pdf_split_combine.pack(pady=5)
btn_pdf_split_combine.bind("<Enter>", lambda e: on_hover(e, "Split specific pages of PDFs.", btn_pdf_split_combine))
btn_pdf_split_combine.bind("<Leave>", lambda e: on_leave(e, btn_pdf_split_combine))
btn_pdf_requests = tk.Button(root, text="PDF - Handwritten", command=pdf_requests, width=30, bg="#2e2e3e", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_pdf_requests.pack(pady=5)
btn_pdf_requests.bind("<Enter>", lambda e: on_hover(e, "Use your account to automatize Pen-To-Print website's OCR process", btn_pdf_requests))
btn_pdf_requests.bind("<Leave>", lambda e: on_leave(e, btn_pdf_requests))
btn_finish = tk.Button(root, text="Finish Program", command=finish_program, width=30, bg="#e74c3c", fg="#ffffff", relief="flat", font=("Helvetica", 12))
btn_finish.pack(pady=20)
# Add hover effect for the Finish Program button
def on_hover_finish(event):
btn_finish.config(bg="#ff6b6b") # Lighter red on hover
def on_leave_finish(event):
btn_finish.config(bg="#e74c3c") # Reset to original red
btn_finish.bind("<Enter>", on_hover_finish)
btn_finish.bind("<Leave>", on_leave_finish)
btn_finish.bind("<Enter>", lambda e: description_label.config(text="Close the application."))
btn_finish.bind("<Leave>", lambda e: description_label.config(text=""))
# Text widget to display terminal output
output_text = ScrolledText(root, wrap=tk.WORD, height=50, width=70, bg="#2e2e3e", fg="#ffffff", font=("Consolas", 10), relief="flat")
output_text.pack(pady=10)
# Make the log widget interactive: allow typing and connect to sys.stdin
class GuiStdin:
def __init__(self, text_widget):
self.text_widget = text_widget
self.queue = queue.Queue()
self.last_prompt_index = None
def _show_prompt(self):
# Insert a prompt marker where user can type
try:
# Ensure widget ends with a newline before inserting prompt
end_index = self.text_widget.index('end-1c')
last_char = self.text_widget.get(f"{end_index}", f"{end_index}")
except Exception:
last_char = "\n"
if not last_char.endswith("\n"):
self.text_widget.insert('end', "\n")
self.text_widget.insert('end', ">>> ")
self.text_widget.see('end')
# store the index where user input starts
self.last_prompt_index = self.text_widget.index('end-1c')
self.text_widget.focus_set()
def readline(self, *args, **kwargs):
# Schedule prompt insertion in the GUI thread
try:
self.text_widget.after(0, self._show_prompt)
except Exception:
pass
# Wait for user input from the queue
line = self.queue.get() # blocks until GUI puts input
return line + "\n"
def read(self, *args, **kwargs):
return self.readline()
gui_stdin = GuiStdin(output_text)
def _on_enter(event):
# Called when user presses Enter inside the text widget
try:
if gui_stdin.last_prompt_index:
start = gui_stdin.last_prompt_index
# Get user-typed content from prompt start to end
user_text = output_text.get(start, 'end-1c')
# Clean trailing newline if present
user_text = user_text.rstrip('\n')
gui_stdin.queue.put(user_text)
# Echo newline to the widget
output_text.insert('end', '\n')
gui_stdin.last_prompt_index = None
return 'break' # prevent default newline insertion
else:
# Fallback: send current line
line = output_text.get('insert linestart', 'insert lineend')
gui_stdin.queue.put(line)
output_text.insert('end', '\n')
return 'break'
except Exception as e:
print(f"Error handling input: {e}")
return None
# Allow typing and bind Enter
output_text.config(state='normal')
output_text.bind('<Return>', _on_enter)
# Replace sys.stdin with our GUI stdin
import sys as _sys
_sys.stdin = gui_stdin
# Redirects stdout and stderr to the text widget
sys.stdout = RedirectOutput(output_text)
sys.stderr = RedirectOutput(output_text)
# Automatically call tools.check_path() after the GUI is initialized
def initialize_check_path():
print("Initializing check_path function...\n")
tools.check_paths()
# Clear the terminal after 2 seconds
def clear_terminal():
output_text.delete(1.0, tk.END)
root.after(1000, clear_terminal) # Schedule terminal clearing after 2 seconds
root.after(100, initialize_check_path) # Calls the function after 100ms
# Starts the main GUI loop
# Register scrapper popup callback so scrapper can request GUI popups
try:
def _show_attention_popup():
def _create():
top = tk.Toplevel(root)
top.title("ATENÇÃO!")
# Increase size and center on screen; make topmost so it's between GUI and browser
popup_w, popup_h = 520, 160
screen_w = root.winfo_screenwidth()
screen_h = root.winfo_screenheight()
pos_x = (screen_w - popup_w) // 2
pos_y = (screen_h - popup_h) // 2
top.geometry(f"{popup_w}x{popup_h}+{pos_x}+{pos_y}")
top.attributes("-topmost", True)
top.lift()
# message in red, larger font
msg = tk.Label(top, text="Enter your email and password in the PROGRAM'S TERMINAL, not in the browser.", fg="red", font=("Helvetica", 14, "bold"), wraplength=480, justify='center')
msg.pack(fill='both', expand=True, padx=20, pady=12)
btn = tk.Button(top, text="OK", command=lambda: (top.attributes('-topmost', False), top.destroy()))
btn.pack(pady=(0, 12))
top.transient(root)
try:
top.grab_set()
except Exception:
pass
root.after(0, _create)
import scrapper as _scr
_scr.show_attention_popup = _show_attention_popup
except Exception:
pass
root.mainloop()
if __name__ == "__main__":
main_menu()