Skip to content

Commit

Permalink
[SCH Variant][*SCH Print][Added] mechanism to paste images from outputs
Browse files Browse the repository at this point in the history
See #714
  • Loading branch information
set-soft committed Nov 12, 2024
1 parent 4ef4e0f commit 03b6265
Show file tree
Hide file tree
Showing 20 changed files with 166 additions and 13 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `use_ref_ranges` alias for `use_alt`
- New *kicad* format to mimic KiCad's internal BoM.
- PCB Print: a mechanism to filter components for a particular layer (#706)
- SCH Variant and *SCH Print:
- A mechanism to paste images from outputs (#714)

### Fixed
- BoM
Expand Down
6 changes: 6 additions & 0 deletions docs/samples/generic_plot.kibot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@ outputs:
layers: all
# DXF Schematic Print (Drawing Exchange Format):
# This output is what you get from the 'File/Plot' menu in eeschema.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
# Important: If you use custom fonts and/or colors please consult the `resources_dir` global variable.
- name: 'dxf_sch_print_example'
comment: 'Exports the schematic to a format commonly used for CAD software.'
Expand Down Expand Up @@ -1432,6 +1433,7 @@ outputs:
layers: all
# HPGL Schematic Print (Hewlett & Packard Graphics Language):
# This output is what you get from the 'File/Plot' menu in eeschema.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
# Important: If you use custom fonts and/or colors please consult the `resources_dir` global variable.
- name: 'hpgl_sch_print_example'
comment: 'Exports the schematic to the most common plotter format.'
Expand Down Expand Up @@ -3117,6 +3119,7 @@ outputs:
# PDF Schematic Print (Portable Document Format):
# This is the main format to document your schematic.
# This output is what you get from the 'File/Plot' menu in eeschema.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
# Important: If you use custom fonts and/or colors please consult the `resources_dir` global variable.
- name: 'pdf_sch_print_example'
comment: 'Exports the schematic to the most common exchange format. Suitable for printing.'
Expand Down Expand Up @@ -3345,6 +3348,7 @@ outputs:
layers: all
# PS Schematic Print (Postscript):
# This output is what you get from the 'File/Plot' menu in eeschema.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
# Important: If you use custom fonts and/or colors please consult the `resources_dir` global variable.
- name: 'ps_sch_print_example'
comment: 'Exports the schematic in postscript. Suitable for printing.'
Expand Down Expand Up @@ -3629,6 +3633,7 @@ outputs:
# Schematic with variant generator:
# This copy isn't intended for development.
# Is just a tweaked version of the original where you can look at the results.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
- name: 'sch_variant_example'
comment: 'Creates a copy of the schematic with all the filters and variants applied.'
type: 'sch_variant'
Expand Down Expand Up @@ -3952,6 +3957,7 @@ outputs:
# SVG Schematic Print:
# This is a format to document your schematic.
# This output is what you get from the 'File/Plot' menu in eeschema.
# Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable
# Important: If you use custom fonts and/or colors please consult the `resources_dir` global variable.
- name: 'svg_sch_print_example'
comment: 'Exports the schematic in a vectorized graphics format.'
Expand Down
3 changes: 3 additions & 0 deletions docs/source/Changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ Added

- PCB Print: a mechanism to filter components for a particular layer
(#706)
- SCH Variant and \*SCH Print:

- A mechanism to paste images from outputs (#714)

Fixed
~~~~~
Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/dxf_sch_print.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ DXF Schematic Print (Drawing Exchange Format)

Exports the schematic to a format commonly used for CAD software.
This output is what you get from the 'File/Plot' menu in eeschema. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

.. note::
If you use custom fonts and/or colors please consult the `resources_dir` global variable. |br|
Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/hpgl_sch_print.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ HPGL Schematic Print (Hewlett & Packard Graphics Language)

Exports the schematic to the most common plotter format.
This output is what you get from the 'File/Plot' menu in eeschema. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

.. note::
If you use custom fonts and/or colors please consult the `resources_dir` global variable. |br|
Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/pdf_sch_print.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ PDF Schematic Print (Portable Document Format)
Exports the schematic to the most common exchange format. Suitable for printing.
This is the main format to document your schematic. |br|
This output is what you get from the 'File/Plot' menu in eeschema. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

.. note::
If you use custom fonts and/or colors please consult the `resources_dir` global variable. |br|
Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/ps_sch_print.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ PS Schematic Print (Postscript)

Exports the schematic in postscript. Suitable for printing.
This output is what you get from the 'File/Plot' menu in eeschema. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

.. note::
If you use custom fonts and/or colors please consult the `resources_dir` global variable. |br|
Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/sch_variant.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Schematic with variant generator
Creates a copy of the schematic with all the filters and variants applied.
This copy isn't intended for development. |br|
Is just a tweaked version of the original where you can look at the results. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

Type: ``sch_variant``

Expand Down
1 change: 1 addition & 0 deletions docs/source/configuration/outputs/svg_sch_print.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ SVG Schematic Print
Exports the schematic in a vectorized graphics format.
This is a format to document your schematic. |br|
This output is what you get from the 'File/Plot' menu in eeschema. |br|
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable

.. note::
If you use custom fonts and/or colors please consult the `resources_dir` global variable. |br|
Expand Down
5 changes: 5 additions & 0 deletions docs/source/configuration/sup_globals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@
- ``restore_project`` :index:`: <pair: global options; restore_project>` [:ref:`boolean <boolean>`] (default: ``false``) Restore the KiCad project after execution.
Note that this option will undo operations like `set_text_variables`. |br|
Starting with 1.6.4 it also restores the PRL (Project Local Settings) and DRU (Design RUles) files.
- ``sch_image_prefix`` :index:`: <pair: global options; sch_image_prefix>` [:ref:`string <string>`] (default: ``'kibot_image'``) Prefix used to paste images from outputs. Used by some outputs.
You must place a text box at the coordinates where you want to paste the image. |br|
The width of the text box will be the width of the image. |br|
The text box must contain *kibot_image_X* where X is the output name. |br|
This option configures the prefix used. If this option is empty no images will be pasted.
- ``set_text_variables_before_output`` :index:`: <pair: global options; set_text_variables_before_output>` [:ref:`boolean <boolean>`] (default: ``false``) Run the `set_text_variables` preflight before running each output that involves variants.
This can be used when a text variable uses the variant and you want to create more than
one variant in the same run. Note that this could be slow because it forces a board
Expand Down
8 changes: 7 additions & 1 deletion kibot/globals.py
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,7 @@ def __init__(self):
self.layer_defaults = Layer
""" [list(dict)=[]] Used to indicate the default suffix and description for the layers.
Note that the name for the layer must match exactly, no aliases """
self.work_layer = 'Margin'
self.work_layer = GS.def_work_layer
""" Layer used for temporal tasks, choose a layer you are not using in your design """
self.include_components_from_pcb = True
""" Include components that are only in the PCB, not in the schematic, for filter and variants processing.
Expand All @@ -402,6 +402,12 @@ def __init__(self):
""" String used for *yes*. Currently used by the **update_pcb_characteristics** preflight """
self.str_no = 'no'
""" String used for *no*. Currently used by the **update_pcb_characteristics** preflight """
self.sch_image_prefix = 'kibot_image'
""" Prefix used to paste images from outputs. Used by some outputs.
You must place a text box at the coordinates where you want to paste the image.
The width of the text box will be the width of the image.
The text box must contain *kibot_image_X* where X is the output name.
This option configures the prefix used. If this option is empty no images will be pasted """
self.set_doc('filters', " [list(dict)=[]] KiBot warnings to be ignored ")
self._filter_what = 'KiBot warnings'
self.filters = FilterOptionsKiBot
Expand Down
2 changes: 2 additions & 0 deletions kibot/gs.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class GS(object):
solved_global_variant = None
# This is used as default value for classes supporting "output" option
def_global_output = '%f-%i%I%v.%x'
def_work_layer = 'Margin'
# The class that controls the global options
class_for_global_opts = None
# The last tree we used to configure it
Expand Down Expand Up @@ -193,6 +194,7 @@ class GS(object):
global_remove_adhesive_for_dnp = None
global_resources_dir = None
global_restore_project = None
global_sch_image_prefix = None
global_set_text_variables_before_output = None
global_silk_screen_color = None
global_silk_screen_color_bottom = None
Expand Down
15 changes: 11 additions & 4 deletions kibot/out_any_sch_print.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2020-2023 Salvador E. Tropea
# Copyright (c) 2020-2023 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Copyright (c) 2020-2024 Salvador E. Tropea
# Copyright (c) 2020-2024 Instituto Nacional de Tecnología Industrial
# License: AGPL-3.0
# Project: KiBot (formerly KiPlot)
import os
from .error import KiPlotConfigurationError
Expand Down Expand Up @@ -42,6 +42,9 @@ def get_targets(self, out_dir):
return [self._parent.expand_filename(out_dir, self.output)]
return [self._parent.expand_filename(out_dir, '%f.%x')]

def desc_box(self, box):
return f"SCH text box @{box.pos_x},{box.pos_y}"

def run(self, name):
super().run(name)
command = self.ensure_tool('KiAuto')
Expand Down Expand Up @@ -75,10 +78,11 @@ def run(self, name):
elif self.sheet_reference_layout:
raise KiPlotConfigurationError('Using `sheet_reference_layout` but no project available')

replaced_images = self.sch_replace_images(GS.sch)
try:
if self.title:
self.set_title(self.title, sch=True)
if self._comps or self.title:
if self._comps or self.title or replaced_images:
# Save it to a temporal dir
sch_dir = GS.mkdtemp(self._expand_ext+'_sch_print')
GS.copy_project_sch(sch_dir)
Expand Down Expand Up @@ -107,6 +111,9 @@ def run(self, name):
self.exec_with_retry(self.add_extra_options(cmd), self._exit_error)
if self.title:
self.restore_title(sch=True)
if replaced_images:
logger.error("Restore")
self.sch_restore_images(GS.sch)
finally:
if prj:
GS.write_pro(prj)
111 changes: 109 additions & 2 deletions kibot/out_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Copyright (c) 2020-2024 Instituto Nacional de Tecnología Industrial
# License: AGPL-3.0
# Project: KiBot (formerly KiPlot)
from base64 import b64encode
from copy import deepcopy
import math
import os
Expand All @@ -11,8 +12,10 @@
from .bom.columnlist import ColumnList
from .gs import GS
from .kicad.pcb import replace_footprints
from .kiplot import get_all_components
from .misc import Rect, W_WRONGPASTE, DISABLE_3D_MODEL_TEXT, W_NOCRTYD, MOD_ALLOW_MISSING_COURTYARD, W_MISSDIR, W_KEEPTMP
from .kicad.v6_sch import SchematicBitmapV6, Stroke, Color
from .kiplot import get_all_components, look_for_output, get_output_targets, run_output
from .misc import (Rect, W_WRONGPASTE, DISABLE_3D_MODEL_TEXT, W_NOCRTYD, MOD_ALLOW_MISSING_COURTYARD, W_MISSDIR, W_KEEPTMP,
RENDERERS, read_png)
if not GS.kicad_version_n:
# When running the regression tests we need it
from kibot.__main__ import detect_kicad
Expand Down Expand Up @@ -1146,6 +1149,110 @@ def undo_show_components(self):
if c.ref in self.undo_show:
c.fitted = True

def sch_replace_one_image(self, sheet, box, output_name, box_index):
""" Replace one image in the schematic, see sch_replace_images """
# Get the image file name
logger.debugl(2, f"- Looking for output {output_name} images")
output_obj = look_for_output(output_name, '`sch print image`', self._parent, RENDERERS)
targets, _, _ = get_output_targets(output_name, self._parent)
targets = [fn for fn in targets if fn.endswith('.png')]
if not targets:
raise KiPlotConfigurationError("{self.desc_box(box)} uses `{output_name}` which doesn't"
" generate any PNG")
fname = targets[0]
logger.debugl(2, f"- Related image: {fname}")
if not os.path.exists(fname):
# The target doesn't exist
if not output_obj._done:
# The output wasn't created in this run, try running it
logger.debug('- Not yet generated, tying to generate it')
run_output(output_obj)
if not os.path.exists(fname):
raise KiPlotConfigurationError("Failed to generate `{fname}` for {self.desc_box(box)}`")
logger.debugl(2, "- Reading image")
# Add the image to the SCH
try:
s, w, h, dpi = read_png(fname, logger, only_size=False)
except TypeError as e:
raise KiPlotConfigurationError(f'Error reading {fname} size: {e} for {self.desc_box(box)}')
# Check if we already have an image there
old_img_index = -1
old_img = None
new_images = []
for index, img in enumerate(sheet.bitmaps):
if abs(img.pos_x-box.size.x/2-box.pos_x) < 0.1 and abs(img.pos_y-box.size.y/2-box.pos_y) < 0.1:
old_img_index = index
old_img = img
else:
new_images.append(img)
sheet.bitmaps = new_images
if old_img_index > 0:
logger.debugl(2, "- Replacing existing image")
# Put the image
img_w = w/dpi*25.4
img_h = h/dpi*25.4
logger.debugl(2, f'- PNG: {w}x{h} px {dpi} PPIs {img_w}x{img_h} mm')
logger.debugl(2, f'- Box: {box.pos_x},{box.pos_y} +{box.size.x},{box.size.y} mm')
scale = box.size.x/img_w
logger.debugl(2, f'- Scale {scale}')
bmp = SchematicBitmapV6()
bmp.pos_x = box.pos_x + box.size.x/2
bmp.pos_y = box.pos_y + box.size.x/2
bmp.scale = scale
bmp.uuid = ''
data = b64encode(s).decode('ascii')
bmp.data = [data[i:i+76] for i in range(0, len(data), 76)]
# Append the new image
sheet.bitmaps.append(bmp)
old_box = deepcopy(box)
sheet._replaced_images.append((old_img_index, old_box, old_img, box_index))
# Ensure the box is invisible
transparent = Color()
transparent.r = 255
transparent.a = 0
new_stroke = Stroke()
new_stroke.color = transparent
box.stroke = new_stroke
box.effects.color = transparent
box.effects.w = box.effects.h = 0
# Adjust the box height
box.size.y = img_h*scale
return True

def sch_replace_images(self, sch):
""" Used by outputs that support replacing 'kibot_image_OUTPUT' in schematics """
if not GS.global_sch_image_prefix:
return False
logger.debug("Replacing images in schematic")
res = False
key = GS.global_sch_image_prefix+'_'
key_l = len(key)
for s in GS.sch.all_sheets:
s._replaced_images = []
for index, b in enumerate(s.text_boxes):
text = b.text.strip()
if text.startswith(key):
res |= self.sch_replace_one_image(s, b, text[key_l:], index)
return res

def sch_restore_images(self, sch):
""" Used to undo sch_replace_images """
if not GS.global_sch_image_prefix:
return False
logger.debug("Restoring images in schematic")
key = GS.global_sch_image_prefix+'_'
len(key)
for s in GS.sch.all_sheets:
for (index, box, img, box_index) in reversed(s._replaced_images):
s.text_boxes[box_index] = box
if index < 0:
# Was appended
s.bitmaps.pop()
else:
# Put the original image back
s.bitmaps[index] = img
s._replaced_images = None


class PcbMargin(Optionable):
""" To adjust each margin """
Expand Down
3 changes: 2 additions & 1 deletion kibot/out_dxf_sch_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def __init__(self):
class DXF_SCH_Print(BaseOutput): # noqa: F821
""" DXF Schematic Print (Drawing Exchange Format)
Exports the schematic to a format commonly used for CAD software.
This output is what you get from the 'File/Plot' menu in eeschema. """
This output is what you get from the 'File/Plot' menu in eeschema.
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable """
__doc__ += FONT_HELP_TEXT

def __init__(self):
Expand Down
3 changes: 2 additions & 1 deletion kibot/out_hpgl_sch_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def config(self, parent):
class HPGL_SCH_Print(BaseOutput): # noqa: F821
""" HPGL Schematic Print (Hewlett & Packard Graphics Language)
Exports the schematic to the most common plotter format.
This output is what you get from the 'File/Plot' menu in eeschema. """
This output is what you get from the 'File/Plot' menu in eeschema.
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable """
__doc__ += FONT_HELP_TEXT

def __init__(self):
Expand Down
3 changes: 2 additions & 1 deletion kibot/out_pdf_sch_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class PDF_SCH_Print(BaseOutput): # noqa: F821
""" PDF Schematic Print (Portable Document Format)
Exports the schematic to the most common exchange format. Suitable for printing.
This is the main format to document your schematic.
This output is what you get from the 'File/Plot' menu in eeschema. """
This output is what you get from the 'File/Plot' menu in eeschema.
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable """
__doc__ += FONT_HELP_TEXT

def __init__(self):
Expand Down
3 changes: 2 additions & 1 deletion kibot/out_ps_sch_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def __init__(self):
class PS_SCH_Print(BaseOutput): # noqa: F821
""" PS Schematic Print (Postscript)
Exports the schematic in postscript. Suitable for printing.
This output is what you get from the 'File/Plot' menu in eeschema. """
This output is what you get from the 'File/Plot' menu in eeschema.
Supports the image replacement using the prefix indicated by the `sch_image_prefix` global variable """
__doc__ += FONT_HELP_TEXT

def __init__(self):
Expand Down
Loading

0 comments on commit 03b6265

Please sign in to comment.