fixing cropping coordinates
This commit is contained in:
113
src/GUI.py
113
src/GUI.py
@@ -371,15 +371,24 @@ class GUI:
|
|||||||
selection_coords["left"], selection_coords["top"],
|
selection_coords["left"], selection_coords["top"],
|
||||||
selection_coords["right"], selection_coords["bottom"]
|
selection_coords["right"], selection_coords["bottom"]
|
||||||
)
|
)
|
||||||
|
# Redraw the selection highlight to ensure it's visible
|
||||||
|
self._renderCurrentImage()
|
||||||
|
|
||||||
def _onRightClick(self, event) -> None:
|
def _onRightClick(self, event) -> None:
|
||||||
"""Handle right-click to show context menu for manipulation options."""
|
"""Handle right-click to show context menu for manipulation options."""
|
||||||
if not self._selectionArea.is_active or not self._selectionArea.is_valid():
|
if not self._selectionArea or not self._selectionArea.is_active:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self._selectionArea.is_valid():
|
||||||
return
|
return
|
||||||
|
|
||||||
# Create context menu with all available manipulations
|
# Create context menu with all available manipulations
|
||||||
context_menu = tk.Menu(self._root, tearoff=0)
|
context_menu = tk.Menu(self._root, tearoff=0)
|
||||||
|
|
||||||
|
# Add crop to selection option first (most common use case)
|
||||||
|
context_menu.add_command(label="Crop to Selection", command=self._cropToSelection)
|
||||||
|
context_menu.add_separator()
|
||||||
|
|
||||||
# Add manipulation options
|
# Add manipulation options
|
||||||
manipulations = GetImageManipulationList()
|
manipulations = GetImageManipulationList()
|
||||||
for manipulation in manipulations:
|
for manipulation in manipulations:
|
||||||
@@ -407,25 +416,37 @@ class GUI:
|
|||||||
if pil_image is None:
|
if pil_image is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
# Convert widget coordinates to canvas coordinates (accounts for borders/scroll)
|
||||||
|
canvas_x1 = self._imageCanvas.canvasx(start_x)
|
||||||
|
canvas_y1 = self._imageCanvas.canvasy(start_y)
|
||||||
|
canvas_x2 = self._imageCanvas.canvasx(end_x)
|
||||||
|
canvas_y2 = self._imageCanvas.canvasy(end_y)
|
||||||
|
|
||||||
# Get image dimensions
|
# Get image dimensions
|
||||||
img_width, img_height = pil_image.size
|
img_width, img_height = pil_image.size
|
||||||
|
|
||||||
# Get canvas dimensions
|
# Get canvas dimensions for scaling
|
||||||
canvas_width = self._imageCanvas.winfo_width()
|
# Use stored canvas image dimensions if available (from when image was rendered)
|
||||||
canvas_height = self._imageCanvas.winfo_height()
|
if self._canvasImageWidth and self._canvasImageHeight:
|
||||||
|
canvas_width = self._canvasImageWidth
|
||||||
|
canvas_height = self._canvasImageHeight
|
||||||
|
else:
|
||||||
|
# Fallback: use actual canvas widget dimensions
|
||||||
|
canvas_width = self._imageCanvas.winfo_width()
|
||||||
|
canvas_height = self._imageCanvas.winfo_height()
|
||||||
|
|
||||||
if canvas_width <= 0 or canvas_height <= 0:
|
if canvas_width <= 0 or canvas_height <= 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Calculate scaling factors
|
# Calculate scaling factors to convert canvas coordinates to image coordinates
|
||||||
scale_x = img_width / canvas_width
|
scale_x = img_width / canvas_width
|
||||||
scale_y = img_height / canvas_height
|
scale_y = img_height / canvas_height
|
||||||
|
|
||||||
# Convert coordinates
|
# Convert canvas coordinates to image coordinates
|
||||||
left = int(min(start_x, end_x) * scale_x)
|
left = int(min(canvas_x1, canvas_x2) * scale_x)
|
||||||
top = int(min(start_y, end_y) * scale_y)
|
top = int(min(canvas_y1, canvas_y2) * scale_y)
|
||||||
right = int(max(start_x, end_x) * scale_x)
|
right = int(max(canvas_x1, canvas_x2) * scale_x)
|
||||||
bottom = int(max(start_y, end_y) * scale_y)
|
bottom = int(max(canvas_y1, canvas_y2) * scale_y)
|
||||||
|
|
||||||
# Ensure coordinates are within image bounds
|
# Ensure coordinates are within image bounds
|
||||||
left = max(0, min(left, img_width))
|
left = max(0, min(left, img_width))
|
||||||
@@ -439,6 +460,58 @@ class GUI:
|
|||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _cropToSelection(self) -> None:
|
||||||
|
"""Crop the entire image to the selected area."""
|
||||||
|
if self._currentImage 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
|
||||||
|
|
||||||
|
# Validate coordinates
|
||||||
|
if right <= left or bottom <= top:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Get the original image
|
||||||
|
original_image = self._currentImage.getImage()
|
||||||
|
if original_image is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
img_width, img_height = original_image.size
|
||||||
|
|
||||||
|
# Ensure coordinates are within image bounds
|
||||||
|
left = max(0, min(left, img_width))
|
||||||
|
top = max(0, min(top, img_height))
|
||||||
|
right = max(left, min(right, img_width))
|
||||||
|
bottom = max(top, min(bottom, img_height))
|
||||||
|
|
||||||
|
# Validate final coordinates
|
||||||
|
if right <= left or bottom <= top:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Take undo snapshot
|
||||||
|
self._currentImage.snapshot()
|
||||||
|
|
||||||
|
# Crop the image to the selection area
|
||||||
|
cropped_image = original_image.crop((left, top, right, bottom))
|
||||||
|
|
||||||
|
# Update the current image
|
||||||
|
self._currentImage._imageData = cropped_image
|
||||||
|
|
||||||
|
# Clear selection before re-rendering
|
||||||
|
self._clearSelection()
|
||||||
|
|
||||||
|
# Re-render the image (without selection)
|
||||||
|
self._renderCurrentImage()
|
||||||
|
except Exception as e:
|
||||||
|
# Silently handle errors - crop operation failed
|
||||||
|
pass
|
||||||
|
|
||||||
def _applyManipulationToSelection(self, manipulation) -> None:
|
def _applyManipulationToSelection(self, manipulation) -> None:
|
||||||
"""Apply the specified manipulation to the selected area only."""
|
"""Apply the specified manipulation to the selected area only."""
|
||||||
if self._currentImage is None or not self._selectionArea.is_active:
|
if self._currentImage is None or not self._selectionArea.is_active:
|
||||||
@@ -531,11 +604,19 @@ class GUI:
|
|||||||
# Convert image coordinates to canvas coordinates
|
# Convert image coordinates to canvas coordinates
|
||||||
pil_image = self._currentImage.getImage()
|
pil_image = self._currentImage.getImage()
|
||||||
img_width, img_height = pil_image.size
|
img_width, img_height = pil_image.size
|
||||||
canvas_width = self._imageCanvas.winfo_width()
|
|
||||||
canvas_height = self._imageCanvas.winfo_height()
|
|
||||||
|
|
||||||
if canvas_width <= 0 or canvas_height <= 0:
|
# Get canvas dimensions for scaling
|
||||||
return
|
# Use stored canvas image dimensions if available (from when image was rendered)
|
||||||
|
if self._canvasImageWidth and self._canvasImageHeight:
|
||||||
|
canvas_width = self._canvasImageWidth
|
||||||
|
canvas_height = self._canvasImageHeight
|
||||||
|
else:
|
||||||
|
# Fallback: use actual canvas widget dimensions
|
||||||
|
canvas_width = self._imageCanvas.winfo_width()
|
||||||
|
canvas_height = self._imageCanvas.winfo_height()
|
||||||
|
|
||||||
|
if canvas_width <= 0 or canvas_height <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
# Calculate scaling factors
|
# Calculate scaling factors
|
||||||
scale_x = canvas_width / img_width
|
scale_x = canvas_width / img_width
|
||||||
|
|||||||
Reference in New Issue
Block a user