From fefe563127cb7b3650457b3f711de205e45a1b7a Mon Sep 17 00:00:00 2001 From: Kent Keirsey <31807370+hipsterusername@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:50:44 -0400 Subject: [PATCH] fix resizing and versioning --- invokeai/app/invocations/flux_denoise.py | 2 +- .../flux/extensions/kontext_extension.py | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/invokeai/app/invocations/flux_denoise.py b/invokeai/app/invocations/flux_denoise.py index ac62e574e5..06471157a3 100644 --- a/invokeai/app/invocations/flux_denoise.py +++ b/invokeai/app/invocations/flux_denoise.py @@ -63,7 +63,7 @@ from invokeai.backend.util.devices import TorchDevice title="FLUX Denoise", tags=["image", "flux"], category="image", - version="4.0.0", + version="4.1.0", ) class FluxDenoiseInvocation(BaseInvocation): """Run denoising process with a FLUX transformer model.""" diff --git a/invokeai/backend/flux/extensions/kontext_extension.py b/invokeai/backend/flux/extensions/kontext_extension.py index bf2062401d..535aaeaafa 100644 --- a/invokeai/backend/flux/extensions/kontext_extension.py +++ b/invokeai/backend/flux/extensions/kontext_extension.py @@ -3,6 +3,9 @@ import numpy as np import torch from einops import repeat from PIL import Image +import torchvision.transforms as T +from dataclasses import dataclass +from typing from invokeai.app.invocations.fields import FluxKontextConditioningField from invokeai.app.invocations.flux_vae_encode import FluxVaeEncodeInvocation @@ -12,6 +15,80 @@ from invokeai.backend.flux.sampling_utils import pack from invokeai.backend.flux.util import PREFERED_KONTEXT_RESOLUTIONS +@dataclass +class KontextResizeConstraints: + """Configurable constraints for FLUX Kontext image resizing.""" + + min_dimension: int = 672 + max_dimension: int = 1568 + multiple: int = 16 # Ensure dimensions are multiples of this value + + +def calculate_optimal_kontext_dimensions( + width: int, height: int, constraints: KontextResizeConstraints = KontextResizeConstraints() +) -> tuple[int, int]: + """Calculate optimal dimensions for FLUX Kontext conditioning. + + This function ensures: + 1. Dimensions are multiples of the specified multiple + 2. Dimensions are within the valid range + 3. Aspect ratio is preserved as closely as possible + 4. Implicit optimization for performance by maximizing within constraints + + Args: + width: Original image width + height: Original image height + constraints: Resize constraints configuration + + Returns: + Tuple of (optimal_width, optimal_height) + """ + aspect_ratio = width / height + + # Calculate the maximum possible dimensions while staying within bounds + if aspect_ratio >= 1.0: # Landscape or square + # Width is the larger dimension + max_width = min(constraints.max_dimension, width) + max_width = (max_width // constraints.multiple) * constraints.multiple + optimal_width = max(constraints.min_dimension, max_width) + optimal_height = int(optimal_width / aspect_ratio) + optimal_height = (optimal_height // constraints.multiple) * constraints.multiple + optimal_height = max(constraints.min_dimension, optimal_height) + else: # Portrait + # Height is the larger dimension + max_height = min(constraints.max_dimension, height) + max_height = (max_height // constraints.multiple) * constraints.multiple + optimal_height = max(constraints.min_dimension, max_height) + optimal_width = int(optimal_height * aspect_ratio) + optimal_width = (optimal_width // constraints.multiple) * constraints.multiple + optimal_width = max(constraints.min_dimension, optimal_width) + + return optimal_width, optimal_height + + +def resize_to_optimal_kontext_resolution( + image: Image.Image, constraints: KontextResizeConstraints = KontextResizeConstraints() +) -> Image.Image: + """Resize image to optimal FLUX Kontext resolution. + + This ensures the image dimensions are compatible with the FLUX packing operation + and provides optimal performance for Kontext conditioning. + + Args: + image: PIL Image to resize + constraints: Resize constraints configuration + + Returns: + Resized PIL Image with optimal dimensions + """ + width, height = image.size + optimal_width, optimal_height = calculate_optimal_kontext_dimensions(width, height, constraints) + + # Resize the image to the optimal resolution + resized_image = image.resize((optimal_width, optimal_height), Image.Resampling.LANCZOS) + return resized_image + + def generate_img_ids_with_offset( latent_height: int, latent_width: int,