Files
orion4d-ComfyUI_DAO_master/svg_preview.py
T
2025-08-21 20:49:25 +02:00

82 lines
3.4 KiB
Python

# ComfyUI_DXF/svg_preview.py
# (imports inchangés)
import torch, numpy as np, io
from PIL import Image
from lxml import etree
try:
import cairosvg
_CAIRO_OK = True
except (ImportError, OSError):
_CAIRO_OK = False
class SvgPreview:
def __init__(self):
if not _CAIRO_OK: raise ImportError("CairoSVG est requis. `pip install cairosvg`")
@classmethod
def INPUT_TYPES(cls):
return {"required": {
"svg_text": ("SVG_TEXT",),
"width": ("INT", {"default": 512, "min": 64, "max": 4096}),
"height": ("INT", {"default": 512, "min": 64, "max": 4096}),
"fit_mode": (["stretch", "fit_width", "fit_height", "contain"],),
"bg_enabled": ("BOOLEAN", {"default": False}),
"bg_color_hex": ("STRING", {"default": "#FFFFFF"}),
}}
RETURN_TYPES = ("IMAGE",)
FUNCTION = "preview"
CATEGORY = "DAO_master/SVG"
def preview(self, svg_text, width, height, fit_mode, bg_enabled, bg_color_hex):
if not svg_text.strip():
img = Image.new('RGB' if bg_enabled else 'RGBA', (width, height), bg_color_hex if bg_enabled else (0,0,0,0))
img_np = np.array(img).astype(np.float32) / 255.0
return (torch.from_numpy(img_np)[None,],)
# Calculer les dimensions de rendu basées sur le fit_mode
render_w, render_h = width, height
if fit_mode != "stretch":
try:
root = etree.fromstring(svg_text.encode('utf-8'))
viewBox = root.get('viewBox')
if viewBox:
_, _, vb_w, vb_h = map(float, viewBox.split())
if vb_h > 0 and vb_w > 0:
aspect_ratio = vb_w / vb_h
if fit_mode == "fit_width":
render_h = int(width / aspect_ratio)
elif fit_mode == "fit_height":
render_w = int(height * aspect_ratio)
elif fit_mode == "contain":
if width / aspect_ratio <= height: # fit width
render_h = int(width / aspect_ratio)
else: # fit height
render_w = int(height * aspect_ratio)
except Exception:
pass # Garder les dimensions par défaut en cas d'erreur
# Rendre le SVG en PNG avec un fond transparent
png_data = cairosvg.svg2png(
bytestring=svg_text.encode('utf-8'),
output_width=render_w,
output_height=render_h
)
rendered_img = Image.open(io.BytesIO(png_data))
# Créer l'image finale
if bg_enabled:
final_img = Image.new('RGB', (width, height), bg_color_hex)
paste_x = (width - rendered_img.width) // 2
paste_y = (height - rendered_img.height) // 2
final_img.paste(rendered_img, (paste_x, paste_y), rendered_img) # Utiliser le canal alpha du PNG comme masque
else: # Pas de fond, on renvoie l'image rendue avec sa transparence
final_img = rendered_img
# Conversion en tenseur
if final_img.mode == 'RGB':
img_np = np.array(final_img).astype(np.float32) / 255.0
else: # RGBA
img_np = np.array(final_img.convert("RGBA")).astype(np.float32) / 255.0
tensor = torch.from_numpy(img_np)[None,]
return (tensor,)