Files
Hasasasa-ComfyUI_DashuaiTools/Image_Nodes/save_image.py
T

170 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from PIL import Image
import torch
import numpy as np
def get_first_image(img):
# 递归取到最内层的非list对象,遇到空list返回None
while isinstance(img, list):
if not img: # 空list
return None
img = img[0]
return img
class SaveImageWithName:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"filename": ("STRING",),
"filename_suffix": ("STRING", {
"default": "",
"multiline": False
}),
"save_path": ("STRING", {
"default": "",
"multiline": False
}),
}
}
RETURN_TYPES = ()
RETURN_NAMES = ()
FUNCTION = "save_image"
CATEGORY = "Image/Save"
OUTPUT_NODE = True
def tensor_to_pil(self, image_tensor):
if isinstance(image_tensor, torch.Tensor):
# 确保张量在CPU上
image = image_tensor.cpu().numpy()
# 如果是批处理格式,取第一张图片
if len(image.shape) == 4:
image = image[0]
# 调整通道顺序
if image.shape[0] == 3:
image = np.transpose(image, (1, 2, 0))
# 转换为uint8格式
image = (image * 255).clip(0, 255).astype(np.uint8)
pil_image = Image.fromarray(image)
# 处理EXIF方向信息,防止图片旋转
try:
# 获取EXIF信息
exif = pil_image.getexif()
if exif:
# 获取方向信息
orientation = exif.get(274) # 274是方向标签的ID
if orientation:
# 根据方向信息旋转图片
rotation_values = {
3: 180,
6: 270,
8: 90
}
if orientation in rotation_values:
pil_image = pil_image.rotate(rotation_values[orientation], expand=True)
# 清除EXIF方向信息,防止重复旋转
exif[274] = 1 # 设置为正常方向
pil_image.info['exif'] = exif.tobytes()
except Exception as e:
print(f"[DaShuai] EXIF处理警告: {str(e)}")
return pil_image
return image_tensor
def get_unique_filename(self, base_path, filename):
"""生成唯一的文件名,避免覆盖"""
name, ext = os.path.splitext(filename)
counter = 1
new_filename = filename
while os.path.exists(os.path.join(base_path, new_filename)):
new_filename = f"{name}_{counter}{ext}"
counter += 1
return new_filename
def process_filename(self, filename, suffix):
"""处理文件名,将后缀拼接到合适的位置"""
if not suffix:
return filename
# 检查文件名中是否有'.'符号
if '.' in filename:
# 有'.'符号,拼接到'.'前面
name, ext = os.path.splitext(filename)
return f"{name}{suffix}{ext}"
else:
# 没有'.'符号,直接拼接到文件名后面
return f"{filename}{suffix}"
def save_image(self, image, filename, save_path, filename_suffix):
try:
os.makedirs(save_path, exist_ok=True)
# 强制转换为list处理
if isinstance(image, list):
if isinstance(filename, str):
# 自动扩展文件名
name, ext = os.path.splitext(filename)
ext = ext if ext else ".png"
filename = [f"{name}({i+1}){ext}" for i in range(len(image))]
# 统一list对list处理
for img, name in zip(image, filename):
img = get_first_image(img)
if img is None:
continue
if not isinstance(name, str):
name = str(name)
if not name.lower().endswith((".png", ".jpg", ".jpeg", ".bmp")):
name += ".png"
# 处理拼接文件名
processed_name = self.process_filename(name, filename_suffix)
# 检查重名并生成唯一文件名
unique_name = self.get_unique_filename(save_path, processed_name)
full_path = os.path.join(save_path, unique_name)
img_pil = self.tensor_to_pil(img)
img_pil.save(full_path)
print(f"[DaShuai] 图片已保存: {full_path}")
else:
# 单张图片处理
img = get_first_image(image)
if img is None:
print("[DaShuai] 跳过空图片")
return ()
if not isinstance(filename, str):
filename = str(filename)
if not filename.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp')):
filename += '.png'
# 处理拼接文件名
processed_name = self.process_filename(filename, filename_suffix)
# 检查重名并生成唯一文件名
unique_name = self.get_unique_filename(save_path, processed_name)
full_path = os.path.join(save_path, unique_name)
img_pil = self.tensor_to_pil(img)
img_pil.save(full_path)
print(f"[DaShuai] 图片已保存: {full_path}")
return ()
except Exception as e:
print(f"[DaShuai] 保存图片失败: {str(e)}")
raise e
# 节点映射
NODE_CLASS_MAPPINGS = {
"SaveImageWithName": SaveImageWithName
}
NODE_DISPLAY_NAME_MAPPINGS = {
"SaveImageWithName": "SaveImageWithName☀"
}