File size: 15,166 Bytes
a3fda21 |
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 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 |
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
import os
import threading, queue
from PIL import Image, UnidentifiedImageError
# Global variables for managing state and errors
stop_processing = False
error_messages = []
selected_files = []
error_list = []
def open_image_error_fix():
global stop_processing, error_messages, selected_files, status_var, num_files_var, errors_var, progress, q, error_list, error_window, thread_count_var
# Initialize the main Tkinter window
root = tk.Tk()
root.title("Image Error Fix")
# Initialize Tkinter variables
status_var = tk.StringVar()
num_files_var = tk.StringVar()
errors_var = tk.StringVar(value="Errors: 0")
progress = tk.IntVar()
thread_count_var = tk.StringVar(value="4") # Default thread count
q = queue.Queue()
def center_window(window):
window.update_idletasks()
width = window.winfo_width() + 120
height = window.winfo_height()
x = (window.winfo_screenwidth() // 2) - (width // 2)
y = (window.winfo_screenheight() // 2) - (height // 2)
window.geometry(f'{width}x{height}+{x}+{y}')
def validate_number(P):
return P.isdigit() or P == ""
def validate_thread_count(var):
value = var.get()
if value != "":
try:
int_value = int(value)
if int_value <= 0:
raise ValueError
except ValueError:
messagebox.showerror("Invalid Input", "Please enter a valid number of threads.")
var.set("")
def select_files():
global selected_files
filetypes = [
("All Image files", "*.jpg;*.jpeg;*.png;*.gif;*.bmp;*.tiff;*.tif;*.svg;*.webp"),
("JPEG files", "*.jpg;*.jpeg"),
("PNG files", "*.png"),
("GIF files", "*.gif"),
("BMP files", "*.bmp"),
("TIFF files", "*.tiff;*.tif"),
("SVG files", "*.svg"),
("WEBP files", "*.webp")
]
filepaths = filedialog.askopenfilenames(title="Select Image Files", filetypes=filetypes)
if filepaths:
selected_files.clear()
selected_files.extend(filepaths)
num_files_var.set(f"{len(selected_files)} files selected.")
def detect_errors(file_path):
"""Detect potential errors in an image file."""
errors = []
if not os.access(file_path, os.R_OK):
errors.append("Permission Denied")
# Additional error checks
try:
with Image.open(file_path) as img:
img.verify() # Verify the image integrity
img = Image.open(file_path)
img.load() # Load the image data to ensure it's not truncated
except UnidentifiedImageError:
errors.append("Unidentified image format or corrupted file")
except IOError as e:
errors.append(f"IOError: {str(e)}")
except Exception as e:
errors.append(f"Unknown error: {str(e)}")
return errors
def fix_error(file_path, error_type):
"""Fix errors in an image file, if possible."""
if error_type == "Permission Denied":
# Attempt to change permissions
try:
os.chmod(file_path, 0o644)
return "Permissions fixed. File permissions were successfully updated."
except Exception as e:
return f"Failed to fix permissions. Ensure you have the necessary permissions to modify this file. Error: {str(e)}"
elif error_type == "Unidentified image format or corrupted file":
return "The file format is unrecognized or the file is corrupted. Please try to re-download or restore from a backup."
elif error_type == "Invalid Format":
return ("Cannot automatically fix invalid formats. Ensure the file extension matches the file content.\n"
"To fix this issue, please follow these steps:\n"
"1. Identify the correct file format by using a file type checker tool (e.g., CheckFileType.com).\n"
"2. Rename the file with the correct extension:\n"
" - Right-click on the file and select 'Rename'.\n"
" - Change the file extension to the correct format (e.g., .jpg, .png).\n"
" - Press Enter to save the changes.\n"
"3. Try opening the file again. If the problem persists, the file may be corrupted or contain unsupported data.")
elif error_type == "File Not Found":
return ("The file could not be found at the specified path. Please ensure that the file has not been moved or deleted.\n"
"1. Verify the file path is correct.\n"
"2. If the file has been moved, update the path in the application or locate the file manually.\n"
"3. If the file was deleted, check your Recycle Bin or use a data recovery tool to attempt to restore it.")
elif error_type == "File Path Too Long":
return ("The file path exceeds the system limit. Windows has a maximum path length of 260 characters.\n"
"To fix this issue:\n"
"1. Move the file to a location with a shorter path, closer to the root directory (e.g., C:\\).\n"
"2. Rename folders in the path to shorter names.\n"
"3. Enable long path support in Windows if using Windows 10 (version 1607 hoặc cao hơn):\n"
" - Open the Group Policy Editor (gpedit.msc).\n"
" - Navigate to 'Local Computer Policy > Computer Configuration > Administrative Templates > System > Filesystem'.\n"
" - Enable the 'Enable Win32 long paths' option.")
elif error_type == "Transmission Errors":
return ("The file may be incomplete or corrupted due to transmission errors. This can happen if the file was downloaded or transferred incorrectly.\n"
"To fix this issue:\n"
"1. Re-download hoặc re-transfer the file.\n"
"2. Use a reliable network connection to ensure the file is not corrupted during transfer.\n"
"3. Verify the integrity of the file by comparing checksums (if available).")
elif error_type == "Unsupported Format":
return ("The file format is not supported by this application. Supported formats include JPEG, PNG, GIF, BMP, TIFF, SVG, và WEBP.\n"
"To fix this issue:\n"
"1. Convert the file to a supported format using an image converter tool.\n"
"2. Ensure that the file is not corrupted and can be opened with other image viewers or editors.")
else:
return "No action taken. This error type is not recognized or cannot be fixed automatically."
def delete_file(file_path):
"""Delete the specified file."""
try:
os.remove(file_path)
# Remove from selected files
selected_files.remove(file_path)
num_files_var.set(f"{len(selected_files)} files selected.")
return f"File {file_path} deleted successfully."
except Exception as e:
return f"Failed to delete file {file_path}. Error: {str(e)}"
def process_image(file_path, q):
if stop_processing:
return
errors = detect_errors(file_path)
if errors:
q.put((file_path, errors))
def worker():
try:
progress.set(0)
total_files = len(selected_files)
thread_count = int(thread_count_var.get()) # Get the number of threads
for i, input_path in enumerate(selected_files, 1):
if stop_processing:
break
thread = threading.Thread(target=process_image, args=(input_path, q))
thread.start()
thread.join()
# Update progress bar
progress.set(int(i / total_files * 100))
q.put(None)
except Exception as e:
if not stop_processing:
q.put(e)
def update_progress():
try:
global error_list
error_list = []
while True:
item = q.get()
if item is None:
break
if isinstance(item, tuple):
error_list.append(item)
if not error_list:
messagebox.showinfo("No Errors Found", "No errors were detected in the selected images.")
else:
errors_var.set(f"Errors: {len(error_list)}")
display_errors(error_list)
except Exception as e:
if not stop_processing:
root.after(0, status_var.set, f"Error: {e}")
def update_error_display():
"""Update the display of errors in the error window."""
global error_list, frame
# Clear all existing widgets in the frame
for widget in frame.winfo_children():
widget.destroy()
# Repopulate the frame with updated error list
for file_path, errors in error_list:
for error in errors:
frame_row = tk.Frame(frame)
frame_row.pack(fill="x", pady=2)
# Hiển thị đường dẫn đầy đủ và tự động xuống dòng
file_label = tk.Label(frame_row, text=f"{file_path}: {error}", anchor="w", wraplength=500, justify='left')
file_label.pack(side=tk.LEFT, fill="x", expand=True)
delete_button = tk.Button(frame_row, text="Delete", command=lambda fp=file_path: delete_file_action(fp))
delete_button.pack(side=tk.RIGHT)
fix_button = tk.Button(frame_row, text="Fix", command=lambda fp=file_path, et=error: fix_error_action(fp, et))
fix_button.pack(side=tk.RIGHT)
# Thêm dấu phân cách giữa các lỗi
separator = ttk.Separator(frame, orient='horizontal')
separator.pack(fill='x', pady=5)
frame.update_idletasks()
canvas.configure(scrollregion=canvas.bbox("all"))
def display_errors(error_list):
global error_window, canvas, frame
# Create or raise the error window
if 'error_window' in globals() and error_window.winfo_exists():
error_window.lift()
else:
error_window = tk.Toplevel(root)
error_window.title("Error Details")
error_window.geometry("600x400")
canvas = tk.Canvas(error_window)
canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar = tk.Scrollbar(error_window, command=canvas.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
canvas.configure(yscrollcommand=scrollbar.set)
frame = tk.Frame(canvas)
canvas.create_window((0, 0), window=frame, anchor="nw")
update_error_display()
def fix_error_action(file_path, error_type):
fix_message = fix_error(file_path, error_type)
messagebox.showinfo("Fix Error", fix_message)
def delete_file_action(file_path):
global error_list
delete_message = delete_file(file_path)
messagebox.showinfo("Delete File", delete_message)
# Remove the error from the error_list and refresh the display
error_list = [(fp, errs) for fp, errs in error_list if fp != file_path]
errors_var.set(f"Errors: {len(error_list)}")
update_error_display()
def delete_all_errors():
global error_list
for file_path, _ in error_list:
delete_file(file_path)
error_list.clear()
errors_var.set("Errors: 0")
messagebox.showinfo("Delete All Files", "All files with errors have been deleted.")
update_error_display() # Update the error display after deleting all errors
def scan_and_fix():
global stop_processing, error_messages
stop_processing = False
error_messages.clear()
errors_var.set("Errors: 0")
if not selected_files:
status_var.set("Please select images to scan.")
return
threading.Thread(target=worker).start()
threading.Thread(target=update_progress).start()
def stop_processing_func():
global stop_processing
stop_processing = True
status_var.set("Processing stopped.")
def return_to_menu():
stop_processing_func()
root.destroy()
import main
main.open_main_menu()
def on_closing():
return_to_menu()
# Create GUI elements
validate_command = root.register(validate_number)
back_button = tk.Button(root, text="<-", font=('Helvetica', 14), command=return_to_menu)
back_button.pack(anchor='nw', padx=10, pady=10)
title_label = tk.Label(root, text="Image Error Fix", font=('Helvetica', 16))
title_label.pack(pady=10)
select_files_button = tk.Button(root, text="Select Files", command=select_files)
select_files_button.pack(pady=5)
num_files_label = tk.Label(root, textvariable=num_files_var)
num_files_label.pack(pady=5)
thread_count_label = tk.Label(root, text="Number of Threads:")
thread_count_label.pack(pady=5)
thread_count_var = tk.StringVar(value="4")
thread_count_entry = tk.Entry(root, textvariable=thread_count_var, width=3, justify='center', validate="key", validatecommand=(validate_command, '%P'))
thread_count_entry.pack(pady=5)
# Separator for aesthetics
separator = ttk.Separator(root, orient='horizontal')
separator.pack(fill='x', pady=10)
scan_fix_button = tk.Button(root, text="Scan and Fix", command=scan_and_fix)
scan_fix_button.pack(pady=10)
stop_button = tk.Button(root, text="Stop", command=stop_processing_func)
stop_button.pack(pady=5)
progress_bar = ttk.Progressbar(root, variable=progress, maximum=100)
progress_bar.pack(pady=5, fill=tk.X)
delete_all_label = tk.Label(root, text="Click 'Delete All' to remove all files with errors.")
delete_all_label.pack(pady=5)
delete_all_button = tk.Button(root, text="Delete All", command=delete_all_errors)
delete_all_button.pack(pady=5)
errors_label = tk.Label(root, textvariable=errors_var, fg="red")
errors_label.pack(pady=5)
status_label = tk.Label(root, textvariable=status_var, fg="green")
status_label.pack(pady=5)
center_window(root)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
if __name__ == "__main__":
open_image_error_fix()
|