From 15b7c100567576d569fe8fd4ca486c7bfa453769 Mon Sep 17 00:00:00 2001 From: tanyar09 Date: Tue, 30 Sep 2025 15:39:51 -0400 Subject: [PATCH] Refactor PhotoTagger GUI to enhance image display and layout. Update canvas background color to match the theme, improve image resizing logic for better aspect ratio handling, and adjust grid configurations for match frames to ensure proper alignment and responsiveness. This enhances overall user experience and visual consistency across the interface. --- photo_tagger.py | 76 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/photo_tagger.py b/photo_tagger.py index 2f3451d..796250b 100644 --- a/photo_tagger.py +++ b/photo_tagger.py @@ -1141,10 +1141,14 @@ class PhotoTagger: # Image display (left panel) image_frame = ttk.Frame(left_panel) image_frame.grid(row=0, column=0, pady=(0, 10), sticky=(tk.W, tk.E, tk.N, tk.S)) + image_frame.columnconfigure(0, weight=1) + image_frame.rowconfigure(0, weight=1) # Create canvas for image display - canvas = tk.Canvas(image_frame, width=400, height=400, bg='white') - canvas.grid(row=0, column=0) + style = ttk.Style() + canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' + canvas = tk.Canvas(image_frame, width=400, height=400, bg=canvas_bg_color, highlightthickness=0) + canvas.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) # Input section (left panel) input_frame = ttk.LabelFrame(left_panel, text="Person Identification", padding="10") @@ -1718,7 +1722,9 @@ class PhotoTagger: clear_all_btn.config(state='disabled') # Create canvas for similar faces with scrollbar - similar_canvas = tk.Canvas(similar_faces_frame, bg='white') + style = ttk.Style() + canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' + similar_canvas = tk.Canvas(similar_faces_frame, bg=canvas_bg_color, highlightthickness=0) similar_scrollbar = ttk.Scrollbar(similar_faces_frame, orient="vertical", command=similar_canvas.yview) similar_scrollable_frame = ttk.Frame(similar_canvas) @@ -2171,12 +2177,43 @@ class PhotoTagger: try: # Load and display the face crop image pil_image = Image.open(face_crop_path) - # Resize image to fit in window (max 400x400) - pil_image.thumbnail((400, 400), Image.Resampling.LANCZOS) + + # Get canvas dimensions + canvas_width = canvas.winfo_width() + canvas_height = canvas.winfo_height() + + # If canvas hasn't been rendered yet, force update and use actual size + if canvas_width <= 1 or canvas_height <= 1: + # Force the canvas to update its geometry + canvas.update_idletasks() + canvas_width = canvas.winfo_width() + canvas_height = canvas.winfo_height() + + # If still not rendered, use default size + if canvas_width <= 1: + canvas_width = 400 + if canvas_height <= 1: + canvas_height = 400 + + # Calculate scaling to fit within the canvas while maintaining aspect ratio + img_width, img_height = pil_image.size + scale_x = canvas_width / img_width + scale_y = canvas_height / img_height + # Allow slight upscaling (up to 1.2x) for better visibility, but cap to avoid excessive blurriness + max_scale = min(1.2, max(scale_x, scale_y)) + scale = min(scale_x, scale_y, max_scale) + + # Resize image to fill canvas + new_width = int(img_width * scale) + new_height = int(img_height * scale) + pil_image = pil_image.resize((new_width, new_height), Image.Resampling.LANCZOS) + photo = ImageTk.PhotoImage(pil_image) - # Update canvas - canvas.create_image(200, 200, image=photo) + # Center the image in the canvas + x = canvas_width // 2 + y = canvas_height // 2 + canvas.create_image(x, y, image=photo) # Keep a reference to prevent garbage collection canvas.image = photo @@ -2592,20 +2629,21 @@ class PhotoTagger: # Bind the callback to the variable match_var.trace('w', make_callback(match_var, current_face_id, similar_face_id)) - # Create a frame for the checkbox and text labels - text_frame = ttk.Frame(match_frame) - text_frame.pack(side=tk.LEFT, padx=(0, 10)) + # Configure match frame for grid layout + match_frame.columnconfigure(0, weight=0) # Checkbox column - fixed width + match_frame.columnconfigure(1, weight=1) # Text column - expandable + match_frame.columnconfigure(2, weight=0) # Image column - fixed width # Checkbox without text - checkbox = ttk.Checkbutton(text_frame, variable=match_var) - checkbox.pack(side=tk.LEFT, padx=(0, 5)) + checkbox = ttk.Checkbutton(match_frame, variable=match_var) + checkbox.grid(row=0, column=0, rowspan=2, sticky=(tk.W, tk.N), padx=(0, 5)) # Create labels for confidence and filename - confidence_label = ttk.Label(text_frame, text=f"{confidence_pct:.1f}% {confidence_desc}", font=("Arial", 9, "bold")) - confidence_label.pack(anchor=tk.W) + confidence_label = ttk.Label(match_frame, text=f"{confidence_pct:.1f}% {confidence_desc}", font=("Arial", 9, "bold")) + confidence_label.grid(row=0, column=1, sticky=tk.W, padx=(0, 10)) - filename_label = ttk.Label(text_frame, text=f"📁 {filename}", font=("Arial", 8), foreground="gray") - filename_label.pack(anchor=tk.W) + filename_label = ttk.Label(match_frame, text=f"📁 {filename}", font=("Arial", 8), foreground="gray") + filename_label.grid(row=1, column=1, sticky=tk.W, padx=(0, 10)) # Face image (reusing auto-match image display) try: @@ -2632,8 +2670,10 @@ class PhotoTagger: face_crops.append(face_crop_path) # Create canvas for face image (like in auto-match) - match_canvas = tk.Canvas(match_frame, width=80, height=80, bg='white') - match_canvas.pack(side=tk.LEFT, padx=(10, 0)) + style = ttk.Style() + canvas_bg_color = style.lookup('TFrame', 'background') or '#d9d9d9' + match_canvas = tk.Canvas(match_frame, width=80, height=80, bg=canvas_bg_color, highlightthickness=0) + match_canvas.grid(row=0, column=2, rowspan=2, sticky=(tk.W, tk.N), padx=(10, 0)) # Load and display image (reusing auto-match image loading) pil_image = Image.open(face_crop_path)