diff --git a/croppa/main.py b/croppa/main.py index ad40cca..aed04eb 100644 --- a/croppa/main.py +++ b/croppa/main.py @@ -2880,38 +2880,67 @@ class VideoEditor: if display_frame is None: return - # Resize to fit window while maintaining aspect ratio - height, width = display_frame.shape[:2] - available_height = self.window_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT) + # Get actual window dimensions (important for fullscreen mode) + window_title = "Image Editor" if self.is_image_mode else "Video Editor" + try: + window_rect = cv2.getWindowImageRect(window_title) + if window_rect[2] > 0 and window_rect[3] > 0: # width and height > 0 + actual_width = window_rect[2] + actual_height = window_rect[3] + else: + # Fallback to stored dimensions + actual_width = self.window_width + actual_height = self.window_height + except: + # Fallback to stored dimensions + actual_width = self.window_width + actual_height = self.window_height - # Don't downscale - keep original video quality - # If video is larger than window, we'll handle it by resizing the window - scale = min(self.window_width / width, available_height / height) - if scale < 1.0: - # Resize window to fit video instead of downscaling video - new_window_width = int(width * 1.1) # Add 10% padding - new_window_height = int(height * 1.1) + (0 if self.is_image_mode else self.TIMELINE_HEIGHT) - - # Update window size - self.window_width = new_window_width - self.window_height = new_window_height - - # Resize the OpenCV window - window_title = "Image Editor" if self.is_image_mode else "Video Editor" - cv2.resizeWindow(window_title, self.window_width, self.window_height) + # Calculate available space for video (accounting for timeline) + available_height = actual_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT) + + # Get original video dimensions to maintain aspect ratio + height, width = display_frame.shape[:2] + + # Calculate scale to fit video in available space while maintaining aspect ratio + scale_x = actual_width / width + scale_y = available_height / height + scale = min(scale_x, scale_y) # Use the smaller scale to ensure video fits + + # Ensure scale is never greater than 1.0 to prevent upscaling beyond screen + scale = min(scale, 1.0) + + # Calculate scaled dimensions + scaled_width = int(width * scale) + scaled_height = int(height * scale) + + # Double-check that scaled dimensions fit within available space + if scaled_height > available_height: + scale = available_height / height + scaled_width = int(width * scale) + scaled_height = int(height * scale) + + if scaled_width > actual_width: + scale = actual_width / width + scaled_width = int(width * scale) + scaled_height = int(height * scale) + + # Resize the frame to fit the window while maintaining aspect ratio + if scale != 1.0: + display_frame = cv2.resize(display_frame, (scaled_width, scaled_height), interpolation=cv2.INTER_LINEAR) # Create canvas with timeline space - canvas = np.zeros((self.window_height, self.window_width, 3), dtype=np.uint8) + canvas = np.zeros((actual_height, actual_width, 3), dtype=np.uint8) # Center the frame on canvas frame_height, frame_width = display_frame.shape[:2] - available_height = self.window_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT) + available_height = actual_height - (0 if self.is_image_mode else self.TIMELINE_HEIGHT) start_y = (available_height - frame_height) // 2 - start_x = (self.window_width - frame_width) // 2 + start_x = (actual_width - frame_width) // 2 # Ensure frame fits within canvas bounds end_y = min(start_y + frame_height, available_height) - end_x = min(start_x + frame_width, self.window_width) + end_x = min(start_x + frame_width, actual_width) actual_frame_height = end_y - start_y actual_frame_width = end_x - start_x