Initial commit: Fast Preview node

This commit is contained in:
curious-george-is-available
2026-04-30 13:28:17 +05:30
commit e3cf180549
4 changed files with 120 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
__pycache__/
*.pyc
.DS_Store
+13
View File
@@ -0,0 +1,13 @@
from .fast_preview import FastPreviewImage
WEB_DIRECTORY = "./web"
NODE_CLASS_MAPPINGS = {
"FastPreviewImage": FastPreviewImage
}
NODE_DISPLAY_NAME_MAPPINGS = {
"FastPreviewImage": "Fast Preview & Optimize"
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
+68
View File
@@ -0,0 +1,68 @@
import os
import random
import string
import numpy as np
from PIL import Image
import folder_paths
class FastPreviewImage:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"images": ("IMAGE",),
"image_format": (["webp", "jpeg", "png"], {"default": "webp"}),
"quality": ("INT", {"default": 80, "min": 1, "max": 100}),
}
}
RETURN_TYPES = ()
OUTPUT_NODE = True
FUNCTION = "save_images"
CATEGORY = "image"
def save_images(self, images, image_format="webp", quality=80):
results = list()
file_sizes = list()
temp_dir = folder_paths.get_temp_directory()
for batch_number, image in enumerate(images):
# Convert tensor to PIL Image
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
if image_format == "jpeg" and img.mode in ("RGBA", "P"):
img = img.convert("RGB")
# Generate random 8-character string for the prefix
prefix = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
filename = f"fast_preview_{prefix}_{batch_number}.{image_format}"
file_path = os.path.join(temp_dir, filename)
# Determine compression kwargs based on format
kwargs = {}
if image_format == "webp":
kwargs = {"quality": quality, "method": 2}
elif image_format == "jpeg":
kwargs = {"quality": quality, "optimize": True}
elif image_format == "png":
kwargs = {"compress_level": max(0, min(9, int((100 - quality) / 10)))}
# Save the image
img.save(file_path, **kwargs)
# Calculate file size
size_in_bytes = os.path.getsize(file_path)
if size_in_bytes < 1024 * 1024:
size_str = f"{size_in_bytes / 1024:.2f} KB"
else:
size_str = f"{size_in_bytes / (1024 * 1024):.2f} MB"
file_sizes.append(size_str)
results.append({
"filename": filename,
"subfolder": "",
"type": "temp"
})
return {"ui": {"images": results, "file_sizes": file_sizes}}
+36
View File
@@ -0,0 +1,36 @@
import { app } from "../../scripts/app.js";
import { ComfyWidgets } from "../../scripts/widgets.js";
app.registerExtension({
name: "Comfy.FastPreviewImage",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "FastPreviewImage") {
const onExecuted = nodeType.prototype.onExecuted;
nodeType.prototype.onExecuted = function(message) {
const r = onExecuted ? onExecuted.apply(this, arguments) : undefined;
if (message?.file_sizes) {
let widget = this.widgets?.find((w) => w.name === "file_size_display");
if (!widget) {
const widgetObj = ComfyWidgets["STRING"](this, "file_size_display", ["STRING", { multiline: false }], app);
widget = widgetObj.widget || widgetObj;
if (widget && widget.inputEl) {
widget.inputEl.readOnly = true;
widget.inputEl.style.opacity = "0.8";
widget.inputEl.style.textAlign = "center";
}
}
if (widget) {
widget.value = `Size: ${message.file_sizes.join(" | ")}`;
}
}
return r;
};
}
}
});