-
Notifications
You must be signed in to change notification settings - Fork 0
/
scorpion_viewer.py
148 lines (124 loc) · 5.19 KB
/
scorpion_viewer.py
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
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
from PIL import Image
import os
from datetime import datetime
from exif_labels import exif_labels_dict
from scorpion import image_extensions, get_metadata, check_extension
class MetadataViewerApp:
def __init__(self, root, width, height):
self.root = root
self.root.title("Metadata Viewer")
self.root.geometry(f"{width}x{height}") # Set the window size
# Setup GUI layout
self.create_widgets()
def create_widgets(self):
# Buttons for file and folder selection
btn_frame = tk.Frame(self.root)
btn_frame.pack(side=tk.TOP, fill=tk.X, pady=10)
tk.Button(btn_frame, text="Open Files", command=self.open_files).pack(side=tk.LEFT, padx=5)
tk.Button(btn_frame, text="Open Folders", command=self.open_dirs).pack(side=tk.LEFT, padx=5)
# Treeview for displaying metadata
self.tree = ttk.Treeview(self.root, columns=("Tag", "Value"), show="headings")
self.tree.heading("Tag", text="Tag")
self.tree.heading("Value", text="Value")
self.tree.pack(fill=tk.BOTH, expand=True)
# Double-click binding for editing the value fields
self.tree.bind("<Double-1>", self.on_double_click)
# Del key binding for deleting metadata entries
self.tree.bind("<Delete>", self.delete_selected_entry)
def delete_selected_entry(self, event):
"""
Deletes the currently selected metadata entry when the
Delete key is pressed.
"""
# Get the selected item
selected_item = self.tree.selection()
if selected_item:
# Remove the selected item from the Treeview
for item in selected_item:
self.tree.delete(item)
def open_files(self) -> None:
"""
Forge the string of the handled extensions.
This is needed by 'filedialog.askopenfilename',
and the format is: "*.jpg *.jpg *.png"
"""
extensions = ""
ext_len = len(image_extensions) - 1
for i, ext in enumerate(image_extensions):
extensions += '*' + ext
if i < ext_len:
extensions += " "
# Set the filetypes argument for the askopenfilename() method
filetypes = (
('Image files', extensions),
)
# Open the dialog to select the file names
file_paths = filedialog.askopenfilename(
title="Select image files",
filetypes=filetypes, # Send the handled file types
multiple=True # Activate multiple selection
)
self.read_metadata_from_files(file_paths)
def read_metadata_from_files(self, files: list[str]) -> None:
for path in files:
if not check_extension(path):
continue
try:
if os.path.isfile(path):
metadata = get_metadata(path)
self.display_metadata(metadata)
except Exception as e:
messagebox.showerror("Error", f"Could not read metadata: {e}")
def open_dirs(self):
dir_path = filedialog.askdirectory(title="Select folders")
if dir_path:
files = [
os.path.join(dir_path, filename)
for filename in os.listdir(dir_path)
]
# Read the metadata of each file in the folder
if files:
self.read_metadata_from_files(files)
def display_metadata(self, metadata: dict[str]) -> None:
try:
if metadata:
for tag, value in metadata.items():
self.tree.insert("", tk.END, values=(tag, value))
else:
messagebox.showinfo("Metadata Viewer", "No metadata found.")
except Exception as e:
messagebox.showerror("Error", f"Could not read metadata: {e}")
self.tree.insert("", tk.END, values=("", ""))
def on_double_click(self, event) -> None:
"""Handles double-clicking a value in the Treeview to edit it."""
# Identify the selected item and column
item_id = self.tree.identify_row(event.y)
column_id = self.tree.identify_column(event.x)
if column_id != "#2": # Only allow editing the "Value" column
return
# Get the current tag/value in a tuple
values = self.tree.item(item_id, "values")
if not values:
return
# Get the value
current_value = values[1]
# Create an entry widget for editing
entry = tk.Entry(self.tree)
entry.insert(0, current_value)
entry.focus()
# Place the entry widget over the cell
bbox = self.tree.bbox(item_id, column_id)
entry.place(x=bbox[0], y=bbox[1], width=bbox[2], height=bbox[3])
# Commit the new value when the entry loses focus or Enter is pressed
def save_edit(event=None):
new_value = entry.get()
self.tree.item(item_id, values=(values[0], new_value))
entry.destroy()
entry.bind("<Return>", save_edit)
entry.bind("<FocusOut>", save_edit)
if __name__ == "__main__":
root = tk.Tk()
app = MetadataViewerApp(root, 600, 600)
root.mainloop()