kopia lustrzana https://github.com/fellesverkstedet/fabmodules
186 wiersze
5.9 KiB
Python
Executable File
186 wiersze
5.9 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
import os
|
|
import sys
|
|
import platform
|
|
import glob
|
|
import subprocess
|
|
import hashlib
|
|
|
|
def find_eagle():
|
|
if platform.uname()[0] == 'Darwin':
|
|
try:
|
|
eagle_dir = glob.glob('/Applications/EAGLE*')[-1]
|
|
except IndexError:
|
|
sys.stderr.write("Error: EAGLE not found.\n")
|
|
sys.exit(1)
|
|
|
|
return eagle_dir + '/EAGLE.app/Contents/MacOS/EAGLE'
|
|
else:
|
|
if subprocess.call(['which','eagle'],
|
|
stdout = open(os.devnull, 'w')):
|
|
sys.stderr.write("Error: EAGLE not found.\n")
|
|
sys.exit(1)
|
|
return 'eagle'
|
|
|
|
def create_images(name, resolution = 1500):
|
|
for img in ['top','bottom','cutout','holes','vias']:
|
|
file = '%s.%s.png' % (name, img)
|
|
if os.path.isfile(file):
|
|
os.remove(file)
|
|
|
|
script = '''
|
|
ratsnest; write;
|
|
set palette black; window;
|
|
display none top vias pads;
|
|
export image '{name}.top.png' monochrome {resolution};
|
|
display none bottom vias pads;
|
|
export image '{name}.bottom.png' monochrome {resolution};
|
|
display none milling;
|
|
export image '{name}.cutout.png' monochrome {resolution};
|
|
display none holes;
|
|
export image '{name}.holes.png' monochrome {resolution};
|
|
display none vias pads;
|
|
export image '{name}.vias.png' monochrome {resolution};
|
|
quit'''.format(name = name, resolution = resolution)
|
|
subprocess.call([find_eagle(), '-C', script, name + '.brd'])
|
|
|
|
def md5(filename):
|
|
with open(filename,'rb') as f:
|
|
m = hashlib.md5()
|
|
for chunk in iter(lambda: f.read(m.block_size*128), ''):
|
|
m.update(chunk)
|
|
return m.digest()
|
|
|
|
def clean_up(name):
|
|
preserve = ['top','bottom','cutout']
|
|
for img in ['top','bottom','cutout','holes','vias']:
|
|
file = '%s.%s.png' % (name, img)
|
|
file_ = '%s.%s_.png' % (name, img)
|
|
if os.path.isfile(file) and img not in preserve:
|
|
os.remove(file)
|
|
if os.path.isfile(file_):
|
|
os.remove(file_)
|
|
|
|
def print_help():
|
|
print """command line: eagle_png [options] target.brd
|
|
target.brd = EAGLE brd file to render
|
|
The board outline should be a solid polygon on the 'milling' layer
|
|
Internal cutouts should be solid shapes on the 'holes' layer
|
|
|
|
Valid options:
|
|
--resolution NUM : sets output image resolution
|
|
--doublesided : forces double-sided mode"""
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) == 1:
|
|
print_help()
|
|
sys.exit(1)
|
|
|
|
# Parse arguments
|
|
sys.argv = sys.argv[1:]
|
|
resolution = 1500
|
|
force_doublesided = False
|
|
|
|
while sys.argv:
|
|
if sys.argv[0] == '--resolution':
|
|
try:
|
|
resolution = sys.argv[1]
|
|
sys.argv = sys.argv[2:]
|
|
except IndexError:
|
|
sys.stderr.write("Error: No resolution provided.\n")
|
|
sys.exit(1)
|
|
try:
|
|
resolution = int(resolution)
|
|
except ValueError:
|
|
sys.stderr.write("Error: Invalid resolution.\n")
|
|
sys.exit(1)
|
|
|
|
elif sys.argv[0] == '--doublesided':
|
|
force_doublesided = True
|
|
sys.argv = sys.argv[1:]
|
|
|
|
elif len(sys.argv) == 1:
|
|
break
|
|
else:
|
|
sys.stderr.write("Error: No filename provided.\n")
|
|
sys.exit(1)
|
|
|
|
name = sys.argv[0].replace('.brd','')
|
|
if not os.path.isfile(name+'.brd'):
|
|
sys.stderr.write("Error: .brd file does not exist.\n")
|
|
sys.exit(1)
|
|
|
|
vias = name + '.vias.png'
|
|
cutout = name + '.cutout.png'
|
|
top = name + '.top.png'
|
|
bottom = name + '.bottom.png'
|
|
holes = name + '.holes.png'
|
|
|
|
print "Rendering images."
|
|
create_images(name, resolution)
|
|
|
|
# Check to make sure that imagemagick is installed.
|
|
if subprocess.call(['which','convert'], stdout = open(os.devnull, 'w')):
|
|
sys.stderr.write("""Error: 'convert' not found.
|
|
ImageMagick command-line tools must be installed to use eagle_png.""")
|
|
sys.exit(1)
|
|
|
|
print "Processing images."
|
|
|
|
# The following command is a set of ImageMagick instructions that
|
|
# combine all of the images.
|
|
|
|
# The following steps take place:
|
|
# - Perform a white flood fill on the vias image, starting in the upper
|
|
# left corner. This makes the via image a set of black holes on
|
|
# a uniform white background
|
|
# - Multiply the vias and cutout images, to cut the via holes from
|
|
# the cutout region.
|
|
# - Invert the cutout image.
|
|
# - Lighten the top and bottom traces with the inverted cutout. This
|
|
# ensures that we don't waste time milling traces in regions that
|
|
# will be cut out of the PCB.
|
|
# - Subtract the holes image from the original cutout image
|
|
# - Save this combined cutout image
|
|
|
|
command = [ 'convert',
|
|
vias, '-fill', 'white', '-draw', 'color 0,0 floodfill',
|
|
cutout, '-compose', 'Darken', '-composite',
|
|
'-compose','Lighten',
|
|
'(',
|
|
'+clone',
|
|
'-negate'
|
|
]
|
|
|
|
# If this is a two-sided board, then process the bottom layer
|
|
if md5(bottom) != md5(vias) or force_doublesided:
|
|
command += [
|
|
'(',
|
|
'+clone', bottom, '-composite',
|
|
'-flop', '-write', bottom, '+delete',
|
|
')'
|
|
]
|
|
else:
|
|
os.remove(bottom)
|
|
|
|
# Process the top layer
|
|
command += [
|
|
top, '-composite', '-write', top,
|
|
'+delete',
|
|
')',
|
|
holes, '-compose', 'Minus_Src', '-composite', cutout
|
|
]
|
|
|
|
# Execute this whole mess
|
|
subprocess.call(command)
|
|
|
|
os.remove(vias)
|
|
os.remove(holes)
|
|
|
|
if bottom in command:
|
|
print "Generated %s, %s, %s." % (top, bottom, cutout)
|
|
else:
|
|
print "Generated %s, %s." % (top, cutout)
|