11from __future__ import annotations
22from inspect import cleandoc
33from comfy .utils import ProgressBar
4+ from comfy_extras .nodes_images import SVG # Added
45from comfy .comfy_types .node_typing import IO
56from comfy_api_nodes .apis .recraft_api import (
67 RecraftImageGenerationRequest ,
2829 resize_mask_to_image ,
2930 validate_string ,
3031)
31- import folder_paths
32- import json
33- import os
3432import torch
3533from io import BytesIO
3634from PIL import UnidentifiedImageError
@@ -162,102 +160,6 @@ def __exit__(self, exc_type, exc_val, exc_tb):
162160 raise Exception ("Received output data was not an image; likely an SVG. If you used style_id, make sure it is not a Vector art style." )
163161
164162
165- class SVG :
166- """
167- Stores SVG representations via a list of BytesIO objects.
168- """
169- def __init__ (self , data : list [BytesIO ]):
170- self .data = data
171-
172- def combine (self , other : SVG ):
173- return SVG (self .data + other .data )
174-
175- @staticmethod
176- def combine_all (svgs : list [SVG ]):
177- all_svgs = []
178- for svg in svgs :
179- all_svgs .extend (svg .data )
180- return SVG (all_svgs )
181-
182-
183- class SaveSVGNode :
184- """
185- Save SVG files on disk.
186- """
187-
188- def __init__ (self ):
189- self .output_dir = folder_paths .get_output_directory ()
190- self .type = "output"
191- self .prefix_append = ""
192-
193- RETURN_TYPES = ()
194- DESCRIPTION = cleandoc (__doc__ or "" ) # Handle potential None value
195- FUNCTION = "save_svg"
196- CATEGORY = "api node/image/Recraft"
197- OUTPUT_NODE = True
198-
199- @classmethod
200- def INPUT_TYPES (s ):
201- return {
202- "required" : {
203- "svg" : (RecraftIO .SVG ,),
204- "filename_prefix" : ("STRING" , {"default" : "svg/ComfyUI" , "tooltip" : "The prefix for the file to save. This may include formatting information such as %date:yyyy-MM-dd% or %Empty Latent Image.width% to include values from nodes." })
205- },
206- "hidden" : {
207- "prompt" : "PROMPT" ,
208- "extra_pnginfo" : "EXTRA_PNGINFO"
209- }
210- }
211-
212- def save_svg (self , svg : SVG , filename_prefix = "svg/ComfyUI" , prompt = None , extra_pnginfo = None ):
213- filename_prefix += self .prefix_append
214- full_output_folder , filename , counter , subfolder , filename_prefix = folder_paths .get_save_image_path (filename_prefix , self .output_dir )
215- results = list ()
216-
217- # Prepare metadata JSON
218- metadata_dict = {}
219- if prompt is not None :
220- metadata_dict ["prompt" ] = prompt
221- if extra_pnginfo is not None :
222- metadata_dict .update (extra_pnginfo )
223-
224- # Convert metadata to JSON string
225- metadata_json = json .dumps (metadata_dict , indent = 2 ) if metadata_dict else None
226-
227- for batch_number , svg_bytes in enumerate (svg .data ):
228- filename_with_batch_num = filename .replace ("%batch_num%" , str (batch_number ))
229- file = f"{ filename_with_batch_num } _{ counter :05} _.svg"
230-
231- # Read SVG content
232- svg_bytes .seek (0 )
233- svg_content = svg_bytes .read ().decode ('utf-8' )
234-
235- # Inject metadata if available
236- if metadata_json :
237- # Create metadata element with CDATA section
238- metadata_element = f""" <metadata>
239- <![CDATA[
240- { metadata_json }
241- ]]>
242- </metadata>
243- """
244- # Insert metadata after opening svg tag using regex
245- import re
246- svg_content = re .sub (r'(<svg[^>]*>)' , r'\1\n' + metadata_element , svg_content )
247-
248- # Write the modified SVG to file
249- with open (os .path .join (full_output_folder , file ), 'wb' ) as svg_file :
250- svg_file .write (svg_content .encode ('utf-8' ))
251-
252- results .append ({
253- "filename" : file ,
254- "subfolder" : subfolder ,
255- "type" : self .type
256- })
257- counter += 1
258- return { "ui" : { "images" : results } }
259-
260-
261163class RecraftColorRGBNode :
262164 """
263165 Create Recraft Color by choosing specific RGB values.
@@ -796,8 +698,8 @@ class RecraftTextToVectorNode:
796698 Generates SVG synchronously based on prompt and resolution.
797699 """
798700
799- RETURN_TYPES = (RecraftIO . SVG ,)
800- DESCRIPTION = cleandoc (__doc__ or "" ) # Handle potential None value
701+ RETURN_TYPES = (" SVG" ,) # Changed
702+ DESCRIPTION = cleandoc (__doc__ or "" ) if 'cleandoc' in globals () else __doc__ # Keep cleandoc if other nodes use it
801703 FUNCTION = "api_call"
802704 API_NODE = True
803705 CATEGORY = "api node/image/Recraft"
@@ -918,8 +820,8 @@ class RecraftVectorizeImageNode:
918820 Generates SVG synchronously from an input image.
919821 """
920822
921- RETURN_TYPES = (RecraftIO . SVG ,)
922- DESCRIPTION = cleandoc (__doc__ or "" ) # Handle potential None value
823+ RETURN_TYPES = (" SVG" ,) # Changed
824+ DESCRIPTION = cleandoc (__doc__ or "" ) if 'cleandoc' in globals () else __doc__ # Keep cleandoc if other nodes use it
923825 FUNCTION = "api_call"
924826 API_NODE = True
925827 CATEGORY = "api node/image/Recraft"
@@ -1193,7 +1095,6 @@ class RecraftCreativeUpscaleNode(RecraftCrispUpscaleNode):
11931095 "RecraftStyleV3InfiniteStyleLibrary" : RecraftStyleInfiniteStyleLibrary ,
11941096 "RecraftColorRGB" : RecraftColorRGBNode ,
11951097 "RecraftControls" : RecraftControlsNode ,
1196- "SaveSVG" : SaveSVGNode ,
11971098}
11981099
11991100# A dictionary that contains the friendly/humanly readable titles for the nodes
@@ -1213,5 +1114,4 @@ class RecraftCreativeUpscaleNode(RecraftCrispUpscaleNode):
12131114 "RecraftStyleV3InfiniteStyleLibrary" : "Recraft Style - Infinite Style Library" ,
12141115 "RecraftColorRGB" : "Recraft Color RGB" ,
12151116 "RecraftControls" : "Recraft Controls" ,
1216- "SaveSVG" : "Save SVG" ,
12171117}
0 commit comments