fix: SmartBatchResize caching, EXIF rotation, skip-all crash, docstring; bump to 1.0.3

- add IS_CHANGED so new/removed files in input_folder are picked up without a widget change
- fix EXIF orientation ignored on load (phone photos were saved rotated)
- when all files are skipped, load existing resized output from disk instead of returning
  an empty list — fixes IndexError downstream (e.g. Preview Image) and removes the
  misleading "No images processed" error
- fix stale docstring in Smart Resolution Multiplier (SeedVR2's resolution input, not max_resolution)
This commit is contained in:
rubz
2026-07-06 11:39:54 +02:00
parent 4b85129857
commit e7caae4a3e
4 changed files with 25 additions and 9 deletions
+1
View File
@@ -1,6 +1,7 @@
# Local Obsidian notes
project-craftkit.md
how-to-publish-comfyui-node.md
fable-review-2026-07-02.md
# Local design source files
assets/*.ai
+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.2"
version = "1.0.3"
license = { file = "LICENSE" }
dependencies = []
+21 -6
View File
@@ -1,6 +1,6 @@
import os
from pathlib import Path
from PIL import Image as PILImage
from PIL import Image as PILImage, ImageOps
import numpy as np
import torch
@@ -132,6 +132,13 @@ class SmartBatchResize:
CATEGORY = "CraftKit"
OUTPUT_NODE = True
@classmethod
def IS_CHANGED(cls, input_folder, **kwargs):
# Folder contents aren't a widget input, so ComfyUI can't see when files
# are added/removed. Force re-execution every run; skip_if_exists keeps
# already-processed files cheap.
return float("nan")
def run(self, input_folder, longest_side, multiple_of, interpolation,
prefix, use_original_name, use_counter, counter_start, suffix_resolution,
folder_resolution, folder_custom,
@@ -164,6 +171,7 @@ class SmartBatchResize:
interp = INTERP_MAP[interpolation]
images_out = []
counter_index = 0
skipped_count = 0
for f in files:
stem = _build_stem(
@@ -182,10 +190,16 @@ class SmartBatchResize:
if skip_if_exists and out_path.exists():
print(f"[SmartBatchResize] Skipped (exists): {out_name}")
skipped_count += 1
counter_index += 1
existing = PILImage.open(out_path).convert("RGB")
arr = np.array(existing).astype("float32") / 255.0
images_out.append(torch.from_numpy(arr).unsqueeze(0))
continue
img = PILImage.open(f).convert("RGB")
img = PILImage.open(f)
img = ImageOps.exif_transpose(img)
img = img.convert("RGB")
w, h = img.size
new_w, new_h = _calc_new_size(w, h, longest_side, multiple_of)
@@ -200,10 +214,11 @@ class SmartBatchResize:
images_out.append(torch.from_numpy(arr).unsqueeze(0))
counter_index += 1
if not images_out:
raise ValueError("[SmartBatchResize] No images processed.")
summary = f"✓ {len(images_out)} images saved → {subfolder}/"
processed_count = len(images_out) - skipped_count
if skipped_count:
summary = f"✓ {processed_count} new, {skipped_count} already existed → {subfolder}/"
else:
summary = f"✓ {processed_count} images saved → {subfolder}/"
return {"ui": {"text": [summary]}, "result": (images_out, len(images_out))}
+2 -2
View File
@@ -2,7 +2,7 @@ class SmartResolutionMultiplier:
"""
Multiplies image dimensions by a factor.
Outputs width, height, and resolution (longest side) as INT.
Use resolution output directly with SeedVR max_resolution.
Use resolution output directly with SeedVR2's resolution input.
"""
@classmethod
@@ -10,7 +10,7 @@ class SmartResolutionMultiplier:
return {
"required": {
"image": ("IMAGE", {
"tooltip": "Source image. Its current width/height are read directly — no separate Get Image Size node needed."
"tooltip": "Source image. Its current width/height are read directly, no separate Get Image Size node needed."
}),
"multiplier": ("FLOAT", {
"default": 2.0,