Add SVG file saver nodes (SVGFileSaver and SVGBatchSaver)

This commit is contained in:
tj_comfyui
2025-11-08 11:35:29 +09:00
parent 2e4ee2cc50
commit fee6fa9da7
2 changed files with 173 additions and 2 deletions
+5 -2
View File
@@ -5,16 +5,19 @@ Line art to vector conversion nodes
from .line_region_detector import NODE_CLASS_MAPPINGS as LINE_NODES, NODE_DISPLAY_NAME_MAPPINGS as LINE_NAMES
from .centerline_to_svg import NODE_CLASS_MAPPINGS as SVG_NODES, NODE_DISPLAY_NAME_MAPPINGS as SVG_NAMES
from .svg_file_saver import NODE_CLASS_MAPPINGS as SAVER_NODES, NODE_DISPLAY_NAME_MAPPINGS as SAVER_NAMES
# Combine all node mappings
NODE_CLASS_MAPPINGS = {
**LINE_NODES,
**SVG_NODES
**SVG_NODES,
**SAVER_NODES
}
NODE_DISPLAY_NAME_MAPPINGS = {
**LINE_NAMES,
**SVG_NAMES
**SVG_NAMES,
**SAVER_NAMES
}
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
+168
View File
@@ -0,0 +1,168 @@
"""
SVG File Saver Node for ComfyUI
Saves SVG strings to files
"""
import os
import json
from datetime import datetime
class SVGFileSaver:
"""
Saves SVG strings to files
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"svg_string": ("STRING", {"forceInput": True}),
"filename_prefix": ("STRING", {"default": "centerline"}),
"output_path": ("STRING", {"default": "output/svg"}),
},
"optional": {
"auto_timestamp": ("BOOLEAN", {"default": True}),
"overwrite": ("BOOLEAN", {"default": False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("file_path",)
FUNCTION = "save_svg"
CATEGORY = "TJ_Vector"
OUTPUT_NODE = True
def save_svg(self, svg_string, filename_prefix="centerline",
output_path="output/svg", auto_timestamp=True, overwrite=False):
"""
Save SVG string to file
"""
# Create output directory if it doesn't exist
os.makedirs(output_path, exist_ok=True)
# Generate filename
if auto_timestamp:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{filename_prefix}_{timestamp}.svg"
else:
filename = f"{filename_prefix}.svg"
filepath = os.path.join(output_path, filename)
# Check if file exists and handle overwrite
if os.path.exists(filepath) and not overwrite:
# Add counter to filename
counter = 1
base_name = filename[:-4] # Remove .svg
while os.path.exists(filepath):
filename = f"{base_name}_{counter}.svg"
filepath = os.path.join(output_path, filename)
counter += 1
# Save SVG file
try:
with open(filepath, 'w', encoding='utf-8') as f:
f.write(svg_string)
print(f"SVG saved to: {filepath}")
return (filepath,)
except Exception as e:
print(f"Error saving SVG: {e}")
return ("",)
class SVGBatchSaver:
"""
Saves multiple SVG files with metadata
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"svg_string": ("STRING", {"forceInput": True}),
"filename_prefix": ("STRING", {"default": "centerline"}),
"output_path": ("STRING", {"default": "output/svg"}),
},
"optional": {
"statistics": ("STRING", {"default": ""}),
"color_info": ("STRING", {"default": ""}),
"save_metadata": ("BOOLEAN", {"default": True}),
}
}
RETURN_TYPES = ("STRING", "STRING")
RETURN_NAMES = ("svg_path", "metadata_path")
FUNCTION = "save_svg_batch"
CATEGORY = "TJ_Vector"
OUTPUT_NODE = True
def save_svg_batch(self, svg_string, filename_prefix="centerline",
output_path="output/svg", statistics="",
color_info="", save_metadata=True):
"""
Save SVG with metadata
"""
# Create output directory
os.makedirs(output_path, exist_ok=True)
# Generate filename with timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
base_filename = f"{filename_prefix}_{timestamp}"
# Save SVG file
svg_filepath = os.path.join(output_path, f"{base_filename}.svg")
try:
with open(svg_filepath, 'w', encoding='utf-8') as f:
f.write(svg_string)
print(f"SVG saved to: {svg_filepath}")
except Exception as e:
print(f"Error saving SVG: {e}")
return ("", "")
# Save metadata if requested
metadata_filepath = ""
if save_metadata:
metadata = {
"timestamp": timestamp,
"svg_file": f"{base_filename}.svg",
"statistics": {},
"color_info": {}
}
# Parse statistics JSON
if statistics:
try:
metadata["statistics"] = json.loads(statistics)
except:
metadata["statistics"] = {"raw": statistics}
# Parse color info JSON
if color_info:
try:
metadata["color_info"] = json.loads(color_info)
except:
metadata["color_info"] = {"raw": color_info}
metadata_filepath = os.path.join(output_path, f"{base_filename}_metadata.json")
try:
with open(metadata_filepath, 'w', encoding='utf-8') as f:
json.dump(metadata, f, indent=2, ensure_ascii=False)
print(f"Metadata saved to: {metadata_filepath}")
except Exception as e:
print(f"Error saving metadata: {e}")
return (svg_filepath, metadata_filepath)
NODE_CLASS_MAPPINGS = {
"SVGFileSaver": SVGFileSaver,
"SVGBatchSaver": SVGBatchSaver
}
NODE_DISPLAY_NAME_MAPPINGS = {
"SVGFileSaver": "SVG File Saver",
"SVGBatchSaver": "SVG Batch Saver"
}