Files
2026-01-05 14:24:51 +08:00

120 lines
4.8 KiB
Python
Raw Permalink 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 torch
import numpy as np
from PIL import Image, ImageDraw
import folder_paths
import os
import uuid
def tensor2pil(image):
"""将 torch tensor 转换为 PIL Image"""
if len(image.shape) == 4:
image = image[0]
image_np = image.cpu().numpy()
if image_np.dtype != np.uint8:
if image_np.max() <= 1.0:
image_np = (image_np * 255).astype(np.uint8)
else:
image_np = np.clip(image_np, 0, 255).astype(np.uint8)
if len(image_np.shape) == 3 and image_np.shape[2] == 1:
image_np = image_np.squeeze(2)
return Image.fromarray(image_np)
def pil2tensor(image):
"""将 PIL Image 转换为 torch tensor"""
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
class ImageABCompare:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"ImageA": ("IMAGE",),
"ImageB": ("IMAGE",),
"split_direction": (["vertical", "horizontal"], {"default": "vertical"}), # 左右/上下
"split_ratio_when_output": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.01}), # 分割比例
}
}
RETURN_TYPES = ("IMAGE",)
RETURN_NAMES = ("Image_output",)
FUNCTION = "compare_images"
CATEGORY = "🎨 图形比比看--ImageABCompareSee"
OUTPUT_NODE = True
def compare_images(self, ImageA, ImageB, split_direction="vertical", split_ratio_when_output=0.5):
print(f"[ImageABCompare] 生成导出用对比图 - 方向: {split_direction}, 比例: {split_ratio_when_output}")
# 转换图片(以image1尺寸为基准)
img1 = tensor2pil(ImageA)
img2 = tensor2pil(ImageB)
base_w, base_h = img1.size # 以图1尺寸为最终保存尺寸
print(f"[ImageABCompare] 基准尺寸(图1): {base_w}x{base_h},图2原始尺寸: {img2.size}")
# 保存原始图片到临时目录(供前端加载实时预览)
unique_id = str(uuid.uuid4())[:8]
img1_filename = f"ab_img1_{unique_id}.png"
img2_filename = f"ab_img2_{unique_id}.png"
output_dir = folder_paths.get_temp_directory()
img1.save(os.path.join(output_dir, img1_filename), format="PNG")
img2.save(os.path.join(output_dir, img2_filename), format="PNG")
# 按规则调整图2尺寸(用于导出)
if split_direction == "vertical":
img2_resized = img2.resize((base_w, base_h), Image.Resampling.LANCZOS)
else:
img2_resized = img2.resize((base_w, base_h), Image.Resampling.LANCZOS)
# 创建最终对比图画布(用于导出)
result_img = Image.new("RGB", (base_w, base_h))
draw = ImageDraw.Draw(result_img)
# 绘制对比图(用于导出)
if split_direction == "vertical":
split_x = int(base_w * split_ratio_when_output)
result_img.paste(img1.crop((0, 0, split_x, base_h)), (0, 0))
result_img.paste(img2_resized.crop((split_x, 0, base_w, base_h)), (split_x, 0))
draw.line([(split_x, 0), (split_x, base_h)], fill=(255, 0, 0), width=3)
else:
split_y = int(base_h * split_ratio_when_output)
result_img.paste(img1.crop((0, 0, base_w, split_y)), (0, 0))
result_img.paste(img2_resized.crop((0, split_y, base_w, base_h)), (0, split_y))
draw.line([(0, split_y), (base_w, split_y)], fill=(255, 0, 0), width=3)
# 生成导出用tensor
result_tensor = pil2tensor(result_img)
# 返回前端需要的所有参数(含实时比例)
return {
"ui": {
"images": [], # 不显示后端生成的静态图,避免覆盖前端画布
"img1_filename": [img1_filename], # 前端加载图1用
"img2_filename": [img2_filename], # 前端加载图2用
"split_direction": [split_direction],
"split_ratio_when_output": [split_ratio_when_output], # 实时返回滑块值
"base_size": [base_w, base_h]
},
"result": (result_tensor,) # 输出tensor可连接保存图像节点
}
NODE_CLASS_MAPPINGS = {
"ImageABCompare": ImageABCompare
}
NODE_DISPLAY_NAME_MAPPINGS = {
"ImageABCompare": "图形比比看--ImageABCompareSee"
}
if __name__ == "__main__":
print("=== 节点注册验证 ===")
print("注册的节点类:", NODE_CLASS_MAPPINGS.keys())
print("显示名称映射:", NODE_DISPLAY_NAME_MAPPINGS)
try:
node = ImageABCompare()
print("✅ 节点类实例化成功")
print("输入类型:", node.INPUT_TYPES())
except Exception as e:
print("❌ 节点类实例化失败:", str(e))