Files
brucew4yn3rp-ComfyUI_Select…/node.py
T
2025-07-20 00:07:54 -04:00

115 lines
4.1 KiB
Python

import os
import json
import numpy as np
from PIL import ExifTags, Image, PngImagePlugin
from comfy.cli_args import args
import folder_paths
class SaveImage:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.type = "output"
self.prefix_append = ""
self.quality = 95 # Default quality for WebP
self.method = 6 # Compression method for WebP
self.compress_level = 4 # Default PNG compression level
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE", {"tooltip": "The images to save."}),
"filename_prefix": ("STRING", {"default": "ComfyUI", "tooltip": "The prefix for the file to save."})
},
"optional": {
"key_1": ("STRING", {"default": "", "tooltip": "Metadata key 1"}),
"metadata_1": ("STRING", {"default": "", "tooltip": "Metadata value 1"}),
"key_2": ("STRING", {"default": "", "tooltip": "Metadata key 2"}),
"metadata_2": ("STRING", {"default": "", "tooltip": "Metadata value 2"}),
"key_3": ("STRING", {"default": "", "tooltip": "Metadata key 3"}),
"metadata_3": ("STRING", {"default": "", "tooltip": "Metadata value 3"}),
"key_4": ("STRING", {"default": "", "tooltip": "Metadata key 4"}),
"metadata_4": ("STRING", {"default": "", "tooltip": "Metadata value 4"}),
"key_5": ("STRING", {"default": "", "tooltip": "Metadata key 5"}),
"metadata_5": ("STRING", {"default": "", "tooltip": "Metadata value 5"}),
}
}
RETURN_TYPES = ()
FUNCTION = "save_images"
OUTPUT_NODE = True
CATEGORY = "image"
DESCRIPTION = "Saves the input images as PNG or WebP with dynamic metadata key-value pairs."
def save_images(self, images, filename_prefix="ComfyUI", unique_id=None, **kwargs):
filename_prefix += self.prefix_append
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(
filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0]
)
results = list()
# Extract dynamic metadata from kwargs
dynamic_metadata = {}
for i in range(1, 6):
key = kwargs.get(f"key_{i}", "").strip()
value = kwargs.get(f"metadata_{i}", "").strip()
if key:
dynamic_metadata[key] = value
for batch_number, image in enumerate(images):
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
file = f"{filename_with_batch_num}_{counter:05}_.png"
metadata = None
if not args.disable_metadata and dynamic_metadata:
metadata = PngImagePlugin.PngInfo()
for key, value in dynamic_metadata.items():
metadata.add_text(key, value)
img.save(
os.path.join(full_output_folder, file),
pnginfo=metadata,
compress_level=self.compress_level
)
results.append({
"filename": file,
"subfolder": subfolder,
"type": self.type
})
counter += 1
return {"ui": {"images": results}}
class MultilineString:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {"multiline": True, "default": "", "tooltip": "Enter your multiline text here"})
},
}
RETURN_TYPES = ("STRING",)
FUNCTION = "process_text"
CATEGORY = "text"
DESCRIPTION = "Converts multiline text input to string output."
def process_text(self, text):
return (text,)
# Node registration
NODE_CLASS_MAPPINGS = {
"SaveImage": SaveImage,
"Multiline String": MultilineString
}
NODE_DISPLAY_NAME_MAPPINGS = {
"SaveImage": "Save Image (Selective Metadata)",
"Multiline String": "Simple Node for Multiline String"
}