Skip to content
Snippets Groups Projects
Select Git revision
  • 97ddc4437b60a18a6913947da67b2a672ae05b46
  • master default protected
  • leo
  • dex
  • pendulum
  • apfelstruder
  • littlerascal
7 results

math.js

Blame
  • eagle_png.py 5.80 KiB
    #!/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)