mirror of
https://github.com/tusharbhutt/Endless-Nodes.git
synced 2026-03-22 04:52:11 -03:00
177 lines
6.1 KiB
Python
177 lines
6.1 KiB
Python
import numpy as np
|
|
from PIL import Image
|
|
from PIL.PngImagePlugin import PngInfo
|
|
import colorama
|
|
from colorama import init, Fore, Back, Style
|
|
import os
|
|
import json
|
|
import time
|
|
import socket
|
|
import re
|
|
import folder_paths
|
|
import datetime # Added to support date and time placeholders
|
|
|
|
# Initialize colorama
|
|
colorama.init(autoreset=True)
|
|
|
|
class EndlessNode_ImageSaver:
|
|
def __init__(self):
|
|
self.output_dir = folder_paths.get_output_directory()
|
|
self.type = "output"
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"images": ("IMAGE",),
|
|
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
|
|
"delimiter": ("STRING", {"default": "_"}),
|
|
"filename_number_padding": ("INT", {"default": 4, "min": 1, "max": 9, "step": 1}),
|
|
"filename_number_start": (["false", "true"],),
|
|
"image_folder": ("STRING", {"default": None}),
|
|
"json_folder": ("STRING", {"default": None}),
|
|
},
|
|
"hidden": {
|
|
"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"
|
|
},
|
|
}
|
|
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "save_images"
|
|
OUTPUT_NODE = True
|
|
CATEGORY = "Endless 🌊✨/IO"
|
|
|
|
def save_images(self, images, filename_prefix="ComfyUI", delimiter="_",
|
|
filename_number_padding=4, filename_number_start='false',
|
|
image_folder=None, json_folder=None, prompt=None, extra_pnginfo=None):
|
|
|
|
# Replace illegal characters in the filename prefix with dashes
|
|
filename_prefix = re.sub(r'[<>:"\/\\|?*]', '-', filename_prefix)
|
|
|
|
# Set IMG Extension
|
|
img_extension = '.png'
|
|
|
|
counter = 1
|
|
|
|
results = list()
|
|
|
|
for image in images:
|
|
i = 255. * image.cpu().numpy()
|
|
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
|
|
|
metadata = PngInfo()
|
|
if prompt is not None:
|
|
metadata.add_text("prompt", json.dumps(prompt))
|
|
if extra_pnginfo is not None:
|
|
for x in extra_pnginfo:
|
|
metadata.add_text(x, json.dumps(extra_pnginfo[x]))
|
|
|
|
img_file, json_file = self.generate_filenames(filename_prefix, delimiter, counter,
|
|
filename_number_padding, filename_number_start,
|
|
img_extension, image_folder, json_folder)
|
|
|
|
try:
|
|
if img_extension == '.png':
|
|
img.save(img_file, pnginfo=metadata, compress_level=4)
|
|
elif img_extension == '.jpeg':
|
|
img.save(img_file, quality=100, optimize=True)
|
|
|
|
with open(json_file, 'w', encoding='utf-8', newline='\n') as f:
|
|
if prompt is not None:
|
|
f.write(json.dumps(prompt, indent=4))
|
|
|
|
print(Fore.GREEN + f"+ File(s) saved to: {img_file}")
|
|
|
|
results.append({
|
|
"image_filename": os.path.basename(img_file),
|
|
"image_path": img_file,
|
|
"json_filename": os.path.basename(json_file),
|
|
"json_path": json_file,
|
|
"type": self.type
|
|
})
|
|
|
|
except OSError as e:
|
|
print(Fore.RED + " + Unable to save file: ", end='')
|
|
print({img_file})
|
|
print(e)
|
|
except Exception as e:
|
|
print(Fore.RED + " + Unable to save file due to the following error: ", end='')
|
|
print(e)
|
|
|
|
counter += 1
|
|
|
|
return {"ui": {"results": results}}
|
|
|
|
def generate_filenames(self, filename_prefix, delimiter, counter,
|
|
filename_number_padding, filename_number_start, img_extension,
|
|
image_folder, json_folder):
|
|
if filename_number_start == 'true':
|
|
img_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}{img_extension}"
|
|
json_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}.json"
|
|
else:
|
|
img_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}{img_extension}"
|
|
json_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}.json"
|
|
|
|
# Apply placeholders for date and time in filenames
|
|
img_file = self.replace_date_time_placeholders(img_file)
|
|
json_file = self.replace_date_time_placeholders(json_file)
|
|
|
|
# Construct full paths for image and text files based on folders provided
|
|
if image_folder:
|
|
img_file = os.path.join(image_folder, img_file)
|
|
else:
|
|
img_file = os.path.join(self.output_dir, img_file)
|
|
|
|
if json_folder:
|
|
json_file = os.path.join(json_folder, json_file)
|
|
else:
|
|
json_file = os.path.join(os.path.dirname(img_file), json_file)
|
|
|
|
# Check if files with the same name exist, increment counter if necessary
|
|
while os.path.exists(img_file) or os.path.exists(json_file):
|
|
counter += 1
|
|
if filename_number_start == 'true':
|
|
img_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}{img_extension}"
|
|
json_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}.json"
|
|
else:
|
|
img_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}{img_extension}"
|
|
json_file = f"{filename_prefix}{delimiter}{counter:0{filename_number_padding}}.json"
|
|
|
|
# Apply placeholders for date and time in filenames
|
|
img_file = self.replace_date_time_placeholders(img_file)
|
|
json_file = self.replace_date_time_placeholders(json_file)
|
|
|
|
if image_folder:
|
|
img_file = os.path.join(image_folder, img_file)
|
|
else:
|
|
img_file = os.path.join(self.output_dir, img_file)
|
|
|
|
if json_folder:
|
|
json_file = os.path.join(json_folder, json_file)
|
|
else:
|
|
json_file = os.path.join(os.path.dirname(img_file), json_file)
|
|
|
|
return img_file, json_file
|
|
|
|
def replace_date_time_placeholders(self, filename):
|
|
# Replace date and time placeholders with actual date and time strings
|
|
now = datetime.datetime.now()
|
|
placeholders = {
|
|
'%Y': now.strftime('%Y'), # Year with century as a decimal number
|
|
'%y': now.strftime('%y'), # Year without century as a zero-padded decimal number
|
|
'%m': now.strftime('%m'), # Month as a zero-padded decimal number
|
|
'%d': now.strftime('%d'), # Day of the month as a zero-padded decimal number
|
|
'%H': now.strftime('%H'), # Hour (24-hour clock) as a zero-padded decimal number
|
|
'%M': now.strftime('%M'), # Minute as a zero-padded decimal number
|
|
'%S': now.strftime('%S'), # Second as a zero-padded decimal number
|
|
}
|
|
|
|
for placeholder, replacement in placeholders.items():
|
|
filename = filename.replace(placeholder, replacement)
|
|
|
|
return filename
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"♾️🌊✨ Image Saver with JSON": EndlessNode_ImageSaver
|
|
}
|