Exemple #1
0
def gerberToPNG(filename, png, pixel_mm=0.1):
    """
    Convert to png.
    Return pixel size in mm.
    """
    try:
        import gerber
    except Exception as e:
        if 'hull' in str(e).lower():
            raise Exception(
                'Module pyhull not found. Try "pip install pyhull"?')
        raise Exception(
            'The gerber module can be found at https://github.com/curtacircuitos/pcb-tools.'
        )
    try:
        from gerber.render.cairo_backend import GerberCairoContext
    except Exception as e:
        if 'cairo' in str(e).lower():
            raise Exception(
                'Failed to load gerber.render. Do you have the py2cairo package, which provides the cairo module?'
            )
        raise e

    # Read gerber and Excellon files
    data = gerber.read(filename)
    data.to_metric()

    # Rendering context
    ctx = GerberCairoContext(scale=1.0 / pixel_mm)  # Scale is pixels/mm

    # Create SVG image
    data.render(ctx)
    ctx.dump(png)
    return png, np.mean(data.size) / np.mean(ctx.size_in_pixels)
Exemple #2
0
    def __init__(self, device_cfg, output=None):

        self.device_cfg = device_cfg
        self.scale = self.device_cfg['size_px']['w'] / self.device_cfg[
            'size_mm']['w']

        self.exp_test_start = self.EXP_TEST_START
        self.exp_test_interval = self.EXP_TEST_INTERVAL
        self.exp_test_samples = self.EXP_TEST_SAMPLES
        self.exp_test_tmp_dir = None

        self.exposure_time = self.DEFAULT_EXPOSURE_TIME

        self.gbr = None
        self.drl = None
        self.output = output
        if not output:
            self.output = self.DEFAULT_OUTPUT

        self.payload_ctx = GerberCairoContext(scale=self.scale)
        self.white = RenderSettings(color=theme.COLORS['white'])
        self.black = RenderSettings(color=theme.COLORS['black'])
        self.pcb_width = None
        self.pcb_height = None

        self.photon_template = None
        if device_cfg['photon_template'] != 'built-in':
            tpl_path = 'data/{}'.format(device_cfg['photon_template'])
            self.photon_template = resource_filename('pcb_msla', tpl_path)
def main():
    setup()

    GERBER_FOLDER = os.path.abspath(
        os.path.join(os.path.dirname(__file__), INPUT_DIR))

    # Create a new drawing context
    ctx = GerberCairoContext()

    # Create a new PCB instance
    # pcb = PCB.from_directory(GERBER_FOLDER)
    outline = load_layer(INPUT_DIR + 'axiom_beta_mixed_panel.boardoutline.ger')
    outline.layer_class = "outline"
    top_layer = load_layer(INPUT_DIR + 'axiom_beta_mixed_panel.toplayer.ger')
    top_layer.layer_class = "toppaste"
    # top_soldermask_layer = load_layer(INPUT_DIR + 'axiom_beta_mixed_panel.topcream.ger')
    # top_soldermask_layer.layer_class = "toppaste"
    top_silkscreen_layer = load_layer(
        INPUT_DIR + 'axiom_beta_mixed_panel.topsilkscreen.ger')
    top_silkscreen_layer.layer_class = "topsilk"
    drill = load_layer(INPUT_DIR + 'axiom_beta_mixed_panel.drills.xln')

    # Render PCB top view
    ctx.render_layers({outline, top_layer, top_silkscreen_layer},
                      OUTPUT_DIR + 'pcb_top.png',
                      theme.THEMES['OSH Park'],
                      verbose=True,
                      max_width=4000,
                      max_height=3000)
Exemple #4
0
 def _render_line(self, line, color):
     if self.isOutline == False or self._render_count != 1:		# outline layer
         GerberCairoContext._render_line(self, line, color)
         return
     start = self.scale_point(line.start)
     end = self.scale_point(line.end)
     # we don't draw lines, we store the line segments
     with self._clip_primitive(line):
         self.addPoint(start, end, None)
Exemple #5
0
 def _render_arc(self, arc, color):
     if self.isOutline == False or self._render_count != 1:		# outline layer
         GerberCairoContext._render_arc(self, arc, color)
         return
     start = self.scale_point(arc.start)
     end = self.scale_point(arc.end)
     # we don't draw arcs, we store them
     with self._clip_primitive(arc):
 	    self.addPoint(start, end, arc)
Exemple #6
0
    def flatten(self, color=None, alpha=None):
        if self.isOutline == True and self._render_count == 1:		# outline layer
            # reconstruct the contour (the original lines go in no particular order)
            curPoint = self.lineList[0]
            countourPoints = []
            for i in range(1000):
                countourPoints.append([curPoint[0][0], curPoint[0][1], curPoint[2]])
                dist = sys.float_info.max
    		    # find the closest point among the
                for ll in self.lineList:
                    llinv = [ll[1], ll[0], ll[2]]
                    if ll == curPoint or llinv == curPoint:
                        continue
                    d = (ll[0][0] - curPoint[1][0])**2 + (ll[0][1] - curPoint[1][1])**2
                    if d < dist:
                        dist = d
                        nextCurPoint = ll
                    d = (ll[1][0] - curPoint[1][0])**2 + (ll[1][1] - curPoint[1][1])**2
                    if d < dist:
                        dist = d
                        nextCurPoint = llinv
                    if dist < 1.e-4:
                        break
                if nextCurPoint[0] in countourPoints:
                    break
                curPoint = nextCurPoint

            # draw the filled contour    
            with self._new_mask() as mask:
                mask.ctx.move_to(countourPoints[0][0], countourPoints[0][1])
                wasArc = False
                for ll in countourPoints:
                    if ll[2]:
                        arc = ll[2]
                        center = self.scale_point(arc.center)
                        radius = self.scale[0] * arc.radius
                        two_pi = 2 * math.pi
                        angle1 = (arc.start_angle + two_pi) % two_pi
                        angle2 = (arc.end_angle + two_pi) % two_pi
                        if arc.direction == 'counterclockwise':
                            mask.ctx.arc(center[0], center[1], radius, angle1, angle2)
                        else:
                            mask.ctx.arc_negative(center[0], center[1], radius, angle1, angle2)
                    else:
                        mask.ctx.line_to(ll[0], ll[1])
                mask.ctx.set_source_rgba(1.0, 1.0, 1.0, 1.0)
                mask.ctx.fill()
                self.ctx.mask_surface(mask.surface, 0.0, 0.0)
        GerberCairoContext.flatten(self, color, alpha)
Exemple #7
0
def generate_mask(outline, target, scale, bounds, debugimg, status_print,
                  extend_overlay_r_mil, subtract_gerber):
    # Render all gerber layers whose features are to be excluded from the target image, such as board outline, the
    # original silk layer and the solder paste layer to binary images.
    with tempfile.TemporaryDirectory() as tmpdir:
        img_file = path.join(tmpdir, 'target.png')

        status_print('Combining keepout composite')
        fg, bg = gerber.render.RenderSettings(
            (1, 1, 1)), gerber.render.RenderSettings((0, 0, 0))
        ctx = GerberCairoContext(scale=scale)
        status_print('  * outline')
        ctx.render_layer(outline, settings=fg, bgsettings=bg, bounds=bounds)
        status_print('  * target layer')
        ctx.render_layer(target, settings=fg, bgsettings=bg, bounds=bounds)
        for fn, sub in subtract_gerber:
            status_print('  * extra layer', os.path.basename(fn))
            layer = gerber.loads(sub)
            ctx.render_layer(layer, settings=fg, bgsettings=bg, bounds=bounds)
        status_print('Rendering keepout composite')
        ctx.dump(img_file)

        # Vertically flip exported image
        original_img = cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)[::-1, :]

    f = 1 if outline.units == 'inch' else 25.4
    r = 1 + 2 * max(1, int(extend_overlay_r_mil / 1000 * f * scale))
    status_print('Expanding keepout composite by', r)

    # Extend image by a few pixels and flood-fill from (0, 0) to mask out the area outside the outermost outline
    # This ensures no polygons are generated outside the board even for non-rectangular boards.
    border = 10
    outh, outw = original_img.shape
    extended_img = np.zeros((outh + 2 * border, outw + 2 * border),
                            dtype=np.uint8)
    extended_img[border:outh + border, border:outw + border] = original_img
    debugimg(extended_img, 'outline')
    cv2.floodFill(extended_img, None, (0, 0), (255, ))
    original_img = extended_img[border:outh + border, border:outw + border]
    debugimg(extended_img, 'flooded')

    # Dilate the white areas of the image using gaussian blur and threshold. Use these instead of primitive dilation
    # here for their non-directionality.
    target_img = cv2.blur(original_img, (r, r))
    _, target_img = cv2.threshold(target_img, 255 // (1 + r), 255,
                                  cv2.THRESH_BINARY)
    return target_img
def generate_previews(fab_output_path, preview_output_path):
    def read(pattern):
        files = glob(os.path.join(fab_output_path, pattern))
        if not files:
            print("WARNING: Nothing found matching %s" % pattern)
            return None
        return gerber.load_layer(files[0])

    def save(name):
        path = os.path.join(preview_output_path, "%s.png" % name)
        print("Saving preview to %s" % path)
        ctx.dump(path)

    def render(pattern, **kw):
        layer = read(pattern)
        if layer is None:
            print("Not rendering %s" % pattern)
            return
        ctx.render_layer(layer, verbose=True, **kw)

    # Rendering context
    ctx = GerberCairoContext(scale=10)
    ctx.color = (80. / 255, 80 / 255., 154 / 255.)
    ctx.drill_color = ctx.color

    # Edges
    render("*.gm1")
    # Copper
    render("*.gtl")
    # Mask
    render("*.gts")
    # Silk
    render("*.gto",
           settings=RenderSettings(color=theme.COLORS['white'], alpha=0.85))
    # Drills
    render("*.drl")

    save("pcb-front")
    ctx.clear()

    # Edges
    render("*.gm1")
    # Copper
    render("*.gbl")
    # Mask
    render("*.gbs")
    # Silk
    render(
        "*.gbo",
        settings=RenderSettings(
            color=theme.COLORS['white'],
            alpha=0.85,
            mirror=
            True,  # for some reason this, but not the other bottom layer files, needs to be flipped horizontally
        ))
    # Drills
    render("*.drl")

    save("pcb-back")
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()

        self.ctx = GerberCairoContext(8)
        self.ctx.units = 'metric'

        self.layers = {}
        self.components = []
        # self.components = self.load_pickplace()
        self.layer = "TopLayer"

        # self.geometry("{}x{}".format(self._image_ref.width(), self._image_ref.height()))

        self.clist = ComponentListGui(self)
        # self.clist.add_components(self.components, self.layer)
        self.clist.pack(expand=True, side="right")

        self.label = tk.Label(self)
        self.label.pack(expand=True, side="left")
        # self.draw_component()

        self.bind('<ButtonRelease-1>', self.draw_component)
Exemple #10
0
def render_gerbers_to_image(*gerbers, scale, bounds=None):
    with tempfile.TemporaryDirectory() as tmpdir:
        img_file = path.join(tmpdir, 'target.png')
        fg, bg = gerber.render.RenderSettings(
            (1, 1, 1)), gerber.render.RenderSettings((0, 0, 0))
        ctx = GerberCairoContext(scale=scale)

        for grb in gerbers:
            ctx.render_layer(grb, settings=fg, bgsettings=bg, bounds=bounds)

        ctx.dump(img_file)
        # Vertically flip exported image to align coordinate systems
        return cv2.imread(img_file, cv2.IMREAD_GRAYSCALE)[::-1, :]
Exemple #11
0
def combine_copper_only(gtl_file, gbl_file, out_copper_only_top,
                        out_copper_only_bottom):
    copper = load_layer(gtl_file)
    ctx = GerberCairoContext()
    ctx.render_layer(copper)
    ctx.dump(os.path.join(os.path.dirname(__file__), out_copper_only_top))
    ctx = GerberCairoContext()
    copper_bottom = load_layer(gbl_file)
    ctx.render_layer(copper_bottom, bounds=copper.bounds)
    ctx.dump(os.path.join(os.path.dirname(__file__), out_copper_only_bottom))
Exemple #12
0
class Converter(object):

    DEFAULT_OUTPUT = 'pcb.cbddlp'
    DEFAULT_EXPOSURE_TIME = 60 * 8
    PNG_OUTPUT = 'pcb.png'

    EXP_TEST_START = 6 * 60
    EXP_TEST_INTERVAL = 60
    EXP_TEST_SAMPLES = 4
    EXP_TEST_PATTERN = 'data/pattern.gbr'

    def __init__(self, device_cfg, output=None):

        self.device_cfg = device_cfg
        self.scale = self.device_cfg['size_px']['w'] / self.device_cfg[
            'size_mm']['w']

        self.exp_test_start = self.EXP_TEST_START
        self.exp_test_interval = self.EXP_TEST_INTERVAL
        self.exp_test_samples = self.EXP_TEST_SAMPLES
        self.exp_test_tmp_dir = None

        self.exposure_time = self.DEFAULT_EXPOSURE_TIME

        self.gbr = None
        self.drl = None
        self.output = output
        if not output:
            self.output = self.DEFAULT_OUTPUT

        self.payload_ctx = GerberCairoContext(scale=self.scale)
        self.white = RenderSettings(color=theme.COLORS['white'])
        self.black = RenderSettings(color=theme.COLORS['black'])
        self.pcb_width = None
        self.pcb_height = None

        self.photon_template = None
        if device_cfg['photon_template'] != 'built-in':
            tpl_path = 'data/{}'.format(device_cfg['photon_template'])
            self.photon_template = resource_filename('pcb_msla', tpl_path)

    @property
    def pcb_width_mm(self):
        return self._px_to_mm(self.pcb_width)

    @property
    def pcb_height_mm(self):
        return self._px_to_mm(self.pcb_height)

    def _px_to_mm(self, px):
        return round(px / self.scale, 2)

    def load_test_input(self, gbr):
        if gbr == None:
            gbr = resource_filename('pcb_msla', self.EXP_TEST_PATTERN)
        self.load_input(gbr)

    def load_input(self, gbr, drl=None):
        if not drl:
            drl = "{}.drl".format(os.path.splitext(gbr)[0])
        self.traces_layer = load_layer(gbr)
        self.drills_layer = load_layer(drl)

    def _output_png_path(self):
        return self.PNG_OUTPUT

    def _exp_test_png_path(self, step):
        return "{}/{:05d}_{:02d}.png".format(self.exp_test_tmp_dir, step, 0)

    def _render_payload_surface(self):
        self.payload_ctx.render_layer(self.traces_layer,
                                      settings=self.black,
                                      bgsettings=self.white)
        self.payload_ctx.render_layer(self.drills_layer, settings=self.white)

    def _prepare_output_surface(self):
        self.ims = cairo.ImageSurface(cairo.FORMAT_ARGB32,
                                      self.device_cfg['size_px']['w'],
                                      self.device_cfg['size_px']['h'])
        self.ic = cairo.Context(self.ims)
        self.ic.set_antialias(cairo.ANTIALIAS_NONE)
        self.ic.paint()

    def _render_output_surface(self):
        self._prepare_output_surface()
        self.ic.set_source_surface(self.payload_ctx.surface, 0, 0)
        self.ic.paint()
        self.ims.write_to_png(self._output_png_path())

    def _render_output_photon(self):
        p = Photon(self.photon_template)
        p.bottom_layers = 1
        p.exposure_time_bottom = self.exposure_time
        p.delete_layers()
        p.append_layer(self._output_png_path())
        p.write(self.output)

    def render(self):
        self._render_payload_surface()
        self._render_output_surface()
        self._render_output_photon()
        self.pcb_width = self.payload_ctx.size_in_pixels[0]
        self.pcb_height = self.payload_ctx.size_in_pixels[1]

    def render_blank(self):
        self._prepare_output_surface()
        self.ic.set_source_rgb(1.0, 1.0, 1.0)
        self.ic.rectangle(0, 0, self.pcb_width, self.pcb_height)
        self.ic.fill()
        self.ims.write_to_png(self._output_png_path())
        output_split = os.path.splitext(self.output)
        self.output = "{}_blank{}".format(output_split[0], output_split[1])
        self._render_output_photon()

    def _render_exp_test_surface(self):
        self._prepare_output_surface()
        step_reversed = self.exp_test_samples
        for i in range(self.exp_test_samples):
            offset_y = self.payload_ctx.size_in_pixels[1] * i
            self.ic.set_source_surface(self.payload_ctx.surface, 0, offset_y)
            self.ic.paint()
            step_png = self._exp_test_png_path(step_reversed)
            self.ims.write_to_png(step_png)
            step_reversed = step_reversed - 1

    def exp_test(self):
        self._render_payload_surface()
        with tempfile.TemporaryDirectory() as tmp_dir:
            self.exp_test_tmp_dir = tmp_dir
            self._render_exp_test_surface()
            p = Photon(self.photon_template)
            p.bottom_layers = 1
            p.exposure_time_bottom = self.exp_test_start
            p.exposure_time = self.exp_test_interval
            p.delete_layers()
            p.append_layers(self.exp_test_tmp_dir)

            p.write(self.output)
        self.pcb_width = self.payload_ctx.size_in_pixels[0]
        self.pcb_height = self.payload_ctx.size_in_pixels[
            1] * self.exp_test_samples
        self.exposure_time = self.exp_test_start + (self.exp_test_samples *
                                                    self.exp_test_interval)
Exemple #13
0
import os
from gerber import *

from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext

GERBER_FOLDER = os.path.abspath(
    os.path.join(os.path.dirname(__file__), 'not-working'))

# Create a new drawing context
ctx = GerberCairoContext()

# Create a new PCB instance
pcb = PCB.from_directory(GERBER_FOLDER)

# Render PCB bottom view
ctx.render_layers(pcb.bottom_layers,
                  os.path.join(os.path.dirname(__file__),
                               'not-working-bottom.png'),
                  max_width=800,
                  max_height=600)
ctx.render_layers(pcb.top_layers,
                  os.path.join(os.path.dirname(__file__),
                               'not-working-top.png'),
                  max_width=800,
                  max_height=600)
Exemple #14
0
def final(copper, mask, drill, colour, name, silk=None):
    new_settings = RenderSettings(color=colour, alpha=0.8)
    new = GerberCairoContext()

    new.render_layer(copper, settings=new_settings)
    new.render_layer(mask, settings=new_settings)
    if (silk != None):
        new.render_layer(silk)
    new.render_layer(drill)
    new.dump(os.path.join(BASE_DIR, name))
Exemple #15
0
bcolor = (6.0 / 300.0, 13.0 / 300.0, 106 / 300.0)

metal_settings = RenderSettings(color=mcolor)
bg_settings = RenderSettings(color=bcolor)
silk_settings = RenderSettings(color=theme.COLORS['white'], alpha=0.80)
hmap_settings = RenderSettings(color=(1.0, 1.0, 1.0))
hmapbg_settings = RenderSettings(color=(0, 0, 0))
mask_settings = RenderSettings(color=(0, 0, 0))
maskbg_settings = RenderSettings(color=(1.0, 1.0, 1.0))

blur_radius = 4

#-------------------------------------------------------------
# generate top base image
#-------------------------------------------------------------
ctx = GerberCairoContext(scale=80)
print('### Top Base Image ###')
print('loading... ', end='', flush=True)
copper = load_layer(prefix + '.GTL')
silk = load_layer(prefix + '.GTO')
print(' end', flush=True)

print('drawing... ', end='', flush=True)
ctx.render_layer(copper, settings=metal_settings, bgsettings=bg_settings)
ctx.render_layer(silk, settings=silk_settings)
print(' end', flush=True)

print('dumping... ', end='', flush=True)
ctx.dump('outputs/pcb-top-base.png')
print(' end', flush=True)
import os
from gerber import load_layer
from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext

GERBER_FOLDER = os.path.abspath(os.path.join(os.path.dirname(__file__), 'gerbers'))


# Open the gerber files
copper = load_layer(os.path.join(GERBER_FOLDER, 'copper.GTL'))
mask = load_layer(os.path.join(GERBER_FOLDER, 'soldermask.GTS'))
silk = load_layer(os.path.join(GERBER_FOLDER, 'silkscreen.GTO'))
drill = load_layer(os.path.join(GERBER_FOLDER, 'ncdrill.DRD'))

# Create a new drawing context
ctx = GerberCairoContext()

# Draw the copper layer. render_layer() uses the default color scheme for the
# layer, based on the layer type. Copper layers are rendered as
ctx.render_layer(copper)

# Draw the soldermask layer
ctx.render_layer(mask)


# The default style can be overridden by passing a RenderSettings instance to
# render_layer().
# First, create a settings object:
our_settings = RenderSettings(color=theme.COLORS['white'], alpha=0.85)

# Draw the silkscreen layer, and specify the rendering settings to use
Exemple #17
0
    def render_top_view(self, output_filename=None, quick=False, nox=False):
        output_filename = '{0}.top.png'.format(output_filename)
        ctx = GerberCairoContext()

        if self.outline_color is not None:
            ctx.color = self.outline_color
        if self.outline_alpha is not None:
            ctx.alpha = self.outline_alpha
        outline = read(self.layers.outline)
        outline.render(ctx)

        if self.copper_color is not None:
            ctx.color = self.copper_color
        if self.copper_alpha is not None:
            ctx.alpha = self.copper_alpha
        copper = read(self.layers.top)
        copper.render(ctx)

        if self.mask_color is not None:
            ctx.color = self.mask_color
        if self.mask_alpha is not None:
            ctx.alpha = self.mask_alpha
        mask = read(self.layers.topmask)
        mask.render(ctx, invert=True)

        if self.silk_color is not None:
            ctx.color = self.silk_color
        if self.silk_alpha is not None:
            ctx.alpha = self.silk_alpha
        silk = read(self.layers.topsilk)
        silk.render(ctx)

        if self.drill_color is not None:
            ctx.color = self.drill_color
        if self.drill_alpha is not None:
            ctx.alpha = self.drill_alpha
        drill = read(self.layers.drill)
        drill.render(ctx)

        ctx.dump(output_filename)
"""
This example demonstrates the use of pcb-tools with cairo to render composite
images using the PCB interface
"""

import os
from gerber import PCB
from gerber.render import theme
from gerber.render.cairo_backend import GerberCairoContext


GERBER_FOLDER = os.path.abspath(os.path.join(os.path.dirname(__file__), 'gerbers'))


# Create a new drawing context
ctx = GerberCairoContext()

# Create a new PCB instance
pcb = PCB.from_directory(GERBER_FOLDER)

# Render PCB top view
ctx.render_layers(pcb.top_layers,
                  os.path.join(os.path.dirname(__file__), 'pcb_top.png',),
                  theme.THEMES['OSH Park'], max_width=800, max_height=600)

# Render PCB bottom view
ctx.render_layers(pcb.bottom_layers,
                  os.path.join(os.path.dirname(__file__), 'pcb_bottom.png'),
                  theme.THEMES['OSH Park'], max_width=800, max_height=600)

# Render copper layers only
Exemple #19
0
def render(BASE_FOLDER):
    ppi = 1000
    # font_size_in = 0.02
    # font_color = 'rgb(255, 0, 0)'
    # textbox_color = "skyblue"
    Image.MAX_IMAGE_PIXELS = 1000000000

    if os.path.exists(os.path.join(BASE_FOLDER, 'board_top.png')):
        os.remove(os.path.join(BASE_FOLDER, 'board_top.png'))
    if os.path.exists(os.path.join(BASE_FOLDER, 'board_bottom.png')):
        os.remove(os.path.join(BASE_FOLDER, 'board_bottom.png'))

    print('Processing ', BASE_FOLDER)

    # Open the gerber files
    copper = load_layer(os.path.join(BASE_FOLDER,
                                     'GerberFiles\copper_top.gbr'))
    mask = load_layer(
        os.path.join(BASE_FOLDER, 'GerberFiles\soldermask_top.gbr'))
    silk = load_layer(
        os.path.join(BASE_FOLDER, 'GerberFiles\silkscreen_top.gbr'))
    outline = load_layer(os.path.join(BASE_FOLDER, 'GerberFiles\profile.gbr'))
    drill = load_layer(os.path.join(BASE_FOLDER, 'DrillFiles\drill_1_16.xln'))

    # Create a new drawing context
    ctx = GerberCairoContext(scale=ppi)

    # Draw the outline first, so it establishes the outer dimensions
    ctx.render_layer(outline,
                     settings=RenderSettings(color=theme.COLORS['black'],
                                             alpha=0.85))

    # Draw the copper layer. render_layer() uses the default color scheme for the
    # layer, based on the layer type. Copper layers are rendered as
    ctx.render_layer(copper,
                     settings=RenderSettings(color=theme.COLORS['hasl copper'],
                                             alpha=0.85))

    # Draw the soldermask layer
    ctx.render_layer(mask,
                     settings=RenderSettings(
                         color=theme.COLORS['green soldermask'],
                         invert=True,
                         alpha=0.8))

    # Draw the silkscreen layer, and specify the rendering settings to use
    ctx.render_layer(silk,
                     settings=RenderSettings(color=theme.COLORS['white'],
                                             alpha=0.85))

    # Draw the drill layer
    ctx.render_layer(drill)

    # Draw the outline again so it's on top of everything
    ctx.render_layer(outline,
                     settings=RenderSettings(color=theme.COLORS['black'],
                                             alpha=0.85))

    size_px = ctx.size_in_pixels
    origin_px = ctx.origin_in_pixels
    origin_in = ctx.origin_in_inch
    print(f"size: {ctx.size_in_inch} in / {ctx.size_in_pixels} px ({ppi} PPI)")
    print(f"origin: {ctx.origin_in_inch} in / {ctx.origin_in_pixels} px")
    config = configparser.ConfigParser()
    config['DIMENSIONS'] = {
        'SIZE_X_IN': ctx.size_in_inch[0],
        'SIZE_Y_IN': ctx.size_in_inch[1],
        'SIZE_X_PX': ctx.size_in_pixels[0],
        'SIZE_Y_PX': ctx.size_in_pixels[1],
        'PPI': ppi,
        'ORIGIN_X_IN': ctx.origin_in_inch[0],
        'ORIGIN_Y_IN': ctx.origin_in_inch[1]
    }

    mtime = 0
    for filename in os.listdir(os.path.join(BASE_FOLDER, 'GerberFiles')):
        mtime = max(
            mtime,
            os.path.getmtime(os.path.join(BASE_FOLDER, 'GerberFiles',
                                          filename)))
    print('Latest file modification time: ', mtime)
    config['OTHER'] = {'GERBERS_LASTMODIFIED': mtime}
    with open(os.path.join(BASE_FOLDER, 'board.ini'), 'w') as configfile:
        config.write(configfile)

    # Write output to png file
    ctx.dump(os.path.join(BASE_FOLDER, 'board_top.png'), verbose=True)

    # Load the bottom layers
    copper = load_layer(
        os.path.join(BASE_FOLDER, 'GerberFiles\copper_bottom.gbr'))
    mask = load_layer(
        os.path.join(BASE_FOLDER, 'GerberFiles\soldermask_bottom.gbr'))
    silk = load_layer(
        os.path.join(BASE_FOLDER, 'GerberFiles\silkscreen_bottom.gbr'))

    # Clear the drawing
    ctx.clear()

    # Render bottom layers
    ctx.render_layer(outline,
                     settings=RenderSettings(color=theme.COLORS['black'],
                                             mirror=True,
                                             alpha=0.85))
    ctx.render_layer(copper,
                     settings=RenderSettings(color=theme.COLORS['hasl copper'],
                                             mirror=True,
                                             alpha=0.85))
    ctx.render_layer(mask,
                     settings=RenderSettings(
                         color=theme.COLORS['green soldermask'],
                         mirror=True,
                         invert=True,
                         alpha=0.8))
    ctx.render_layer(silk,
                     settings=RenderSettings(color=theme.COLORS['white'],
                                             mirror=True,
                                             alpha=0.85))
    ctx.render_layer(drill, settings=RenderSettings(mirror=True))
    ctx.render_layer(outline,
                     settings=RenderSettings(color=theme.COLORS['black'],
                                             mirror=True,
                                             alpha=0.85))

    # Write png file
    ctx.dump(os.path.join(BASE_FOLDER, 'board_bottom.png'), verbose=True)
GerberCairoContext. The color and opacity of each layer can be set individually.
Once all thedesired layers are drawn on the context, the context is written to
a .png file.
"""

import os
from gerber import load_layer, PCB
from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext
from gerber.render.theme import COLORS

GERBER_FOLDER = os.path.abspath(
    os.path.join(os.path.dirname(__file__), 'not-working'))

# Create a new drawing context
ctx = GerberCairoContext()

pcb = PCB.from_directory(GERBER_FOLDER, verbose=True)
# Draw the copper layer. render_layer() uses the default color scheme for the
# layer, based on the layer type. Copper layers are rendered as
red_theme = theme.Theme(topmask=RenderSettings(COLORS['red soldermask'],
                                               alpha=0.8,
                                               invert=True),
                        bottommask=RenderSettings(COLORS['red soldermask'],
                                                  alpha=0.8,
                                                  invert=True))

#Rendering layers using the red_theme
ctx.render_layers(layers=pcb.top_layers,
                  filename=os.path.join(
                      os.path.dirname(__file__),
Exemple #21
0
def combine(gtl_file, gts_file, gto_file, txt_file, gtp_file, gbl_file,
            gbs_file, basedir):
    # Open the gerber files
    copper = load_layer(gtl_file)
    mask = load_layer(gts_file)
    silk = load_layer(gto_file)
    drill = load_layer(txt_file)
    placement = load_layer(gtp_file)

    # Create a new drawing context
    ctx = GerberCairoContext()

    # Draw the copper layer. render_layer() uses the default color scheme for the
    # layer, based on the layer type. Copper layers are rendered as
    # Draw the soldermask layer
    ctx.render_layer(copper)
    ctx.render_layer(mask)
    ctx.render_layer(silk,
                     settings=RenderSettings(color=theme.COLORS['white'],
                                             alpha=0.85))
    ctx.render_layer(drill)

    # Write output to png file
    ctx.dump(os.path.join(basedir, "top.png"))

    # Load the bottom layers
    copper = load_layer(gbl_file)
    copper_top = load_layer(gtl_file)
    mask = load_layer(gbs_file)

    # Clear the drawing
    ctx = GerberCairoContext()
    from gerber.rs274x import read, GerberFile

    # Render bottom layers
    ctx.render_layer(copper, bounds=copper_top.bounds)
    ctx.render_layer(mask)
    ctx.render_layer(drill, settings=RenderSettings(mirror=True))

    # Write png file
    ctx.dump(os.path.join(basedir, "bottom.png"))

    copper = load_layer(gtl_file)
    ctx = GerberCairoContext()
    ctx.render_layer(copper)

    ctx.dump(os.path.join(basedir, "top-copper.png"))
    ctx = GerberCairoContext()
    copper_bottom = load_layer(gbl_file)
    ctx.render_layer(copper_bottom, bounds=copper.bounds)
    ctx.dump(os.path.join(basedir, "bottom-copper.png"))
Exemple #22
0
import os
from gerber import load_layer
from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext

GERBER_FOLDER = os.path.abspath(
    os.path.join(os.path.dirname(__file__), 'gerbers'))

# Open the gerber files
copper = load_layer(os.path.join(GERBER_FOLDER, 'copper.GTL'))
mask = load_layer(os.path.join(GERBER_FOLDER, 'soldermask.GTS'))
silk = load_layer(os.path.join(GERBER_FOLDER, 'silkscreen.GTO'))
drill = load_layer(os.path.join(GERBER_FOLDER, 'ncdrill.DRD'))

# Create a new drawing context
ctx = GerberCairoContext()

# Draw the copper layer. render_layer() uses the default color scheme for the
# layer, based on the layer type. Copper layers are rendered as
ctx.render_layer(copper)

# Draw the soldermask layer
ctx.render_layer(mask)

# The default style can be overridden by passing a RenderSettings instance to
# render_layer().
# First, create a settings object:
our_settings = RenderSettings(color=theme.COLORS['white'], alpha=0.85)

# Draw the silkscreen layer, and specify the rendering settings to use
ctx.render_layer(silk, settings=our_settings)
class PcbGui(tk.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.pack()

        self.ctx = GerberCairoContext(8)
        self.ctx.units = 'metric'

        self.layers = {}
        self.components = []
        # self.components = self.load_pickplace()
        self.layer = "TopLayer"

        # self.geometry("{}x{}".format(self._image_ref.width(), self._image_ref.height()))

        self.clist = ComponentListGui(self)
        # self.clist.add_components(self.components, self.layer)
        self.clist.pack(expand=True, side="right")

        self.label = tk.Label(self)
        self.label.pack(expand=True, side="left")
        # self.draw_component()

        self.bind('<ButtonRelease-1>', self.draw_component)

    def select_gerber_folder(self):
        dir = tk.filedialog.askdirectory(title="Select folder with Gerbers")
        self.layers = {}
        for infile in listdir(dir):
            path = os.path.join(dir, infile)
            if infile.lower().endswith('gbl'):
                self.layers['gbl'] = gerber.load_layer(path)
            if infile.lower().endswith('gtl'):
                self.layers['gtl'] = gerber.load_layer(path)
            if infile.lower().endswith('gtp'):
                self.layers['gtp'] = gerber.load_layer(path)
        self.draw_component()

    def set_layer(self, layer):
        self.layer = layer
        self.draw_component()
        self.clist.add_components(self.components, self.layer)

    def menubar(self, root):
        menubar = tk.Menu(root)
        pageMenu = tk.Menu(menubar)
        pageMenu.add_command(label="Open Gerber folder",
                             command=self.select_gerber_folder)
        pageMenu.add_command(label="Open pick and place file",
                             command=self.load_pickplace)
        menubar.add_cascade(label="File", menu=pageMenu)

        layerMenu = tk.Menu(menubar)
        layerMenu.add_radiobutton(label="Top Layer",
                                  command=lambda: self.set_layer("TopLayer"))
        layerMenu.add_radiobutton(
            label="Bottom Layer",
            command=lambda: self.set_layer("BottomLayer"))
        menubar.add_cascade(label="Layer", menu=layerMenu)

        helpMenu = tk.Menu(menubar, name="help")
        helpMenu.add_command(label="About")
        menubar.add_cascade(label="Help", menu=helpMenu)
        return menubar

    # def load_gerber(self):
    #     self.layers = {}
    #     self.layers.append(gerber.load_layer('example.GTL'))
    # self.ctx.render_layers(layers, buffer, max_width=self.w, max_height=self.h, verbose=True)

    def draw_component(self, event=None):
        self.ctx.clear()

        if len(self.layers) > 0:
            if self.layer == "TopLayer":
                copper_settings = RenderSettings(color=theme.COLORS['black'],
                                                 alpha=0.8,
                                                 mirror=False)
                self.ctx.render_layer(self.layers["gtl"],
                                      settings=copper_settings,
                                      verbose=True)
                self.ctx.new_render_layer(mirror=False)
            if self.layer == "BottomLayer":
                copper_settings = RenderSettings(color=theme.COLORS['black'],
                                                 alpha=0.8,
                                                 mirror=True)
                self.ctx.render_layer(self.layers["gbl"],
                                      settings=copper_settings)
                self.ctx.new_render_layer(mirror=True)

            self.ctx._color = (1.0, 0.0, 1.0)
            layer = self.layer
            if self.clist.tb.selected_row != None:
                part_number = self.clist.tb.selected_row['PN']
            else:
                part_number = None
            for c in self.components:
                if (c['layer'] == layer) and (c['part_number'] == part_number):
                    print("{} {}".format(c['x_mm'], c['y_mm']))
                    self.ctx.render(
                        gerber.primitives.Circle((c['x_mm'], c['y_mm']), 1))
            self.ctx.flatten()
            buffer = BytesIO()
            self.ctx.dump(buffer)
            img = ImageTk.PhotoImage(Image.open(buffer))
            self.label.configure(image=img)
            self.label.image = img

    def load_pickplace(self):
        filename = tk.filedialog.askopenfilename(
            title="Select pick and place file")
        components = []
        filetype = "Kicad"
        with open(filename, "r") as ppfile:
            header_read = False
            for line in ppfile:
                line = shlex.split(line)
                if len(line) > 0:
                    if header_read == False:
                        # Try to determine the file type based on the contents
                        if line[0] == "Altium":
                            filetype = "Altium"
                        if line[0] == "Designator" or line[0] == "#":
                            header_read = True
                    else:
                        if filetype == "Altium":
                            component = {}
                            component['designator'] = line[0]
                            component['part_number'] = line[1]
                            component['x_mm'] = float(line[4][:-2])
                            component['y_mm'] = float(line[5][:-2])
                            component['layer'] = line[2]
                            component['description'] = line[7]
                            components.append(component)
                        elif filetype == "Kicad":
                            if len(line) > 6:
                                print(line)
                                component = {}
                                component['designator'] = line[0]
                                component['part_number'] = line[1]
                                component['x_mm'] = float(line[3])
                                component['y_mm'] = float(line[4])
                                component['layer'] = "TopLayer" if line[
                                    6] == "top" else "BottomLayer"
                                if component['layer'] == "BottomLayer":
                                    component['x_mm'] *= -1
                                component['description'] = line[2]
                                components.append(component)
        self.components = components
        self.clist.add_components(self.components, self.layer)
Exemple #24
0
"""

import gerber
from gerber.render.cairo_backend import GerberCairoContext
from gerber.render import RenderSettings, theme
from gerber import load_layer
import os

BASE_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),'gerbers'))

copper=load_layer(os.path.join(BASE_DIR,'copper.GTL'))
mask=load_layer(os.path.join(BASE_DIR,'soldermask.GTS'))
silk=load_layer(os.path.join(BASE_DIR,'silkscreen.GTO'))
drill=load_layer(os.path.join(BASE_DIR,'ncdrill.DRD'))

new=GerberCairoContext()
new_settings=RenderSettings(color=theme.COLORS['red'],alpha=0.8)
white_text_settings=RenderSettings(color=theme.COLORS['white'],alpha=0.8)
new.render_layer(copper,settings=new_settings)
new.render_layer(mask,settings=new_settings)
new.render_layer(silk,settings=white_text_settings)
new.render_layer(drill)

new.dump(os.path.join(BASE_DIR,'front.png'))    

new.clear()
copper_bottom=load_layer(os.path.join(BASE_DIR,'bottom_copper.GBL'))
mask_bottom=load_layer(os.path.join(BASE_DIR,'bottom_mask.GBS'))

new.render_layer(copper_bottom,settings=new_settings)
new.render_layer(mask_bottom,settings=new_settings)
Exemple #25
0
def generate_template(
        silk,
        mask,
        copper,
        outline,
        drill,
        image,
        process_resolution: float = 6,  # mil
        resolution_oversampling: float = 10,  # times
        status_print=lambda *args: None):

    silk, mask, copper, outline, *drill = map(
        gerber.load_layer_data, [silk, mask, copper, outline, *drill])
    silk.layer_class = 'topsilk'
    mask.layer_class = 'topmask'
    copper.layer_class = 'top'
    outline.layer_class = 'outline'

    f = 1.0 if outline.cam_source.units == 'metric' else 25.4
    scale = (1000 /
             process_resolution) / 25.4 * resolution_oversampling * f  # dpmm
    bounds = outline.cam_source.bounding_box

    # Create a new drawing context
    ctx = GerberCairoContext(scale=scale)

    ctx.render_layer(outline, bounds=bounds)
    ctx.render_layer(copper, bounds=bounds)
    ctx.render_layer(mask, bounds=bounds)
    ctx.render_layer(silk, bounds=bounds)
    for dr in drill:
        ctx.render_layer(dr, bounds=bounds)
    ctx.dump(image)
Exemple #26
0
    def render_devel_view(self, output_filename=None, quick=False, nox=False):
        output_filename = '{0}.devel.png'.format(output_filename)
        ctx = GerberCairoContext()

        ctx.color = theme.COLORS['fr-4']
        ctx.alpha = 1.0
        outline = read(self.layers.outline)
        outline.render(ctx)

        ctx.color = self.copper_color
        bottompaste = read(self.layers.bottompaste)
        bottompaste.render(ctx)

        ctx.alpha = 0.9
        ctx.color = self.silk_color
        bottomsilk = read(self.layers.bottomsilk)
        bottomsilk.render(ctx)

        num_copper_layers = len(self.layers.internal)
        if self.layers.top is not None:
            num_copper_layers += 1
        if self.layers.bottom is not None:
            num_copper_layers += 1

        ctx.color = self.layer_colors[num_copper_layers - 1]
        bottom = read(self.layers.bottom)
        bottom.render(ctx)

        ctx.alpha = 0.5
        for idx, l in enumerate(self.layers.internal):
            layer = read(l)
            ctx.color = self.layer_colors[num_copper_layers - 2 - idx]
            layer.render(ctx)

        ctx.alpha = 0.9
        ctx.color = self.layer_colors[0]
        top = read(self.layers.top)
        top.render(ctx)

        ctx.color = self.silk_color
        topsilk = read(self.layers.topsilk)
        topsilk.render(ctx)

        ctx.color = self.copper_color
        toppaste = read(self.layers.toppaste)
        toppaste.render(ctx)

        ctx.color = theme.COLORS['black']
        ctx.alpha = 1.0
        drill = read(self.layers.drill)
        drill.render(ctx)

        ctx.dump(output_filename)
Exemple #27
0
    def render_devel_view(self, output_filename=None,
                          quick=False, nox=False):
        output_filename = '{0}.devel.png'.format(output_filename)
        ctx = GerberCairoContext()

        ctx.color = theme.COLORS['fr-4']
        ctx.alpha = 1.0
        outline = read(self.layers.outline)
        outline.render(ctx)

        ctx.color = self.copper_color
        bottompaste = read(self.layers.bottompaste)
        bottompaste.render(ctx)

        ctx.alpha = 0.9
        ctx.color = self.silk_color
        bottomsilk = read(self.layers.bottomsilk)
        bottomsilk.render(ctx)

        num_copper_layers = len(self.layers.internal)
        if self.layers.top is not None:
            num_copper_layers += 1
        if self.layers.bottom is not None:
            num_copper_layers += 1

        ctx.color = self.layer_colors[num_copper_layers - 1]
        bottom = read(self.layers.bottom)
        bottom.render(ctx)

        ctx.alpha = 0.5
        for idx, l in enumerate(self.layers.internal):
            layer = read(l)
            ctx.color = self.layer_colors[num_copper_layers - 2 - idx]
            layer.render(ctx)

        ctx.alpha = 0.9
        ctx.color = self.layer_colors[0]
        top = read(self.layers.top)
        top.render(ctx)

        ctx.color = self.silk_color
        topsilk = read(self.layers.topsilk)
        topsilk.render(ctx)

        ctx.color = self.copper_color
        toppaste = read(self.layers.toppaste)
        toppaste.render(ctx)

        ctx.color = theme.COLORS['black']
        ctx.alpha = 1.0
        drill = read(self.layers.drill)
        drill.render(ctx)

        ctx.dump(output_filename)
Exemple #28
0
legend = load_layer('gerber_files/silkscreen.GTO')
drill = load_layer('gerber_files/ncdrill.DRD')

#Bottom View Layers
copper_btm = load_layer('gerber_files/bottom_copper.GBL')
soldermask_btm = load_layer('gerber_files/bottom_mask.GBS')

## Color Settings
mask_settings = RenderSettings(color=theme.COLORS['red soldermask'],
                               alpha=0.5,
                               invert=True)
legend_settings = RenderSettings(color=theme.COLORS['white'], alpha=0.8)

## Rendering
#Top View
cont = GerberCairoContext()
cont.render_layer(copper)
cont.render_layer(soldermask, settings=mask_settings)
cont.render_layer(legend, settings=legend_settings)
cont.render_layer(drill)

cont.dump('gen_images/redpcb.png')

#Clear cont
cont.clear()

#Bottom View
cont.render_layer(copper_btm)
cont.render_layer(soldermask_btm, settings=mask_settings)

cont.dump('gen_images/redpcb_bottom.png')
Exemple #29
0
#!/usr/bin/env python
from gerber import load_layer
from gerber.render import RenderSettings, theme
from gerber.render.cairo_backend import GerberCairoContext

prefix = 'outputs/sonopi-dac-panelized'

ctx = GerberCairoContext(scale=40)

print('loading ', end='', flush=True)
copper = load_layer(prefix + '.GTL')
print('.', end='', flush=True)
mask = load_layer(prefix + '.GTS')
print('.', end='', flush=True)
silk = load_layer(prefix + '.GTO')
print('.', end='', flush=True)
drill = load_layer(prefix + '.TXT')
print('.', end='', flush=True)
outline = load_layer(prefix + '-fill.GML')
print('.', end='', flush=True)
print('. end', flush=True)

print('drawing ', end='', flush=True)
print('.', end='', flush=True)

metal_settings = RenderSettings(color=(30.0 / 255.0, 119.0 / 255.0,
                                       93 / 255.0))
bg_settings = RenderSettings(color=(30.0 / 300.0, 110.0 / 300.0, 93 / 300.0))
ctx.render_layer(copper, settings=metal_settings, bgsettings=bg_settings)
print('.', end='', flush=True)
Exemple #30
0
    def render_top_view(self, output_filename=None,
                        quick=False, nox=False):
        output_filename = '{0}.top.png'.format(output_filename)
        ctx = GerberCairoContext()

        if self.outline_color is not None:
            ctx.color = self.outline_color
        if self.outline_alpha is not None:
            ctx.alpha = self.outline_alpha
        outline = read(self.layers.outline)
        outline.render(ctx)

        if self.copper_color is not None:
            ctx.color = self.copper_color
        if self.copper_alpha is not None:
            ctx.alpha = self.copper_alpha
        copper = read(self.layers.top)
        copper.render(ctx)

        if self.mask_color is not None:
            ctx.color = self.mask_color
        if self.mask_alpha is not None:
            ctx.alpha = self.mask_alpha
        mask = read(self.layers.topmask)
        mask.render(ctx, invert=True)

        if self.silk_color is not None:
            ctx.color = self.silk_color
        if self.silk_alpha is not None:
            ctx.alpha = self.silk_alpha
        silk = read(self.layers.topsilk)
        silk.render(ctx)

        if self.drill_color is not None:
            ctx.color = self.drill_color
        if self.drill_alpha is not None:
            ctx.alpha = self.drill_alpha
        drill = read(self.layers.drill)
        drill.render(ctx)

        ctx.dump(output_filename)