69 lines
2.9 KiB
Python
69 lines
2.9 KiB
Python
#!/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 <style> and <defs> references stay; remove style blocks
|
|
svg_text = re.sub(r"<style>.*?</style>", "", 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"<svg.*?</svg>", 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")
|