diff --git a/meyo_node_File.py b/meyo_node_File.py index f2be737..6ce1e95 100644 --- a/meyo_node_File.py +++ b/meyo_node_File.py @@ -1,5 +1,4 @@ -import os, re, io, base64, csv, torch -import shutil, requests, chardet, pathlib +import os, re, io, base64, csv, torch, shutil, requests, chardet, pathlib import openpyxl, folder_paths, node_helpers import numpy as np from PIL import Image, ImageOps, ImageSequence @@ -7,8 +6,7 @@ from pathlib import Path from openpyxl.drawing.image import Image as OpenpyxlImage from PIL import Image as PILImage from io import BytesIO -from . import AnyType, any_typ - +from . import any_typ, note @@ -25,10 +23,8 @@ class GenericImageLoader: FUNCTION = "load_image" OUTPUT_NODE = False CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def load_image(self, image_input): path = image_input.strip() @@ -92,10 +88,8 @@ class LoadAndAdjustImage: RETURN_NAMES = ("image", "mask", "info") FUNCTION = "load_image" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def load_image(self, image, max_dimension, size_option): image_path = folder_paths.get_annotated_filepath(image) @@ -192,24 +186,17 @@ class LoadAndAdjustImage: if not folder_paths.exists_annotated_filepath(image): return f"Invalid image file: {image}" return True - def _resize_to_million_pixels(self, W, H): - # Calculate the aspect ratio of the original image aspect_ratio = W / H target_area = 1000000 # 1 million pixels - - # Calculate the new width and height while maintaining the aspect ratio if aspect_ratio > 1: # Landscape width = int(np.sqrt(target_area * aspect_ratio)) height = int(target_area / width) else: # Portrait height = int(np.sqrt(target_area / aspect_ratio)) width = int(target_area / height) - - # Round width and height to the nearest multiple of 8 width = (width + 7) // 8 * 8 height = (height + 7) // 8 * 8 - return width, height @@ -234,10 +221,8 @@ class ImageAdjuster: RETURN_NAMES = ("image", "mask", "width", "height") FUNCTION = "process_image" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(self): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def process_image(self, image, mask, max_dimension=1024, size_option="Custom"): batch_size = image.shape[0] @@ -352,7 +337,6 @@ class ImageAdjuster: return width, height - #======裁剪图像 class CustomCrop: @classmethod @@ -370,10 +354,8 @@ class CustomCrop: RETURN_NAMES = ("image", "mask", "width", "height") FUNCTION = "process_image" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def process_image(self, image, mask, width=768, height=768): input_image = Image.fromarray((image.squeeze(0).numpy() * 255).astype(np.uint8)) @@ -434,10 +416,8 @@ class SaveImagEX: FUNCTION = "save_image" OUTPUT_NODE = True CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def save_image(self, image, save_path, image_name, image_format): if not isinstance(image, torch.Tensor): @@ -455,7 +435,6 @@ class SaveImagEX: channel_to_mode = {1: "L", 3: "RGB", 4: "RGBA"} for i in range(batch_size): - # 根据选择的格式动态设置扩展名 if image_format == "PNG": filename = f"{base_name}.png" if batch_size == 1 else f"{base_name}_{i:05d}.png" save_format = "PNG" @@ -476,7 +455,6 @@ class SaveImagEX: single_image = single_image[:, :, 0] pil_image = Image.fromarray(single_image, mode) - # 如果是JPG格式,需要转换为RGB模式 if image_format == "JPG": pil_image = pil_image.convert("RGB") @@ -509,14 +487,11 @@ class FileCopyCutNode: def copy_cut_file(self, source_path, destination_path, operation, any=None): result = "执行失败" try: - # 检查文件是否存在 if not os.path.isfile(source_path): raise FileNotFoundError(f"源文件未找到: {source_path}") - - # 确保目标目录存在 + os.makedirs(os.path.dirname(destination_path), exist_ok=True) - # 执行复制或剪切操作 if operation == "copy": shutil.copy2(source_path, destination_path) result = "执行成功: 文件已复制" @@ -535,8 +510,6 @@ class FileCopyCutNode: return (result,) - - #======替换文件名 class FileNameReplacer: @classmethod @@ -552,26 +525,16 @@ class FileNameReplacer: RETURN_TYPES = ("STRING",) FUNCTION = "replace_file_name" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def replace_file_name(self, file_path, new_file_name, any=None): - # 获取目录和原始文件名与扩展名 dir_name = os.path.dirname(file_path) _, file_ext = os.path.splitext(file_path) - - # 替换非法字符 new_file_name = self.sanitize_file_name(new_file_name) - - # 构造新的文件路径 new_file_path = os.path.join(dir_name, new_file_name + file_ext) - return (new_file_path,) - def sanitize_file_name(self, file_name): - # 替换不能作为文件名的字符为"_" invalid_chars = r'[\/:*?"<>|]' return re.sub(invalid_chars, '_', file_name) @@ -591,10 +554,8 @@ class WriteToTxtFile: RETURN_TYPES = ("STRING",) FUNCTION = "write_to_txt" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def write_to_txt(self, text_content, file_path, any=None): try: @@ -624,31 +585,22 @@ class FileDeleteNode: RETURN_NAMES = ("result",) FUNCTION = "delete_files" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def delete_files(self, items_to_delete, any=None): result = "执行成功: 所有指定项已从output目录删除" error_messages = [] - - # 确保只操作COMFYUI_OUTPUT_DIR目录下的内容 base_output_dir = Path.cwd() / COMFYUI_OUTPUT_DIR - - # 处理多行文本输入 items = items_to_delete.strip().split('\n') for item in items: item = item.strip() if not item: continue - - # 检查是否有特殊命令[DeleteAll] if item == "[DeleteAll]": try: - # 删除output目录下所有内容 for file_or_dir in base_output_dir.glob('*'): if file_or_dir.is_file() or file_or_dir.is_symlink(): file_or_dir.unlink() @@ -658,23 +610,15 @@ class FileDeleteNode: except Exception as e: error_messages.append(f"从output目录删除全部失败: {str(e)}") continue - - # 构建完整路径 target_path = base_output_dir / item - - # 检查是否位于output目录下 try: target_path.relative_to(base_output_dir) except ValueError: error_messages.append(f"{item} 不在output目录范围内,无法删除") continue - - # 检查文件/目录是否存在 if not target_path.exists(): error_messages.append(f"在output目录下找不到 {item}") continue - - # 删除操作 try: if target_path.is_file() or target_path.is_symlink(): target_path.unlink() @@ -682,8 +626,6 @@ class FileDeleteNode: shutil.rmtree(target_path) except Exception as e: error_messages.append(f"从output目录删除 {item} 失败: {str(e)}") - - # 汇总结果 if error_messages: result = "部分执行失败:\n" + "\n".join(error_messages) return (result,) @@ -704,10 +646,8 @@ class FileListAndSuffix: RETURN_TYPES = ("STRING", "INT", "LIST") FUNCTION = "file_list_and_suffix" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def file_list_and_suffix(self, folder_path, file_extension, any=None): try: @@ -743,10 +683,8 @@ class ReadExcelData: RETURN_TYPES = ("STRING",) FUNCTION = "read_excel_data" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def read_excel_data(self, excel_path, sheet_name, row_range, col_range, any=None): try: @@ -801,10 +739,8 @@ class WriteExcelData: RETURN_TYPES = ("STRING",) FUNCTION = "write_excel_data" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def write_excel_data(self, excel_path, sheet_name, row_range, col_range, data, any=None): try: @@ -875,10 +811,8 @@ class WriteExcelImage: RETURN_TYPES = ("STRING",) FUNCTION = "write_image" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def write_image(self, excel_path, sheet_name, row_range, col_range, image_path, any=None): try: @@ -920,7 +854,6 @@ class WriteExcelImage: return (f"Error: {str(e)}",) - #======查找表格数据 class FindExcelData: @classmethod @@ -938,10 +871,8 @@ class FindExcelData: RETURN_TYPES = ("STRING", "INT", "INT") FUNCTION = "find_excel_data" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def find_excel_data(self, excel_path, sheet_name, search_content, search_mode, any=None): try: @@ -975,7 +906,6 @@ class FindExcelData: return (f"Error: {str(e)}", None, None) - #======读取表格数量差 class ReadExcelRowOrColumnDiff: @classmethod @@ -993,10 +923,8 @@ class ReadExcelRowOrColumnDiff: RETURN_TYPES = ("INT",) FUNCTION = "read_excel_row_or_column_diff" CATEGORY = "Meeeyo/File" - DESCRIPTION = "如需更多帮助或商务需求(For tech and business support)+VX/WeChat: meeeyo" - - def IS_CHANGED(): - return float("NaN") + DESCRIPTION = note + def IS_CHANGED(): return float("NaN") def read_excel_row_or_column_diff(self, excel_path, sheet_name, read_mode, indices, any=None): try: