commit 171efb7d0cade55900b8d4587f649688171b5d0f Author: BuddyBytes.co Date: Sat Nov 29 02:18:50 2025 +0700 Initial commit Smart Resolution Toolkit for ComfyUI diff --git a/README.md b/README.md new file mode 100644 index 0000000..7b67440 --- /dev/null +++ b/README.md @@ -0,0 +1,68 @@ +# ComfyUI-SmartResolutionPicker + +A lightweight yet powerful resolution assistant for ComfyUI. +It allows you to **select image size using human-friendly dropdowns** instead of typing width and height manually. + +Designed for: +✓ EmptyLatentImage +✓ Video / TikTok / IG / Story formats +✓ ControlNet / AnimateDiff / Sampler +✓ Latent-safe (auto snap to 64) + +--- + +## ✨ Features + +🧠 Smart width & height calculation +– Choose **Resolution Preset** (HD, FullHD, 2K, 4K, 8K) +– Choose **Aspect Ratio** (1:1, 9:16, 4:5, 21:9 etc.) +– Output: clean `width` and `height` (INT values) + +⚙ Latent-safe scaling +– Automatically snaps resolution to the nearest multiple of 64 +– 100% compatible with latent operations + +🎯 Two Nodes Included + +| Node | Description | +|------|-------------| +| Smart Resolution Picker | Returns width & height (INT) for image/latent initialization | +| Smart Latent Generator | Directly creates empty LATENT tensor from resolution + ratio | + +--- + +## 📐 Available Resolution Presets + +| Name | Size | +|------|------| +| SD | 512 × 512 | +| HD | 1280 × 720 | +| FullHD | 1920 × 1080 | +| 2K Cinema | 2048 × 1080 | +| QHD | 2560 × 1440 | +| 4K UHD | 3840 × 2160 | +| 8K UHD | 7680 × 4320 | + +--- + +## 📸 Available Aspect Ratios + +| Ratio | Common Usage | +|-------|--------------| +| 1:1 | Square / Album Cover | +| 4:5 | Instagram Portrait | +| 3:4 | Classic Portrait / Photography | +| 2:3 | DSLR Photo / Print | +| 5:4 | Medium Format | +| 9:16 | TikTok / Reel / Story | +| 16:9 | YouTube / Widescreen | +| 21:9 | Cinematic Ultra-wide | + +--- + +## 🚀 SmartLatentGenerator Node +Generates latent **directly**, no need for EmptyLatentImage. + +```mermaid +flowchart LR + A[SmartLatentGenerator] --> B[Sampler / KSampler] diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..4f059a2 --- /dev/null +++ b/__init__.py @@ -0,0 +1,12 @@ +from .smart_resolution import SmartResolutionPicker +from .smart_latent import SmartLatentGenerator + +NODE_CLASS_MAPPINGS = { + "SmartResolutionPicker": SmartResolutionPicker, + "SmartLatentGenerator": SmartLatentGenerator, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "SmartResolutionPicker": "Smart Resolution Picker", + "SmartLatentGenerator": "Smart Latent Generator", +} diff --git a/__pycache__/__init__.cpython-310.pyc b/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..5c24cf9 Binary files /dev/null and b/__pycache__/__init__.cpython-310.pyc differ diff --git a/__pycache__/latent_utils.cpython-310.pyc b/__pycache__/latent_utils.cpython-310.pyc new file mode 100644 index 0000000..abebac2 Binary files /dev/null and b/__pycache__/latent_utils.cpython-310.pyc differ diff --git a/__pycache__/nodes.cpython-310.pyc b/__pycache__/nodes.cpython-310.pyc new file mode 100644 index 0000000..48ca796 Binary files /dev/null and b/__pycache__/nodes.cpython-310.pyc differ diff --git a/__pycache__/smart_latent.cpython-310.pyc b/__pycache__/smart_latent.cpython-310.pyc new file mode 100644 index 0000000..50fd461 Binary files /dev/null and b/__pycache__/smart_latent.cpython-310.pyc differ diff --git a/__pycache__/smart_noise.cpython-310.pyc b/__pycache__/smart_noise.cpython-310.pyc new file mode 100644 index 0000000..d079ddb Binary files /dev/null and b/__pycache__/smart_noise.cpython-310.pyc differ diff --git a/__pycache__/smart_resolution.cpython-310.pyc b/__pycache__/smart_resolution.cpython-310.pyc new file mode 100644 index 0000000..b25ef26 Binary files /dev/null and b/__pycache__/smart_resolution.cpython-310.pyc differ diff --git a/latent_utils.py b/latent_utils.py new file mode 100644 index 0000000..57f0d32 --- /dev/null +++ b/latent_utils.py @@ -0,0 +1,36 @@ +PRESETS = { + "SD–512px": 512, + "HD–1280px": 1280, + "FullHD–1920px": 1920, + "2K–2048px": 2048, + "QHD–2560px": 2560, + "4K–3840px": 3840, + "8K–7680px": 7680, +} + +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 snap64(x): + """Snap to nearest multiple of 64 — Latent-safe resolution""" + return max(64, int(round(x / 64.0)) * 64) diff --git a/smart_latent.py b/smart_latent.py new file mode 100644 index 0000000..2f46eb8 --- /dev/null +++ b/smart_latent.py @@ -0,0 +1,29 @@ +import torch +from .latent_utils import PRESETS, ASPECT_RATIOS, snap64 + +class SmartLatentGenerator: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "resolution_preset": (list(PRESETS.keys()), {"default": "FullHD_1920x1080"}), + "aspect_ratio": (list(ASPECT_RATIOS.keys()), {"default": "16:9_Widescreen"}), + "batch_size": ("INT", {"default": 1, "min": 1, "max": 16}), + } + } + + RETURN_TYPES = ("LATENT",) + RETURN_NAMES = ("LATENT",) + FUNCTION = "generate" + CATEGORY = "latent/generator" + + def generate(self, resolution_preset, aspect_ratio, batch_size): + long_side = PRESETS[resolution_preset] + ar_w, ar_h = ASPECT_RATIOS[aspect_ratio] + + scale = long_side / float(max(ar_w, ar_h)) + width = snap64(ar_w * scale) + height = snap64(ar_h * scale) + + latent = torch.zeros([batch_size, 4, height // 8, width // 8]) + return ({"samples": latent},) diff --git a/smart_resolution.py b/smart_resolution.py new file mode 100644 index 0000000..14fb926 --- /dev/null +++ b/smart_resolution.py @@ -0,0 +1,26 @@ +from .latent_utils import PRESETS, ASPECT_RATIOS, snap64 + +class SmartResolutionPicker: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "resolution_preset": (list(PRESETS.keys()), {"default": "FullHD_1920x1080"}), + "aspect_ratio": (list(ASPECT_RATIOS.keys()), {"default": "16:9_Widescreen"}), + } + } + + RETURN_TYPES = ("INT", "INT") + RETURN_NAMES = ("width", "height") + FUNCTION = "calculate" + CATEGORY = "utils/latent" + + def calculate(self, resolution_preset, aspect_ratio): + long_side = PRESETS[resolution_preset] + ar_w, ar_h = ASPECT_RATIOS[aspect_ratio] + + scale = long_side / float(max(ar_w, ar_h)) + width = snap64(ar_w * scale) + height = snap64(ar_h * scale) + + return (width, height)