Files
Dontdrunk-ComfyUI-DD-Nodes/node/color_generator.py
T

235 lines
9.5 KiB
Python

import torch
import numpy as np
from enum import Enum
class ColorMode(Enum):
HSLA = "HSLA颜色" # 色相-饱和度-亮度-透明度
HSVA = "HSVA颜色" # 色相-饱和度-明度-透明度
CMYK = "CMYK颜色" # 青-品红-黄-黑
class ColorBackgroundGenerator:
"""Current Date and Time (UTC): 2025-02-19 13:59:10
Current User's Login: 1761696257"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"图层设置": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 1.0}),
"宽度": ("INT", {"default": 512, "min": 64, "max": 8192}),
"高度": ("INT", {"default": 512, "min": 64, "max": 8192}),
"颜色模式": (list(mode.value for mode in ColorMode), {"default": "HSLA颜色"}),
# 通用透明度
"透明度": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.1}),
# HSLA inputs
"HSLA色相": ("INT", {"default": 0, "min": 0, "max": 360}),
"HSLA饱和度": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1}),
"HSLA亮度": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1}),
# HSVA inputs
"HSVA色相": ("INT", {"default": 0, "min": 0, "max": 360}),
"HSVA饱和度": ("FLOAT", {"default": 0.5, "min": 0.0, "max": 1.0, "step": 0.1}),
"HSVA明度": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 1.0, "step": 0.1}),
# CMYK inputs
"CMYK青色": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.1}),
"CMYK品红": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.1}),
"CMYK黄色": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.1}),
"CMYK黑色": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.1}),
# 颜色选择器控制
"使用取色器": ("BOOLEAN", {"default": False}),
"颜色选择器": ("COLOR", {"default": "#FFFFFF"}),
},
"optional": {
# 图片输入
"输入图片": ("IMAGE",),
"遮罩": ("MASK",),
}
}
RETURN_TYPES = ("IMAGE", "INT", "INT", "INT", "FLOAT")
RETURN_NAMES = ("图像", "红", "绿", "蓝", "透明度")
FUNCTION = "generate_background"
CATEGORY = "🍺DD系列节点"
def hex_to_rgba(self, hex_color):
"""将十六进制颜色转换为RGBA,忽略原始透明度"""
hex_color = hex_color.lstrip('#')
if len(hex_color) == 8:
r, g, b, _ = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4, 6))
return r, g, b
else:
r, g, b = tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
return r, g, b
def hsla_to_rgba(self, h, s, l, a=1.0):
h = h/360
def hue_to_rgb(p, q, t):
if t < 0: t += 1
if t > 1: t -= 1
if t < 1/6: return p + (q - p) * 6 * t
if t < 1/2: return q
if t < 2/3: return p + (q - p) * (2/3 - t) * 6
return p
if s == 0:
r = g = b = l
else:
q = l * (1 + s) if l < 0.5 else l + s - l * s
p = 2 * l - q
r = hue_to_rgb(p, q, h + 1/3)
g = hue_to_rgb(p, q, h)
b = hue_to_rgb(p, q, h - 1/3)
return int(r * 255), int(g * 255), int(b * 255), a
def hsva_to_rgba(self, h, s, v, a=1.0):
h = h/360
i = int(h*6)
f = h*6 - i
p = v * (1-s)
q = v * (1-f*s)
t = v * (1-(1-f)*s)
if i % 6 == 0:
r, g, b = v, t, p
elif i % 6 == 1:
r, g, b = q, v, p
elif i % 6 == 2:
r, g, b = p, v, t
elif i % 6 == 3:
r, g, b = p, q, v
elif i % 6 == 4:
r, g, b = t, p, v
else:
r, g, b = v, p, q
return int(r * 255), int(g * 255), int(b * 255), a
def cmyk_to_rgba(self, c, m, y, k, a=1.0):
r = int(255 * (1-c) * (1-k))
g = int(255 * (1-m) * (1-k))
b = int(255 * (1-y) * (1-k))
return r, g, b, a
def ensure_rgba(self, image):
"""确保图像为RGBA格式"""
if image.shape[-1] == 3: # RGB格式
# 添加alpha通道(完全不透明)
alpha = torch.ones((*image.shape[:-1], 1), device=image.device)
return torch.cat([image, alpha], dim=-1)
return image
def adjust_mask_size(self, mask, height, width):
"""调整遮罩大小的辅助函数"""
if mask.shape[-2:] != (height, width): # 使用最后两个维度比较尺寸
# ComfyUI中的MASK通常是2D或3D的,需要正确处理维度
if len(mask.shape) == 2:
mask = mask.unsqueeze(0).unsqueeze(0) # (H,W) -> (1,1,H,W)
elif len(mask.shape) == 3:
mask = mask.unsqueeze(1) # (B,H,W) -> (B,1,H,W)
# 调整大小
mask = torch.nn.functional.interpolate(
mask,
size=(height, width),
mode='nearest'
)
# 恢复原始维度
if len(mask.shape) == 4:
mask = mask.squeeze(0).squeeze(0) # (1,1,H,W) -> (H,W)
return mask
def get_output_size(self, 宽度, 高度, 输入图片=None):
"""确定输出尺寸"""
output_height, output_width = 高度, 宽度
# 如果有输入图片,使用输入图片的尺寸
if 输入图片 is not None:
if len(输入图片.shape) == 4: # BCHW或BHWC格式
if 输入图片.shape[1] == 3 or 输入图片.shape[1] == 4: # BCHW格式
output_height = 输入图片.shape[2]
output_width = 输入图片.shape[3]
else: # BHWC格式
output_height = 输入图片.shape[1]
output_width = 输入图片.shape[2]
return output_height, output_width
def generate_background(self, 图层设置, 宽度, 高度, 颜色模式,
透明度, HSLA色相, HSLA饱和度, HSLA亮度,
HSVA色相, HSVA饱和度, HSVA明度,
CMYK青色, CMYK品红, CMYK黄色, CMYK黑色,
使用取色器, 颜色选择器,
输入图片=None, 遮罩=None):
# 确定输出尺寸
output_height, output_width = self.get_output_size(宽度, 高度, 输入图片)
# 生成颜色值
if 使用取色器:
r, g, b = self.hex_to_rgba(颜色选择器)
a = 透明度
else:
if 颜色模式 == "HSLA颜色":
r, g, b, a = self.hsla_to_rgba(HSLA色相, HSLA饱和度, HSLA亮度, 透明度)
elif 颜色模式 == "HSVA颜色":
r, g, b, a = self.hsva_to_rgba(HSVA色相, HSVA饱和度, HSVA明度, 透明度)
elif 颜色模式 == "CMYK颜色":
r, g, b, a = self.cmyk_to_rgba(CMYK青色, CMYK品红, CMYK黄色, CMYK黑色, 透明度)
# 确保颜色值在有效范围内
r = max(0, min(255, r))
g = max(0, min(255, g))
b = max(0, min(255, b))
a = max(0.0, min(1.0, a))
# 创建颜色图层 (BHWC格式)
color = np.array([r, g, b, int(a * 255)]) / 255.0
color_image = np.ones((1, output_height, output_width, 4)) * color
color_image = torch.from_numpy(color_image).float()
# 如果没有输入图片,直接返回颜色图层
if 输入图片 is None:
return (color_image, r, g, b, a)
# 处理输入图片
if 输入图片.shape[1] == 3 or 输入图片.shape[1] == 4: # 如果是BCHW格式
输入图片 = 输入图片.permute(0, 2, 3, 1)
输入图片 = self.ensure_rgba(输入图片)
# 调整输入图片大小
if 输入图片.shape[1:3] != (output_height, output_width):
输入图片 = torch.nn.functional.interpolate(
输入图片.permute(0, 3, 1, 2),
size=(output_height, output_width),
mode='bilinear',
align_corners=False
).permute(0, 2, 3, 1)
# 处理遮罩
if 遮罩 is not None:
遮罩 = self.adjust_mask_size(遮罩, output_height, output_width)
遮罩 = 遮罩.view(1, output_height, output_width, 1).expand(-1, -1, -1, 4)
# 根据图层设置决定混合方式
if 图层设置 == 0: # 输入图片在底层
# 遮罩区域显示颜色图层,非遮罩区域显示输入图片
result = 输入图片 * (1 - 遮罩) + color_image * 遮罩
else: # 输入图片在顶层
# 遮罩区域显示输入图片,非遮罩区域显示颜色图层
result = color_image * (1 - 遮罩) + 输入图片 * 遮罩
else:
# 如果没有遮罩,根据图层设置决定叠加顺序
if 图层设置 == 0: # 输入图片在底层
alpha = 输入图片[..., 3:4]
result = color_image * alpha + 输入图片 * (1 - alpha)
else: # 输入图片在顶层
alpha = color_image[..., 3:4]
result = 输入图片 * alpha + color_image * (1 - alpha)
return (result, r, g, b, a)
NODE_CLASS_MAPPINGS = {
"DD-ColorBackgroundGenerator": ColorBackgroundGenerator
}