Skip to content

Commit

Permalink
fix type errors and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
weclaw1 committed Jun 7, 2024
1 parent d6092bb commit af33b4c
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 91 deletions.
51 changes: 27 additions & 24 deletions inbac/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from inbac.model import Model
from inbac.view import View


class Controller():
def __init__(self, model: Model, view: View):
self.model: Model = model
Expand Down Expand Up @@ -60,9 +59,11 @@ def load_images(self):
except IOError:
self.next_image()

def display_image_on_canvas(self, image: Image):
def display_image_on_canvas(self, image: Image.Image):
self.clear_canvas()
self.model.current_image = image
if self.model.current_image is None:
return
self.model.canvas_image_scaling_ratio = self.calculate_canvas_image_scaling(
self.model.current_image.size[0],
self.model.current_image.size[1],
Expand All @@ -76,9 +77,9 @@ def display_image_on_canvas(self, image: Image):
self.model.current_image.size[0],
self.model.current_image.size[1],
self.model.canvas_image_scaling_ratio)
displayed_image: Image = self.model.current_image.copy()
displayed_image: Image.Image = self.model.current_image.copy()
displayed_image.thumbnail(
self.model.canvas_image_dimensions, Image.ANTIALIAS)
self.model.canvas_image_dimensions, Image.Resampling.LANCZOS)
self.model.displayed_image = ImageTk.PhotoImage(displayed_image)
self.model.canvas_image = self.view.display_image(
self.model.displayed_image)
Expand All @@ -96,6 +97,7 @@ def clear_selection_box(self):

def update_selection_box(self):
selected_box: Tuple[int, int, int, int] = self.get_selected_box(
self.model.selected_fixed_size, self.model.canvas_image_scaling_ratio,
self.model.press_coord, self.model.move_coord, self.model.args.aspect_ratio)

if self.model.selection_box is None:
Expand Down Expand Up @@ -156,23 +158,23 @@ def save_next(self):
self.next_image()

def save(self) -> bool:
if self.model.selection_box is None:
if self.model.selection_box is None or self.model.current_image is None:
return False
selected_box: Tuple[int, int, int, int] = self.view.get_canvas_object_coords(
self.model.selection_box)
box: Tuple[int, int, int, int] = self.get_real_box(
selected_box, self.model.current_image.size, self.model.canvas_image_dimensions)
if self.model.selected_fixed_size is not None:
box = [box[0],
box = (box[0],
box[1],
box[0] + self.model.selected_fixed_size[0],
box[1] + self.model.selected_fixed_size[1]]
box[1] + self.model.selected_fixed_size[1])
new_filename: str = self.find_available_name(
self.model.args.output_dir, self.model.images[self.model.current_file])
saved_image: Image = self.model.current_image.copy().crop(box)
saved_image: Image.Image = self.model.current_image.copy().crop(box)
if self.model.args.resize:
saved_image = saved_image.resize(
(self.model.args.resize[0], self.model.args.resize[1]), Image.LANCZOS)
(self.model.args.resize[0], self.model.args.resize[1]), Image.Resampling.LANCZOS)
if self.model.args.image_format:
new_filename, _ = os.path.splitext(new_filename)
if not os.path.exists(self.model.args.output_dir):
Expand All @@ -198,7 +200,7 @@ def save(self) -> bool:

def rotate_image(self):
if self.model.current_image is not None:
rotated_image = self.model.current_image.transpose(Image.ROTATE_90)
rotated_image = self.model.current_image.transpose(Image.Transpose.ROTATE_90)
self.model.current_image.close()
self.model.current_image = None
self.display_image_on_canvas(rotated_image)
Expand Down Expand Up @@ -241,7 +243,7 @@ def load_image_list(directory: str) -> List[str]:

@staticmethod
def coordinates_in_selection_box(
coordinates: Tuple[int, int], selection_box: Tuple[int, int]) -> bool:
coordinates: Tuple[int, int], selection_box: Tuple[int, int, int, int]) -> bool:
return (coordinates[0] > selection_box[0] and coordinates[0] < selection_box[2]
and coordinates[1] > selection_box[1] and coordinates[1] < selection_box[3])

Expand All @@ -258,6 +260,7 @@ def find_available_name(directory: str, filename: str) -> str:
str(num) +
extension)):
return name + str(num) + extension
raise ValueError("No available name found")

@staticmethod
def get_selection_box_for_aspect_ratio(selection_box: Tuple[int,
Expand All @@ -272,24 +275,26 @@ def get_selection_box_for_aspect_ratio(selection_box: Tuple[int,
int,
int,
int]:
selection_box: List[int] = list(selection_box)
width: int = selection_box[2] - selection_box[0]
height: int = selection_box[3] - selection_box[1]
if float(width) / float(height) > aspect_ratio:
height = round(width / aspect_ratio)
if mouse_move_coord[1] > mouse_press_coord[1]:
selection_box[3] = selection_box[1] + height
return (selection_box[0], selection_box[1], selection_box[2], selection_box[1] + height)
else:
selection_box[1] = selection_box[3] - height
return (selection_box[0], selection_box[3] - height, selection_box[2], selection_box[3])
else:
width = round(height * aspect_ratio)
if mouse_move_coord[0] > mouse_press_coord[0]:
selection_box[2] = selection_box[0] + width
return (selection_box[0], selection_box[1], selection_box[0] + width, selection_box[3])
else:
selection_box[0] = selection_box[2] - width
return tuple(selection_box)
return (selection_box[2] - width, selection_box[1], selection_box[2], selection_box[3])

def get_selected_box(self,

@staticmethod
def get_selected_box(selected_fixed_size: Optional[Tuple[int,
int]],
canvas_image_scaling_ratio: Optional[float],
mouse_press_coord: Tuple[int,
int],
mouse_move_coord: Tuple[int,
Expand All @@ -300,10 +305,10 @@ def get_selected_box(self,
int,
int]:

if self.model.selected_fixed_size is not None:
if selected_fixed_size is not None and canvas_image_scaling_ratio is not None:
mouse_press_coord = mouse_move_coord
mouse_move_coord = (mouse_press_coord[0] + self.model.selected_fixed_size[0] * self.model.canvas_image_scaling_ratio,
mouse_press_coord[1] + self.model.selected_fixed_size[1] * self.model.canvas_image_scaling_ratio)
mouse_move_coord = (int(mouse_press_coord[0] + selected_fixed_size[0] * canvas_image_scaling_ratio),
int(mouse_press_coord[1] + selected_fixed_size[1] * canvas_image_scaling_ratio))


selection_top_left_x: int = min(
Expand All @@ -323,11 +328,9 @@ def get_selected_box(self,
selection_bottom_right_y)

if aspect_ratio is not None:
aspect_ratio: float = float(
aspect_ratio[0]) / float(aspect_ratio[1])
try:
selection_box: Tuple[int, int, int, int] = Controller.get_selection_box_for_aspect_ratio(
selection_box, aspect_ratio, mouse_press_coord, mouse_move_coord)
selection_box, float(aspect_ratio[0]) / float(aspect_ratio[1]), mouse_press_coord, mouse_move_coord)
except ZeroDivisionError:
pass

Expand Down
2 changes: 2 additions & 0 deletions inbac/inbac.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def __init__(self, args: Namespace, master: Tk):

if args.input_dir is None:
args.input_dir = filedialog.askdirectory(parent=master)
if args.input_dir == () or args.input_dir == "" or args.input_dir is None:
raise ValueError("No input directory specified")
args.output_dir = getattr(
args, "output_dir", os.path.join(args.input_dir, "crops"))

Expand Down
4 changes: 2 additions & 2 deletions inbac/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ def __init__(self, args):
self.move_coord: Tuple[int, int] = (0, 0)
self.displayed_image: Optional[PhotoImage] = None
self.canvas_image: Optional[Any] = None
self.cavnas_image_scaling_ratio: Optional[float] = None
self.canvas_image_scaling_ratio: Optional[float] = None
self.canvas_image_dimensions: Tuple[int, int] = (0, 0)
self.current_image: Optional[Image] = None
self.current_image: Optional[Image.Image] = None
self.enabled_selection_mode: bool = False
self.box_selected: bool = False
self.current_file: int = 0
Expand Down
112 changes: 66 additions & 46 deletions inbac/view.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import tkinter as tk
import types
from tkinter import Tk, Frame, Canvas, Event, Menu, messagebox, filedialog, Toplevel
from typing import Tuple, Any
from typing import Tuple, Any, Optional
from PIL.ImageTk import PhotoImage
import inbac

from typing import TYPE_CHECKING
if TYPE_CHECKING:
from inbac.controller import Controller

class View():
def __init__(self, master: Tk, initial_window_size: Tuple[int, int]):
Expand All @@ -16,7 +18,7 @@ def __init__(self, master: Tk, initial_window_size: Tuple[int, int]):
self.master.geometry(
str(initial_window_size[0]) + "x" + str(initial_window_size[1]))
self.master.update()
self.controller = None
self.controller: Optional['Controller'] = None

self.bind_events()
self.create_menu()
Expand Down Expand Up @@ -56,10 +58,13 @@ def ask_directory(self) -> str:
return filedialog.askdirectory(parent=self.master)

def open_dialog(self):
self.controller.select_images_folder()
self.controller.load_images()
if self.controller is not None:
self.controller.select_images_folder()
self.controller.load_images()

def create_settings_window(self):
if self.controller is None:
return
settings_window = tk.Toplevel(self.master)
settings_window.title("Settings")
settings_window.geometry("{}x{}".format(400, 400))
Expand Down Expand Up @@ -149,7 +154,7 @@ def create_settings_window(self):
settings.selection_box_color_choices = [
"black", "white", "red", "green", "blue", "cyan", "yellow", "magenta"]
settings.selection_box_color_listbox = tk.Listbox(
settings_window, listvariable=tk.StringVar(
settings_window, listvariable=tk.ListVar( # type: ignore
value=settings.selection_box_color_choices))
if self.controller.model.args.selection_box_color in settings.selection_box_color_choices:
selection_box_color_index = settings.selection_box_color_choices.index(
Expand All @@ -176,6 +181,8 @@ def create_settings_window(self):

def save_settings(self, settings_window: Toplevel,
settings: types.SimpleNamespace):
if self.controller is None:
return
if settings.aspect_ratio_checked.get():
self.controller.model.args.aspect_ratio = (
int(settings.aspect_ratio_x.get()), int(settings.aspect_ratio_y.get()))
Expand Down Expand Up @@ -213,7 +220,7 @@ def create_rectangle(
self, box: Tuple[int, int, int, int], outline_color: str) -> Any:
return self.image_canvas.create_rectangle(box, outline=outline_color)

def change_canvas_object_coords(self, obj: Any, coords: Tuple[int, int]):
def change_canvas_object_coords(self, obj: Any, coords: Tuple[int, int, int, int]):
self.image_canvas.coords(obj, coords)

def get_canvas_object_coords(self, obj: Any) -> Any:
Expand All @@ -226,58 +233,71 @@ def move_canvas_object_by_offset(
offset_y: int):
self.image_canvas.move(obj, offset_x, offset_y)

def enable_selection_mode(self, event: Event = None):
self.controller.model.enabled_selection_mode = True
def enable_selection_mode(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.model.enabled_selection_mode = True

def disable_selection_mode(self, event: Event = None):
self.controller.model.enabled_selection_mode = False
def disable_selection_mode(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.model.enabled_selection_mode = False

def on_mouse_down(self, event: Event):
self.controller.start_selection((event.x, event.y))
if self.controller is not None:
self.controller.start_selection((event.x, event.y))

def on_mouse_drag(self, event: Event):
self.controller.move_selection((event.x, event.y))
if self.controller is not None:
self.controller.move_selection((event.x, event.y))

def on_mouse_up(self, event: Event):
self.controller.stop_selection()
if self.controller is not None:
self.controller.stop_selection()

def next_image(self, event: Event = None):
self.controller.next_image()
def next_image(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.next_image()

def previous_image(self, event: Event = None):
self.controller.previous_image()
def previous_image(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.previous_image()

def on_resize(self, event: Event = None):
self.controller.display_image_on_canvas(
self.controller.model.current_image)
def on_resize(self, event: Optional[Event] = None):
if self.controller is not None and self.controller.model.current_image is not None:
self.controller.display_image_on_canvas(
self.controller.model.current_image)

def save_next(self, event: Event = None):
self.controller.save_next()
def save_next(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.save_next()

def save(self, event: Event = None):
self.controller.save()
def save(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.save()

def set_title(self, title: str):
self.master.title(title)

def rotate_image(self, event: Event = None):
self.controller.rotate_image()

def rotate_aspect_ratio(self, event: Event = None):
self.controller.rotate_aspect_ratio()

def cycle_fixed_selection_sizes(self, event: Event = None):
model = self.controller.model
if len(model.args.fixed_sizes) == 0:
return

if model.selected_fixed_size_index is None:
model.selected_fixed_size_index = 0
else:
model.selected_fixed_size_index += 1

if model.selected_fixed_size_index == len(model.args.fixed_sizes):
model.selected_fixed_size_index = None
model.selected_fixed_size = None
else:
model.selected_fixed_size = model.args.fixed_sizes[model.selected_fixed_size_index]
def rotate_image(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.rotate_image()

def rotate_aspect_ratio(self, event: Optional[Event] = None):
if self.controller is not None:
self.controller.rotate_aspect_ratio()

def cycle_fixed_selection_sizes(self, event: Optional[Event] = None):
if self.controller is not None:
model = self.controller.model
if len(model.args.fixed_sizes) == 0:
return

if model.selected_fixed_size_index is None:
model.selected_fixed_size_index = 0
else:
model.selected_fixed_size_index += 1

if model.selected_fixed_size_index == len(model.args.fixed_sizes):
model.selected_fixed_size_index = None
model.selected_fixed_size = None
else:
model.selected_fixed_size = model.args.fixed_sizes[model.selected_fixed_size_index]
Loading

0 comments on commit af33b4c

Please sign in to comment.