Split a symbol's SVG into (artwork_without_text, embedded_texts). Embedded labels (e.g. +/- polarity markers, noise-source labels) are removed from the artwork so they can be redrawn upright and unmirrored on top, regardless of the component's rotation/flip. Each text is {x,
(svg_bytes: bytes)
| 88 | |
| 89 | |
| 90 | def _split_symbol_text(svg_bytes: bytes) -> tuple[bytes, list[dict]]: |
| 91 | """Split a symbol's SVG into (artwork_without_text, embedded_texts). |
| 92 | |
| 93 | Embedded <text> labels (e.g. +/- polarity markers, noise-source labels) are |
| 94 | removed from the artwork so they can be redrawn upright and unmirrored on top, |
| 95 | regardless of the component's rotation/flip. Each text is |
| 96 | {x, y, size, content} in symbol-local coordinates.""" |
| 97 | texts: list[dict] = [] |
| 98 | |
| 99 | def _num(s, default): |
| 100 | try: |
| 101 | return float(s) |
| 102 | except (TypeError, ValueError): |
| 103 | return default |
| 104 | |
| 105 | def _attr(attrs: str, name: str, default: float) -> float: |
| 106 | m = re.search(rf'{name}\s*=\s*"([^"]*)"', attrs) |
| 107 | return _num(m.group(1), default) if m else default |
| 108 | |
| 109 | def _repl(m): |
| 110 | attrs = m.group(1).decode("utf-8", "replace") |
| 111 | content = m.group(2).decode("utf-8", "replace").strip() |
| 112 | if content: |
| 113 | texts.append({ |
| 114 | "x": _attr(attrs, "x", 0.0), |
| 115 | "y": _attr(attrs, "y", 0.0), |
| 116 | "size": _attr(attrs, "font-size", 8.0), |
| 117 | "content": content, |
| 118 | }) |
| 119 | return b"" |
| 120 | |
| 121 | return _TEXT_RE.sub(_repl, svg_bytes), texts |
| 122 | |
| 123 | |
| 124 | def draw_symbol_texts(painter, texts, rotation: float, |
no outgoing calls
no test coverage detected