Files
2024-12-29 19:11:12 +08:00

141 lines
5.8 KiB
Python

import os
import json
import numpy as np
from PIL import Image
from PIL.PngImagePlugin import PngInfo
import subprocess
import folder_paths
class AD_ImageSaver:
def __init__(self):
self.output_dir = folder_paths.get_output_directory()
self.compression = 4
self.type = "output"
self.prefix_append = ""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"folder": ("STRING", {"default": ""}),
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
"overwrite_warning": ("BOOLEAN", {"default": False}),
"include_metadata": ("BOOLEAN", {"default": True}),
"extension": (["png", "jpg"],),
"quality": ("INT", {"default": 95, "min": 0, "max": 100}),
"open_output_directory": ("BOOLEAN", {"default": False}),
},
"optional": {
"filename_opt": ("STRING", {"forceInput": True}),
},
"hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"},
}
RETURN_TYPES = ()
FUNCTION = "save_images"
OUTPUT_NODE = True
CATEGORY = "🌻 Addoor/Image"
def save_images(self, images, folder, filename_prefix, overwrite_warning, include_metadata,
extension, quality, open_output_directory, filename_opt=None, prompt=None, extra_pnginfo=None):
try:
# 处理保存路径
if folder:
# 如果提供了文件夹路径,从 ComfyUI 根目录开始
comfy_path = os.path.dirname(self.output_dir) # 获取 ComfyUI 根目录
full_output_folder = os.path.join(comfy_path, folder)
else:
# 如果没有提供,使用默认输出目录
full_output_folder = self.output_dir
os.makedirs(full_output_folder, exist_ok=True)
results = list()
for batch_number, image in enumerate(images):
i = 255. * image.cpu().numpy()
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
metadata = None
if not filename_opt:
filename_with_batch_num = filename_prefix.replace("%batch_num%", str(batch_number))
counter = 1
if os.path.exists(full_output_folder) and os.listdir(full_output_folder):
filtered_filenames = list(filter(
lambda filename: filename.startswith(filename_with_batch_num + "_")
and filename[len(filename_with_batch_num) + 1:-4].isdigit(),
os.listdir(full_output_folder)
))
if filtered_filenames:
max_counter = max(
int(filename[len(filename_with_batch_num) + 1:-4])
for filename in filtered_filenames
)
counter = max_counter + 1
file = f"{filename_with_batch_num}_{counter:05}.{extension}"
else:
if len(images) == 1:
file = f"{filename_opt}.{extension}"
else:
raise Exception("Multiple images and filename detected: Images will overwrite themselves!")
save_path = os.path.join(full_output_folder, file)
if os.path.exists(save_path) and overwrite_warning:
raise Exception("Filename already exists.")
else:
if extension == "png":
if include_metadata:
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.save(save_path, pnginfo=metadata, compress_level=self.compression)
else: # jpg
if include_metadata:
metadata = {}
if prompt is not None:
metadata["prompt"] = prompt
if extra_pnginfo is not None:
for key, value in extra_pnginfo.items():
metadata[key] = value
metadata_json = json.dumps(metadata)
img.info["comment"] = metadata_json
img.save(save_path, quality=quality)
# 计算相对路径用于预览
subfolder = os.path.relpath(full_output_folder, self.output_dir) if folder else ""
results.append({
"filename": file,
"subfolder": subfolder,
"type": self.type
})
if open_output_directory:
self.open_directory(full_output_folder)
return {"ui": {"images": results}}
except Exception as e:
print(f"Error saving images: {e}")
return {"ui": {"images": []}}
@staticmethod
def open_directory(path):
if os.name == 'nt': # Windows
os.startfile(path)
elif os.name == 'posix': # macOS and Linux
try:
subprocess.call(['open', path]) # macOS
except:
try:
subprocess.call(['xdg-open', path]) # Linux
except:
print(f"Could not open directory: {path}")