remove test file
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Filename: click_popup.py
|
||||
# Developer: jammyfu
|
||||
# Category: 🎨Painting👓Coder/🔧Utils
|
||||
|
||||
class ClickPopup:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"button": ("BOOLEAN", {"default": False}),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("message",)
|
||||
FUNCTION = "show_popup"
|
||||
CATEGORY = "🎨Painting👓Coder/🔧Utils"
|
||||
|
||||
def show_popup(self, button):
|
||||
return ("Button clicked!",)
|
||||
|
||||
# 添加到 ComfyUI 节点注册
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ClickPopup": ClickPopup,
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
class ColorPicker:
|
||||
"""
|
||||
颜色选择器节点,使用 jscolor 实现颜色选择和吸管工具
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.color = "#000000"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {}} # 不需要输入项
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("color",)
|
||||
FUNCTION = "pick_color"
|
||||
CATEGORY = "🎨Painting👓Coder/🎨Color"
|
||||
|
||||
def pick_color(self):
|
||||
return (self.color,)
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, **kwargs):
|
||||
return True
|
||||
|
||||
def widget_value_updated(self, widget, value):
|
||||
if widget.name == "color_picker":
|
||||
self.color = value
|
||||
|
||||
@classmethod
|
||||
def WIDGETS(s):
|
||||
return {"color_picker": ("color", {"default": "#000000"})}
|
||||
|
||||
# 在 __init__.py 中添加节点注册
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"ColorPicker": ColorPicker
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"ColorPicker": "Color Picker"
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Filename: image_scale_calculator.py
|
||||
# Developer: jammyfu
|
||||
# Category: 🎨Painting👓Coder/🖼️Image
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
|
||||
def resize_image(image, target_width, target_height, method='contain'):
|
||||
"""Resize an image while maintaining aspect ratio.
|
||||
method: 'contain' (保持宽高比,缩放图像以完全适应容器),
|
||||
'cover' (保持宽高比,缩放图像以覆盖整个容器),
|
||||
'fill' (忽略宽高比,缩放图像以完全填充容器),
|
||||
'inside' (保持宽高比,缩小或不改变图像使其完全适合容器),
|
||||
'outside' (保持宽高比,放大或不改变图像使其完全覆盖容器).
|
||||
"""
|
||||
# 将ComfyUI的图像Tensor转换为PIL图像对象
|
||||
img = Image.fromarray(np.clip(255. * image.cpu().numpy(), 0, 255).astype(np.uint8))
|
||||
img_width, img_height = img.size
|
||||
|
||||
if method == 'contain':
|
||||
# Contain: 缩放图像以适应目标尺寸,保持宽高比,可能出现黑边
|
||||
img_ratio = img_width / img_height
|
||||
target_ratio = target_width / target_height
|
||||
if img_ratio > target_ratio:
|
||||
new_width = target_width
|
||||
new_height = int(target_width / img_ratio)
|
||||
else:
|
||||
new_height = target_height
|
||||
new_width = int(target_height * img_ratio)
|
||||
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
padded_img = Image.new('RGB', (target_width, target_height), 'black') # 创建黑色背景
|
||||
x_offset = (target_width - new_width) // 2
|
||||
y_offset = (target_height - new_height) // 2
|
||||
padded_img.paste(resized_img, (x_offset, y_offset)) # 将缩放后的图片贴到中心
|
||||
return np.array(padded_img).astype(np.float32)/255.0, new_width, new_height
|
||||
|
||||
elif method == 'cover':
|
||||
# Cover: 缩放图像以覆盖目标尺寸,保持宽高比,可能裁剪
|
||||
img_ratio = img_width / img_height
|
||||
target_ratio = target_width / target_height
|
||||
if img_ratio > target_ratio:
|
||||
new_height = target_height
|
||||
new_width = int(target_height * img_ratio)
|
||||
else:
|
||||
new_width = target_width
|
||||
new_height = int(target_width / img_ratio)
|
||||
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
x_offset = (new_width - target_width) // 2
|
||||
y_offset = (new_height - target_height) // 2
|
||||
cropped_img = resized_img.crop((x_offset, y_offset, x_offset + target_width, y_offset + target_height)) # 裁剪中心部分
|
||||
return np.array(cropped_img).astype(np.float32)/255.0 , target_width, target_height
|
||||
|
||||
elif method == 'fill':
|
||||
# Fill: 拉伸图像以填充目标尺寸,忽略宽高比,可能变形
|
||||
resized_img = img.resize((target_width, target_height), Image.Resampling.LANCZOS)
|
||||
return np.array(resized_img).astype(np.float32)/255.0, target_width, target_height
|
||||
|
||||
elif method == 'inside':
|
||||
# Inside: 和 contain 相同,保持宽高比,缩小或不改变图像使其完全适合容器
|
||||
img_ratio = img_width / img_height
|
||||
target_ratio = target_width / target_height
|
||||
if img_ratio > target_ratio:
|
||||
new_width = target_width
|
||||
new_height = int(target_width / img_ratio)
|
||||
else:
|
||||
new_height = target_height
|
||||
new_width = int(target_height * img_ratio)
|
||||
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
padded_img = Image.new('RGB', (target_width, target_height), 'black')
|
||||
x_offset = (target_width - new_width) // 2
|
||||
y_offset = (target_height - new_height) // 2
|
||||
padded_img.paste(resized_img, (x_offset, y_offset))
|
||||
return np.array(padded_img).astype(np.float32)/255.0, new_width, new_height
|
||||
|
||||
elif method == 'outside':
|
||||
# Outside: 和 cover 相同,保持宽高比,放大或不改变图像使其完全覆盖容器
|
||||
img_ratio = img_width / img_height
|
||||
target_ratio = target_width / target_height
|
||||
if img_ratio > target_ratio:
|
||||
new_height = target_height
|
||||
new_width = int(target_height * img_ratio)
|
||||
else:
|
||||
new_width = target_width
|
||||
new_height = int(target_width / img_ratio)
|
||||
resized_img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||
x_offset = (new_width - target_width) // 2
|
||||
y_offset = (new_height - target_height) // 2
|
||||
cropped_img = resized_img.crop((x_offset, y_offset, x_offset + target_width, y_offset + target_height))
|
||||
return np.array(cropped_img).astype(np.float32)/255.0 , target_width, target_height
|
||||
|
||||
def crop_image(image, target_width, target_height, position='center'):
|
||||
"""Crop an image to the target dimensions.
|
||||
position: 'center' (居中),
|
||||
'top-left' (左上角),
|
||||
'top-right' (右上角),
|
||||
'bottom-left' (左下角),
|
||||
'bottom-right' (右下角).
|
||||
"""
|
||||
img = Image.fromarray(np.clip(255. * image.cpu().numpy(), 0, 255).astype(np.uint8))
|
||||
img_width, img_height = img.size
|
||||
|
||||
if img_width < target_width or img_height < target_height:
|
||||
raise ValueError(f"image size is less than target size, current width={img_width}, height={img_height}, target_width={target_width}, target_height={target_height}")
|
||||
|
||||
if position == 'center':
|
||||
x_offset = (img_width - target_width) // 2
|
||||
y_offset = (img_height - target_height) // 2
|
||||
elif position == 'top-left':
|
||||
x_offset = 0
|
||||
y_offset = 0
|
||||
elif position == 'top-right':
|
||||
x_offset = img_width - target_width
|
||||
y_offset = 0
|
||||
elif position == 'bottom-left':
|
||||
x_offset = 0
|
||||
y_offset = img_height - target_height
|
||||
elif position == 'bottom-right':
|
||||
x_offset = img_width - target_width
|
||||
y_offset = img_height - target_height
|
||||
else:
|
||||
raise ValueError(f"Invalid crop position: {position}")
|
||||
|
||||
cropped_img = img.crop((x_offset, y_offset, x_offset + target_width, y_offset + target_height))
|
||||
return np.array(cropped_img).astype(np.float32) / 255.0, target_width, target_height
|
||||
|
||||
|
||||
class ImageScaleCalculator:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",), # Input image
|
||||
"scale_type": (["ratio", "max_width", "max_height", "force_size", "crop"],), # Scale type
|
||||
"scale_ratio": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 100.0, "step": 0.01}), # Scale ratio
|
||||
"max_width": ("INT", {"default": 512, "min": 1, "max": 8192, "step": 1}), # Max width
|
||||
"max_height": ("INT", {"default": 512, "min": 1, "max": 8192, "step": 1}), # Max height
|
||||
"target_width": ("INT", {"default": 512, "min": 1, "max": 8192, "step": 1}), # Target width
|
||||
"target_height": ("INT", {"default": 512, "min": 1, "max": 8192, "step": 1}), # Target height
|
||||
"crop_position": (["center", "top-left", "top-right", "bottom-left", "bottom-right"],), # Crop position
|
||||
"method": (["contain", "cover", "fill", "inside", "outside"],), # Resize method
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "INT", "INT")
|
||||
RETURN_NAMES = ("image", "width", "height")
|
||||
FUNCTION = "scale_image"
|
||||
CATEGORY = "🎨Painting👓Coder/🖼️Image" # Node category
|
||||
|
||||
def scale_image(self, image, scale_type, scale_ratio, max_width, max_height, target_width, target_height, crop_position, method):
|
||||
img = image[0] # Get the image
|
||||
img_width = img.shape[1]
|
||||
img_height = img.shape[0]
|
||||
|
||||
if scale_type == "ratio":
|
||||
target_width = int(img_width * scale_ratio)
|
||||
target_height = int(img_height * scale_ratio)
|
||||
|
||||
# 应用最大尺寸限制
|
||||
target_width = min(target_width, max_width)
|
||||
target_height = min(target_height, max_height)
|
||||
|
||||
scaled_image, width, height = resize_image(img, target_width, target_height, method=method) # Scale by ratio with limits
|
||||
|
||||
elif scale_type == "max_width":
|
||||
target_width = max_width
|
||||
target_height = int(img_height * (max_width / img_width))
|
||||
|
||||
# 应用最大尺寸限制
|
||||
target_height = min(target_height, max_height)
|
||||
|
||||
scaled_image, width, height = resize_image(img, target_width, target_height, method="contain") # Scale by max width with limits
|
||||
|
||||
elif scale_type == "max_height":
|
||||
target_height = max_height
|
||||
target_width = int(img_width * (max_height / img_height))
|
||||
|
||||
# 应用最大尺寸限制
|
||||
target_width = min(target_width, max_width)
|
||||
scaled_image, width, height = resize_image(img, target_width, target_height, method="contain") # Scale by max height with limits
|
||||
|
||||
elif scale_type == "force_size":
|
||||
scaled_image, width, height = resize_image(img, target_width, target_height, method="fill") # Force target width and height
|
||||
|
||||
elif scale_type == "crop":
|
||||
scaled_image, width, height = crop_image(img, target_width, target_height, crop_position) # Crop image
|
||||
|
||||
|
||||
return (torch.from_numpy(scaled_image).unsqueeze(0), width, height)
|
||||
@@ -1,92 +0,0 @@
|
||||
# 创建者: jammyfu
|
||||
import re
|
||||
|
||||
class RemoveEmptyLinesAndLeadingSpacesAdvance:
|
||||
"""
|
||||
一个 ComfyUI 自定义节点,用于移除文本中多余的空行和行首空格。
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
"""
|
||||
定义节点的输入类型。
|
||||
|
||||
Returns:
|
||||
dict: 包含 'required' 和 'optional' 输入定义的字典。
|
||||
"""
|
||||
return {
|
||||
"required": {
|
||||
"text": ("STRING", {"multiline": True}),
|
||||
"output_type": (["String", "List"], {"default": "String"}),
|
||||
},
|
||||
"optional": {
|
||||
"remove_empty_lines_option": ("BOOLEAN", {"default": True}),
|
||||
"remove_leading_spaces_option": ("BOOLEAN", {"default": True}),
|
||||
"preview": ("BOOLEAN", {"default": False}),
|
||||
"output_preview": ("STRING", {"multiline": True, "readonly": True, "default": "", "display": "none"})
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("output",)
|
||||
OUTPUT_NODE = True
|
||||
FUNCTION = "process_text"
|
||||
CATEGORY = "🎨Painting👓Coder/📝Text"
|
||||
|
||||
# 定义 OUTPUT_IS_LIST
|
||||
OUTPUT_IS_LIST = [False]
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(s, **kwargs):
|
||||
preview = kwargs.get("preview", False)
|
||||
if preview:
|
||||
return float("nan")
|
||||
return False
|
||||
|
||||
def process_text(self, text, output_type, remove_empty_lines_option, remove_leading_spaces_option, preview, output_preview):
|
||||
"""
|
||||
处理文本的函数,根据按钮值移除空行和行首空格。
|
||||
|
||||
Args:
|
||||
text (str): 输入的文本字符串。
|
||||
output_type (str): 输出类型,"String" 或 "List"。
|
||||
remove_empty_lines_option (bool): 是否移除空行的标志。
|
||||
remove_leading_spaces_option (bool): 是否移除行首空格的标志。
|
||||
preview (bool): 是否显示预览窗口。
|
||||
output_preview (str): 输出预览文本。
|
||||
Returns:
|
||||
tuple: 包含处理后的文本(字符串或字符串列表)和预览UI。
|
||||
"""
|
||||
processed_text = text
|
||||
|
||||
if remove_empty_lines_option or remove_leading_spaces_option:
|
||||
lines = processed_text.split('\n')
|
||||
|
||||
if remove_leading_spaces_option:
|
||||
lines = [line.strip() for line in lines]
|
||||
|
||||
if remove_empty_lines_option:
|
||||
lines = [line for line in lines if line.strip()]
|
||||
|
||||
result = lines if output_type == "List" else "\n".join(lines)
|
||||
else:
|
||||
result = text.splitlines() if output_type == "List" else text
|
||||
|
||||
if preview:
|
||||
return {
|
||||
"ui": {
|
||||
"output_preview": [result, {"multiline": True, "readonly": True, "height": 300}]
|
||||
},
|
||||
"result": (result,)
|
||||
}
|
||||
else:
|
||||
return (result,)
|
||||
|
||||
# 节点类映射,用于 ComfyUI 注册
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"RemoveEmptyLinesAndLeadingSpacesAdvance": RemoveEmptyLinesAndLeadingSpacesAdvance
|
||||
}
|
||||
|
||||
# 节点显示名称映射,用于 ComfyUI 显示
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"RemoveEmptyLinesAndLeadingSpacesAdv": "Remove Empty Lines & Leading Spaces Advance"
|
||||
}
|
||||
Reference in New Issue
Block a user