From 1507300fe41bf48b4d556a3b03f63654fdb7b15d Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Mon, 11 Apr 2022 19:02:26 -0300 Subject: [PATCH] Added option to generate a better frame on pcb_print (KiCad 6) - Also documented more details about pcb_print. --- README.md | 10 ++++- docs/README.in | 1 + docs/samples/generic_plot.kibot.yaml | 10 ++++- kibot/out_pcb_print.py | 58 ++++++++++++++++++------- kibot/out_pdf_pcb_print.py | 3 +- kibot/out_svg_pcb_print.py | 3 +- tests/yaml_samples/pcb_print.kibot.yaml | 3 +- 7 files changed, 67 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 29980d0f..3033e64f 100644 --- a/README.md +++ b/README.md @@ -645,6 +645,7 @@ The available values for *type* are: - `svg_sch_print` schematic in SVG format - `pdf_pcb_print` PDF file containing one or more layer and the page frame - `svg_pcb_print` SVG file containing one or more layer and the page frame + - `pcb_print` PDF/SVG, similar to `pdf_pcb_print` and `svg_pcb_print`, with more flexibility - `report` generates a report about the PDF. Can include images from the above outputs. - Bill of Materials - `bom` The internal BoM generator. @@ -1519,7 +1520,9 @@ Next time you need this list just use an alias, like this: * PCB Print * Type: `pcb_print` - * Description: Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print`. + * Description: Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print` and `svg_pcb_print`. + KiCad 5: including the frame is slow. + KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. * Valid keys: - `comment`: [string=''] A comment for documentation purposes. - `dir`: [string='./'] Output directory for the generated files. If it starts with `+` the rest is concatenated to the default dir. @@ -1536,6 +1539,9 @@ Next time you need this list just use an alias, like this: - `dnf_filter`: [string|list(string)='_none'] Name of the filter to mark components as not fitted. A short-cut to use for simple cases where a variant is an overkill. - `drill_marks`: [string='full'] What to use to indicate the drill places, can be none, small or full (for real scale). + - `enable_ki6_frame_fix`: [boolean=false] KiCad 6 doesn't support custom title-block/frames from Python. + This option uses KiCad GUI to print the frame, is slow, but works. + Always enabled for KiCad 5, which crashes if we try to plot the frame. - `format`: [string='PDF'] [PDF,SVG] Format for the output file/s. - `hide_excluded`: [boolean=false] Hide components in the Fab layer that are marked as excluded by a variant. - `output`: [string='%f-%i%I%v.%x'] Filename for the output (%i=assembly, %x=pdf)/(%i=assembly_page_NN, %x=svg). Affected by global options. @@ -1695,6 +1701,7 @@ Next time you need this list just use an alias, like this: * Description: Exports the PCB to the most common exchange format. Suitable for printing. This is the main format to document your PCB. This output is what you get from the 'File/Print' menu in pcbnew. + The `pcb_print` is an alternative. * Valid keys: - `comment`: [string=''] A comment for documentation purposes. - `dir`: [string='./'] Output directory for the generated files. If it starts with `+` the rest is concatenated to the default dir. @@ -2096,6 +2103,7 @@ Next time you need this list just use an alias, like this: * Type: `svg_pcb_print` * Description: Exports the PCB to the scalable vector graphics format. This output is what you get from the 'File/Print' menu in pcbnew. + The `pcb_print` is an alternative. * Valid keys: - `comment`: [string=''] A comment for documentation purposes. - `dir`: [string='./'] Output directory for the generated files. If it starts with `+` the rest is concatenated to the default dir. diff --git a/docs/README.in b/docs/README.in index 4e096924..ff3cfae0 100644 --- a/docs/README.in +++ b/docs/README.in @@ -438,6 +438,7 @@ The available values for *type* are: - `svg_sch_print` schematic in SVG format - `pdf_pcb_print` PDF file containing one or more layer and the page frame - `svg_pcb_print` SVG file containing one or more layer and the page frame + - `pcb_print` PDF/SVG, similar to `pdf_pcb_print` and `svg_pcb_print`, with more flexibility - `report` generates a report about the PDF. Can include images from the above outputs. - Bill of Materials - `bom` The internal BoM generator. diff --git a/docs/samples/generic_plot.kibot.yaml b/docs/samples/generic_plot.kibot.yaml index 7b6375ab..746f2b18 100644 --- a/docs/samples/generic_plot.kibot.yaml +++ b/docs/samples/generic_plot.kibot.yaml @@ -952,8 +952,10 @@ outputs: # Don't use the `kicost_variant` when using internal variants/filters variant: '' # PCB Print: + # KiCad 5: including the frame is slow. + # KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. - name: 'pcb_print_example' - comment: 'Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print`.' + comment: 'Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print` and `svg_pcb_print`.' type: 'pcb_print' dir: 'Example/pcb_print_dir' options: @@ -966,6 +968,10 @@ outputs: dnf_filter: '_none' # [string='full'] What to use to indicate the drill places, can be none, small or full (for real scale) drill_marks: 'full' + # [boolean=false] KiCad 6 doesn't support custom title-block/frames from Python. + # This option uses KiCad GUI to print the frame, is slow, but works. + # Always enabled for KiCad 5, which crashes if we try to plot the frame + enable_ki6_frame_fix: false # [string='PDF'] [PDF,SVG] Format for the output file/s format: 'PDF' # [boolean=false] Hide components in the Fab layer that are marked as excluded by a variant @@ -1142,6 +1148,7 @@ outputs: # PDF PCB Print (Portable Document Format): # This is the main format to document your PCB. # This output is what you get from the 'File/Print' menu in pcbnew. + # The `pcb_print` is an alternative. - name: 'pdf_pcb_print_example' comment: 'Exports the PCB to the most common exchange format. Suitable for printing.' type: 'pdf_pcb_print' @@ -1554,6 +1561,7 @@ outputs: layers: all # SVG PCB Print (Scalable Vector Graphics): # This output is what you get from the 'File/Print' menu in pcbnew. + # The `pcb_print` is an alternative. - name: 'svg_pcb_print_example' comment: 'Exports the PCB to the scalable vector graphics format.' type: 'svg_pcb_print' diff --git a/kibot/out_pcb_print.py b/kibot/out_pcb_print.py index 4f7320e7..c850363f 100644 --- a/kibot/out_pcb_print.py +++ b/kibot/out_pcb_print.py @@ -71,23 +71,40 @@ def load_svg(file, color, black_holes, monochrome): if black_holes: content = content.replace('#FFFFFF', '**black_hole**') if color != '#000000': + # Files plotted content = content.replace('#000000', color) + # Files generated by "Print" + content = content.replace('stroke:rgb(0%,0%,0%)', 'stroke:'+color) if black_holes: content = content.replace('**black_hole**', '#000000') return content +def get_width(svg): + """ Finds the width in viewBox units """ + return float(svg.root.get('viewBox').split(' ')[2]) + + def merge_svg(input_folder, input_files, output_folder, output_file, black_holes, monochrome): """ Merge all pages into one """ first = True for (file, color) in input_files: file = os.path.join(input_folder, file) new_layer = fromstring(load_svg(file, color, black_holes, monochrome)) + width = get_width(new_layer) if first: svg_out = new_layer + # This is the width declared at the beginning of the file + base_width = width first = False else: root = new_layer.getroot() + # Adjust the coordinates of this section to the main width + scale = base_width/width + if scale != 1.0: + logger.debug(' - Scaling {} by {}'.format(file, scale)) + for e in root: + e.scale(scale) root.moveto(1, 1) svg_out.append([root]) svg_out.save(os.path.join(output_folder, output_file)) @@ -230,6 +247,10 @@ class PCB_PrintOptions(VariantOptions): Usually user colors are stored as `user`, but you can give it another name """ self.plot_sheet_reference = True """ Include the title-block """ + self.enable_ki6_frame_fix = False + """ KiCad 6 doesn't support custom title-block/frames from Python. + This option uses KiCad GUI to print the frame, is slow, but works. + Always enabled for KiCad 5, which crashes if we try to plot the frame """ self.pages = PagesOptions """ [list(dict)] List of pages to include in the output document. Each page contains one or more layers of the PCB """ @@ -291,38 +312,38 @@ class PCB_PrintOptions(VariantOptions): def get_targets(self, out_dir): return [self._parent.expand_filename(out_dir, self.output)] - def clear_edge_cuts(self): + def clear_layer(self, layer): tmp_layer = GS.board.GetLayerID(GS.work_layer) - edge = GS.board.GetLayerID('Edge.Cuts') + cleared_layer = GS.board.GetLayerID(layer) moved = [] for g in GS.board.GetDrawings(): - if g.GetLayer() == edge: + if g.GetLayer() == cleared_layer: g.SetLayer(tmp_layer) moved.append(g) for m in GS.get_modules(): for gi in m.GraphicalItems(): - if gi.GetLayer() == edge: + if gi.GetLayer() == cleared_layer: gi.SetLayer(tmp_layer) moved.append(gi) self.moved_items = moved - self.edge_layer = edge + self.cleared_layer = cleared_layer - def restore_edge_cuts(self): + def restore_layer(self): for g in self.moved_items: - g.SetLayer(self.edge_layer) + g.SetLayer(self.cleared_layer) def plot_frame_ki6(self, pc, po, p): """ KiCad 6 can plot the frame because it loads the worksheet format """ - self.clear_edge_cuts() + self.clear_layer('Edge.Cuts') po.SetPlotFrameRef(True) po.SetScale(1.0) po.SetNegative(False) pc.SetLayer(self.edge_layer) pc.OpenPlotfile('frame', PLOT_FORMAT_SVG, p.sheet) pc.PlotLayer() - self.restore_edge_cuts() + self.restore_layer() - def plot_frame_ki5(self, dir_name): + def plot_frame_ki5(self, dir_name, layer='Edge.Cuts'): """ KiCad 5 crashes if we try to print the frame. So we print a frame using pcbnew_do export. We use SVG output to then generate a vectorized PDF. """ @@ -330,14 +351,14 @@ class PCB_PrintOptions(VariantOptions): check_script(CMD_PCBNEW_PRINT_LAYERS, URL_PCBNEW_PRINT_LAYERS, '1.6.7') # Move all the drawings away # KiCad 5 always prints Edge.Cuts, so we make it empty - self.clear_edge_cuts() + self.clear_layer(layer) # Save the PCB pcb_name, pcb_dir = self.save_tmp_dir_board('pcb_print') # Restore the layer - self.restore_edge_cuts() + self.restore_layer() # Output file name - cmd = [CMD_PCBNEW_PRINT_LAYERS, 'export', '--output_name', output, '--monochrome', '--svg', - pcb_name, dir_name, 'Edge.Cuts'] + cmd = [CMD_PCBNEW_PRINT_LAYERS, 'export', '--output_name', output, '--monochrome', '--svg', '--pads', '0', + pcb_name, dir_name, layer] cmd, video_remove = add_extra_options(cmd) # Execute it ret = exec_with_retry(cmd) @@ -398,7 +419,10 @@ class PCB_PrintOptions(VariantOptions): if self.plot_sheet_reference: logger.debug('- Plotting the frame') if GS.ki6(): - self.plot_frame_ki6(pc, po, p) + if self.enable_ki6_frame_fix: + self.plot_frame_ki5(temp_dir) + else: + self.plot_frame_ki6(pc, po, p) else: self.plot_frame_ki5(temp_dir) color = p.sheet_reference_color if p.sheet_reference_color else self._color_theme.pcb_frame @@ -431,7 +455,9 @@ class PCB_PrintOptions(VariantOptions): @output_class class PCB_Print(BaseOutput): # noqa: F821 """ PCB Print - Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print`. """ + Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print` and `svg_pcb_print`. + KiCad 5: including the frame is slow. + KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. """ def __init__(self): super().__init__() with document: diff --git a/kibot/out_pdf_pcb_print.py b/kibot/out_pdf_pcb_print.py index 21955adf..37bb198f 100644 --- a/kibot/out_pdf_pcb_print.py +++ b/kibot/out_pdf_pcb_print.py @@ -27,7 +27,8 @@ class PDF_PCB_Print(BaseOutput): # noqa: F821 """ PDF PCB Print (Portable Document Format) Exports the PCB to the most common exchange format. Suitable for printing. This is the main format to document your PCB. - This output is what you get from the 'File/Print' menu in pcbnew. """ + This output is what you get from the 'File/Print' menu in pcbnew. + The `pcb_print` is an alternative. """ def __init__(self): super().__init__() with document: diff --git a/kibot/out_svg_pcb_print.py b/kibot/out_svg_pcb_print.py index 60957aa5..3a800dda 100644 --- a/kibot/out_svg_pcb_print.py +++ b/kibot/out_svg_pcb_print.py @@ -41,7 +41,8 @@ class SVG_PCB_PrintOptions(Any_PCB_PrintOptions): class SVG_PCB_Print(BaseOutput): # noqa: F821 """ SVG PCB Print (Scalable Vector Graphics) Exports the PCB to the scalable vector graphics format. - This output is what you get from the 'File/Print' menu in pcbnew. """ + This output is what you get from the 'File/Print' menu in pcbnew. + The `pcb_print` is an alternative. """ def __init__(self): super().__init__() with document: diff --git a/tests/yaml_samples/pcb_print.kibot.yaml b/tests/yaml_samples/pcb_print.kibot.yaml index 9526c7e9..bc1eb06c 100644 --- a/tests/yaml_samples/pcb_print.kibot.yaml +++ b/tests/yaml_samples/pcb_print.kibot.yaml @@ -13,7 +13,8 @@ outputs: # drill_marks: small title: Chau # plot_sheet_reference: false - format: 'SVG' + # format: 'SVG' + enable_ki6_frame_fix: true pages: - # monochrome: true scaling: 2.0