[PcbDraw] Removed PIL as dependency

- So now the save function only supports SVG as input and SVG/PNG as
  output. All other cases are handled from outside
- This is because KiBot heavily uses ImageMagick and migrating to PIL
  is not something simple.
- There is no point in using PIL just for file conversion, as we don't
  use `render` this is the only use.
This commit is contained in:
Salvador E. Tropea 2022-10-18 10:49:13 -03:00
parent f61ca58ffa
commit 207dd8f67c
7 changed files with 147 additions and 35 deletions

View File

@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Diff:
- Option to compare only the first schematic page. (See #319)
- PcbDraw:
- Support for BMP output
### Changed
- Diff:

View File

@ -173,16 +173,18 @@ Notes:
- Create outputs preview for `navigate_results`
- Create PNG icons for `navigate_results`
- Create PDF, PNG, PS and EPS formats for `pcb_print`
[**Ghostscript**](https://www.ghostscript.com/) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://www.ghostscript.com/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/ghostscript) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Optional to:
- Create outputs preview for `navigate_results`
- Create PNG, PS and EPS formats for `pcb_print`
- Create PNG, JPG and BMP images for `pcbdraw`
[**ImageMagick**](https://imagemagick.org/) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://imagemagick.org/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/imagemagick) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Optional to:
- Create outputs preview for `navigate_results`
- Create monochrome prints and scaled PNG files for `pcb_print`
- Create JPG and BMP images for `pcbdraw`
[**Ghostscript**](https://www.ghostscript.com/) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://www.ghostscript.com/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/ghostscript) ![Auto-download](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/auto_download-22x22.png)
- Optional to:
- Create outputs preview for `navigate_results`
- Create PNG, PS and EPS formats for `pcb_print`
[**Pandoc**](https://pandoc.org/) [![Tool](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/llave-inglesa-22x22.png)](https://pandoc.org/) [![Debian](https://raw.githubusercontent.com/INTI-CMNB/KiBot/master/docs/images/debian-openlogo-22x22.png)](https://packages.debian.org/bullseye/pandoc)
- Optional to create PDF/ODF/DOCX files for `report`
@ -2557,7 +2559,7 @@ Notes:
- **`options`**: [dict] Options for the `pcbdraw` output.
* Valid keys:
- **`bottom`**: [boolean=false] Render the bottom side of the board (default is top side).
- **`format`**: [string='svg'] [svg,png,jpg] Output format. Only used if no `output` is specified.
- **`format`**: [string='svg'] [svg,png,jpg,bmp] Output format. Only used if no `output` is specified.
- **`mirror`**: [boolean=false] Mirror the board.
- **`output`**: [string='%f-%i%I%v.%x'] Name for the generated file. Affected by global options.
- **`show_components`**: [list(string)|string=none] [none,all] List of components to draw, can be also a string for none or all.

View File

@ -1356,7 +1356,7 @@ outputs:
dnf_filter: '_none'
# [number=300] [10,1200] Dots per inch (resolution) of the generated image
dpi: 300
# [string='svg'] [svg,png,jpg] Output format. Only used if no `output` is specified
# [string='svg'] [svg,png,jpg,bmp] Output format. Only used if no `output` is specified
format: 'svg'
# [list(string)=[]] List of components to highlight
highlight: []

View File

@ -17,6 +17,61 @@ Currently only the `plot` module is included.
### convert.py
- Made the `pcbdraw` import relative
- Removed PIL as dependency
- So now the save function only supports SVG as input and SVG/PNG as output
- All other cases are handled from outside
- This is because KiBot heavily uses ImageMagick and migrating to PIL is not something simple
- There is no point in using PIL just for file conversion, as we don't use `render` this is the only use
```diff
diff --git a/kibot/PcbDraw/convert.py b/kibot/PcbDraw/convert.py
index ba856a69..7fe64738 100644
--- a/kibot/PcbDraw/convert.py
+++ b/kibot/PcbDraw/convert.py
@@ -6,7 +6,7 @@ import textwrap
import os
from typing import Union
from tempfile import TemporaryDirectory
-from PIL import Image
+# from PIL import Image
from lxml.etree import _ElementTree # type: ignore
# Converting SVG to bitmap is a hard problem. We used Wand (and thus
@@ -66,17 +66,17 @@ def svgToPng(inputFilename: str, outputFilename: str, dpi: int=300) -> None:
message += textwrap.indent(m, " ")
raise RuntimeError(message)
-def save(image: Union[_ElementTree, Image.Image], filename: str, dpi: int=600) -> None:
+def save(image: _ElementTree, filename: str, dpi: int=600, format: str=None) -> None:
"""
Given an SVG tree or an image, save to a filename. The format is deduced
from the extension.
"""
- ftype = os.path.splitext(filename)[1][1:].lower()
- if isinstance(image, Image.Image):
- if ftype not in ["jpg", "jpeg", "png", "bmp"]:
- raise TypeError(f"Cannot save bitmap image into {ftype}")
- image.save(filename)
- return
+ ftype = os.path.splitext(filename)[1][1:].lower() if format is None else format
+# if isinstance(image, Image.Image):
+# if ftype not in ["jpg", "jpeg", "png", "bmp"]:
+# raise TypeError(f"Cannot save bitmap image into {ftype}")
+# image.save(filename)
+# return
if isinstance(image, _ElementTree):
if ftype == "svg":
image.write(filename)
@@ -91,6 +91,6 @@ def save(image: Union[_ElementTree, Image.Image], filename: str, dpi: int=600) -
svgToPng(svg_filename, png_filename, dpi=dpi)
if ftype == "png":
return
- Image.open(png_filename).convert("RGB").save(filename)
- return
+# Image.open(png_filename).convert("RGB").save(filename)
+# return
raise TypeError(f"Unknown image type: {type(image)}")
```
### convert_common.py
@ -32,7 +87,9 @@ No current changes
### unit.py
No current changes
- Replaced `unit` code.
- So we have only one units conversion
- I think the only difference is that KiBot code currently supports the locales decimal point
### plot.py
@ -183,6 +240,3 @@ index f8990722..17f90185 100644
- Find the index of the smaller element (1 line code)
- I added a replacemt for the `array` function, it just makes all matrix elements float
- Replaced `unit` code.
- So we have only one units conversion
- I think the only difference is that KiBot code currently supports the locales decimal point

View File

@ -6,7 +6,7 @@ import textwrap
import os
from typing import Union
from tempfile import TemporaryDirectory
from PIL import Image
# from PIL import Image
from lxml.etree import _ElementTree # type: ignore
# Converting SVG to bitmap is a hard problem. We used Wand (and thus
@ -66,17 +66,17 @@ def svgToPng(inputFilename: str, outputFilename: str, dpi: int=300) -> None:
message += textwrap.indent(m, " ")
raise RuntimeError(message)
def save(image: Union[_ElementTree, Image.Image], filename: str, dpi: int=600) -> None:
def save(image: _ElementTree, filename: str, dpi: int=600, format: str=None) -> None:
"""
Given an SVG tree or an image, save to a filename. The format is deduced
from the extension.
"""
ftype = os.path.splitext(filename)[1][1:].lower()
if isinstance(image, Image.Image):
if ftype not in ["jpg", "jpeg", "png", "bmp"]:
raise TypeError(f"Cannot save bitmap image into {ftype}")
image.save(filename)
return
ftype = os.path.splitext(filename)[1][1:].lower() if format is None else format
# if isinstance(image, Image.Image):
# if ftype not in ["jpg", "jpeg", "png", "bmp"]:
# raise TypeError(f"Cannot save bitmap image into {ftype}")
# image.save(filename)
# return
if isinstance(image, _ElementTree):
if ftype == "svg":
image.write(filename)
@ -91,6 +91,6 @@ def save(image: Union[_ElementTree, Image.Image], filename: str, dpi: int=600) -
svgToPng(svg_filename, png_filename, dpi=dpi)
if ftype == "png":
return
Image.open(png_filename).convert("RGB").save(filename)
return
# Image.open(png_filename).convert("RGB").save(filename)
# return
raise TypeError(f"Unknown image type: {type(image)}")

View File

@ -3,19 +3,18 @@
# Copyright (c) 2020-2022 Instituto Nacional de Tecnología Industrial
# License: GPL-3.0
# Project: KiBot (formerly KiPlot)
# TODO: PIL dependency?
# TODO: Package resources
# TODO: wxApp messages
# """
# Dependencies:
# - from: RSVG
# role: Create PNG and JPG images
# - from: ImageMagick
# role: Create JPG images
# - from: PcbDraw
# role: mandatory
# """
"""
Dependencies:
- from: RSVG
role: Create PNG, JPG and BMP images
- from: ImageMagick
role: Create JPG and BMP images
"""
import os
import shlex
import subprocess
from tempfile import NamedTemporaryFile
# Here we import the whole module to make monkeypatch work
from .error import KiPlotConfigurationError
@ -37,6 +36,26 @@ def pcbdraw_warnings(tag, msg):
logger.warning('{}({}) {}'.format(W_PCBDRAW, tag, msg))
def _get_tmp_name(ext):
with NamedTemporaryFile(mode='w', suffix=ext, delete=False) as f:
f.close()
return f.name
def _run_command(cmd):
logger.debug('Executing: '+shlex.join(cmd))
try:
cmd_output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
logger.error('Failed to run %s, error %d', cmd[0], e.returncode)
if e.output:
logger.debug('Output from command: '+e.output.decode())
exit(PCBDRAW_ERR)
out = cmd_output.decode()
if out.strip():
logger.debug('Output from command:\n'+out)
class PcbDrawStyle(Optionable):
def __init__(self):
super().__init__()
@ -140,7 +159,7 @@ class PcbDrawOptions(VariantOptions):
self.dpi = 300
""" [10,1200] Dots per inch (resolution) of the generated image """
self.format = 'svg'
""" *[svg,png,jpg] Output format. Only used if no `output` is specified """
""" *[svg,png,jpg,bmp] Output format. Only used if no `output` is specified """
self.output = GS.def_global_output
""" *Name for the generated file """
super().__init__()
@ -260,6 +279,19 @@ class PcbDrawOptions(VariantOptions):
def run(self, name):
super().run(name)
# Select a name and format that PcbDraw can handle
save_output_name = name
save_output_format = self.format
self.convert_command = None
# Check we have the tools needed for the output format
if self.format != 'svg':
# We need RSVG for anything other than SVG
self.ensure_tool('RSVG')
# We need ImageMagick for anything other than SVG and PNG
if self.format != 'png':
self.convert_command = self.ensure_tool('ImageMagick')
save_output_name = _get_tmp_name('.png')
save_output_format = 'png'
try:
# TODO: Avoid loading the PCB again
@ -311,7 +343,15 @@ class PcbDrawOptions(VariantOptions):
if tmp_style:
os.remove(tmp_style)
save(image, name, self.dpi)
save(image, save_output_name, self.dpi, format=save_output_format)
# Do we need to convert the saved file?
if self.convert_command is not None:
cmd = [self.convert_command, save_output_name]
if self.format == 'jpg':
cmd += ['-quality', '85%']
cmd.append(name)
_run_command(cmd)
os.remove(save_output_name)
return

View File

@ -159,7 +159,7 @@ deps = '{\
],\
"extra_deb": null,\
"help_option": "--version",\
"importance": 2,\
"importance": 3,\
"in_debian": true,\
"is_kicad_plugin": false,\
"is_python": false,\
@ -183,6 +183,13 @@ deps = '{\
"max_version": null,\
"output": "pcb_print",\
"version": null\
},\
{\
"desc": "Create JPG and BMP images",\
"mandatory": false,\
"max_version": null,\
"output": "pcbdraw",\
"version": null\
}\
],\
"tests": [],\
@ -719,7 +726,7 @@ deps = '{\
"extra_arch": null,\
"extra_deb": null,\
"help_option": "--version",\
"importance": 3,\
"importance": 4,\
"in_debian": true,\
"is_kicad_plugin": false,\
"is_python": false,\
@ -750,6 +757,13 @@ deps = '{\
"max_version": null,\
"output": "pcb_print",\
"version": null\
},\
{\
"desc": "Create PNG, JPG and BMP images",\
"mandatory": false,\
"max_version": null,\
"output": "pcbdraw",\
"version": null\
}\
],\
"tests": [\