kopia lustrzana https://github.com/jaseg/gerbolyze
116 wiersze
3.9 KiB
Python
116 wiersze
3.9 KiB
Python
#/usr/bin/env python3
|
|
|
|
import re
|
|
import tempfile
|
|
import os
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
from bs4 import BeautifulSoup
|
|
import click
|
|
|
|
default_widths = '3mm,5mm,8mm,10mm,12mm,15mm,18mm,20mm,25mm,30mm,35mm,40mm,45mm,50mm,60mm,70mm,80mm,90mm,100mm,120mm,150mm'
|
|
|
|
|
|
# Mostly from https://www.w3.org/TR/css-values/#absolute-lengths
|
|
UNIT_FACTORS = {
|
|
'm': 1000,
|
|
'cm': 10,
|
|
'mm': 1,
|
|
'Q': 1/4,
|
|
'in': 25.4,
|
|
'mil': 25.4/1000,
|
|
'pc': 25.4/6,
|
|
'pt': 25.4/72,
|
|
'px': 25.4/96,
|
|
}
|
|
|
|
def parse_length(foo, default_unit=None):
|
|
''' Parse given physical length, and return result converted to mm. '''
|
|
|
|
match = re.fullmatch(r'(.*?)(m|cm|mm|Q|in|mil|pc|pt|px|)', foo.strip().lower())
|
|
if not match:
|
|
raise ValueError(f'Invalid length "{foo}"')
|
|
num, unit = match.groups()
|
|
|
|
if not unit:
|
|
if default_unit:
|
|
unit = default_unit
|
|
else:
|
|
raise ValueError(f'Unit missing from length "{foo}"')
|
|
|
|
return float(num) * UNIT_FACTORS[unit]
|
|
|
|
|
|
@click.command()
|
|
@click.option('--width')
|
|
@click.option('--height')
|
|
@click.option('--sexp-layer', default='F.SilkS')
|
|
@click.option('--basename', help='Base name for generated symbols and library')
|
|
@click.argument('input_svg')
|
|
def export(width, height, basename, sexp_layer, input_svg):
|
|
svg_flatten = str(Path(os.environ.get('SVG_FLATTEN', 'svg-flatten')).expanduser())
|
|
usvg = str(Path(os.environ.get('USVG', 'usvg')).expanduser())
|
|
|
|
if not basename:
|
|
match = re.fullmatch(r'(.*?)(([-_.][0-9.,]+)(m|cm|mm|Q|in|mil|pc|pt|px|))?', Path(input_svg).stem)
|
|
basename, *rest = match.groups()
|
|
print(f'No --basename given. Using "{basename}"')
|
|
|
|
export_width, export_height = width, height
|
|
if not export_width or export_height:
|
|
export_width = default_widths
|
|
|
|
elif export_width and export_height:
|
|
raise click.ClickException('Only one of --width or --height must be given.')
|
|
|
|
if export_width:
|
|
targets = export_width
|
|
axis = 'width'
|
|
else:
|
|
targets = export_height
|
|
axis = 'height'
|
|
|
|
# Determine input document size
|
|
with tempfile.NamedTemporaryFile() as f:
|
|
try:
|
|
subprocess.run([usvg, input_svg, f.name], check=True)
|
|
except FileNotFoundError:
|
|
raise click.ClickException('Cannot find usvg binary in PATH. You can give a custom path to the usvg binary by setting the USVG environment variable.')
|
|
|
|
soup = BeautifulSoup(f.read(), features='xml')
|
|
svg = soup.find('svg')
|
|
doc_w_mm, doc_h_mm = parse_length(svg['width'], default_unit='px'), parse_length(svg['height'], default_unit='px')
|
|
|
|
print(f'Input file has dimensions width {doc_w_mm:.1f} mm by height {doc_h_mm:.1f} mm')
|
|
|
|
outdir = Path(f'{basename}.pretty')
|
|
outdir.mkdir(exist_ok=True)
|
|
|
|
for target_length in targets.split(','):
|
|
target_length = parse_length(target_length, default_unit='mm')
|
|
|
|
if axis == 'width':
|
|
scaling_factor = target_length / doc_w_mm
|
|
else:
|
|
scaling_factor = target_length / doc_h_mm
|
|
|
|
instance_name = f'{basename}_{target_length:.1f}mm'
|
|
outfile = outdir / f'{instance_name}.kicad_mod'
|
|
print(f'{outfile}: Scaling to target {axis} {target_length:.1f} mm using scaling factor {scaling_factor:.3f}')
|
|
|
|
try:
|
|
proc = subprocess.run([svg_flatten,
|
|
'-o', 'sexp',
|
|
'--sexp-layer', sexp_layer,
|
|
'--sexp-mod-name', instance_name,
|
|
'--scale', str(scaling_factor),
|
|
input_svg], check=True, capture_output=True)
|
|
outfile.write_bytes(proc.stdout)
|
|
except FileNotFoundError:
|
|
raise click.ClickException('Cannot find svg-flatten binary in PATH. You can give a custom path to the svg-flatten binary by setting the SVG_FLATTEN environment variable.')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
export()
|