fix: get_schematic_view_region SVG export and coordinate system
- Use a temp directory (not file) for kicad-cli svg output, which expects a directory path - Clean up temp dir with shutil.rmtree instead of individual file unlinks - Fix viewBox cropping: KiCad schematic SVGs use mm directly, not mils (removed erroneous 39.3701 multiplier) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2592,48 +2592,45 @@ class KiCADInterface:
|
|||||||
if not kicad_cli:
|
if not kicad_cli:
|
||||||
return {"success": False, "message": "kicad-cli not found"}
|
return {"success": False, "message": "kicad-cli not found"}
|
||||||
|
|
||||||
with tempfile.NamedTemporaryFile(suffix=".svg", delete=False) as tmp:
|
tmp_dir = tempfile.mkdtemp()
|
||||||
svg_output = tmp.name
|
svg_output = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cmd = [kicad_cli, "sch", "export", "svg", "--output", svg_output, schematic_path]
|
cmd = [kicad_cli, "sch", "export", "svg", "--output", tmp_dir, schematic_path]
|
||||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
||||||
|
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
return {"success": False, "message": f"SVG export failed: {result.stderr}"}
|
return {"success": False, "message": f"SVG export failed: {result.stderr}"}
|
||||||
|
|
||||||
|
# kicad-cli names the file after the schematic
|
||||||
|
svg_files = [f for f in os.listdir(tmp_dir) if f.endswith(".svg")]
|
||||||
|
if not svg_files:
|
||||||
|
return {"success": False, "message": "kicad-cli produced no SVG output"}
|
||||||
|
svg_output = os.path.join(tmp_dir, svg_files[0])
|
||||||
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
tree = ET.parse(svg_output)
|
tree = ET.parse(svg_output)
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
|
|
||||||
# Read original viewBox to determine SVG coordinate mapping
|
# KiCad schematic SVGs use mm as viewBox units directly
|
||||||
ns = {"svg": "http://www.w3.org/2000/svg"}
|
|
||||||
vb = root.get("viewBox", "")
|
vb = root.get("viewBox", "")
|
||||||
if vb:
|
if vb:
|
||||||
parts = vb.split()
|
parts = vb.split()
|
||||||
if len(parts) == 4:
|
if len(parts) == 4:
|
||||||
# KiCad SVG viewBox is in mils (1 mil = 0.0254 mm)
|
|
||||||
# or internal units. Detect scale from original viewBox.
|
|
||||||
orig_vb_x = float(parts[0])
|
orig_vb_x = float(parts[0])
|
||||||
orig_vb_y = float(parts[1])
|
orig_vb_y = float(parts[1])
|
||||||
orig_vb_w = float(parts[2])
|
|
||||||
orig_vb_h = float(parts[3])
|
|
||||||
|
|
||||||
# KiCad schematic SVGs use mils (1/1000 inch) as user units
|
new_x = orig_vb_x + x1
|
||||||
# 1 mm = 39.3701 mils
|
new_y = orig_vb_y + y1
|
||||||
mils_per_mm = 39.3701
|
new_w = x2 - x1
|
||||||
|
new_h = y2 - y1
|
||||||
new_x = orig_vb_x + x1 * mils_per_mm
|
|
||||||
new_y = orig_vb_y + y1 * mils_per_mm
|
|
||||||
new_w = (x2 - x1) * mils_per_mm
|
|
||||||
new_h = (y2 - y1) * mils_per_mm
|
|
||||||
|
|
||||||
root.set("viewBox", f"{new_x} {new_y} {new_w} {new_h}")
|
root.set("viewBox", f"{new_x} {new_y} {new_w} {new_h}")
|
||||||
root.set("width", str(width))
|
root.set("width", str(width))
|
||||||
root.set("height", str(height))
|
root.set("height", str(height))
|
||||||
|
|
||||||
# Write modified SVG
|
# Write modified SVG
|
||||||
cropped_svg_path = svg_output + ".cropped.svg"
|
cropped_svg_path = os.path.join(tmp_dir, "cropped.svg")
|
||||||
tree.write(cropped_svg_path, xml_declaration=True, encoding="utf-8")
|
tree.write(cropped_svg_path, xml_declaration=True, encoding="utf-8")
|
||||||
|
|
||||||
if out_format == "svg":
|
if out_format == "svg":
|
||||||
@@ -2652,9 +2649,8 @@ class KiCADInterface:
|
|||||||
"format": "png",
|
"format": "png",
|
||||||
}
|
}
|
||||||
finally:
|
finally:
|
||||||
for f in [svg_output, svg_output + ".cropped.svg"]:
|
import shutil
|
||||||
if os.path.exists(f):
|
shutil.rmtree(tmp_dir, ignore_errors=True)
|
||||||
os.unlink(f)
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in get_schematic_view_region: {e}")
|
logger.error(f"Error in get_schematic_view_region: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user