212 lines
6.8 KiB
Python
212 lines
6.8 KiB
Python
"""
|
|
ComfyUI Save Image Pro - 简化版节点
|
|
|
|
简化版图像保存节点,提供基础的图像保存功能。
|
|
|
|
@version: 1.1.0
|
|
@author: AudioscavengeR
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import json
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Dict, List, Any, Optional, Tuple
|
|
import folder_paths
|
|
|
|
# 导入重构后的核心模块
|
|
from .core import (
|
|
SaveConfig, ConfigManager, ValidationResult,
|
|
ImageSaver, FileNameGenerator, CounterManager,
|
|
MetadataHandler, PathManager, JobDataExporter
|
|
)
|
|
|
|
# 版本信息
|
|
VERSION = "1.1.0"
|
|
|
|
# 设置日志
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def check_optional_dependencies():
|
|
"""检查可选依赖项"""
|
|
supported = {
|
|
'avif': False,
|
|
'jxl': False
|
|
}
|
|
|
|
try:
|
|
from PIL import Image
|
|
# 检查 AVIF 支持
|
|
try:
|
|
import pillow_avif
|
|
supported['avif'] = True
|
|
except ImportError:
|
|
pass
|
|
|
|
# 检查 JXL 支持
|
|
try:
|
|
import jxlpy
|
|
supported['jxl'] = True
|
|
except ImportError:
|
|
pass
|
|
except ImportError:
|
|
pass
|
|
|
|
return supported
|
|
|
|
# 检查支持的格式
|
|
SUPPORTED_FORMATS = check_optional_dependencies()
|
|
|
|
|
|
class SaveImageSimple:
|
|
"""
|
|
ComfyUI Save Image Pro - 简化版
|
|
|
|
提供基础的图像保存功能,包含最常用的参数。
|
|
"""
|
|
|
|
RETURN_TYPES = ("IMAGE",)
|
|
RETURN_NAMES = ("images",)
|
|
FUNCTION = 'save_images'
|
|
OUTPUT_NODE = True
|
|
CATEGORY = 'image'
|
|
DESCRIPTION = """
|
|
### ComfyUI Save Image Pro - 简化版
|
|
|
|
**基础功能:**
|
|
- 支持多种图像格式 (PNG, WebP, JPEG, AVIF, JXL, TIFF, GIF, BMP)
|
|
- 自定义文件名前缀
|
|
- 自定义文件夹前缀
|
|
- 质量控制
|
|
- 作业数据导出
|
|
- 图像预览
|
|
|
|
**简化设计:**
|
|
- 精简的参数设置
|
|
- 快速上手使用
|
|
- 保留核心功能
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.config_manager = ConfigManager()
|
|
self.output_dir = folder_paths.get_output_directory()
|
|
self.image_saver = None
|
|
self.job_exporter = None
|
|
|
|
# 初始化日志
|
|
self._setup_logging()
|
|
|
|
def _setup_logging(self):
|
|
"""设置日志系统"""
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='[%(name)s] %(levelname)s: %(message)s'
|
|
)
|
|
logger.info("ComfyUI Save Image Pro (Simple) initialized")
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
"""定义输入类型 - 简化版"""
|
|
# 获取支持的格式列表
|
|
output_formats = ['.webp', '.png', '.jpg', '.jpeg', '.gif', '.tiff', '.bmp']
|
|
|
|
if SUPPORTED_FORMATS['jxl']:
|
|
output_formats.insert(0, '.jxl')
|
|
if SUPPORTED_FORMATS['avif']:
|
|
output_formats.insert(0, '.avif')
|
|
|
|
return {
|
|
"required": {
|
|
"images": ("IMAGE", {"tooltip": "The images to save and pass through."}),
|
|
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
|
|
"foldername_prefix": ("STRING", {"default": ""}),
|
|
"output_format": (output_formats, {"default": ".webp"}),
|
|
"quality": ("INT", {"default": 75, "min": 1, "max": 100, "step": 1}),
|
|
"save_image_metadata": ("BOOLEAN", {"default": True, "tooltip": "Embed metadata in saved files. Turn off to save plain images."}),
|
|
"metadata_mode": (["comfy", "a1111", "comfy+a1111", "off"], {"default": "comfy", "tooltip": "comfy writes prompt/workflow; a1111 writes share-site parameters; comfy+a1111 writes both."}),
|
|
"sidecar_mode": (["off", "json", "txt", "both"], {"default": "off", "tooltip": "Optionally write metadata sidecar files next to each saved image."}),
|
|
"image_preview": ("BOOLEAN", {"default": True}),
|
|
},
|
|
"hidden": {
|
|
"prompt": "PROMPT",
|
|
"extra_pnginfo": "EXTRA_PNGINFO"
|
|
}
|
|
}
|
|
|
|
def save_images(self, images, filename_prefix="ComfyUI", foldername_prefix="",
|
|
output_format=".webp", quality=75, save_image_metadata=True,
|
|
metadata_mode="comfy", sidecar_mode="off", image_preview=True,
|
|
prompt=None, extra_pnginfo=None):
|
|
"""
|
|
保存图像的主要方法 - 简化版
|
|
"""
|
|
try:
|
|
# 创建简化的配置对象
|
|
config = SaveConfig(
|
|
filename_prefix=filename_prefix,
|
|
filename_keys="", # 简化版不使用复杂的文件名键
|
|
foldername_prefix=foldername_prefix, # 使用用户输入的文件夹前缀
|
|
foldername_keys="", # 简化版不使用文件夹键
|
|
delimiter="-",
|
|
output_format=output_format,
|
|
quality=quality,
|
|
save_metadata=save_image_metadata,
|
|
metadata_mode=metadata_mode,
|
|
sidecar_mode=sidecar_mode,
|
|
counter_digits=4,
|
|
counter_position="last",
|
|
one_counter_per_folder=True,
|
|
save_job_data="disabled", # 强制禁用JSON导出
|
|
job_data_per_image=False, # 彻底禁用JSON导出
|
|
job_custom_text="",
|
|
image_preview=image_preview
|
|
)
|
|
|
|
# 验证配置
|
|
validation = self.config_manager.validate_config(config)
|
|
if not validation.valid:
|
|
logger.error(f"Configuration validation failed: {validation.errors}")
|
|
return {"ui": {"images": []}, "result": (images,)}
|
|
|
|
# 初始化图像保存器
|
|
if not self.image_saver:
|
|
self.image_saver = ImageSaver(config, self.output_dir)
|
|
else:
|
|
self.image_saver.update_config(config)
|
|
|
|
# 保存图像
|
|
results = self.image_saver.save_images(
|
|
images=images,
|
|
prompt=prompt,
|
|
extra_pnginfo=extra_pnginfo
|
|
)
|
|
|
|
# JSON导出功能已禁用 - 图片本身已包含完整元数据
|
|
# 不再需要额外的JSON文件
|
|
|
|
logger.info(f"Successfully saved {len(results)} images")
|
|
|
|
# 返回结果
|
|
if config.image_preview:
|
|
return {"ui": {"images": results}, "result": (images,)}
|
|
else:
|
|
return {"ui": {"images": []}, "result": (images,)}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error occurred while saving images: {str(e)}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
return {"ui": {"images": []}, "result": (images,)}
|
|
|
|
|
|
# 节点类映射
|
|
NODE_CLASS_MAPPINGS = {
|
|
"SaveImageSimple": SaveImageSimple
|
|
}
|
|
|
|
# 节点显示名称映射
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"SaveImageSimple": "comfyui-save-image-pro (Simple)"
|
|
}
|