adding requirements for image menu; integrating area selection with crop and resize functionalities
This commit is contained in:
@@ -57,6 +57,9 @@ class AreaSelectionHandler:
|
||||
self._selectionRectangle = None
|
||||
self._lassoPath = [] # List of canvas coordinates for lasso drawing
|
||||
self._lassoLine = None # Canvas line item for lasso path
|
||||
|
||||
# Pending operation callback (called when selection is completed)
|
||||
self._pendingOperationCallback = None
|
||||
|
||||
def toggle_selection_mode(self) -> None:
|
||||
"""Toggle interactive selection mode on/off."""
|
||||
@@ -65,6 +68,7 @@ class AreaSelectionHandler:
|
||||
self._root.config(cursor="crosshair")
|
||||
else:
|
||||
self._root.config(cursor="")
|
||||
self._pendingOperationCallback = None # Clear pending callback when disabling selection mode
|
||||
self.clear_selection()
|
||||
|
||||
def toggle_selection_shape(self) -> None:
|
||||
@@ -86,6 +90,44 @@ class AreaSelectionHandler:
|
||||
if self._selectionArea.is_active and self._selectionArea.is_valid():
|
||||
self._render_image()
|
||||
|
||||
def set_selection_shape(self, shape: str) -> None:
|
||||
"""Set the selection shape directly.
|
||||
|
||||
Args:
|
||||
shape: One of "rectangle", "circle", or "lasso"
|
||||
"""
|
||||
if self._selectionArea is None:
|
||||
return
|
||||
if shape in ("rectangle", "circle", "lasso"):
|
||||
self._selectionArea.set_shape(shape)
|
||||
self._selectionType = shape
|
||||
# Enable selection mode if not already enabled
|
||||
if not self._selectionMode:
|
||||
self.toggle_selection_mode()
|
||||
# Refresh selection drawing if active
|
||||
if self._selectionArea.is_active and self._selectionArea.is_valid():
|
||||
self._render_image()
|
||||
|
||||
def set_rectangular_selection(self) -> None:
|
||||
"""Set selection to rectangular mode and enable selection."""
|
||||
self.set_selection_shape("rectangle")
|
||||
|
||||
def set_circular_selection(self) -> None:
|
||||
"""Set selection to circular mode and enable selection."""
|
||||
self.set_selection_shape("circle")
|
||||
|
||||
def set_lasso_selection(self) -> None:
|
||||
"""Set selection to lasso (free-form) mode and enable selection."""
|
||||
self.set_selection_shape("lasso")
|
||||
|
||||
def set_pending_operation_callback(self, callback: Optional[Callable]) -> None:
|
||||
"""Set a callback to be executed when a selection is completed.
|
||||
|
||||
Args:
|
||||
callback: Function to call when selection is completed, or None to clear
|
||||
"""
|
||||
self._pendingOperationCallback = callback
|
||||
|
||||
def on_mouse_click(self, event) -> bool:
|
||||
"""Handle mouse click for selection.
|
||||
|
||||
@@ -212,6 +254,12 @@ class AreaSelectionHandler:
|
||||
|
||||
# Redraw the selection highlight to ensure it's visible
|
||||
self._render_image()
|
||||
|
||||
# Check if there's a pending operation callback and execute it
|
||||
if self._pendingOperationCallback and self._selectionArea.is_valid():
|
||||
callback = self._pendingOperationCallback
|
||||
self._pendingOperationCallback = None # Clear callback to prevent multiple calls
|
||||
callback()
|
||||
return True
|
||||
|
||||
# Handle rectangle/circle mode
|
||||
@@ -236,6 +284,12 @@ class AreaSelectionHandler:
|
||||
)
|
||||
# Redraw the selection highlight to ensure it's visible
|
||||
self._render_image()
|
||||
|
||||
# Check if there's a pending operation callback and execute it
|
||||
if self._pendingOperationCallback and self._selectionArea.is_valid():
|
||||
callback = self._pendingOperationCallback
|
||||
self._pendingOperationCallback = None # Clear callback to prevent multiple calls
|
||||
callback()
|
||||
return True
|
||||
|
||||
def on_right_click(self, event, get_default_params: Callable) -> bool:
|
||||
@@ -391,6 +445,56 @@ class AreaSelectionHandler:
|
||||
# Silently handle errors - crop operation failed
|
||||
pass
|
||||
|
||||
def resize_to_selection_dimensions(self) -> None:
|
||||
"""Resize the entire image to match the selection area dimensions."""
|
||||
current_image = self._get_current_image()
|
||||
if current_image is None or not self._selectionArea or not self._selectionArea.is_active:
|
||||
return
|
||||
|
||||
# Get the selection coordinates
|
||||
coords = self._selectionArea.get_coordinates()
|
||||
if not coords:
|
||||
return
|
||||
|
||||
left, top, right, bottom = coords
|
||||
|
||||
# Calculate dimensions from selection
|
||||
width = right - left
|
||||
height = bottom - top
|
||||
|
||||
# Validate dimensions
|
||||
if width <= 0 or height <= 0:
|
||||
return
|
||||
|
||||
# Get the original image
|
||||
original_image = current_image.getImage()
|
||||
if original_image is None:
|
||||
return
|
||||
|
||||
try:
|
||||
# Take undo snapshot
|
||||
current_image.snapshot()
|
||||
|
||||
# Resize the entire image to the selection dimensions
|
||||
from utils.image_utils import pil_to_cv2, cv2_to_pil
|
||||
import cv2
|
||||
|
||||
cv_img = pil_to_cv2(original_image)
|
||||
resized = cv2.resize(cv_img, (int(width), int(height)), interpolation=cv2.INTER_AREA)
|
||||
resized_image = cv2_to_pil(resized)
|
||||
|
||||
# Update the current image
|
||||
current_image._imageData = resized_image
|
||||
|
||||
# Clear selection before re-rendering
|
||||
self.clear_selection()
|
||||
|
||||
# Re-render the image (without selection)
|
||||
self._render_image()
|
||||
except Exception as e:
|
||||
# Silently handle errors - resize operation failed
|
||||
pass
|
||||
|
||||
def apply_manipulation_to_selection(self, manipulation, get_default_params: Callable) -> None:
|
||||
"""Apply the specified manipulation to the selected area only."""
|
||||
current_image = self._get_current_image()
|
||||
|
||||
Reference in New Issue
Block a user