feat: mode-based image/video presets, multiple profiles, and compatibility fixes

This commit is contained in:
younisch96
2026-03-24 02:17:56 +05:00
parent 124c314db6
commit e9812b5686
3 changed files with 221 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
MODES = ["Image", "Video"]
IMAGE_PRESETS = {
"SD (512)": 512,
"HD (768)": 768,
"1K (1024)": 1024,
"2K (2048)": 2048,
"3K (3072)": 3072,
"4K (4096)": 4096,
}
VIDEO_PRESETS = {
"520p (960x520)": 960,
"720p (1280x720)": 1280,
"1080p (1920x1080) - Premium": 1920,
}
MULTIPLE_PROFILES = {
"Auto (Image=64, Video=32)": "auto",
"Flux / SDXL (64)": 64,
"LTX (32)": 32,
"Wan (16)": 16,
"SD1.5 (8)": 8,
}
IMAGE_PRESET_KEYS = list(IMAGE_PRESETS.keys())
VIDEO_PRESET_KEYS = list(VIDEO_PRESETS.keys())
MULTIPLE_PROFILE_KEYS = list(MULTIPLE_PROFILES.keys())
LEGACY_PRESETS = {
"SD-512px": 512,
"HD-1280px": 1280,
"FullHD-1920px": 1920,
"2K-2048px": 2048,
"QHD-2560px": 2560,
"4K-3840px": 3840,
"8K-7680px": 7680,
"FullHD_1920x1080": 1920,
}
ASPECT_RATIOS = {
# Square
"1:1-AlbumArt": (1, 1),
# Portrait Formats
"4:5-InstagramPortrait": (4, 5),
"2:3-ClassicPortrait": (2, 3),
"3:4-EditorialPortrait": (3, 4),
# Vertical Video
"9:16-TikTokReel": (9, 16),
# Landscape / Video
"4:3-ClassicVideo": (4, 3),
"16:9-Widescreen": (16, 9),
# Cinematic Aspect
"21:9-CinemaScope": (21, 9),
# Ultra Wide
"32:9-UltraWideBanner": (32, 9),
}
def snap_to_multiple(x, multiple):
return max(multiple, int(round(x / float(multiple))) * multiple)
def resolve_multiple(mode, multiple_profile):
value = MULTIPLE_PROFILES.get(multiple_profile, "auto")
if value == "auto":
return 32 if mode == "Video" else 64
return int(value)
def normalize_aspect_ratio(aspect_ratio):
# Allow old broken saved values too
if aspect_ratio == "16:9_Widescreen":
return "16:9-Widescreen"
if aspect_ratio in ASPECT_RATIOS:
return aspect_ratio
return "16:9-Widescreen"
def nearest_image_preset(long_side):
return min(IMAGE_PRESETS, key=lambda k: abs(IMAGE_PRESETS[k] - long_side))
def nearest_video_preset(long_side):
return min(VIDEO_PRESETS, key=lambda k: abs(VIDEO_PRESETS[k] - long_side))
def parse_mode_presets(mode, image_preset, video_preset, multiple_profile, resolution_preset=""):
if mode not in MODES:
mode = "Image"
# Migrate old workflows carrying resolution_preset only
if resolution_preset in LEGACY_PRESETS:
legacy_long = LEGACY_PRESETS[resolution_preset]
if mode == "Video":
video_preset = nearest_video_preset(legacy_long)
else:
image_preset = nearest_image_preset(legacy_long)
if image_preset not in IMAGE_PRESETS:
image_preset = "1K (1024)"
if video_preset not in VIDEO_PRESETS:
video_preset = "720p (1280x720)"
if multiple_profile not in MULTIPLE_PROFILES:
multiple_profile = "Auto (Image=64, Video=32)"
return mode, image_preset, video_preset, multiple_profile
def get_long_side(mode, image_preset, video_preset):
if mode == "Video":
return VIDEO_PRESETS[video_preset]
return IMAGE_PRESETS[image_preset]
+51
View File
@@ -0,0 +1,51 @@
import torch
from .latent_utils import (
MODES,
IMAGE_PRESET_KEYS,
VIDEO_PRESET_KEYS,
MULTIPLE_PROFILE_KEYS,
ASPECT_RATIOS,
snap_to_multiple,
resolve_multiple,
normalize_aspect_ratio,
parse_mode_presets,
get_long_side,
)
class SmartLatentGenerator:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mode": (MODES, {"default": "Image"}),
"image_preset": (IMAGE_PRESET_KEYS, {"default": "1K (1024)"}),
"video_preset": (VIDEO_PRESET_KEYS, {"default": "720p (1280x720)"}),
"multiple_profile": (MULTIPLE_PROFILE_KEYS, {"default": "Auto (Image=64, Video=32)"}),
"aspect_ratio": (list(ASPECT_RATIOS.keys()), {"default": "16:9-Widescreen"}),
"batch_size": ("INT", {"default": 1, "min": 1, "max": 16}),
},
"optional": {
"resolution_preset": ("STRING", {"default": "HD-1280px"}),
},
}
RETURN_TYPES = ("LATENT",)
RETURN_NAMES = ("LATENT",)
FUNCTION = "generate"
CATEGORY = "latent/generator"
def generate(self, mode, image_preset, video_preset, multiple_profile, aspect_ratio, batch_size, resolution_preset=""):
mode, image_preset, video_preset, multiple_profile = parse_mode_presets(
mode, image_preset, video_preset, multiple_profile, resolution_preset
)
aspect_ratio = normalize_aspect_ratio(aspect_ratio)
long_side = get_long_side(mode, image_preset, video_preset)
multiple = resolve_multiple(mode, multiple_profile)
ar_w, ar_h = ASPECT_RATIOS[aspect_ratio]
scale = long_side / float(max(ar_w, ar_h))
width = snap_to_multiple(ar_w * scale, multiple)
height = snap_to_multiple(ar_h * scale, multiple)
latent = torch.zeros([batch_size, 4, height // 8, width // 8])
return ({"samples": latent},)
+53
View File
@@ -0,0 +1,53 @@
from .latent_utils import (
MODES,
IMAGE_PRESET_KEYS,
VIDEO_PRESET_KEYS,
MULTIPLE_PROFILE_KEYS,
ASPECT_RATIOS,
snap_to_multiple,
resolve_multiple,
normalize_aspect_ratio,
parse_mode_presets,
get_long_side,
)
class SmartResolutionPicker:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"mode": (MODES, {"default": "Image"}),
"image_preset": (IMAGE_PRESET_KEYS, {"default": "1K (1024)"}),
"video_preset": (VIDEO_PRESET_KEYS, {"default": "720p (1280x720)"}),
"multiple_profile": (MULTIPLE_PROFILE_KEYS, {"default": "Auto (Image=64, Video=32)"}),
"aspect_ratio": (list(ASPECT_RATIOS.keys()), {"default": "16:9-Widescreen"}),
},
"optional": {
# Backward compatibility with older saved workflows
"resolution_preset": ("STRING", {"default": "HD-1280px"}),
},
}
RETURN_TYPES = ("INT", "INT", "STRING")
RETURN_NAMES = ("width", "height", "resolution_info")
FUNCTION = "calculate"
CATEGORY = "utils/latent"
def calculate(self, mode, image_preset, video_preset, multiple_profile, aspect_ratio, resolution_preset=""):
mode, image_preset, video_preset, multiple_profile = parse_mode_presets(
mode, image_preset, video_preset, multiple_profile, resolution_preset
)
aspect_ratio = normalize_aspect_ratio(aspect_ratio)
long_side = get_long_side(mode, image_preset, video_preset)
multiple = resolve_multiple(mode, multiple_profile)
ar_w, ar_h = ASPECT_RATIOS[aspect_ratio]
scale = long_side / float(max(ar_w, ar_h))
width = snap_to_multiple(ar_w * scale, multiple)
height = snap_to_multiple(ar_h * scale, multiple)
info = f"{width}x{height} | {mode} | {aspect_ratio} | mul={multiple}"
return {
"ui": {"text": [info]},
"result": (width, height, info),
}