239 lines
6.1 KiB
Python
239 lines
6.1 KiB
Python
"""
|
||
Size preset definitions and calculation logic for the ComfyUI Auto Size plugin.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
|
||
# ============================================================================
|
||
# Model Specifications
|
||
# ============================================================================
|
||
|
||
MODEL_SPECS: dict[str, int] = {
|
||
"qwen-image": 28,
|
||
"illustrious": 32,
|
||
"z-image": 32,
|
||
"flux": 32,
|
||
}
|
||
|
||
DEFAULT_MODEL: str = "qwen-image"
|
||
|
||
# ============================================================================
|
||
# Fixed Size Presets
|
||
# ============================================================================
|
||
|
||
QWEN_SIZES: dict[str, tuple[int, int]] = {
|
||
"1:1": (1328, 1328),
|
||
"9:16": (928, 1664),
|
||
"16:9": (1664, 928),
|
||
"3:4": (1104, 1472),
|
||
"4:3": (1472, 1104),
|
||
"2:3": (1056, 1584),
|
||
"3:2": (1584, 1056),
|
||
}
|
||
|
||
ILLUSTRIOUS_SIZES: dict[str, tuple[int, int]] = {
|
||
"1:1": (1024, 1024),
|
||
"9:16": (768, 1344),
|
||
"16:9": (1344, 768),
|
||
"13:19": (832, 1216),
|
||
"19:13": (1216, 832),
|
||
"9:7": (1152, 896),
|
||
"7:9": (896, 1152),
|
||
"12:5": (1536, 640),
|
||
"5:12": (640, 1536),
|
||
"2:3": (1024, 1536),
|
||
"4:5": (896, 1120),
|
||
"5:4": (1120, 896),
|
||
"3:4": (864, 1152),
|
||
"4:3": (1152, 864),
|
||
}
|
||
|
||
Z_IMAGE_SIZES: dict[str, tuple[int, int]] = {
|
||
"1:1": (1280, 1280),
|
||
"9:16": (896, 1600),
|
||
"16:9": (1600, 896),
|
||
"7:9": (1120, 1440),
|
||
"9:7": (1440, 1120),
|
||
"3:4": (1104, 1472),
|
||
"4:3": (1472, 1104),
|
||
"2:3": (1024, 1536),
|
||
"3:2": (1536, 1024),
|
||
"9:21": (720, 1680),
|
||
"21:9": (1680, 720),
|
||
}
|
||
|
||
FLUX_SIZES: dict[str, tuple[int, int]] = {
|
||
"1:1": (1024, 1024),
|
||
"9:16": (720, 1280),
|
||
"16:9": (1280, 720),
|
||
"7:9": (896, 1152),
|
||
"9:7": (1152, 896),
|
||
"3:4": (864, 1152),
|
||
"4:3": (1152, 864),
|
||
"2:3": (832, 1248),
|
||
"3:2": (1248, 832),
|
||
"9:21": (576, 1344),
|
||
"21:9": (1344, 576),
|
||
}
|
||
|
||
|
||
FAV_SIZES: dict[str, tuple[int, int]] = {
|
||
"1:1": (1536, 1536),
|
||
"9:7": (1728, 1344),
|
||
"7:9": (1344, 1728),
|
||
"3:2": (1824, 1248),
|
||
"2:3": (1248, 1824),
|
||
"16:9": (2016, 1152),
|
||
"9:16": (1152, 2016),
|
||
}
|
||
|
||
# Combine for dropdown (labelled with size)
|
||
SIZE_LIST: list[str] = ["Full Custom (Use Inputs Below)"]
|
||
|
||
|
||
def add_to_list(prefix: str, sizes: dict[str, tuple[int, int]]) -> None:
|
||
"""
|
||
Populate the `SIZE_LIST` with human‑readable entries for a given size map.
|
||
"""
|
||
for ratio_label, (width, height) in sizes.items():
|
||
SIZE_LIST.append(f"{prefix} - {ratio_label} ({width}x{height})")
|
||
|
||
|
||
add_to_list("Qwen", QWEN_SIZES)
|
||
add_to_list("Illustrious", ILLUSTRIOUS_SIZES)
|
||
add_to_list("Z-Image", Z_IMAGE_SIZES)
|
||
add_to_list("Flux", FLUX_SIZES)
|
||
add_to_list("Fav", FAV_SIZES)
|
||
|
||
|
||
# ============================================================================
|
||
# Ratios
|
||
# ============================================================================
|
||
|
||
RATIOS: dict[str, float] = {
|
||
"1:1": 1.0,
|
||
"9:16": 9 / 16,
|
||
"16:9": 16 / 9,
|
||
"4:5": 4 / 5,
|
||
"5:4": 5 / 4,
|
||
"3:4": 3 / 4,
|
||
"4:3": 4 / 3,
|
||
"2:3": 2 / 3,
|
||
"3:2": 3 / 2,
|
||
"5:7": 5 / 7,
|
||
"7:5": 7 / 5,
|
||
"9:21": 9 / 21,
|
||
"21:9": 21 / 9,
|
||
"1:2": 1 / 2,
|
||
"2:1": 2 / 1,
|
||
}
|
||
|
||
# ============================================================================
|
||
# Lists for UI
|
||
# ============================================================================
|
||
|
||
MODEL_LIST: list[str] = list(MODEL_SPECS.keys())
|
||
RATIO_LIST: list[str] = [
|
||
"1:1",
|
||
"1:2",
|
||
"2:1",
|
||
"2:3",
|
||
"3:2",
|
||
"3:4",
|
||
"4:3",
|
||
"4:5",
|
||
"5:4",
|
||
"5:7",
|
||
"7:5",
|
||
"9:16",
|
||
"16:9",
|
||
"9:21",
|
||
"21:9",
|
||
]
|
||
|
||
# ============================================================================
|
||
# Method Constants
|
||
# ============================================================================
|
||
|
||
CROP_METHODS: list[str] = [
|
||
"Center Crop",
|
||
"Top-Left Crop",
|
||
"Bottom-Right Crop",
|
||
"Scale to Fit",
|
||
"Stretch to Fill",
|
||
]
|
||
|
||
SCALE_METHODS: list[str] = ["lanczos", "bilinear", "bicubic", "nearest"]
|
||
|
||
INTERPOLATION_MODES: dict[str, str] = {
|
||
"lanczos": "bicubic",
|
||
"bilinear": "bilinear",
|
||
"bicubic": "bicubic",
|
||
"nearest": "nearest",
|
||
}
|
||
|
||
# ============================================================================
|
||
# Calculation Logic
|
||
# ============================================================================
|
||
|
||
|
||
def resolve_resolution(
|
||
size_selection: str,
|
||
longer_side: int,
|
||
custom_ratio: str,
|
||
model: str,
|
||
) -> tuple[int, int]:
|
||
"""
|
||
Resolve final resolution based on priority:
|
||
|
||
1. Size selection (if not "Full Custom")
|
||
2. Custom calculation (longer side + ratio)
|
||
|
||
Args:
|
||
size_selection: The selected size string from defaults.
|
||
longer_side: The manual long side size.
|
||
custom_ratio: The manual aspect ratio.
|
||
model: The selected model (for strict alignment).
|
||
|
||
Returns:
|
||
(width, height) in pixels, snapped to the model's required multiple.
|
||
"""
|
||
|
||
# 1. Custom calculation (Primary if explicit value provided)
|
||
if longer_side > 0:
|
||
target_ratio = RATIOS.get(custom_ratio, 1.0)
|
||
multiple = MODEL_SPECS.get(model, 32)
|
||
|
||
if target_ratio > 1.0:
|
||
width = float(longer_side)
|
||
height = width / target_ratio
|
||
elif target_ratio < 1.0:
|
||
height = float(longer_side)
|
||
width = height * target_ratio
|
||
else:
|
||
width = float(longer_side)
|
||
height = float(longer_side)
|
||
|
||
final_width = round(width / multiple) * multiple
|
||
final_height = round(height / multiple) * multiple
|
||
|
||
final_width = max(final_width, multiple)
|
||
final_height = max(final_height, multiple)
|
||
|
||
return int(final_width), int(final_height)
|
||
|
||
# 2. Fixed "Size" selection (Fallback)
|
||
# data format example: "Qwen - 1:1 (1328x1328)"
|
||
if size_selection and "Full Custom" not in size_selection:
|
||
try:
|
||
# Extract "1328x1328" from inside parens
|
||
dim_part = size_selection.rsplit("(", 1)[-1].strip(")")
|
||
w_str, h_str = dim_part.split("x")
|
||
return int(w_str), int(h_str)
|
||
except (ValueError, IndexError):
|
||
pass
|
||
|
||
# 3. Default Fallback
|
||
return 1024, 1024
|