From b7b9b70ac362ef89cc5fd6cb77bd4d9d2a66a07d Mon Sep 17 00:00:00 2001 From: "Salvador E. Tropea" Date: Tue, 12 Apr 2022 15:43:53 -0300 Subject: [PATCH] Added PNG, EPS and PS outputs to pcb_print. --- README.md | 7 ++- debian/control | 2 +- docs/README.in | 2 +- docs/samples/generic_plot.kibot.yaml | 6 ++- kibot/out_pcb_print.py | 72 +++++++++++++++++++++---- tests/yaml_samples/pcb_print.kibot.yaml | 4 +- 6 files changed, 75 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e868227b..66c1a801 100644 --- a/README.md +++ b/README.md @@ -646,7 +646,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 + - `pcb_print` PDF/SVG/PNG/EPS/PS, 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. @@ -1522,6 +1522,7 @@ 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` and `svg_pcb_print`. + Supports PDF, SVG, PNG, EPS and PS formats. KiCad 5: including the frame is slow. KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. * Valid keys: @@ -1543,7 +1544,8 @@ Next time you need this list just use an alias, like this: - `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. + - `format`: [string='PDF'] [PDF,SVG,PNG,EPS,PS] Format for the output file/s. + Note that for PS you need `ghostscript` which isn't part of the default docker images. - `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. - *output_name*: Alias for output. @@ -1573,6 +1575,7 @@ Next time you need this list just use an alias, like this: - `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. If it starts with `+` the text is concatenated. - `plot_sheet_reference`: [boolean=true] Include the title-block. + - `png_width`: [number=1280] Width of the PNG in pixels. - `title`: [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. If it starts with `+` the text is concatenated. - `variant`: [string=''] Board variant to apply. diff --git a/debian/control b/debian/control index e4d831c5..9f2dfe33 100644 --- a/debian/control +++ b/debian/control @@ -12,7 +12,7 @@ Architecture: all Multi-Arch: foreign Depends: ${misc:Depends}, ${python3:Depends}, python3-distutils, python3-yaml, kicad (>= 5.1.6), python3-wxgtk4.0 Recommends: kibom.inti-cmnb (>= 1.8.0), interactivehtmlbom.inti-cmnb, pcbdraw, imagemagick, librsvg2-bin, python3-xlsxwriter, rar, poppler-utils, python3-lxml -Suggests: pandoc, texlive-latex-base, texlive-latex-recommended, git +Suggests: pandoc, texlive-latex-base, texlive-latex-recommended, git, ghostscript Description: KiCad Bot KiBot is a program which helps you to automate the generation of KiCad output documents easily, repeatable, and most of all, scriptably. diff --git a/docs/README.in b/docs/README.in index fd03aa6a..ec50dda6 100644 --- a/docs/README.in +++ b/docs/README.in @@ -439,7 +439,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 + - `pcb_print` PDF/SVG/PNG/EPS/PS, 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 746f2b18..5aab4aad 100644 --- a/docs/samples/generic_plot.kibot.yaml +++ b/docs/samples/generic_plot.kibot.yaml @@ -952,6 +952,7 @@ outputs: # Don't use the `kicost_variant` when using internal variants/filters variant: '' # PCB Print: + # Supports PDF, SVG, PNG, EPS and PS formats. # KiCad 5: including the frame is slow. # KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. - name: 'pcb_print_example' @@ -972,7 +973,8 @@ outputs: # 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 + # [string='PDF'] [PDF,SVG,PNG,EPS,PS] Format for the output file/s. + # Note that for PS you need `ghostscript` which isn't part of the default docker images format: 'PDF' # [boolean=false] Hide components in the Fab layer that are marked as excluded by a variant hide_excluded: false @@ -1025,6 +1027,8 @@ outputs: title: '' # [boolean=true] Include the title-block plot_sheet_reference: true + # [number=1280] Width of the PNG in pixels + png_width: 1280 # [string=''] Text used to replace the sheet title. %VALUE expansions are allowed. # If it starts with `+` the text is concatenated title: '' diff --git a/kibot/out_pcb_print.py b/kibot/out_pcb_print.py index c4b6f2e1..78e0df54 100644 --- a/kibot/out_pcb_print.py +++ b/kibot/out_pcb_print.py @@ -27,9 +27,9 @@ from . import log logger = log.get_logger() SVG2PDF = 'rsvg-convert' +PDF2PS = 'pdf2ps' -# - Implement other rsvg-convert formats # - Use PyPDF2 for pdfunite # - Implement pad, vias, etc colors # - Allow hole color config @@ -47,7 +47,8 @@ def _run_command(cmd): if e.output: logger.debug('Output from command: '+e.output.decode()) exit(PDF_PCB_PRINT) - logger.debug('Output from command:\n'+cmd_output.decode()) + if cmd_output.strip(): + logger.debug('Output from command:\n'+cmd_output.decode()) def hex_to_rgb(value): @@ -94,6 +95,17 @@ def get_width(svg): return float(svg.root.get('viewBox').split(' ')[2]) +def to_inches(w): + val = float(w[:-2]) + units = w[-2:] + if units == 'cm': + return val/2.54 + if units == 'pt': + return val/72.0 + # Currently impossible for KiCad + return val + + def merge_svg(input_folder, input_files, output_folder, output_file, black_holes, monochrome): """ Merge all pages into one """ first = True @@ -105,6 +117,7 @@ def merge_svg(input_folder, input_files, output_folder, output_file, black_holes svg_out = new_layer # This is the width declared at the beginning of the file base_width = width + phys_width = to_inches(new_layer.width) first = False else: root = new_layer.getroot() @@ -117,6 +130,7 @@ def merge_svg(input_folder, input_files, output_folder, output_file, black_holes root.moveto(1, 1) svg_out.append([root]) svg_out.save(os.path.join(output_folder, output_file)) + return phys_width def create_pdf_from_pages(input_folder, input_files, output_fn): @@ -160,6 +174,23 @@ def svg_to_pdf(input_folder, svg_file, pdf_file): _run_command(cmd) +def svg_to_png(input_folder, svg_file, png_file, width): + cmd = [SVG2PDF, '-w', str(width), '-f', 'png', '-o', os.path.join(input_folder, png_file), + os.path.join(input_folder, svg_file)] + _run_command(cmd) + + +def svg_to_eps(input_folder, svg_file, eps_file): + cmd = [SVG2PDF, '-d', '72', '-p', '72', '-f', 'eps', '-o', os.path.join(input_folder, eps_file), + os.path.join(input_folder, svg_file)] + _run_command(cmd) + + +def pdf_to_ps(ps_file, output): + cmd = [PDF2PS, ps_file, output] + _run_command(cmd) + + def create_pdf_from_svg_pages(input_folder, input_files, output_fn): svg_files = [] for svg_file in input_files: @@ -267,7 +298,10 @@ class PCB_PrintOptions(VariantOptions): """ Text used to replace the sheet title. %VALUE expansions are allowed. If it starts with `+` the text is concatenated """ self.format = 'PDF' - """ [PDF,SVG] Format for the output file/s """ + """ [PDF,SVG,PNG,EPS,PS] Format for the output file/s. + Note that for PS you need `ghostscript` which isn't part of the default docker images """ + self.png_width = 1280 + """ Width of the PNG in pixels """ super().__init__() self._expand_id = 'assembly' @@ -319,7 +353,7 @@ class PCB_PrintOptions(VariantOptions): self.restore_fab(GS.board, comps_hash) def get_targets(self, out_dir): - if self.format == 'SVG': + if self.format in ['SVG', 'PNG', 'EPS']: files = [] for n in range(len(self.pages)): id = self._expand_id+('_page_%02d' % (n+1)) @@ -391,8 +425,11 @@ class PCB_PrintOptions(VariantOptions): patch_svg_file(output, remove_bkg=True) def generate_output(self, output): - if which(SVG2PDF) is None: - logger.error('`{}` not installed and needed for PDF output'.format(SVG2PDF)) + if self.format != 'SVG' and which(SVG2PDF) is None: + logger.error('`{}` not installed. Install `librsvg2-bin` or equivalent'.format(SVG2PDF)) + exit(MISSING_TOOL) + if self.format == 'PS' and which(PDF2PS) is None: + logger.error('`{}` not installed. '.format(PDF2PS)) logger.error('Install `librsvg2-bin` or equivalent') exit(MISSING_TOOL) output_dir = os.path.dirname(output) @@ -445,19 +482,31 @@ class PCB_PrintOptions(VariantOptions): filelist.append((GS.pcb_basename+"-frame.svg", color)) pc.ClosePlot() # 3) Stack all layers in one file - if self.format == 'PDF': - assembly_file = GS.pcb_basename+"-"+str(n+1)+".svg" - else: + if self.format == 'SVG': id = self._expand_id+('_page_%02d' % (n+1)) assembly_file = self.expand_filename(output_dir, self.output, id, self._expand_ext) + else: + assembly_file = GS.pcb_basename+"-"+str(n+1)+".svg" logger.debug('- Merging layers to {}'.format(assembly_file)) merge_svg(temp_dir, filelist, temp_dir, assembly_file, p.black_holes, p.monochrome) + if self.format in ['PNG', 'EPS']: + id = self._expand_id+('_page_%02d' % (n+1)) + out_file = self.expand_filename(output_dir, self.output, id, self._expand_ext) + if self.format == 'PNG': + svg_to_png(temp_dir, assembly_file, out_file, self.png_width) + else: + svg_to_eps(temp_dir, assembly_file, out_file) pages.append(assembly_file) self.restore_title() # Join all pages in one file - if self.format == 'PDF': + if self.format in ['PDF', 'PS']: logger.debug('- Creating output file {}'.format(output)) - create_pdf_from_svg_pages(temp_dir, pages, output) + if self.format == 'PDF': + create_pdf_from_svg_pages(temp_dir, pages, output) + else: + ps_file = os.path.join(temp_dir, GS.pcb_basename+'.ps') + create_pdf_from_svg_pages(temp_dir, pages, ps_file) + pdf_to_ps(ps_file, output) # Remove the temporal files rmtree(temp_dir) @@ -472,6 +521,7 @@ class PCB_PrintOptions(VariantOptions): class PCB_Print(BaseOutput): # noqa: F821 """ PCB Print Prints the PCB using a mechanism that is more flexible than `pdf_pcb_print` and `svg_pcb_print`. + Supports PDF, SVG, PNG, EPS and PS formats. KiCad 5: including the frame is slow. KiCad 6: for custom frames use the `enable_ki6_frame_fix`, is slow. """ def __init__(self): diff --git a/tests/yaml_samples/pcb_print.kibot.yaml b/tests/yaml_samples/pcb_print.kibot.yaml index bc1eb06c..34121f92 100644 --- a/tests/yaml_samples/pcb_print.kibot.yaml +++ b/tests/yaml_samples/pcb_print.kibot.yaml @@ -13,8 +13,8 @@ outputs: # drill_marks: small title: Chau # plot_sheet_reference: false - # format: 'SVG' - enable_ki6_frame_fix: true + format: 'PS' + # enable_ki6_frame_fix: true pages: - # monochrome: true scaling: 2.0