Dreamspire's picture
custom_nodes
f2dbf59
import os
import re
from pathlib import Path
import numpy as np
import torch
from PIL import Image, ImageOps
import comfy.utils
from .utils.image_convert import pil2tensor
_CATEGORY = 'fnodes/files'
class ReadImage:
@classmethod
def INPUT_TYPES(cls):
return {
'required': {
'image_path': ('STRING', {'default': 'images'}),
}
}
RETURN_TYPES = ('IMAGE', 'STRING')
RETURN_NAMES = ('image', 'file_stem')
FUNCTION = 'execute'
CATEGORY = _CATEGORY
DESCRIPTION = '读取指定路径图片,返回图片和图片名称'
def execute(self, image_path):
# 去掉可能存在的双引号
image_path = image_path.strip('"')
if not os.path.exists(image_path):
raise FileNotFoundError(f'文件未找到: {image_path}')
file_stem = str(Path(image_path).stem)
img = Image.open(image_path)
img = ImageOps.exif_transpose(img)
if img is None:
raise ValueError(f'无法从文件中读取有效图像: {image_path}')
if img.mode == 'I':
img = img.point(lambda i: i * (1 / 255))
img = img.convert('RGB')
image = np.array(img).astype(np.float32) / 255.0
image = torch.from_numpy(image)[None,]
return (image, file_stem)
class LoadImagesFromFolder:
@classmethod
def INPUT_TYPES(cls):
return {
'required': {
'input_path': ('STRING', {'default': '', 'multiline': False}),
'start_index': ('INT', {'default': 0, 'min': 0, 'max': 9999}),
'max_index': ('INT', {'default': 1, 'min': 1, 'max': 9999}),
}
}
RETURN_TYPES = (
'IMAGE',
'IMAGE',
)
RETURN_NAMES = (
'images_list',
'image_batch',
)
OUTPUT_IS_LIST = (
True,
False,
)
FUNCTION = 'make_list'
CATEGORY = _CATEGORY
DESCRIPTION = '读取文件夹中的图片,返回图片列表和图片批次'
def make_list(self, start_index, max_index, input_path):
# 检查输入路径是否存在
if not os.path.exists(input_path):
raise FileNotFoundError(f'文件夹未找到: {input_path}')
# 检查文件夹是否为空
if not os.listdir(input_path):
raise ValueError(f'文件夹为空: {input_path}')
# 对文件列表进行排序
file_list = sorted(
os.listdir(input_path),
key=lambda s: sum(((s, int(n)) for s, n in re.findall(r'(\D+)(\d+)', 'a%s0' % s)), ()),
)
image_list = []
# 确保 start_index 在列表范围内
start_index = max(0, min(start_index, len(file_list) - 1))
# 计算结束索引
end_index = min(start_index + max_index, len(file_list))
ref_image = None
for num in range(start_index, end_index):
fname = os.path.join(input_path, file_list[num])
img = Image.open(fname)
img = ImageOps.exif_transpose(img)
if img is None:
raise ValueError(f'无法从文件中读取有效图像: {fname}')
image = img.convert('RGB')
t_image = pil2tensor(image)
# 确保所有图像的尺寸相同
if ref_image is None:
ref_image = t_image
else:
if t_image.shape[1:] != ref_image.shape[1:]:
t_image = comfy.utils.common_upscale(
t_image.movedim(-1, 1),
ref_image.shape[2],
ref_image.shape[1],
'lanczos',
'center',
).movedim(1, -1)
image_list.append(t_image)
if not image_list:
raise ValueError('未找到有效图像')
image_batch = torch.cat(image_list, dim=0)
images_out = [image_batch[i : i + 1, ...] for i in range(image_batch.shape[0])]
return (
images_out,
image_batch,
)
class FilePathAnalyzer:
@classmethod
def INPUT_TYPES(cls):
return {
'required': {
'file_path': ('STRING', {'default': 'file.txt'}),
}
}
RETURN_TYPES = ('STRING', 'STRING', 'STRING', 'STRING')
RETURN_NAMES = ('parent_dir', 'file_stem', 'file_extension', 'full_path')
FUNCTION = 'execute'
CATEGORY = _CATEGORY
DESCRIPTION = '从文件路径中提取上层目录、文件名(不含扩展名)、扩展名和完整路径'
def execute(self, file_path):
# 去掉可能存在的双引号
file_path = file_path.strip('"')
path = Path(file_path)
parent_dir = str(path.parent)
file_stem = path.stem
file_extension = path.suffix
full_path = str(path.absolute())
return (parent_dir, file_stem, file_extension, full_path)
class RegexExtractor:
@classmethod
def INPUT_TYPES(cls):
return {
'required': {
'input_string': ('STRING', {'default': ''}),
'regex_pattern': ('STRING', {'default': ''}),
'group_number': ('INT', {'default': 0, 'min': 0, 'max': 100}),
}
}
RETURN_TYPES = ('STRING',)
RETURN_NAMES = ('extracted_text',)
FUNCTION = 'execute'
CATEGORY = _CATEGORY
DESCRIPTION = '使用正则表达式从输入字符串中提取文本'
def execute(self, input_string, regex_pattern, group_number):
try:
match = re.search(regex_pattern, input_string)
if match:
groups = match.groups()
if 0 <= group_number <= len(groups):
return (match.group(group_number),)
else:
return ('组号超出范围',)
else:
return ('未找到匹配',)
except re.error:
return ('无效的正则表达式',)
class SelectFace:
dir_dict = {}
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
target_dir = r'D:\aidraw\fworker\assets\face_pieces'
for d in Path(target_dir).iterdir():
if d.is_dir():
cls.dir_dict[d.name] = d
return {'required': {'face_name': (list(cls.dir_dict.keys()),)}}
RETURN_TYPES = (
'STRING',
'STRING',
)
RETURN_NAMES = (
'face_path',
'face_name',
)
FUNCTION = 'execute'
CATEGORY = _CATEGORY
DESCRIPTION = '选择人脸'
def execute(self, face_name):
return (
str(self.dir_dict[face_name]),
face_name,
)
FILE_CLASS_MAPPINGS = {
'ReadImage-': ReadImage,
'LoadImagesFromFolder-': LoadImagesFromFolder,
'FilePathAnalyzer-': FilePathAnalyzer,
'RegexExtractor-': RegexExtractor,
'SelectFace-': SelectFace,
}
FILE_NAME_MAPPINGS = {
'ReadImage-': 'Read Image from Path',
'LoadImagesFromFolder-': 'Load Images From Folder',
'FilePathAnalyzer-': 'FilePath Analyzer',
'RegexExtractor-': 'Regex Extractor',
'SelectFace-': 'Select Face',
}