diff --git a/README.md b/README.md index 63138cb..2598418 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,12 @@ Cycle through up to 4 prompt lists using a single incrementing counter. Counts l The node displays a status label showing the current position: `List 1 — 4/5 | total: 8` + + --- ### 📐 Smart Resize -Resize any image (or batch) so the **longest side** equals `max_pixels`, with aspect ratio preserved. +Resize any image (or batch) so the **longest side** equals `longest_side`, with aspect ratio preserved. Use this as a **pipeline node** — IMAGE in, IMAGE out. No files are saved to disk. @@ -42,13 +44,15 @@ Use this as a **pipeline node** — IMAGE in, IMAGE out. No files are saved to d | Input | Type | Default | Description | |---|---|---|---| | image | IMAGE | — | Single image or batch | -| max_pixels | INT | 1536 | Target size for longest side | +| longest_side | INT | 1536 | Target size for longest side | | multiple_of | INT | 8 | Snap dimensions to this multiple (8 = SD/Flux compatible) | | interpolation | ENUM | lanczos | lanczos / bicubic / bilinear / nearest | -| upscale_if_smaller | BOOLEAN | false | Also upscale images already smaller than max_pixels | +| upscale_if_smaller | BOOLEAN | false | Also upscale images already smaller than longest_side | **Outputs:** `image`, `width`, `height` + + --- ### 📁 Smart Batch Resize @@ -59,7 +63,7 @@ Use this for **bulk preprocessing** — e.g. preparing a LoRA dataset from a fol | Input | Type | Default | Description | |---|---|---|---| | input_folder | STRING | D:/images/input | Source folder path | -| max_pixels | INT | 1536 | Target size for longest side | +| longest_side | INT | 1536 | Target size for longest side | | filename_suffix | STRING | _Small | Appended to each output filename before the extension | | output_subfolder | STRING | resized | Subfolder created inside input_folder | | multiple_of | INT | 8 | Snap dimensions to this multiple | @@ -70,12 +74,12 @@ Use this for **bulk preprocessing** — e.g. preparing a LoRA dataset from a fol --- -### 📏 Smart Size Multiplier +### 📏 Smart Resolution Multiplier Multiply image dimensions by a factor and output the results as integers. SeedVR takes a single `resolution` INT (the longest side) — not a width and height separately. Standard math nodes give you a FLOAT or require multiple steps to get there. This node does it cleanly in one step: give it your image and a multiplier, and it outputs `width`, `height`, and `resolution` (longest side) ready to connect directly to SeedVR's `max_resolution` input. -Also useful for LoRA dataset prep — using mixed resolutions in your training set generally produces better results than training on a single fixed size. Smart Size Multiplier makes it easy to dynamically calculate the right target size per image rather than hardcoding a value. +Also useful for LoRA dataset prep — using mixed resolutions in your training set generally produces better results than training on a single fixed size. Smart Resolution Multiplier makes it easy to dynamically calculate the right target size per image rather than hardcoding a value. | Input | Type | Default | Description | |---|---|---|---| @@ -85,6 +89,8 @@ Also useful for LoRA dataset prep — using mixed resolutions in your training s **Outputs:** `width`, `height`, `resolution` (longest side as INT → directly into SeedVR) + + --- ## Why these nodes? @@ -111,7 +117,7 @@ Restart ComfyUI. All nodes appear under **Craftopia** in the node menu: - `Craftopia` → **Smart Prompt Controller 🎛️** - `Craftopia` → **Smart Resize 📐** - `Craftopia` → **Smart Batch Resize 📁** -- `Craftopia` → **Smart Size Multiplier 📏** +- `Craftopia` → **Smart Resolution Multiplier 📏** --- diff --git a/__init__.py b/__init__.py index 4f5b719..fd98c92 100644 --- a/__init__.py +++ b/__init__.py @@ -2,10 +2,10 @@ WEB_DIRECTORY = "./js" from .smart_resize import NODE_CLASS_MAPPINGS as A, NODE_DISPLAY_NAME_MAPPINGS as A_NAMES from .smart_batch_resize import NODE_CLASS_MAPPINGS as B, NODE_DISPLAY_NAME_MAPPINGS as B_NAMES -from .smart_size_multiplier import NODE_CLASS_MAPPINGS as C, NODE_DISPLAY_NAME_MAPPINGS as C_NAMES +from .smart_resolution_multiplier import NODE_CLASS_MAPPINGS as C, NODE_DISPLAY_NAME_MAPPINGS as C_NAMES from .smart_prompt_controller import NODE_CLASS_MAPPINGS as D, NODE_DISPLAY_NAME_MAPPINGS as D_NAMES NODE_CLASS_MAPPINGS = {**A, **B, **C, **D} NODE_DISPLAY_NAME_MAPPINGS = {**A_NAMES, **B_NAMES, **C_NAMES, **D_NAMES} -__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] \ No newline at end of file +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/assets/screenshot-smart-batch resize.png b/assets/screenshot-smart-batch resize.png new file mode 100644 index 0000000..5f5f20e Binary files /dev/null and b/assets/screenshot-smart-batch resize.png differ diff --git a/assets/screenshot-smart-prompt-controller.png b/assets/screenshot-smart-prompt-controller.png new file mode 100644 index 0000000..711f374 Binary files /dev/null and b/assets/screenshot-smart-prompt-controller.png differ diff --git a/assets/screenshot-smart-resize.png b/assets/screenshot-smart-resize.png new file mode 100644 index 0000000..f1ffd49 Binary files /dev/null and b/assets/screenshot-smart-resize.png differ diff --git a/assets/screenshot-smart-resolution-multiplier.png b/assets/screenshot-smart-resolution-multiplier.png new file mode 100644 index 0000000..ae88829 Binary files /dev/null and b/assets/screenshot-smart-resolution-multiplier.png differ diff --git a/smart_batch_resize.py b/smart_batch_resize.py index 9f6e422..a341f84 100644 --- a/smart_batch_resize.py +++ b/smart_batch_resize.py @@ -15,12 +15,12 @@ INTERP_MAP = { SUPPORTED_EXT = {".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tiff", ".tif"} -def _calc_new_size(w, h, max_pixels, multiple_of): +def _calc_new_size(w, h, longest_side, multiple_of): longest = max(w, h) - if longest <= max_pixels: + if longest <= longest_side: new_w, new_h = w, h else: - scale = max_pixels / longest + scale = longest_side / longest new_w = int(w * scale) new_h = int(h * scale) if multiple_of > 1: @@ -43,7 +43,7 @@ class SmartBatchResize: }), # RESIZE SETTINGS - "max_pixels": ("INT", { + "longest_side": ("INT", { "default": 1024, "min": 64, "max": 8192, "step": 64, "tooltip": "Longest side target in pixels. Aspect ratio is always preserved." }), @@ -97,7 +97,7 @@ class SmartBatchResize: CATEGORY = "Craftopia" OUTPUT_NODE = True - def run(self, input_folder, max_pixels, multiple_of, interpolation, + def run(self, input_folder, longest_side, multiple_of, interpolation, suffix_resolution, suffix_custom, folder_resolution, folder_custom, skip_if_exists, delimiter): @@ -106,9 +106,9 @@ class SmartBatchResize: suffix_raw = suffix_custom.strip() if suffix_resolution: if suffix_raw == "": - suffix_raw = f"{delimiter}{max_pixels}" + suffix_raw = f"{delimiter}{longest_side}" else: - suffix_raw = f"{suffix_raw}{delimiter}{max_pixels}" + suffix_raw = f"{suffix_raw}{delimiter}{longest_side}" # Ensure delimiter is prepended if there's a suffix if suffix_raw != "" and not suffix_raw.startswith(delimiter): @@ -121,12 +121,12 @@ class SmartBatchResize: if subfolder == "": if folder_resolution: - subfolder = str(max_pixels) # Only resolution + subfolder = str(longest_side) # Only resolution else: subfolder = "resized" # Fallback else: if folder_resolution: - subfolder = f"{subfolder}{delimiter}{max_pixels}" + subfolder = f"{subfolder}{delimiter}{longest_side}" input_folder = input_folder.strip() if not os.path.isdir(input_folder): @@ -156,7 +156,7 @@ class SmartBatchResize: img = PILImage.open(f).convert("RGB") w, h = img.size - new_w, new_h = _calc_new_size(w, h, max_pixels, multiple_of) + new_w, new_h = _calc_new_size(w, h, longest_side, multiple_of) img_resized = img.resize((new_w, new_h), interp) diff --git a/smart_resize.py b/smart_resize.py index b188014..8ffa8c5 100644 --- a/smart_resize.py +++ b/smart_resize.py @@ -11,12 +11,12 @@ INTERP_MAP = { } -def _calc_new_size(w, h, max_pixels, multiple_of, upscale_if_smaller): +def _calc_new_size(w, h, longest_side, multiple_of, upscale_if_smaller): longest = max(w, h) - if longest <= max_pixels and not upscale_if_smaller: + if longest <= longest_side and not upscale_if_smaller: new_w, new_h = w, h else: - scale = max_pixels / longest + scale = longest_side / longest new_w = int(w * scale) new_h = int(h * scale) if multiple_of > 1: @@ -36,7 +36,7 @@ class SmartResize: return { "required": { "image": ("IMAGE",), - "max_pixels": ("INT", { + "longest_side": ("INT", { "default": 1536, "min": 64, "max": 8192, "step": 8, "tooltip": "Longest side target in pixels. Aspect ratio is always preserved." }), @@ -47,7 +47,7 @@ class SmartResize: "interpolation": (["lanczos", "bicubic", "bilinear", "nearest"],), "upscale_if_smaller": ("BOOLEAN", { "default": False, - "tooltip": "Upscale images that are already smaller than max_pixels." + "tooltip": "Upscale images that are already smaller than longest_side." }), } } @@ -57,7 +57,7 @@ class SmartResize: FUNCTION = "run" CATEGORY = "Craftopia" - def run(self, image, max_pixels, multiple_of, interpolation, upscale_if_smaller): + def run(self, image, longest_side, multiple_of, interpolation, upscale_if_smaller): interp = INTERP_MAP[interpolation] results = [] last_w, last_h = 0, 0 @@ -65,7 +65,7 @@ class SmartResize: for i in range(image.shape[0]): frame = image[i] # [H, W, C] h, w = frame.shape[0], frame.shape[1] - new_w, new_h = _calc_new_size(w, h, max_pixels, multiple_of, upscale_if_smaller) + new_w, new_h = _calc_new_size(w, h, longest_side, multiple_of, upscale_if_smaller) if new_w == w and new_h == h: results.append(frame) diff --git a/smart_size_multiplier.py b/smart_resolution_multiplier.py similarity index 82% rename from smart_size_multiplier.py rename to smart_resolution_multiplier.py index 77043a6..dd456d0 100644 --- a/smart_size_multiplier.py +++ b/smart_resolution_multiplier.py @@ -1,4 +1,4 @@ -class SmartSizeMultiplier: +class SmartResolutionMultiplier: """ Multiplies image dimensions by a factor. Outputs width, height, and resolution (longest side) as INT. @@ -44,9 +44,9 @@ class SmartSizeMultiplier: new_h = max(multiple_of, round(new_h / multiple_of) * multiple_of) resolution = max(new_w, new_h) - print(f"[SmartSizeMultiplier] {w}x{h} x {multiplier} -> {new_w}x{new_h} (resolution: {resolution})") + print(f"[SmartResolutionMultiplier] {w}x{h} x {multiplier} -> {new_w}x{new_h} (resolution: {resolution})") return (new_w, new_h, resolution) -NODE_CLASS_MAPPINGS = {"SmartSizeMultiplier": SmartSizeMultiplier} -NODE_DISPLAY_NAME_MAPPINGS = {"SmartSizeMultiplier": "Smart Size Multiplier 📏"} +NODE_CLASS_MAPPINGS = {"SmartResolutionMultiplier": SmartResolutionMultiplier} +NODE_DISPLAY_NAME_MAPPINGS = {"SmartResolutionMultiplier": "Smart Resolution Multiplier 📏"}