Fix Image Saver bug, add standalone image saver

This commit is contained in:
tusharbhutt
2023-10-08 08:13:52 -06:00
committed by GitHub
parent 6d929a2c05
commit 6c7712b845
5 changed files with 214 additions and 53 deletions

View File

@@ -2,7 +2,7 @@
Some basic custom nodes for the ComfyUI user interface for Stable Diffusion. Features:
+ An image saver for images and JSON files to base folder, custom folders for one, or custom folders for both. Also allows for Python timestamping
+ Two aesthetic scoring models, one based on the same as AUTO1111, the other based on Image Reward
+ (REMOVED FOR NOW) Two aesthetic scoring models, one based on the same as AUTO1111, the other based on Image Reward
+ Converters for various numerical functions to the other (int, float, number) and to strings. Still in beta
+ Switches for text and numbers
+ Parameter collection nodes
@@ -12,6 +12,11 @@ When using the [ComfyUI](https://github.com/comfyanonymous/ComfyUI) interface fo
Rightly or wrongly, I am pretending to teach myself a bit of Python to get some nodes up and running to do what I'd like. Yes, I am using ChatGPT, and yes I am a glutton for punishment. There are no promises that these nodes will work for you or that I will maintain them. Feel free to do with them as you wish, according to the license model.
**UPDATE: Oct 8, 2023**
+ ***Added a standalone saver node. Fixed bug in this node and main node where image files were overwritten***
**UPDATE: Oct 7, 2023**
+ ***REMOVED THE AESTHETIC SCORERS, TOO MANY PEOPLE CAN'T GET CLIP LOADED. WILL REVISIT AFTER VACATION***
@@ -25,7 +30,7 @@ Rightly or wrongly, I am pretending to teach myself a bit of Python to get some
**UPDATE: Oct 3, 2023**
+ Added an Image Saver that can place JSON files ***in separate folders***
+ Added nodes to convert from one numeric type to another, and to string. **Still in beta**
+ Added nodes to convert from one numeric type to another, and to string.
**UPDATE: Sep 24, 2023**

176
RevertSaver.py Normal file
View File

@@ -0,0 +1,176 @@
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
}

View File

@@ -51,9 +51,9 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ESS Combo Parameterizer": "♾️🌊✨ Combo Parameterizer",
"ESS Combo Parameterizer & Prompts": "♾️🌊✨ Combo Parameterizer & Prompts",
"ESS Image Saver with JSON": "♾️🌊✨ Image Saver with JSON",
"ESS Aesthetic Scoring": "♾️🌊✨ Aesthetic Scoring",
# "ESS Aesthetic Scoring": "♾️🌊✨ Aesthetic Scoring",
# "ESS Aesthetic Scoring Auto": "♾️🌊✨ Aesthetic Scoring Auto",
"ESS Image Reward": "♾️🌊✨ Image Reward",
# "ESS Image Reward": "♾️🌊✨ Image Reward",
# "ESS Image Reward Auto": "♾️🌊✨ Image Reward Auto",
"ESS Float to Integer": "♾️🌊✨ Float to Integer",
"ESS Float to Number": "♾️🌊✨ Float to Number",
@@ -75,4 +75,4 @@ NODE_DISPLAY_NAME_MAPPINGS = {
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
print("\033[36m An Endless Sea of Stars Custom Nodes V0.31 \033[34m: \033[92mLoaded\033[0m")
print("\033[36m An Endless Sea of Stars Custom Nodes V0.37 \033[34m: \033[92mLoaded\033[0m")

View File

@@ -10,6 +10,8 @@
# Endless Sea of Stars Custom Node Collection
#https://github.com/tusharbhutt/Endless-Nodes
#----------------------------------------------
# Oct 08/23, V0.37: Bug fix in Image Saver module that would overwrite files was corrected
# Oct 07/23, V0.36: Killed the scorers until I figure out why CLIP won't load for some people
# Oct 06/23, V0.35: Reverted the Image Saver module as I had inadvertently removed the ability to add date and time to the filenames
# Oct 05/23, V0.34: Renamed nodes to make them shorter and easier to search for, breaks names of previous workflows though
# Oct 05/23, V0.33: Added random text input choice for six and eight nodes inputs
@@ -54,7 +56,7 @@ import json
import math
import numpy as np
import os
import pytorch_lightning as pl
#import pytorch_lightning as pl
import re
import socket
import statistics
@@ -623,7 +625,6 @@ class EndlessNode_ComboXLParameterizer:
# ----------------------------------------------
# Saver type one: saves IMAGE and JSON files, can specify separate folders for each, or one, or none, and use Python timestamps
class EndlessNode_ImageSaver:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
@@ -638,7 +639,7 @@ class EndlessNode_ImageSaver:
"delimiter": ("STRING", {"default": "_"}),
"filename_number_padding": ("INT", {"default": 4, "min": 1, "max": 9, "step": 1}),
"filename_number_start": (["false", "true"],),
"img_folder": ("STRING", {"default": None}),
"image_folder": ("STRING", {"default": None}),
"json_folder": ("STRING", {"default": None}),
},
"hidden": {
@@ -653,7 +654,7 @@ class EndlessNode_ImageSaver:
def save_images(self, images, filename_prefix="ComfyUI", delimiter="_",
filename_number_padding=4, filename_number_start='false',
img_folder=None, json_folder=None, prompt=None, extra_pnginfo=None):
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)
@@ -678,7 +679,7 @@ class EndlessNode_ImageSaver:
img_file, json_file = self.generate_filenames(filename_prefix, delimiter, counter,
filename_number_padding, filename_number_start,
img_extension, img_folder, json_folder)
img_extension, image_folder, json_folder)
try:
if img_extension == '.png':
@@ -696,7 +697,7 @@ class EndlessNode_ImageSaver:
"image_filename": os.path.basename(img_file),
"image_path": img_file,
"json_filename": os.path.basename(json_file),
"text_path": json_file,
"json_path": json_file,
"type": self.type
})
@@ -714,7 +715,7 @@ class EndlessNode_ImageSaver:
def generate_filenames(self, filename_prefix, delimiter, counter,
filename_number_padding, filename_number_start, img_extension,
img_folder, json_folder):
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"
@@ -722,28 +723,21 @@ class EndlessNode_ImageSaver:
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"
# Construct full paths for image and text files based on folders provided
# 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 img_folder:
img_folder = self.replace_date_time_placeholders(img_folder)
os.makedirs(img_folder, exist_ok=True) # Create the image folder if it doesn't exist
img_file = os.path.join(img_folder, img_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_folder = self.replace_date_time_placeholders(json_folder)
os.makedirs(json_folder, exist_ok=True) # Create the image folder if it doesn't exist
json_file = os.path.join(json_folder, json_file)
else:
json_file = os.path.join(os.path.dirname(img_file), json_file)
# Apply placeholders for date and time in filenames and folder
img_file = self.replace_date_time_placeholders(img_file)
json_file = self.replace_date_time_placeholders(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
@@ -754,26 +748,20 @@ class EndlessNode_ImageSaver:
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"
# Construct full paths for image and text files based on folders provided
# 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 img_folder:
img_folder = self.replace_date_time_placeholders(img_folder)
os.makedirs(img_folder, exist_ok=True) # Create the image folder if it doesn't exist
img_file = os.path.join(img_folder, img_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_folder = self.replace_date_time_placeholders(json_folder)
os.makedirs(json_folder, exist_ok=True) # Create the image folder if it doesn't exist
json_file = os.path.join(json_folder, json_file)
else:
json_file = os.path.join(os.path.dirname(img_file), json_file)
# Apply placeholders for date and time in filenames and folder
img_file = self.replace_date_time_placeholders(img_file)
json_file = self.replace_date_time_placeholders(json_file)
return img_file, json_file
def replace_date_time_placeholders(self, filename):
@@ -793,8 +781,6 @@ class EndlessNode_ImageSaver:
filename = filename.replace(placeholder, replacement)
return filename
# ______________________________________________________________________________________________________________________________________________________________
# CONVERTER NODES BLOCK #
#

View File

@@ -1,7 +1 @@
# clip @ git+https://github.com/openai/CLIP.git
pytorch-lightning
# image-reward==1.4
colorama
# ftfy
# regex
# tqdm