|
|
@ -251,13 +251,12 @@ class VAEEncodeForInpaint: |
|
|
|
|
|
|
|
|
|
|
|
class SaveLatent: |
|
|
|
class SaveLatent: |
|
|
|
def __init__(self): |
|
|
|
def __init__(self): |
|
|
|
self.output_dir = os.path.join(folder_paths.get_input_directory(), "latents") |
|
|
|
self.output_dir = folder_paths.get_output_directory() |
|
|
|
self.type = "output" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
|
def INPUT_TYPES(s): |
|
|
|
def INPUT_TYPES(s): |
|
|
|
return {"required": { "samples": ("LATENT", ), |
|
|
|
return {"required": { "samples": ("LATENT", ), |
|
|
|
"filename_prefix": ("STRING", {"default": "ComfyUI"})}, |
|
|
|
"filename_prefix": ("STRING", {"default": "latents/ComfyUI"})}, |
|
|
|
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, |
|
|
|
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, |
|
|
|
} |
|
|
|
} |
|
|
|
RETURN_TYPES = () |
|
|
|
RETURN_TYPES = () |
|
|
@ -268,31 +267,7 @@ class SaveLatent: |
|
|
|
CATEGORY = "_for_testing" |
|
|
|
CATEGORY = "_for_testing" |
|
|
|
|
|
|
|
|
|
|
|
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None): |
|
|
|
def save(self, samples, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None): |
|
|
|
def map_filename(filename): |
|
|
|
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir) |
|
|
|
prefix_len = len(os.path.basename(filename_prefix)) |
|
|
|
|
|
|
|
prefix = filename[:prefix_len + 1] |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
digits = int(filename[prefix_len + 1:].split('_')[0]) |
|
|
|
|
|
|
|
except: |
|
|
|
|
|
|
|
digits = 0 |
|
|
|
|
|
|
|
return (digits, prefix) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subfolder = os.path.dirname(os.path.normpath(filename_prefix)) |
|
|
|
|
|
|
|
filename = os.path.basename(os.path.normpath(filename_prefix)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
full_output_folder = os.path.join(self.output_dir, subfolder) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.commonpath((self.output_dir, os.path.abspath(full_output_folder))) != self.output_dir: |
|
|
|
|
|
|
|
print("Saving latent outside the 'input/latents' folder is not allowed.") |
|
|
|
|
|
|
|
return {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
counter = max(filter(lambda a: a[1][:-1] == filename and a[1][-1] == "_", map(map_filename, os.listdir(full_output_folder))))[0] + 1 |
|
|
|
|
|
|
|
except ValueError: |
|
|
|
|
|
|
|
counter = 1 |
|
|
|
|
|
|
|
except FileNotFoundError: |
|
|
|
|
|
|
|
os.makedirs(full_output_folder, exist_ok=True) |
|
|
|
|
|
|
|
counter = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# support save metadata for latent sharing |
|
|
|
# support save metadata for latent sharing |
|
|
|
prompt_info = "" |
|
|
|
prompt_info = "" |
|
|
@ -316,11 +291,10 @@ class SaveLatent: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LoadLatent: |
|
|
|
class LoadLatent: |
|
|
|
input_dir = os.path.join(folder_paths.get_input_directory(), "latents") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
|
def INPUT_TYPES(s): |
|
|
|
def INPUT_TYPES(s): |
|
|
|
files = [f for f in os.listdir(s.input_dir) if os.path.isfile(os.path.join(s.input_dir, f)) and f.endswith(".latent")] |
|
|
|
input_dir = folder_paths.get_input_directory() |
|
|
|
|
|
|
|
files = [f for f in os.listdir(input_dir) if os.path.isfile(os.path.join(input_dir, f)) and f.endswith(".latent")] |
|
|
|
return {"required": {"latent": [sorted(files), ]}, } |
|
|
|
return {"required": {"latent": [sorted(files), ]}, } |
|
|
|
|
|
|
|
|
|
|
|
CATEGORY = "_for_testing" |
|
|
|
CATEGORY = "_for_testing" |
|
|
@ -329,13 +303,25 @@ class LoadLatent: |
|
|
|
FUNCTION = "load" |
|
|
|
FUNCTION = "load" |
|
|
|
|
|
|
|
|
|
|
|
def load(self, latent): |
|
|
|
def load(self, latent): |
|
|
|
file = folder_paths.get_annotated_filepath(latent, self.input_dir) |
|
|
|
latent_path = folder_paths.get_annotated_filepath(latent) |
|
|
|
|
|
|
|
latent = safetensors.torch.load_file(latent_path, device="cpu") |
|
|
|
latent = safetensors.torch.load_file(file, device="cpu") |
|
|
|
|
|
|
|
samples = {"samples": latent["latent_tensor"]} |
|
|
|
samples = {"samples": latent["latent_tensor"]} |
|
|
|
|
|
|
|
|
|
|
|
return (samples, ) |
|
|
|
return (samples, ) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
|
|
def IS_CHANGED(s, latent): |
|
|
|
|
|
|
|
image_path = folder_paths.get_annotated_filepath(latent) |
|
|
|
|
|
|
|
m = hashlib.sha256() |
|
|
|
|
|
|
|
with open(image_path, 'rb') as f: |
|
|
|
|
|
|
|
m.update(f.read()) |
|
|
|
|
|
|
|
return m.digest().hex() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod |
|
|
|
|
|
|
|
def VALIDATE_INPUTS(s, latent): |
|
|
|
|
|
|
|
if not folder_paths.exists_annotated_filepath(latent): |
|
|
|
|
|
|
|
return "Invalid latent file: {}".format(latent) |
|
|
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CheckpointLoader: |
|
|
|
class CheckpointLoader: |
|
|
|
@classmethod |
|
|
|
@classmethod |
|
|
@ -1020,39 +1006,7 @@ class SaveImage: |
|
|
|
CATEGORY = "image" |
|
|
|
CATEGORY = "image" |
|
|
|
|
|
|
|
|
|
|
|
def save_images(self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None): |
|
|
|
def save_images(self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None): |
|
|
|
def map_filename(filename): |
|
|
|
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]) |
|
|
|
prefix_len = len(os.path.basename(filename_prefix)) |
|
|
|
|
|
|
|
prefix = filename[:prefix_len + 1] |
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
digits = int(filename[prefix_len + 1:].split('_')[0]) |
|
|
|
|
|
|
|
except: |
|
|
|
|
|
|
|
digits = 0 |
|
|
|
|
|
|
|
return (digits, prefix) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def compute_vars(input): |
|
|
|
|
|
|
|
input = input.replace("%width%", str(images[0].shape[1])) |
|
|
|
|
|
|
|
input = input.replace("%height%", str(images[0].shape[0])) |
|
|
|
|
|
|
|
return input |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
filename_prefix = compute_vars(filename_prefix) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subfolder = os.path.dirname(os.path.normpath(filename_prefix)) |
|
|
|
|
|
|
|
filename = os.path.basename(os.path.normpath(filename_prefix)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
full_output_folder = os.path.join(self.output_dir, subfolder) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if os.path.commonpath((self.output_dir, os.path.abspath(full_output_folder))) != self.output_dir: |
|
|
|
|
|
|
|
print("Saving image outside the output folder is not allowed.") |
|
|
|
|
|
|
|
return {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
counter = max(filter(lambda a: a[1][:-1] == filename and a[1][-1] == "_", map(map_filename, os.listdir(full_output_folder))))[0] + 1 |
|
|
|
|
|
|
|
except ValueError: |
|
|
|
|
|
|
|
counter = 1 |
|
|
|
|
|
|
|
except FileNotFoundError: |
|
|
|
|
|
|
|
os.makedirs(full_output_folder, exist_ok=True) |
|
|
|
|
|
|
|
counter = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
results = list() |
|
|
|
results = list() |
|
|
|
for image in images: |
|
|
|
for image in images: |
|
|
|
i = 255. * image.cpu().numpy() |
|
|
|
i = 255. * image.cpu().numpy() |
|
|
|