app
Adom Fields
Public Made by Adomby adom
Adom Fields: where the current and the heat go on your board.
main
John Lauer
adom-fields 0.7.2: the energy cycle of a switching converter, the board's silkscreen over every view, part values, subt…
7d9e35b
//! The silkscreen, so the human can read what is printed on the board (J1, VIN, the logo) over the fields:
//! KiCad exports each silk layer as an SVG of the board area, exactly as it prints it; the app draws it on
//! one textured plane per side. A board KiCad cannot export (a Fusion .brd, no kicad-cli) simply has none.
use serde_json::{json, Value};
use std::path::Path;
fn export(board: &Path, out: &Path, layer: &str, name: &str) -> Result<(f64, f64), String> {
let file = out.join(name);
let o = std::process::Command::new("kicad-cli").args(["pcb", "export", "svg", "--layers", &format!("{layer},Edge.Cuts"), "--mode-single", "--page-size-mode", "2", "--exclude-drawing-sheet", "--black-and-white", "-o", &file.display().to_string(), &board.display().to_string()]).output().map_err(|e| format!("kicad-cli: {e}"))?;
if !o.status.success() || !file.exists() { return Err(format!("kicad-cli could not export {layer}: {}", String::from_utf8_lossy(&o.stderr).lines().last().unwrap_or(""))); }
let svg = std::fs::read_to_string(&file).map_err(|e| e.to_string())?;
// the SVG frame is the board area in mm: viewBox="0 0 w h"
let vb = svg.split("viewBox=\"").nth(1).and_then(|r| r.split('"').next()).ok_or("no viewBox in the silkscreen SVG")?;
let n: Vec<f64> = vb.split_whitespace().filter_map(|x| x.parse().ok()).collect();
if n.len() != 4 { return Err("unreadable viewBox".into()); }
Ok((n[2], n[3]))
}
/// Export both silk layers into `out`; returns the fields.json `silk` block (null when there is none).
pub fn build(board: &str, out: &Path, log: &mut dyn FnMut(&str)) -> Value {
if !board.to_lowercase().ends_with(".kicad_pcb") { log("silkscreen: only KiCad boards export it so far"); return Value::Null; }
let b = std::fs::canonicalize(board).unwrap_or_else(|_| Path::new(board).to_path_buf());
let mut res = json!({});
for (layer, name, key) in [("F.SilkS", "silk-front.svg", "front"), ("B.SilkS", "silk-back.svg", "back")] {
match export(&b, out, layer, name) { Ok((w, h)) => { res[key] = json!({"file": name, "widthMm": w, "heightMm": h}); } Err(e) => { log(&format!("silkscreen: {e}")); } }
}
if res.as_object().map_or(true, |o| o.is_empty()) { Value::Null } else { log("silkscreen: front and back exported"); res }
}