1 Commits
Author SHA1 Message Date
rubz b5536b7605 ```
fix: reorganize Smart Batch Resize into labeled sections; bump to 1.1.0

- Add section-header dividers (Resize/Filename/Output Location/Output
  Format/Options) to js/smart_batch_resize.js — the node grew to ~19
  widgets after the review fixes and needed grouping to stay scannable
- Move `delimiter` next to the other filename-building fields, and
  reorder Output Location/Output Format/Options into a more logical
  flow. This changes the node's widget order — workflows saved before
  this change will need the node re-placed once (values shift on load)
- Update README: new screenshot, full input table rewritten to match
  the new field order and the alpha_mode/output_format/quality/
  preview_limit/upscale_if_smaller additions, "Why these nodes?" bullet
  on the transparency handling
```
2026-07-28 00:23:31 +02:00
6 changed files with 62 additions and 21 deletions
+11 -5
View File
@@ -85,13 +85,13 @@ Use this as a **pipeline node** — IMAGE in, IMAGE out. No files are saved to d
### 📁 Smart Batch Resize
<img src="assets/screenshot-smart-batch-resize.png" width="100%">
<img src="assets/screenshot-smart-batch-resize_v2.png" width="100%">
Load **all images from a folder**, resize each one by longest side, and save into a subfolder. Build clean dataset filenames from a prefix, the original name, and/or a sequential counter — combined with an optional resolution suffix.
Use this for **bulk preprocessing** — e.g. preparing a LoRA dataset from a folder of high-res images. It works as a **standalone node**: it needs no upstream input and no downstream connection to do its job — drop it on the canvas, point it at a folder, hit **Run Batch**, and it reads, resizes, and saves everything itself. Connecting the `images`/`count` outputs is entirely optional, e.g. for previewing results.
Use this for **bulk preprocessing** — e.g. preparing a LoRA dataset from a folder of high-res images, or a batch of frames/renders for After Effects where transparency needs to survive the resize. It works as a **standalone node**: it needs no upstream input and no downstream connection to do its job — drop it on the canvas, point it at a folder, hit **Run Batch**, and it reads, resizes, and saves everything itself. Connecting the `images`/`count` outputs is entirely optional, e.g. for previewing results.
Includes a **Browse folder** button to pick the input folder directly from the node, and quick presets (512 / 768 / 1024 / 1536) for the longest side — or type any custom value directly into the field.
Includes a **Browse folder** button to pick the input folder directly from the node, and quick presets (512 / 768 / 1024 / 1536) for the longest side — or type any custom value directly into the field. Widgets are grouped into labeled sections (Resize, Filename, Output Location, Output Format, Options) to keep the node scannable despite the number of settings.
| Input | Type | Default | Description |
|---|---|---|---|
@@ -99,15 +99,20 @@ Includes a **Browse folder** button to pick the input folder directly from the n
| Longest side (px) | INT | 1024 | Target size for longest side. Quick presets: 512 / 768 / 1024 / 1536 — or type any custom value directly into the field |
| Round to multiple of | INT | 8 | Snap dimensions to this multiple |
| Interpolation method | ENUM | lanczos | lanczos / bicubic / bilinear / nearest |
| Upscale if smaller | BOOLEAN | true | Upscale images smaller than the target longest side. Turn off to only ever downscale, never upscale |
| Filename prefix | STRING | — | Label prepended to filename — e.g. `headshot` → `headshot_photo_001_1024.jpg` |
| Keep original filename | BOOLEAN | true | Include the original filename in the output name |
| Add counter | BOOLEAN | false | Add a sequential 3-digit counter to each filename (001, 002, ...) |
| Counter start | INT | 1 | Starting number for the counter |
| Add resolution to filename | BOOLEAN | true | Append resolution to filename — e.g. `photo_1024.png` |
| Filename delimiter | STRING | _ | Separator between filename parts |
| Create resolution subfolder | BOOLEAN | false | Append resolution to subfolder name — e.g. `resized_1024` |
| Custom output subfolder | STRING | resized | Subfolder name inside the input folder |
| Skip existing files | BOOLEAN | true | Skip files that already exist in the output folder |
| Filename delimiter | STRING | _ | Separator between filename parts |
| Output format | ENUM | keep_source | keep_source / png / webp / jpg — keep_source preserves each file's original extension; jpg cannot store transparency |
| Alpha mode | ENUM | auto | auto: keep transparency only if the source has it · flatten: always composite onto white and output opaque RGB · keep: always output RGBA |
| Quality | INT | 95 | Compression quality for jpg/webp output (1–100). Ignored for png (always lossless) |
| Skip existing files | BOOLEAN | true | Skip files that already exist in the output folder **and** still match the current size settings — a settings change (e.g. a different longest_side) triggers a reprocess instead of silently serving a stale file |
| Preview limit | INT | 32 | Max images kept in memory for the preview output. All files are still processed and saved to disk regardless — this only caps what's returned for preview. 0 = no limit |
**Outputs:** Images (list), Count
@@ -148,6 +153,7 @@ Ready-to-load workflows are included in [`example_workflows/`](example_workflows
- ComfyUI's built-in `Resize Images by Longer Edge` [BETA] has no Lanczos and no `multiple_of` snapping
- `JWImageResizeByLongerSide` (comfyui-various) has no Lanczos in the official release
- No existing node combines batch folder loading + longest-side resize + original filename preservation
- Smart Batch Resize handles transparency deliberately instead of by accident — choose whether alpha is preserved, always kept, or flattened onto a solid background, and force a specific output format (png/webp/jpg) independent of the source files' own extensions
- No existing node outputs a ready-to-use `resolution` INT for SeedVR2
- No existing node cycles through multiple prompt lists with automatic list switching and an index
- No existing node switches label + width + height together per category in one place
Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 KiB

+35
View File
@@ -106,6 +106,41 @@ app.registerExtension({
}
}
// Section-header dividers — visual only, not serialized. Standalone node
// with a lot of inputs, so grouping them keeps it scannable at a glance.
const addSectionDivider = (beforeWidgetName, label) => {
const target = node.widgets.find(w => w.name === beforeWidgetName);
if (!target) return;
const div = node.addWidget("button", `_div_${label}`, null, () => {}, { serialize: false });
div.serialize = false;
div.draw = function (ctx, node, widgetWidth, y, height) {
const lx = 14;
ctx.save();
ctx.font = "bold 10px sans-serif";
ctx.textBaseline = "middle";
ctx.textAlign = "left";
ctx.fillStyle = "#888";
ctx.fillText(label, lx, y + height / 2);
const lineX = lx + ctx.measureText(label).width + 8;
ctx.beginPath();
ctx.moveTo(lineX, y + height / 2);
ctx.lineTo(widgetWidth - 14, y + height / 2);
ctx.strokeStyle = "#333";
ctx.lineWidth = 1;
ctx.stroke();
ctx.restore();
};
const targetIdx = node.widgets.indexOf(target);
const divIdx = node.widgets.indexOf(div);
node.widgets.splice(divIdx, 1);
node.widgets.splice(targetIdx, 0, div);
};
addSectionDivider("longest_side", "RESIZE");
addSectionDivider("prefix", "FILENAME");
addSectionDivider("folder_resolution", "OUTPUT LOCATION");
addSectionDivider("skip_if_exists", "OPTIONS");
addSectionDivider("output_format", "OUTPUT FORMAT");
// Override serialize so non-serializable JS widgets (Browse, presets, status,
// run batch) are excluded from widgets_values in the saved workflow JSON.
// Without this, LiteGraph saves null slots for these widgets which then shift
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui-craftkit"
description = "Smart resize, batch resize, resolution multiplier and prompt controller nodes for ComfyUI"
version = "1.0.3"
version = "1.1.0"
readme = "README.md"
requires-python = ">=3.10"
license = { file = "LICENSE" }
+15 -15
View File
@@ -152,6 +152,11 @@ class SmartBatchResize:
"default": True,
"tooltip": "Append resolution to filename. E.g. photo_1024.png"
}),
"delimiter": ("STRING", {
"default": "_",
"multiline": False,
"tooltip": "Separator between filename parts. E.g. _ or -"
}),
# OUTPUT LOCATION
"folder_resolution": ("BOOLEAN", {
@@ -164,21 +169,6 @@ class SmartBatchResize:
"tooltip": "Subfolder name. Resolution is appended if 'Create resolution subfolder' is on."
}),
# OPTIONS
"skip_if_exists": ("BOOLEAN", {
"default": True,
"tooltip": "Skip files that already exist in the output folder AND still match the current size settings. If longest_side/multiple_of/upscale_if_smaller changed since the file was made, it's reprocessed instead of skipped."
}),
"delimiter": ("STRING", {
"default": "_",
"multiline": False,
"tooltip": "Separator between filename parts. E.g. _ or -"
}),
"preview_limit": ("INT", {
"default": 32, "min": 0, "max": 10000, "step": 1,
"tooltip": "Max images to keep in memory for the preview output. All files are still processed and saved to disk; this only limits what's returned/previewed. 0 = no limit."
}),
# OUTPUT FORMAT
"output_format": (["keep_source", "png", "webp", "jpg"], {
"default": "keep_source",
@@ -192,6 +182,16 @@ class SmartBatchResize:
"default": 95, "min": 1, "max": 100, "step": 1,
"tooltip": "Compression quality for jpg/webp output. Ignored for png (always lossless)."
}),
# OPTIONS
"skip_if_exists": ("BOOLEAN", {
"default": True,
"tooltip": "Skip files that already exist in the output folder AND still match the current size settings. If longest_side/multiple_of/upscale_if_smaller changed since the file was made, it's reprocessed instead of skipped."
}),
"preview_limit": ("INT", {
"default": 32, "min": 0, "max": 10000, "step": 1,
"tooltip": "Max images to keep in memory for the preview output. All files are still processed and saved to disk; this only limits what's returned/previewed. 0 = no limit."
}),
}
}