skill
Adom SF Convert
Public Made by Adomby adom
Native Rust converter: EAGLE/Fusion .lbr + Altium .SchLib/.PcbLib → KiCad, rendering each format's own geometry.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
//! Altium `.SchLib` / `.PcbLib` / `.IntLib` → KiCad, **fully native**.
//!
//! These are OLE2 compound-binary files. We read them with the pure-Rust
//! `altium-schlib` (symbols) and `altium-pcblib` (footprints) crates — no KiCad
//! install, no service round-trip. Each format renders its OWN geometry from its
//! OWN bytes (the native-fidelity rule), and we emit `.kicad_sym` / `.kicad_mod`
//! only as an EXPORT convenience.
use anyhow::{anyhow, Result};
use std::path::Path;
/// What a conversion produced, so callers can wire thumbnails + exports.
pub struct AltiumOut {
pub files: Vec<String>,
}
/// Convert an Altium library. `ext` routes which half we read: `.SchLib` →
/// symbol, `.PcbLib` → footprint, `.IntLib` (or a bare OLE) → try both. Writes
/// `<stem>.kicad_sym` / `<stem>.kicad_mod` (export) and, when `svg` is true, the
/// native `<stem>-symbol.svg` / `<stem>-footprint.svg` thumbnails.
pub fn convert(file: &Path, out_dir: &Path, stem: &str, ext: &str, svg: bool) -> Result<AltiumOut> {
std::fs::create_dir_all(out_dir).ok();
let want_sym = matches!(ext, "schlib" | "intlib") || ext.is_empty();
let want_fp = matches!(ext, "pcblib" | "intlib") || ext.is_empty();
let mut files = Vec::new();
let mut errs = Vec::new();
if want_sym {
match altium_schlib::parse_altium_schlib_path(file) {
Ok(symbol) => {
let ks = altium_schlib::to_kicad_sym(&symbol, stem);
let p = out_dir.join(format!("{stem}.kicad_sym"));
std::fs::write(&p, ks)?;
files.push(p.display().to_string());
if svg {
let s = altium_schlib::render_symbol_svg(&symbol);
let p = out_dir.join(format!("{stem}-symbol.svg"));
std::fs::write(&p, s)?;
files.push(p.display().to_string());
}
}
Err(e) => errs.push(format!("sym: {e}")),
}
}
if want_fp {
match altium_pcblib::parse_altium_pcblib_path(file) {
Ok(fp) => {
// altium_pcblib hardcodes RefDes/Value at (0, ±3) — re-place it
// clear of the whole footprint, the same rule adom-footprint uses.
let km = crate::eagle::reposition_fp_text(&altium_pcblib::to_kicad_mod(&fp, stem));
let p = out_dir.join(format!("{stem}.kicad_mod"));
std::fs::write(&p, km)?;
files.push(p.display().to_string());
if svg {
let s = altium_pcblib::render_footprint_svg(&fp);
let p = out_dir.join(format!("{stem}-footprint.svg"));
std::fs::write(&p, s)?;
files.push(p.display().to_string());
}
}
Err(e) => errs.push(format!("fp: {e}")),
}
}
if files.is_empty() {
return Err(anyhow!(
"Altium import produced nothing: {}",
if errs.is_empty() { "empty library".into() } else { errs.join("; ") }
));
}
Ok(AltiumOut { files })
}