def plot_drill(self, pcb): "plot drill files" pctl = pcbnew.PLOT_CONTROLLER(pcb) drill_path = os.path.dirname( pcb.GetFileName()) + PCB_MAN_PACK_DIR + "Drill/" if not os.path.exists(drill_path): os.makedirs(drill_path) report_path = os.path.dirname(pcb.GetFileName()) + REPORTS_DIR if not os.path.exists(report_path): os.makedirs(report_path) pctl = pcbnew.PLOT_CONTROLLER(pcb) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(drill_path) # Set some important plot options: popt.SetPlotFrameRef(False) popt.SetLineWidth(pcbnew.FromMM(0.1)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetExcludeEdgeLayer(False) popt.SetPlotValue(False) popt.SetPlotReference(False) popt.SetUseGerberAttributes(True) popt.SetUseGerberProtelExtensions(False) popt.SetUseAuxOrigin(True) # Fabricators need drill files. # sometimes a drill map file is asked (for verification purpose) drlwriter = pcbnew.EXCELLON_WRITER(pcb) drlwriter.SetMapFileFormat(pcbnew.PLOT_FORMAT_PDF) mirror = False minimalHeader = False offset = pcb.GetAuxOrigin() # False to generate 2 separate drill files (one for plated holes, one for non plated holes) # True to generate only one drill file mergeNPTH = True drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH) metricFmt = True drlwriter.SetFormat(metricFmt) genDrl = True genMap = True drlwriter.CreateDrillandMapFilesSet(drill_path, genDrl, genMap) # One can create a text file to report drill statistics rptfn = report_path + 'drill_report.rpt' drlwriter.GenDrillReportFile(rptfn) pctl.ClosePlot()
def plot(self, brd_file): logging.debug("Starting plot of board {}".format(brd_file)) board = pcbnew.LoadBoard(brd_file) logging.debug("Board loaded") self._preflight_checks(board) for op in self.cfg.outputs: logging.debug("Processing output: {}".format(op.name)) # fresh plot controller pc = pcbnew.PLOT_CONTROLLER(board) self._configure_output_dir(pc, op) if self._output_is_layer(op): self._do_layer_plot(board, pc, op) elif self._output_is_drill(op): self._do_drill_plot(board, pc, op) elif self._output_is_position(op): self._do_position_plot(board, pc, op) else: raise PlotError("Don't know how to plot type {}".format( op.options.type)) pc.ClosePlot()
def Run(self): pcb = pcbnew.GetBoard() pctl = pcbnew.PLOT_CONTROLLER(pcb) popt = pctl.GetPlotOptions() popt.SetOutputDirectory("Outputs/PCB_Manufacturing/") # Set some important plot options: popt.SetPlotFrameRef(True) popt.SetLineWidth(pcbnew.FromMM(0.1)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetExcludeEdgeLayer(False) popt.SetPlotValue(False) popt.SetPlotReference(True) #Create a pdf file of the top fab Layer pctl.SetLayer(pcbnew.Dwgs_User) pctl.OpenPlotfile("Fab_Drawings", pcbnew.PLOT_FORMAT_PDF, "Fab_Drawings") pctl.PlotLayer() pctl.ClosePlot()
def plot_fab_drawings(self, pcb): "plot fab drawings" pctl = pcbnew.PLOT_CONTROLLER(pcb) popt = pctl.GetPlotOptions() fab_path = os.path.dirname(pcb.GetFileName()) + PCB_MAN_PACK_DIR popt.SetOutputDirectory(fab_path) # Set some important plot options: popt.SetPlotFrameRef(True) popt.SetLineWidth(pcbnew.FromMM(0.1)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetExcludeEdgeLayer(False) popt.SetPlotValue(False) popt.SetPlotReference(True) #Create a pdf file of the top fab Layer pctl.SetLayer(pcbnew.Dwgs_User) pctl.OpenPlotfile("Fab_Drawings", pcbnew.PLOT_FORMAT_PDF, "Fab_Drawings") pctl.PlotLayer() pctl.ClosePlot()
def plot(board_filename=None, layers=None): if board_filename is None: board = pcbnew.GetBoard() else: board = pcbnew.LoadBoard(os.path.expanduser(board_filename)) if layers is None: layers = LAYERS elif isinstance(layers, list): layers = layers.keys() plot_ctrl = pcbnew.PLOT_CONTROLLER(board) plot_opts = plot_ctrl.GetPlotOptions() plot_opts.SetPlotFrameRef(False) plot_opts.SetLineWidth(pcbnew.FromMM(0.35)) plot_opts.SetAutoScale(False) plot_opts.SetScale(1) plot_opts.SetUseGerberAttributes(True) plot_opts.SetExcludeEdgeLayer(False) plot_opts.SetUseAuxOrigin(False) plot_opts.SetPlotViaOnMaskLayer(True) for layer, layer_info in layers.items(): layer_name = layers.get('name', board.GetLayerName(layer)) plot_opts.SetMirror(layer_info.get('mirrored', False)) plot_opts.SetNegative(layer_info.get('negative', False)) plot_ctrl.SetLayer(layer) plot_ctrl.OpenPlotfile(layer_name, pcbnew.PLOT_FORMAT_PDF, layer_info.get('description', layer_name)) plot_ctrl.PlotLayer()
def genPostscript(self, board, path): pc = pcbnew.PLOT_CONTROLLER(board) po = pc.GetPlotOptions() # set global options po.SetPlotFrameRef(False) po.SetOutputDirectory(path) po.SetA4Output(True) po.SetScale(1.0) po.SetExcludeEdgeLayer(False) po.SetDrillMarksType(po.SMALL_DRILL_SHAPE) # Set options for front Copper layer pc.SetLayer(pcbnew.F_Cu) po.SetMirror(True) # Plot front Copper pc.OpenPlotfile("CuTOP", pcbnew.PLOT_FORMAT_POST, "front_copper") pc.PlotLayer() pc.ClosePlot() #Plot bottom Copper # Set options for Bottom Copper layer pc.SetLayer(pcbnew.B_Cu) po.SetMirror(False) pc.OpenPlotfile("CuBOT", pcbnew.PLOT_FORMAT_POST, "bottom_copper") pc.PlotLayer() pc.ClosePlot() logging.info('Postcripts done')
def get_board_substrate(board, colors, holes, back, silk): """ Plots all front layers from the board and arranges them in a visually appealing style. return SVG g element with the board substrate """ toPlot = [] if (back): toPlot = [("board", [pcbnew.Edge_Cuts], process_board_substrate_base), ("clad", [pcbnew.B_Mask], process_board_substrate_layer), ("copper", [pcbnew.B_Cu], process_board_substrate_layer), ("pads", [pcbnew.B_Cu], process_board_substrate_layer), ("pads-mask", [pcbnew.B_Mask], process_board_substrate_mask)] if silk: toPlot.append( ("silk", [pcbnew.B_SilkS], process_board_substrate_layer)) else: toPlot = [("board", [pcbnew.Edge_Cuts], process_board_substrate_base), ("clad", [pcbnew.F_Mask], process_board_substrate_layer), ("copper", [pcbnew.F_Cu], process_board_substrate_layer), ("pads", [pcbnew.F_Cu], process_board_substrate_layer), ("pads-mask", [pcbnew.F_Mask], process_board_substrate_mask)] if silk: toPlot.append( ("silk", [pcbnew.F_SilkS], process_board_substrate_layer)) toPlot.append( ("outline", [pcbnew.Edge_Cuts], process_board_substrate_layer)) container = etree.Element('g') container.attrib["clip-path"] = "url(#cut-off)" tmp = tempfile.mkdtemp() pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(tmp) popt.SetScale(1) popt.SetMirror(False) popt.SetSubtractMaskFromSilk(True) try: popt.SetPlotOutlineMode(False) except: # Method does not exist in older versions of KiCad pass popt.SetTextMode(pcbnew.PLOTTEXTMODE_STROKE) for f, layers, _ in toPlot: pctl.OpenPlotfile(f, pcbnew.PLOT_FORMAT_SVG, f) for l in layers: pctl.SetColorMode(False) pctl.SetLayer(l) pctl.PlotLayer() pctl.ClosePlot() boardsize = get_board_size(board) for f, _, process in toPlot: for svg_file in os.listdir(tmp): if svg_file.endswith("-" + f + ".svg"): process(container, f, os.path.join(tmp, svg_file), colors, boardsize) shutil.rmtree(tmp) if holes: container.append(get_hole_mask(board)) container.attrib["mask"] = "url(#hole-mask)" return container
def get_board_substrate(board, colors): """ Plots all front layers from the board and arranges them in a visually appealing style. return SVG g element with the board substrate """ toPlot = [("board", [pcbnew.Edge_Cuts], process_board_substrate_base), ("copper", [pcbnew.F_Cu], process_board_substrate_layer), ("pads", [pcbnew.F_Paste], process_board_substrate_layer), ("silk", [pcbnew.F_SilkS], process_board_substrate_layer)] container = etree.Element('g') tmp = tempfile.mkdtemp() pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(tmp) popt.SetScale(1) popt.SetMirror(False) popt.SetTextMode(pcbnew.PLOTTEXTMODE_STROKE) for f, layers, _ in toPlot: pctl.OpenPlotfile(f, pcbnew.PLOT_FORMAT_SVG, f) for l in layers: pctl.SetColorMode(False) pctl.SetLayer(l) pctl.PlotLayer() pctl.ClosePlot() for f, _, process in toPlot: for svg_file in os.listdir(tmp): if svg_file.endswith("-" + f + ".svg"): process(container, f, os.path.join(tmp, svg_file), colors) shutil.rmtree(tmp) return container
def render(layers, name, mirror): # Export new files pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(plotDir) popt.SetPlotFrameRef(False) popt.SetLineWidth(pcbnew.FromMM(0.15)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(mirror) popt.SetUseGerberAttributes(True) popt.SetExcludeEdgeLayer(False) popt.SetUseAuxOrigin(False) popt.SetUseAuxOrigin(False) popt.SetPlotReference(True) popt.SetPlotValue(True) popt.SetPlotInvisibleText(False) popt.SetPlotFrameRef(False) pctl.SetLayer(Dwgs_User) pctl.OpenPlotfile(name, PLOT_FORMAT_PDF, name) pctl.SetColorMode(True) for layer_info in layers: pctl.SetLayer(layer_info[1]) pctl.PlotLayer() pctl.ClosePlot()
def get_layers(board, colors, toPlot): """ Plot given layers, process them and return them as <g> """ container = etree.Element('g') tmp = tempfile.mkdtemp() pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(tmp) popt.SetScale(1) popt.SetMirror(False) popt.SetSubtractMaskFromSilk(True) try: popt.SetPlotOutlineMode(False) except: # Method does not exist in older versions of KiCad pass popt.SetTextMode(pcbnew.PLOTTEXTMODE_STROKE) for f, layers, _ in toPlot: pctl.OpenPlotfile(f, pcbnew.PLOT_FORMAT_SVG, f) for l in layers: pctl.SetColorMode(False) pctl.SetLayer(l) pctl.PlotLayer() pctl.ClosePlot() boardsize = board.ComputeBoundingBox() for f, _, process in toPlot: for svg_file in os.listdir(tmp): if svg_file.endswith("-" + f + ".svg"): process(container, f, os.path.join(tmp, svg_file), colors, boardsize) shutil.rmtree(tmp) return container
def processBoard(boardName, plotDir): """Convert layers of KiCad PCB to SVGs""" print(boardName) print(plotDir) # Load board and initialize plot controller board = pcbnew.LoadBoard(boardName) boardBox = board.ComputeBoundingBox() boardXl = boardBox.GetX() boardYl = boardBox.GetY() boardWidth = boardBox.GetWidth() boardHeight = boardBox.GetHeight() print(boardXl, boardYl, boardWidth, boardHeight) pctl = pcbnew.PLOT_CONTROLLER(board) pctl.SetColorMode(True) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(plotDir) popt.SetPlotFrameRef(False) popt.SetLineWidth(pcbnew.FromMM(0.15)) popt.SetAutoScale(False) popt.SetScale(2) popt.SetMirror(False) popt.SetUseGerberAttributes(True) popt.SetExcludeEdgeLayer(False) popt.SetUseAuxOrigin(True) layers = [ ("F_Cu", pcbnew.F_Cu, "Top layer"), ("B_Cu", pcbnew.B_Cu, "Bottom layer"), ("B_Paste", pcbnew.B_Paste, "Paste bottom"), ("F_Paste", pcbnew.F_Paste, "Paste top"), ("F_SilkS", pcbnew.F_SilkS, "Silk top"), ("B_SilkS", pcbnew.B_SilkS, "Silk top"), ("B_Mask", pcbnew.B_Mask, "Mask bottom"), ("F_Mask", pcbnew.F_Mask, "Mask top"), ("Edge_Cuts", pcbnew.Edge_Cuts, "Edges"), ("Margin", pcbnew.Margin, "Margin"), ("In1_Cu", pcbnew.In1_Cu, "Inner1"), ("In2_Cu", pcbnew.In2_Cu, "Inner2"), ("Dwgs_User", pcbnew.Dwgs_User, "Dwgs_User"), ("Cmts_User", pcbnew.Cmts_User, "Comments_User"), ("Eco1_User", pcbnew.Eco1_User, "ECO1"), ("Eco2_User", pcbnew.Eco2_User, "ECO2"), ("B_Fab", pcbnew.B_Fab, "Fab bottom"), ("F_Fab", pcbnew.F_Fab, "Fab top"), ("B_Adhes", pcbnew.B_Adhes, "Adhesive bottom"), ("F_Adhes", pcbnew.F_Adhes, "Adhesive top"), ("B_CrtYd", pcbnew.B_CrtYd, "Courtyard bottom"), ("F_CrtYd", pcbnew.F_CrtYd, "Courtyard top"), ] for layer_info in layers: pctl.SetLayer(layer_info[1]) pctl.OpenPlotfile(layer_info[0], pcbnew.PLOT_FORMAT_SVG, layer_info[2]) pctl.PlotLayer() return (boardXl, boardYl, boardWidth, boardHeight)
def RunCheck(name): # Load board and initialize plot controller #board = pcbnew.LoadBoard(name) board = pcbnew.GetBoard() pc = pcbnew.PLOT_CONTROLLER(board) po = pc.GetPlotOptions() po.SetPlotFrameRef(False) # Set current layer pc.SetLayer(pcbnew.F_Cu) # Plot single layer to file #pc.OpenPlotfile("front_copper", pcbnew.PLOT_FORMAT_SVG, "front_copper") #print("Plotting to " + pc.GetPlotFileName()) #pc.PlotLayer() #pc.ClosePlot() #F.Mask pc.SetLayer(pcbnew.F_Mask) pc.OpenPlotfile("front_mask", pcbnew.PLOT_FORMAT_SVG, "front_mask") print("Plotting to " + pc.GetPlotFileName()) name_mask = pc.GetPlotFileName() pc.PlotLayer() pc.ClosePlot() #F.SilkS pc.SetLayer(pcbnew.F_SilkS) pc.OpenPlotfile("front_silk", pcbnew.PLOT_FORMAT_SVG, "front_silk") print("Plotting to " + pc.GetPlotFileName()) name_silk = pc.GetPlotFileName() pc.PlotLayer() pc.ClosePlot() out_silk = io.BytesIO() cairosvg.svg2png(url=name_silk, write_to=out_silk, scale=2.0) image_silk = Image.open(out_silk) out_mask = io.BytesIO() cairosvg.svg2png(url=name_mask, write_to=out_mask, scale=2.0) image_mask = Image.open(out_mask) #image_silk.show() pixels_silk = image_silk.load() # create the pixel map pixels_mask = image_mask.load() # https://pillow.readthedocs.io/en/3.1.x/reference/Image.html#PIL.Image.Image.paste #image_silk = image_silk.convert("RGB") for i in range(image_silk.size[0]): # for every pixel: for j in range(image_silk.size[1]): if pixels_silk[i, j] != (0, 0, 0, 0) and pixels_mask[i, j] != (0, 0, 0, 0): pixels_silk[i, j] = (255, 0, 0) image_silk = trim(image_silk) #image_silk.save("test.png",optimize=0) image_silk.show()
def generate_pcb_gerber(args): logging.info('Generating PCB gerber files') check_args(args) output_dir = os.path.join(args.output_dir, 'gerber') if not os.path.exists(output_dir): os.makedirs(output_dir) logging.info(' Reading %s', args.input_pcb) board = pcbnew.LoadBoard(args.input_pcb) plot_controller = pcbnew.PLOT_CONTROLLER(board) plot_options = plot_controller.GetPlotOptions() plot_options.SetOutputDirectory(output_dir) plot_options.SetPlotFrameRef(False) plot_options.SetLineWidth(pcbnew.FromMM(0.1)) plot_options.SetAutoScale(False) plot_options.SetScale(1) plot_options.SetMirror(False) plot_options.SetUseGerberAttributes(True) plot_options.SetUseGerberProtelExtensions(True) plot_options.SetExcludeEdgeLayer(True) plot_options.SetUseAuxOrigin(False) plot_controller.SetColorMode(True) plot_options.SetSubtractMaskFromSilk(True) plot_options.SetPlotReference(True) plot_options.SetPlotValue(False) layers = [ ("F.Cu", pcbnew.F_Cu, "Top layer"), ("B.Cu", pcbnew.B_Cu, "Bottom layer"), ("F.Paste", pcbnew.F_Paste, "Paste top"), ("B.Paste", pcbnew.B_Paste, "Paste bottom"), ("F.SilkS", pcbnew.F_SilkS, "Silk top"), ("B.SilkS", pcbnew.B_SilkS, "Silk top"), ("F.Mask", pcbnew.F_Mask, "Mask top"), ("B.Mask", pcbnew.B_Mask, "Mask bottom"), ("Edge.Cuts", pcbnew.Edge_Cuts, "Edges"), ] logging.info(' Writing to %s' % output_dir) for layer_info in layers: plot_controller.SetLayer(layer_info[1]) plot_controller.OpenPlotfile(layer_info[0], pcbnew.PLOT_FORMAT_GERBER, layer_info[2]) plot_controller.PlotLayer() plot_controller.ClosePlot()
def plot_layers(f_name, plot_dir, layers=['F.Cu', 'B.Cu'], zone_refill=True): ''' f_name: the .kicad_pcb file to plot plot_dir: output directory for the .pdf files layers: list of layer names to plot zone_refill: if True, re-calculate copper fills before plotting returns: dict with coordinates of bounding box containing the PCB [inches] ''' if not os.path.isfile(f_name) or not os.access(f_name, os.R_OK): print("%s: not readable, aborting" % f_name) return None try: board = pcbnew.LoadBoard(f_name) except Exception: print("%s: failed to load with pcbnew, aborting" % f_name) return None # after this point, chances of failure are low if zone_refill: print('filling zones ...') zf = pcbnew.ZONE_FILLER(board) zf.Fill(board.Zones()) boardbox = board.ComputeBoundingBox() bounds = { 'x': boardbox.GetX() / 1e6 / 25.4, 'y': boardbox.GetY() / 1e6 / 25.4, 'W': boardbox.GetWidth() / 1e6 / 25.4, 'H': boardbox.GetHeight() / 1e6 / 25.4, } # print('bounds [inch]:', bounds) pctl = pcbnew.PLOT_CONTROLLER(board) # pctl.SetColorMode(True) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(plot_dir) popt.SetPlotFrameRef(False) # popt.SetLineWidth(pcbnew.FromMM(0.15)) # popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) # popt.SetUseGerberAttributes(True) popt.SetExcludeEdgeLayer(False) # popt.SetUseAuxOrigin(True) popt.SetDrillMarksType(popt.FULL_DRILL_SHAPE) for layer in layers: pctl.SetLayer(board.GetLayerID(layer)) pctl.OpenPlotfile(layer, pcbnew.PLOT_FORMAT_PDF, layer) pctl.PlotLayer() pctl.ClosePlot() return bounds
def __init__(self, board, build_directory): self.board = board self.build_directory = build_directory self.plot_controller = pcbnew.PLOT_CONTROLLER(board) self.plot_options = self.plot_controller.GetPlotOptions() self.plot_options.SetOutputDirectory(build_directory) self.plot_options.SetPlotFrameRef(False) self.plot_options.SetLineWidth(pcbnew.FromMM(0.35)) self.plot_options.SetScale(1) self.plot_options.SetUseAuxOrigin(True) self.plot_options.SetMirror(False) self.plot_options.SetExcludeEdgeLayer(True)
def __init__(self, board_file): self.name = os.path.splitext(os.path.basename(board_file))[0] self.board = pcbnew.LoadBoard(board_file) self.plot_controller = pcbnew.PLOT_CONTROLLER(self.board) self.plot_options = self.plot_controller.GetPlotOptions() self.plot_options.SetPlotFrameRef(False) self.plot_options.SetLineWidth(pcbnew.FromMM(0.35)) self.plot_options.SetScale(1) self.plot_options.SetUseAuxOrigin(True) self.plot_options.SetMirror(False) self.plot_options.SetExcludeEdgeLayer(False) self.plot_controller.SetColorMode(True)
def export_gerbers(self, layers=None, n_inner_layers=0): ''' layers: list of layer names to plot or n_inner_layers: number of inner layers to plot ''' if layers is None: l_names = ['Cu', 'Mask', 'Paste', 'SilkS'] layers = [f + ll for ll in l_names for f in ['F.', 'B.']] layers += ['Edge.Cuts'] layers += ['In{}.Cu'.format(i + 1) for i in range(n_inner_layers)] # ----------------------- # Generate Gerber files # ----------------------- pctl = pcbnew.PLOT_CONTROLLER(self.board) # General options popt = pctl.GetPlotOptions() popt.SetOutputDirectory(self.plot_dir) popt.SetPlotFrameRef(False) popt.SetPlotValue(True) popt.SetPlotReference(True) popt.SetPlotInvisibleText(False) popt.SetExcludeEdgeLayer(True) popt.SetPlotPadsOnSilkLayer(False) popt.SetPlotViaOnMaskLayer(False) popt.SetUseAuxOrigin(False) popt.SetDrillMarksType(popt.NO_DRILL_SHAPE) popt.SetScale(1.0) popt.SetLineWidth(pcbnew.FromMM(0.1)) # .1 mm popt.SetMirror(False) popt.SetNegative(False) # Gerber options popt.SetUseGerberProtelExtensions(False) popt.SetCreateGerberJobFile(False) popt.SetSubtractMaskFromSilk(False) popt.SetGerberPrecision(6) popt.SetUseGerberAttributes(False) popt.SetIncludeGerberNetlistInfo(False) f_name = self.f_name.replace('.kicad_pcb', '') for layer in layers: print('> {:s}-{:s}.gbr'.format(f_name, layer.replace('.', '_'))) pctl.SetLayer(self.board.GetLayerID(layer)) pctl.OpenPlotfile(layer, pcbnew.PLOT_FORMAT_GERBER, layer) pctl.PlotLayer() pctl.ClosePlot()
def plot(self, brd_file, target, invert, skip_pre): logger.debug("Starting plot of board {}".format(brd_file)) board = pcbnew.LoadBoard(brd_file) logger.debug("Board loaded") self._preflight_checks(brd_file, skip_pre) n = len(target) if n == 0 and invert: # Skip all targets logger.debug('Skipping all outputs') return for op in self.cfg.outputs: if (n == 0) or ((op.name in target) ^ invert): logger.debug("Processing output: {}".format(op.name)) logger.info('- %s (%s) [%s]' % (op.description, op.name, op.options.type)) # fresh plot controller pc = pcbnew.PLOT_CONTROLLER(board) self._configure_output_dir(pc, op) try: if self._output_is_layer(op): self._do_layer_plot(board, pc, op, brd_file) elif self._output_is_drill(op): self._do_drill_plot(board, pc, op) elif self._output_is_position(op): self._do_position_plot(board, pc, op) elif self._output_is_bom(op): self._do_bom(board, pc, op, brd_file) elif self._output_is_sch_print(op): self._do_sch_print(board, pc, op, brd_file) elif self._output_is_pcb_print(op): self._do_pcb_print(board, pc, op, brd_file) else: plot_error("Don't know how to plot type " + op.options.type) except PlotError as e: plot_error("In section '" + op.name + "' (" + op.options.type + "): " + str(e)) else: logger.debug('Skipping %s output', op.name)
def plotLayers( board, gerberDirPath, useAuxOrigin, gerberProtelExtensions, layerRenameRules, boardProjectName, ): targetLayerCount = board.GetCopperLayerCount() + 5 pc = pcbnew.PLOT_CONTROLLER(board) po = pc.GetPlotOptions() po.SetOutputDirectory(gerberDirPath) po.SetPlotValue(True) po.SetPlotReference(True) po.SetExcludeEdgeLayer(False) if hasattr(po, "SetLineWidth"): po.SetLineWidth(pcbnew.FromMM(0.1)) else: po.SetSketchPadLineWidth(pcbnew.FromMM(0.1)) po.SetSubtractMaskFromSilk(True) po.SetUseAuxOrigin(useAuxOrigin) po.SetUseGerberProtelExtensions(gerberProtelExtensions) plotFiles = [] for i in range(targetLayerCount): layerId = layers[i][0] layerTypeName = layers[i][1] pc.SetLayer(layerId) pc.OpenPlotfile(layerTypeName, pcbnew.PLOT_FORMAT_GERBER, layerTypeName) pc.PlotLayer() plotFiles.append(pc.GetPlotFileName()) pc.ClosePlot() if len(layerRenameRules) > 0: for i in range(targetLayerCount): plotFilePath = plotFiles[i] layerId = layers[i][0] if layerId in layerRenameRules: newFileName = layerRenameRules[layerId] newFileName = newFileName.replace('[boardProjectName]', boardProjectName) newFilePath = '%s/%s' % (gerberDirPath, newFileName) renameFile(plotFilePath, newFilePath)
def Run(self): # config = Config() pcb_file_name = pcbnew.GetBoard().GetFileName() if not pcb_file_name: ibom.logerror( 'Please save the board file before generating manufactoring data.' ) return print(pcb_file_name) board = pcbnew.LoadBoard(pcb_file_name) pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory("export/") # popt.SetOutputDirectory(sys.argv[2]) plot_pdf.generatePdf(pctl, popt) popt.SetMirror(False) rtlab.generateGerber(pctl, popt, board)
def plot_assembly_drawings(self, pcb, top_en, bottom_en): "plot assembly drawings" pctl = pcbnew.PLOT_CONTROLLER(pcb) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(self.pcb_assembly_path) # Set some important plot options: popt.SetPlotFrameRef(True) popt.SetLineWidth(pcbnew.FromMM(0.1)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetExcludeEdgeLayer(False) popt.SetPlotValue(False) popt.SetPlotReference(True) if (top_en): #Create a pdf file of the top fab Layer pctl.SetLayer(pcbnew.F_Fab) pctl.OpenPlotfile("Assembly_TOP", pcbnew.PLOT_FORMAT_PDF, "Assembly_TOP") pctl.PlotLayer() if (bottom_en): popt.SetMirror(True) #Create a pdf file of the bottom fab Layer pctl.SetLayer(pcbnew.B_Fab) pctl.OpenPlotfile("Assembly_BOTTOM", pcbnew.PLOT_FORMAT_PDF, "Assembly_BOTTOM") pctl.PlotLayer() pctl.ClosePlot()
def generate_gerber(name, output_dir): board = pcbnew.LoadBoard(name) pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() ########################################################################### # Output options plot_format = pcbnew.PLOT_FORMAT_GERBER popt.SetOutputDirectory(output_dir) ########################################################################### # Included Layers: layers = [ { 'layer': pcbnew.F_Cu, 'suffix': 'F.Cu' }, { 'layer': pcbnew.B_Cu, 'suffix': 'B.Cu' }, { 'layer': pcbnew.F_SilkS, 'suffix': 'F.SilkS' }, { 'layer': pcbnew.B_SilkS, 'suffix': 'B.SilkS' }, { 'layer': pcbnew.B_Paste, 'suffix': 'B.Paste' }, { 'layer': pcbnew.F_Paste, 'suffix': 'F.Paste' }, { 'layer': pcbnew.B_Mask, 'suffix': 'B.Mask' }, { 'layer': pcbnew.F_Mask, 'suffix': 'F.Mask' }, { 'layer': pcbnew.Edge_Cuts, 'suffix': 'Edge.Cuts' }, ] ########################################################################### # General Options: popt.SetPlotFrameRef(False) popt.SetPlotValue(True) popt.SetPlotReference(True) # popt.SetPlotInvisibleText(False) # popt.SetPlotViaOnMaskLayer(False) popt.SetExcludeEdgeLayer(True) popt.SetPlotPadsOnSilkLayer(False) popt.SetUseAuxOrigin(False) # popt.SetMirror(False) # popt.SetNegative(False) ########################################################################### popt.SetDrillMarksType(popt.NO_DRILL_SHAPE) popt.SetAutoScale(False) popt.SetScale(1) popt.SetPlotMode(pcbnew.FILLED) popt.SetLineWidth(pcbnew.FromMM(0.1)) ########################################################################### # Gerber Options: popt.SetUseGerberProtelExtensions(True) # popt.SetUseGerberAttributes(True) popt.SetCreateGerberJobFile(False) popt.SetSubtractMaskFromSilk(False) # popt.SetFormat() ########################################################################### # Generate files now for l in layers: pctl.SetLayer(l['layer']) # pctl.OpenPlotfile() pctl.OpenPlotfile(l['suffix'], pcbnew.PLOT_FORMAT_GERBER, l['layer']) print(l['suffix']) pctl.PlotLayer() pctl.ClosePlot()
def OnExec(self, e): try: self.settings = self.editor.Get() global zip_fname board = pcbnew.GetBoard() board_fname = board.GetFileName() board_dir = os.path.dirname(board_fname) board_basename = (os.path.splitext( os.path.basename(board_fname)))[0] gerber_dir = '%s/%s' % (board_dir, self.gerberdir.GetValue()) zip_fname = '%s/%s' % (gerber_dir, self.zipfilename.GetValue().replace( '*', board_basename)) if not os.path.exists(gerber_dir): os.mkdir(gerber_dir) refill(board) zipfiles = [] # PLOT message('PlotStart') pc = pcbnew.PLOT_CONTROLLER(board) po = pc.GetPlotOptions() po.SetOutputDirectory(gerber_dir) po.SetPlotFrameRef( self.settings.get('PlotBorderAndTitle', False)) po.SetPlotValue( self.settings.get('PlotFootprintValues', True)) po.SetPlotReference( self.settings.get('PlotFootprintReferences', True)) po.SetPlotInvisibleText( self.settings.get('ForcePlotInvisible', False)) po.SetExcludeEdgeLayer( self.settings.get('ExcludeEdgeLayer', True)) if hasattr(po, 'SetPlotPadsOnSilkLayer'): po.SetPlotPadsOnSilkLayer(not self.settings.get( 'ExcludePadsFromSilk', False)) po.SetPlotViaOnMaskLayer( self.settings.get('DoNotTentVias', False)) if hasattr(po, 'SetUseAuxOrigin'): po.SetUseAuxOrigin( self.settings.get('UseAuxOrigin', False)) if hasattr(po, 'SetLineWidth'): po.SetLineWidth( FromMM(float(self.settings.get('LineWidth')))) po.SetSubtractMaskFromSilk( self.settings.get('SubtractMaskFromSilk', True)) po.SetUseGerberX2format( self.settings.get('UseExtendedX2format', False)) po.SetIncludeGerberNetlistInfo( self.settings.get('IncludeNetlistInfo', False)) po.SetGerberPrecision(6 if self.settings.get( 'CoodinateFormat46', True) else 5) # SetDrillMarksType() : Draw Drill point to Cu layers if 1 (default) # But seems set to 0 in Plot Dialog po.SetDrillMarksType(0) layer = self.settings.get('Layers', {}) forcedel(zip_fname) for i in range(len(layer_list)): layer_list[i]['fname'] = '' for i in layer: fnam = layer[i] id = getid(i) if (len(fnam) > 0 and board.IsLayerEnabled(id)): pc.SetLayer(id) pc.OpenPlotfile(i, PLOT_FORMAT_GERBER, i) pc.PlotLayer() pc.ClosePlot() targetname = '%s/%s' % ( gerber_dir, fnam.replace('*', board_basename)) forcedel(targetname) forceren(pc.GetPlotFileName(), targetname) layer_list[getindex(i)]['fname'] = targetname zipfiles.append(targetname) message('Drill') # DRILL drill_fname = '' drill_map_fname = '' npth_fname = '' npth_map_fname = '' drill_report_fname = '' drill = self.settings.get('Drill', {}) fname = drill.get('Drill', '') if len(fname) > 0: drill_fname = '%s/%s' % ( gerber_dir, fname.replace('*', board_basename)) forcedel(drill_fname) fname = drill.get('DrillMap', '') if len(fname) > 0: drill_map_fname = '%s/%s' % ( gerber_dir, fname.replace('*', board_basename)) forcedel(drill_map_fname) fname = drill.get('NPTH', '') if len(fname) > 0: npth_fname = '%s/%s' % ( gerber_dir, fname.replace('*', board_basename)) forcedel(npth_fname) fname = drill.get('NPTHMap', '') if len(fname) > 0: npth_map_fname = '%s/%s' % ( gerber_dir, fname.replace('*', board_basename)) forcedel(npth_map_fname) fname = drill.get('Report', '') if len(fname) > 0: drill_report_fname = '%s/%s' % ( gerber_dir, fname.replace('*', board_basename)) forcedel(drill_report_fname) ew = EXCELLON_WRITER(board) excellon_format = EXCELLON_WRITER.DECIMAL_FORMAT zeros = self.settings.get('ZerosFormat') if zeros.get('SuppressLeading'): excellon_format = EXCELLON_WRITER.SUPPRESS_LEADING if zeros.get('SuppressTrailing'): excellon_format = EXCELLON_WRITER.SUPPRESS_TRAILING if zeros.get('KeepZeros'): excellon_format = EXCELLON_WRITER.KEEP_ZEROS ew.SetFormat(self.settings.get('DrillUnitMM', True), excellon_format, 3, 3) offset = wxPoint(0, 0) if self.settings.get('UseAuxOrigin', False): if hasattr(board, 'GetAuxOrigin'): offset = board.GetAuxOrigin() else: bds = board.GetDesignSettings() offset = bds.m_AuxOrigin ew.SetOptions(self.settings.get('MirrorYAxis', False), self.settings.get('MinimalHeader', False), offset, self.settings.get('MergePTHandNPTH', False)) ew.SetRouteModeForOvalHoles( self.settings.get('RouteModeForOvalHoles')) map_format = pcbnew.PLOT_FORMAT_GERBER map_ext = 'gbr' map = self.settings.get('MapFileFormat') if map.get('HPGL'): map_format = pcbnew.PLOT_FORMAT_HPGL map_ext = 'plt' if map.get('PostScript'): map_format = pcbnew.PLOT_FORMAT_POST map_ext = 'ps' if map.get('Gerber'): map_format = pcbnew.PLOT_FORMAT_GERBER map_ext = 'gbr' if map.get('DXF'): map_format = pcbnew.PLOT_FORMAT_DXF map_ext = 'dxf' if map.get('SVG'): map_format = pcbnew.PLOT_FORMAT_SVG map_ext = 'svg' if map.get('PDF'): map_format = pcbnew.PLOT_FORMAT_PDF map_ext = 'pdf' ew.SetMapFileFormat(map_format) enable_map = len(drill_map_fname) > 0 or len( npth_map_fname) > 0 message('MapFile') ew.CreateDrillandMapFilesSet(gerber_dir, True, enable_map) if self.settings.get('MergePTHandNPTH', False): if drill_fname: forceren( '%s/%s.drl' % (gerber_dir, board_basename), drill_fname) zipfiles.append(drill_fname) if drill_map_fname: forceren( '%s/%s-drl_map.%s' % (gerber_dir, board_basename, map_ext), drill_map_fname) zipfiles.append(drill_map_fname) else: if drill_fname: forceren( '%s/%s-PTH.drl' % (gerber_dir, board_basename), drill_fname) zipfiles.append(drill_fname) if drill_map_fname: forceren( '%s/%s-PTH-drl_map.%s' % (gerber_dir, board_basename, map_ext), drill_map_fname) zipfiles.append(drill_map_fname) if npth_fname: forceren( '%s/%s-NPTH.drl' % (gerber_dir, board_basename), npth_fname) zipfiles.append(npth_fname) if npth_map_fname: forceren( '%s/%s-NPTH-drl_map.gbr' % (gerber_dir, board_basename), npth_map_fname) zipfiles.append(npth_map_fname) if drill_report_fname: ew.GenDrillReportFile(drill_report_fname) zipfiles.append(drill_report_fname) # OptionalFile message('optional') files = self.settings.get('OptionalFiles', []) for n in range(len(files)): if (len(files[n]['name'])): optional_fname = '%s/%s' % (gerber_dir, files[n]['name']) optional_content = files[n]['content'] optional_content = optional_content.replace( '${basename}', board_basename) for i in range(len(layer_list)): kpath = '${filepath(' + layer_list[i][ 'name'] + ')}' kname = '${filename(' + layer_list[i][ 'name'] + ')}' path = layer_list[i]['fname'] name = os.path.basename(path) optional_content = optional_content.replace( kname, name) if optional_fname: with codecs.open(optional_fname, 'w', 'utf-8') as f: f.write(optional_content) zipfiles.append(optional_fname) # ZIP message('Zip') with zipfile.ZipFile( zip_fname, 'w', compression=zipfile.ZIP_DEFLATED) as f: for i in range(len(zipfiles)): fnam = zipfiles[i] if os.path.exists(fnam): f.write(fnam, os.path.basename(fnam)) alert(getstr('COMPLETE') % zip_fname, wx.ICON_INFORMATION) except Exception: s = traceback.format_exc(chain=False) print(s) alert(s, wx.ICON_ERROR) e.Skip()
#!/usr/bin/env python3 import sys # from pcbnew import * import pcbnew import plot_pdf import rtlab # http://scottbezek.blogspot.com/2016/04/scripting-kicad-pcbnew-exports.html filename = sys.argv[1] #e.g left-main/left-main.kicad_pcb board = pcbnew.LoadBoard(filename) pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() # popt.SetOutputDirectory("plot/") popt.SetOutputDirectory(sys.argv[2]) plot_pdf.generatePdf(pctl, popt) popt.SetMirror(False) rtlab.generateGerber(pctl, popt, board)
def screenshot(self): print("Taking a screenshot") self.board = pcbnew.GetBoard() board_path = self.board.GetFileName() board_filename = os.path.basename(board_path) board_filename_noex = os.path.splitext(board_filename)[0] project_folder = os.path.dirname(board_path) timelapse_folder = board_filename_noex + '-timelapse' timelapse_folder_path = os.path.join(project_folder, timelapse_folder) if not os.path.exists(timelapse_folder_path): print('Timelapse folder does not exist. creating one now') os.mkdir(timelapse_folder_path) print('Timelapse folder created') timelapse_files = os.listdir(timelapse_folder_path) timelapse_number = extract_biggest_number(timelapse_files) pc = pcbnew.PLOT_CONTROLLER(self.board) po = pc.GetPlotOptions() po.SetOutputDirectory(timelapse_folder_path) po.SetPlotFrameRef(False) po.SetLineWidth(pcbnew.FromMM(0.35)) po.SetScale(1) po.SetUseAuxOrigin(True) po.SetMirror(False) po.SetExcludeEdgeLayer(True) # Set current layer # Plot single layer to file timelapse_number += 1 processed_svg_files = [] for layer in layers: pc.SetLayer(layer['layer']) layer['layer'] pc.OpenPlotfile( '-' + layer['name'] + '-' + str(timelapse_number).zfill(4), pcbnew.PLOT_FORMAT_SVG, layer['name']) pc.PlotLayer() pc.ClosePlot() output_filename = pc.GetPlotFileName() processor = SvgProcessor(output_filename) def colorize(original): if original.lower() == '#000000': return layer['color'] return original processor.apply_color_transform(colorize) processor.wrap_with_group({ 'opacity': str(layer['alpha']), }) output_filename2 = os.path.join( timelapse_folder_path, 'processed-' + os.path.basename(output_filename)) processor.write(output_filename2) processed_svg_files.append((output_filename2, processor)) os.remove(output_filename) final_svg = os.path.join( timelapse_folder_path, board_filename_noex + '-' + str(timelapse_number).zfill(4) + '.svg') shutil.copyfile(processed_svg_files[0][0], final_svg) output_processor = SvgProcessor(final_svg) for processed_svg_file, processor in processed_svg_files: output_processor.import_groups(processor) os.remove(processed_svg_file) output_processor.write(final_svg)
def convert(pcb, dir): board = pcb plotDir = os.path.abspath(dir) # prepare the gerber job file gen_job_file = False pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetOutputDirectory(plotDir) # Set some important plot options (see pcb_plot_params.h): popt.SetPlotFrameRef(False) # do not change it popt.SetLineWidth(pcbnew.FromMM(0.35)) popt.SetAutoScale(False) # do not change it popt.SetScale(1) # do not change it popt.SetMirror(False) popt.SetUseGerberAttributes(True) popt.SetIncludeGerberNetlistInfo(True) popt.SetCreateGerberJobFile(gen_job_file) popt.SetUseGerberProtelExtensions(False) popt.SetExcludeEdgeLayer(False) popt.SetScale(1) popt.SetUseAuxOrigin(True) # This by gerbers only popt.SetSubtractMaskFromSilk(False) # Disable plot pad holes popt.SetDrillMarksType(pcbnew.PCB_PLOT_PARAMS.NO_DRILL_SHAPE) # Skip plot pad NPTH when possible: when drill size and shape == pad size and shape # usually sel to True for copper layers popt.SetSkipPlotNPTH_Pads(False) # prepare the gerber job file jobfile_writer = pcbnew.GERBER_JOBFILE_WRITER(board) # Once the defaults are set it become pretty easy... # I have a Turing-complete programming language here: I'll use it... # param 0 is a string added to the file base name to identify the drawing # param 1 is the layer ID # param 2 is a comment plot_plan = [ ("F_Cu", pcbnew.F_Cu, "Top layer"), ("B_Cu", pcbnew.B_Cu, "Bottom layer"), ("B_Paste", pcbnew.B_Paste, "Paste Bottom"), ("F_Paste", pcbnew.F_Paste, "Paste top"), ("F_SilkS", pcbnew.F_SilkS, "Silk top"), ("B_SilkS", pcbnew.B_SilkS, "Silk top"), ("B_Mask", pcbnew.B_Mask, "Mask bottom"), ("F_Mask", pcbnew.F_Mask, "Mask top"), ("Edge_Cuts", pcbnew.Edge_Cuts, "Edges"), ] for layer_info in plot_plan: if layer_info[1] <= pcbnew.B_Cu: popt.SetSkipPlotNPTH_Pads(True) else: popt.SetSkipPlotNPTH_Pads(False) pctl.SetLayer(layer_info[1]) pctl.OpenPlotfile(layer_info[0], pcbnew.PLOT_FORMAT_GERBER, layer_info[2]) print 'plot %s' % pctl.GetPlotFileName() if gen_job_file == True: jobfile_writer.AddGbrFile(layer_info[1], os.path.basename(pctl.GetPlotFileName())) if pctl.PlotLayer() == False: print "plot error" # generate internal copper layers, if any lyrcnt = board.GetCopperLayerCount() for innerlyr in range(1, lyrcnt - 1): popt.SetSkipPlotNPTH_Pads(True) pctl.SetLayer(innerlyr) lyrname = 'In%s_Cu' % innerlyr pctl.OpenPlotfile(lyrname, pcbnew.PLOT_FORMAT_GERBER, "inner") print 'plot %s' % pctl.GetPlotFileName() if pctl.PlotLayer() == False: print "plot error" # At the end you have to close the last plot, otherwise you don't know when # the object will be recycled! pctl.ClosePlot() # Fabricators need drill files. # sometimes a drill map file is asked (for verification purpose) drlwriter = pcbnew.EXCELLON_WRITER(board) drlwriter.SetMapFileFormat(pcbnew.PLOT_FORMAT_PDF) mirror = False minimalHeader = False offset = pcbnew.wxPoint(0, 0) # False to generate 2 separate drill files (one for plated holes, one for non plated holes) # True to generate only one drill file mergeNPTH = True drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH) metricFmt = True drlwriter.SetFormat(metricFmt) genDrl = True genMap = True print 'create drill and map files in %s' % pctl.GetPlotDirName() drlwriter.CreateDrillandMapFilesSet(pctl.GetPlotDirName(), genDrl, genMap)
def main(): if len(sys.argv) <= 1 or len(sys.argv) >= 3: print("Usage: " + sys.argv[0] + " <project name>") exit(1) cwd = os.getcwd() projectname = sys.argv[1] board = pcbnew.LoadBoard(cwd + "/" + projectname + ".kicad_pcb") pc = pcbnew.PLOT_CONTROLLER(board) po = pc.GetPlotOptions() # Set General Options: po.SetOutputDirectory(cwd) po.SetPlotFrameRef(False) po.SetPlotValue(True) po.SetPlotReference(True) po.SetPlotInvisibleText(False) po.SetPlotViaOnMaskLayer(True) po.SetExcludeEdgeLayer(False) #po.SetPlotPadsOnSilkLayer(PLOT_PADS_ON_SILK_LAYER) #po.SetUseAuxOrigin(PLOT_USE_AUX_ORIGIN) po.SetMirror(False) #po.SetNegative(PLOT_NEGATIVE) #po.SetDrillMarksType(PLOT_DRILL_MARKS_TYPE) #po.SetScale(PLOT_SCALE) po.SetAutoScale(True) #po.SetPlotMode(PLOT_MODE) #po.SetLineWidth(pcbnew.FromMM(PLOT_LINE_WIDTH)) # Set Gerber Options #po.SetUseGerberAttributes(GERBER_USE_GERBER_ATTRIBUTES) #po.SetUseGerberProtelExtensions(GERBER_USE_GERBER_PROTEL_EXTENSIONS) #po.SetCreateGerberJobFile(GERBER_CREATE_GERBER_JOB_FILE) #po.SetSubtractMaskFromSilk(GERBER_SUBTRACT_MASK_FROM_SILK) #po.SetIncludeGerberNetlistInfo(GERBER_INCLUDE_GERBER_NETLIST_INFO) # plot layers dict_layerInfo = ({ "F_Cu": pcbnew.F_Cu, "F_Mask": pcbnew.F_Mask, "F_Paste": pcbnew.F_Paste, "F_SilkS": pcbnew.F_SilkS, "B_Cu": pcbnew.B_Cu, "B_Mask": pcbnew.B_Mask, "B_Paste": pcbnew.B_Paste, "B_SilkS": pcbnew.B_SilkS, "Edge_Cuts": pcbnew.Edge_Cuts, "Eco1_User": pcbnew.Eco1_User, "Eco2_User": pcbnew.Eco2_User }) for key in dict_layerInfo : val = dict_layerInfo[key] pc.SetLayer(val) sheetDesc = key if val not in [ pcbnew.Edge_Cuts, pcbnew.Eco1_User, pcbnew.Eco2_User ]: sheetDesc = sheetDesc.replace("F_", "Front ").replace("B_", "Back ") + " Layer" pc.OpenPlotfile(key, pcbnew.PLOT_FORMAT_GERBER, sheetDesc) pc.PlotLayer() pc.ClosePlot() # generate drill file # options: METRIC = True ZERO_FORMAT = pcbnew.GENDRILL_WRITER_BASE.DECIMAL_FORMAT INTEGER_DIGITS = 3 MANTISSA_DIGITS = 3 MIRROR_Y_AXIS = False HEADER = True OFFSET = pcbnew.wxPoint(0,0) MERGE_PTH_NPTH = False DRILL_FILE = True MAP_FILE = False REPORTER = None drill_writer = pcbnew.EXCELLON_WRITER(board) drill_writer.SetFormat(METRIC, ZERO_FORMAT, INTEGER_DIGITS, MANTISSA_DIGITS) drill_writer.SetOptions(MIRROR_Y_AXIS, HEADER, OFFSET, MERGE_PTH_NPTH) drill_writer.CreateDrillandMapFilesSet(cwd, DRILL_FILE, MAP_FILE, REPORTER)
def main(args): # kicad helpfully avoids simply writing to named files # and mangles everything based on the name of the input # file. :( # hope this never changes... basename, _junk = os.path.splitext(os.path.basename(args.pcb)) board = pcb.LoadBoard(args.pcb) pctrl = pcb.PLOT_CONTROLLER(board) popt = pctrl.GetPlotOptions() # Default options popt.SetPlotFrameRef(False) popt.SetLineWidth(pcb.FromMM(0.35)) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetUseGerberAttributes(True) popt.SetUseGerberProtelExtensions(False) popt.SetExcludeEdgeLayer(False) popt.SetScale(1) popt.SetUseAuxOrigin(True) popt.SetSubtractMaskFromSilk(False) # layers are number from front F_Cu==0, B_Cu==31 # inner layers are 1..30 # count includes B_Cu ncu = board.GetCopperLayerCount() log.info("Design has %d Cu layers", ncu) if ncu == 1: log.warn("Not tested w/ single layer board") assert ncu >= 1, "No Cu layers?" with TempDir() as dname, ZipFile(args.gbrzip, mode='w') as zip: popt.SetOutputDirectory(dname) generated = [] for ext, layer, desc in oshnames: if layer >= ncu - 1 and layer < pcb.B_Cu: log.info("No %s", desc) continue # skip unused inner pctrl.SetLayer(layer) pctrl.OpenPlotfile(ext, pcb.PLOT_FORMAT_GERBER, desc) if not pctrl.PlotLayer(): log.error("Failed to write layer %s", desc) generated.append((os.path.join(dname, "%s-%s.gbr" % (basename, ext)), '%s.%s' % (basename, ext))) pctrl.ClosePlot() # files actually generated at this point for inf, outf in generated: zip.write(inf, outf) drill = pcb.EXCELLON_WRITER(board) drill.SetMapFileFormat(pcb.PLOT_FORMAT_GERBER) mirror = False minimalHeader = False offset = pcb.wxPoint(0, 0) merge = True drill.SetOptions(mirror, minimalHeader, offset, merge) metricFmt = True drill.SetFormat(metricFmt) # can't use drlwriter.CreateDrillFile() # as this wants swig wrapped FILE* # and I can't see how to create one (can't just use ctypes) genDrl = True genMap = True drill.CreateDrillandMapFilesSet(dname, genDrl, genMap) zip.write(os.path.join(dname, "%s.drl" % basename), "%s.XLN" % basename) zip.write(os.path.join(dname, "%s-drl_map.gbr" % basename), "%s.fab.gbr" % basename)
def main(): # load command-line arguments parser = argparse.ArgumentParser() parser.add_argument('--pcb') parser.add_argument('--plot') args = parser.parse_args() # load board board = pcbnew.LoadBoard(args.pcb) # get plot options pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() # set up output directory plotDir = args.plot + '/' popt.SetOutputDirectory(plotDir) # Set plot options according to: # http://docs.oshpark.com/design-tools/kicad/generating-kicad-gerbers/ # Options popt.SetPlotFrameRef(False) popt.SetPlotPadsOnSilkLayer(False) popt.SetPlotValue(True) popt.SetPlotReference(True) popt.SetPlotInvisibleText(False) popt.SetPlotViaOnMaskLayer(True) popt.SetExcludeEdgeLayer(True) popt.SetMirror(False) popt.SetNegative(False) popt.SetUseAuxOrigin(False) popt.SetDrillMarksType(pcbnew.PCB_PLOT_PARAMS.NO_DRILL_SHAPE) popt.SetAutoScale(False) popt.SetScale(1) # TODO: Plot mode = filled popt.SetLineWidth(pcbnew.FromMM(0.1)) # Gerber options popt.SetUseGerberProtelExtensions(True) popt.SetUseGerberAttributes(False) popt.SetSubtractMaskFromSilk(False) popt.SetGerberPrecision(6) # Layers to be plotted plot_plan = [ ("CuTop", pcbnew.F_Cu, "Top layer"), ("CuBottom", pcbnew.B_Cu, "Bottom layer"), ("EdgeCuts", pcbnew.Edge_Cuts, "Edges")] # Plot the layers for layer_info in plot_plan: pctl.SetLayer(layer_info[1]) pctl.OpenPlotfile(layer_info[0], pcbnew.PLOT_FORMAT_GERBER, layer_info[2]) fullname = pctl.GetPlotFileName() basename = os.path.basename(fullname) print 'Plotting %s' % basename if not pctl.PlotLayer(): raise Exception('Plotting error.') # Done with plotting gerbers pctl.ClosePlot() drlwriter = pcbnew.EXCELLON_WRITER(board) # Set Excellon format according to: # http://docs.oshpark.com/design-tools/kicad/generating-kicad-gerbers/ # Drill units, zeros format metricFmt = False zerosFmt = pcbnew.EXCELLON_WRITER.DECIMAL_FORMAT drlwriter.SetFormat(metricFmt, zerosFmt) # Drill map format drlwriter.SetMapFileFormat(pcbnew.PLOT_FORMAT_POST) # Drill file options mirror = False minimalHeader = False mergeNPTH = True offset = pcbnew.wxPoint(0, 0) drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH) genDrl = True genMap = False pctl.GetPlotDirName() print 'Creating drill file.' drlwriter.CreateDrillandMapFilesSet(plotDir, genDrl, genMap)
def kicad_file_to_gerber_archive_file(input_path, output_path): board = pcbnew.LoadBoard(input_path) pctl = pcbnew.PLOT_CONTROLLER(board) popt = pctl.GetPlotOptions() popt.SetPlotFrameRef(False) popt.SetAutoScale(False) popt.SetScale(1) popt.SetMirror(False) popt.SetUseGerberAttributes(False) popt.SetExcludeEdgeLayer(True) popt.SetScale(1) popt.SetUseAuxOrigin(True) popt.SetNegative(False) popt.SetPlotReference(True) popt.SetPlotValue(True) popt.SetPlotInvisibleText(False) popt.SetSubtractMaskFromSilk(True) popt.SetMirror(False) popt.SetDrillMarksType(pcbnew.PCB_PLOT_PARAMS.NO_DRILL_SHAPE) # TODO(kleinpa): Will JLCPCB accept file without this set? popt.SetUseGerberProtelExtensions(True) plot_plan = [("F_Cu", pcbnew.F_Cu, "Top layer"), ("B_Cu", pcbnew.B_Cu, "Bottom layer"), ("B_Mask", pcbnew.B_Mask, "Mask Bottom"), ("F_Mask", pcbnew.F_Mask, "Mask top"), ("B_Paste", pcbnew.B_Paste, "Paste Bottom"), ("F_Paste", pcbnew.F_Paste, "Paste Top"), ("F_SilkS", pcbnew.F_SilkS, "Silk Top"), ("B_SilkS", pcbnew.B_SilkS, "Silk Bottom"), ("Edge_Cuts", pcbnew.Edge_Cuts, "Edges")] for layer in range(1, board.GetCopperLayerCount() - 1): plot_plan += (f"inner{layer}", layer, "inner") with tempfile.TemporaryDirectory() as temp_path: popt.SetOutputDirectory(temp_path) # Plot layers for suffix, layer, description in plot_plan: pctl.SetLayer(layer) pctl.OpenPlotfile(suffix, pcbnew.PLOT_FORMAT_GERBER, description) pctl.PlotLayer() pctl.ClosePlot() # Generate drill file drlwriter = pcbnew.EXCELLON_WRITER(board) drlwriter.SetMapFileFormat(aMapFmt=pcbnew.PLOT_FORMAT_GERBER) drlwriter.SetOptions(aMirror=False, aMinimalHeader=False, aOffset=pcbnew.wxPoint(0, 0), aMerge_PTH_NPTH=True) formatMetric = True drlwriter.SetFormat(formatMetric) drlwriter.CreateDrillandMapFilesSet(aPlotDirectory=temp_path, aGenDrill=True, aGenMap=False) # Copy files from output directory to in-memory zip file fp = io.BytesIO() with zipfile.ZipFile(output_path, 'w', zipfile.ZIP_DEFLATED) as z: for root, dirs, files in os.walk(temp_path): for file in files: z.write( os.path.join(root, file), # TODO(kleinpa): Required for JLCPCB, any alternative? file.replace("gm1", "gko")) fp.seek(0) return fp