#!/usr/bin/env python3 """Extract SVGs from HTML, inline styles (light theme), output standalone .svg files.""" import re, sys, html SRC = "/root/.openclaw/workspace/loop-detector/loop-detector-principle.html" CSS = { "title": {"font-size": "20px", "font-weight": "650", "fill": "#172033"}, "label": {"font-size": "14px", "font-weight": "600", "fill": "#172033"}, "small": {"font-size": "12px", "fill": "#5b6475"}, "tiny": {"font-size": "11px", "fill": "#5b6475"}, "node": {"stroke": "#64748b", "stroke-width": "1"}, "neutral": {"fill": "#e2e8f0"}, "input": {"fill": "#bfdbfe"}, "process": {"fill": "#c7d2fe"}, "storage": {"fill": "#99f6e4"}, "external":{"fill": "#fde68a"}, "risk": {"fill": "#fecaca"}, "edge": {"stroke": "#64748b", "stroke-width": "1.5", "fill": "none"}, "wire": {"stroke": "#64748b", "stroke-width": "1.3", "fill": "none"}, "wireb": {"stroke": "#64748b", "stroke-width": "2", "fill": "none"}, "zone": {"fill": "none", "stroke": "#64748b", "stroke-width": "1", "stroke-dasharray": "6 5", "opacity": "0.8"}, "comp": {"fill": "none", "stroke": "#172033", "stroke-width": "1.6"}, "compf": {"fill": "#172033", "stroke": "none"}, "rec": {"fill": "#172033", "stroke": "none"}, "rec-o": {"fill": "none", "stroke": "#172033", "stroke-width": "1.4"}, "badge": {"fill": "#16a34a"}, "badge-t": {"fill": "#ffffff", "font-size": "11px", "font-weight": "700"}, "hl": {"stroke": "#16a34a", "stroke-width": "2.5"}, } def inline(el): classes = el.get("class", "").split() merged = {} for c in classes: if c in CSS: merged.update(CSS[c]) # element-level attributes override classes (fill attr etc.) for attr in ("fill", "stroke", "stroke-width", "opacity"): v = el.get(attr) if v is not None: merged[attr] = v if merged: style = "; ".join(f"{k}: {v}" for k, v in merged.items()) old = el.get("style", "") el.set("style", (old + ";" + style).strip(";") if old else style) el.attrib.pop("class", None) for child in el: inline(child) def process(svg_text, out_path): # drop ", "", svg_text, flags=re.S) import xml.etree.ElementTree as ET root = ET.fromstring(svg_text) # add width/height for predictable output root.set("xmlns", "http://www.w3.org/2000/svg") inline(root) tree = ET.ElementTree(root) tree.write(out_path, encoding="utf-8", xml_declaration=True) print("wrote", out_path) data = open(SRC, encoding="utf-8").read() svgs = re.findall(r"", data, flags=re.S) print("found", len(svgs), "svgs") process(svgs[0], "/root/.openclaw/workspace/loop-detector/fig1-methods.svg") process(svgs[1], "/root/.openclaw/workspace/loop-detector/fig2-schematic.svg")