[PcbDraw][PCB_Print] Removed all PcbDraw convert.py usage

- Currently not needed
This commit is contained in:
Salvador E. Tropea 2022-10-28 13:41:33 -03:00
parent 700bf5bff3
commit 1df9d1da46
7 changed files with 38 additions and 212 deletions

View File

@ -1,96 +0,0 @@
# Author: Jan Mrázek
# License: MIT
import platform
import subprocess
import textwrap
import os
from typing import Union
from tempfile import TemporaryDirectory
# from PIL import Image
from lxml.etree import _ElementTree # type: ignore
# Converting SVG to bitmap is a hard problem. We used Wand (and thus
# imagemagick) to do the conversion. However, imagemagick is really hard to
# configure properly and it breaks often. Therefore, we provide a custom module
# that has several conversion strategies that reflect the platform. We also try
# to provide descriptive enough message so the user can detect what is wrong.
if platform.system() == "Windows":
from .convert_windows import detectInkscape
else:
from .convert_unix import detectInkscape, rsvgSvgToPng
def inkscapeSvgToPng(inputFilename: str, outputFilename: str, dpi: int) -> None:
"""
A strategy to convert an SVG file into a PNG file using Inkscape
"""
command = [detectInkscape(), "--export-type=png", f"--export-dpi={dpi}",
f"--export-filename={outputFilename}", inputFilename]
def reportError(message: str) -> None:
raise RuntimeError(f"Cannot convert {inputFilename} to {outputFilename}. Inkscape failed with:\n"
+ textwrap.indent(message, " "))
try:
r = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = r.stdout.decode("utf-8") + "\n" + r.stderr.decode("utf-8")
# Inkscape doesn't respect error codes
if "Can't open file" in output:
reportError(output)
except subprocess.CalledProcessError as e:
output = e.stdout.decode("utf-8") + "\n" + e.stderr.decode("utf-8")
reportError(output)
def svgToPng(inputFilename: str, outputFilename: str, dpi: int=300) -> None:
"""
Convert SVG file into a PNG file based on platform-dependent strategies
"""
if platform.system() == "Windows":
strategies = {
"Inkscape": inkscapeSvgToPng
}
else:
strategies = {
"RSVG": rsvgSvgToPng, # We prefer it over Inkscape as it is much faster
"Inkscape": inkscapeSvgToPng
}
errors = {}
for name, strategy in strategies.items():
try:
strategy(inputFilename, outputFilename, dpi)
return
except Exception as e:
errors[name] = str(e)
message = "Cannot convert PNG to SVG; all strategies failed:\n"
for name, error in errors.items():
m = f"- Strategy '{name}' failed with: {textwrap.indent(error, ' ')}\n"
message += textwrap.indent(m, " ")
raise RuntimeError(message)
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 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)
return
with TemporaryDirectory() as d:
svg_filename = os.path.join(d, "image.svg")
if ftype == "png":
png_filename = filename
else:
png_filename = os.path.join(d, "image.png")
image.write(svg_filename)
svgToPng(svg_filename, png_filename, dpi=dpi)
if ftype == "png":
return
# Image.open(png_filename).convert("RGB").save(filename)
# return
raise TypeError(f"Unknown image type: {type(image)}")

View File

@ -1,29 +0,0 @@
# Author: Jan Mrázek
# License: MIT
import subprocess
from typing import List
def isValidInkscape(executable: str) -> bool:
try:
out = subprocess.check_output([executable, "--version"]).decode("utf-8")
parts = out.split(" ")
if parts[0] != "Inkscape":
return False
version = parts[1].split(".")
return int(version[0]) == 1
except FileNotFoundError:
return False
except subprocess.CalledProcessError as e:
return False
def chooseInkscapeCandidate(candidates: List[str]) -> str:
for candidate in candidates:
if isValidInkscape(candidate):
return candidate
raise RuntimeError("No Inkscape executable found. Please check:\n" +
"- if Inkscape is installed\n" +
"- if it is version at least 1.0\n" +
"If the conditions above are true, please ensure Inkscape is in PATH or\n" +
"ensure there is environmental variable 'PCBDRAW_INKSCAPE' pointing to the Inkscape executable\n\n" +
"Checked paths: \n" +
"\n".join([f"- {x}" for x in candidates]))

View File

@ -1,37 +0,0 @@
# Author: Jan Mrázek
# License: MIT
import subprocess
import os
import textwrap
from .convert_common import chooseInkscapeCandidate
def detectInkscape() -> str:
"""
Return path to working Inkscape >v1.0 executable
"""
candidates = []
if "PCBDRAW_INKSCAPE" in os.environ:
# Ensure there is the .com extension needed for CLI interface
path = os.path.splitext(os.environ["PCBDRAW_INKSCAPE"])[0] + ".com"
candidates.append(path)
candidates.append("inkscape") # Inkscape in path
return chooseInkscapeCandidate(candidates)
def rsvgSvgToPng(inputFilename: str, outputFilename: str, dpi: int) -> None:
tool = os.environ.get("PCBDRAW_RSVG", "rsvg-convert")
command = [tool, "--dpi-x", str(dpi), "--dpi-y", str(dpi),
"--output", outputFilename, "--format", "png", inputFilename]
def reportError(message: str) -> None:
raise RuntimeError(f"Cannot convert {inputFilename} to {outputFilename}. RSVG failed with:\n"
+ textwrap.indent(message, " "))
try:
r = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if r.returncode != 0:
output = r.stdout.decode("utf-8") + "\n" + r.stderr.decode("utf-8")
reportError(output)
except subprocess.CalledProcessError as e:
output = e.stdout.decode("utf-8") + "\n" + e.stderr.decode("utf-8")
reportError(output)
except FileNotFoundError:
reportError("rsvg-convert is not available. Please make sure it is installed.\n" +
f"It was executed via invoking '{tool}'")

View File

@ -1,40 +0,0 @@
# Author: Jan Mrázek
# License: MIT
import os
# Reports false error on Linux as LnkParse3 is Windows-only dependency
import LnkParse3 # type: ignore
from typing import List
from .convert_common import chooseInkscapeCandidate
def detectInkscape() -> str:
"""
Return path to working Inkscape >v1.0 executable
"""
candidates = []
if "PCBDRAW_INKSCAPE" in os.environ:
# Ensure there is the .com extension needed for CLI interface
path = os.path.splitext(os.environ["PCBDRAW_INKSCAPE"])[0] + ".com"
candidates.append(path)
candidates.append("inkscape") # Inkscape in path
candidates += readInkscapeFromStartMenu()
return chooseInkscapeCandidate(candidates)
def readInkscapeFromStartMenu() -> List[str]:
candidates = []
for profile in [os.environ.get("ALLUSERSPROFILE", ""), os.environ.get("USERPROFILE", "")]:
path = os.path.join(profile, "Microsoft", "Windows", "Start Menu",
"Programs", "Inkscape", "Inkscape.lnk")
try:
with open(path, "rb") as f:
lnk = LnkParse3.lnk_file(f)
abspath = os.path.realpath(lnk.string_data.relative_path())
# The .com version provides CLI interface
abspath = os.path.splitext(abspath)[0] + ".com"
candidates.append(abspath)
except FileNotFoundError:
continue
return candidates
if __name__ == "__main__":
print(detectInkscape())

View File

@ -771,7 +771,6 @@ class PCB_PrintOptions(VariantOptions):
def pcbdraw_by_module(self, pcbdraw_file, back):
self.ensure_tool('LXML')
from .PcbDraw.plot import PcbPlotter, PlotSubstrate
from .PcbDraw.convert import save
# Run PcbDraw to make the heavy work (find the Edge.Cuts path and create masks)
try:
plotter = PcbPlotter(GS.board)
@ -786,7 +785,7 @@ class PCB_PrintOptions(VariantOptions):
if GS.debug_level > 1:
# Save the SVG only for debug purposes
save(image, pcbdraw_file, 300)
image.write(pcbdraw_file)
# Return the SVG as a string
from lxml.etree import tostring
return tostring(image).decode()

View File

@ -399,20 +399,19 @@ class PcbDrawOptions(VariantOptions):
super().run(name)
self.ensure_tool('LXML')
from .PcbDraw.plot import PcbPlotter, PlotPaste, PlotPlaceholders, PlotSubstrate, PlotVCuts
from .PcbDraw.convert import save
# Select a name and format that PcbDraw can handle
save_output_name = name
save_output_format = self.format
svg_save_output_name = save_output_name = name
self.rsvg_command = None
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')
self.rsvg_command = self.ensure_tool('RSVG')
svg_save_output_name = _get_tmp_name('.svg')
# 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'
# Apply any variant
self.filter_pcb_components(GS.board, do_3D=True)
@ -468,10 +467,18 @@ class PcbDrawOptions(VariantOptions):
exit(PCBDRAW_ERR)
# Save the result
logger.debug('Saving output to '+save_output_name)
save(image, save_output_name, self.dpi, format=save_output_format)
# Do we need to convert the saved file?
logger.debug('Saving output to '+svg_save_output_name)
image.write(svg_save_output_name)
# Do we need to convert to PNG?
if self.rsvg_command:
logger.debug('Converting {} -> {}'.format(svg_save_output_name, save_output_name))
cmd = [self.rsvg_command, '--dpi-x', str(self.dpi), '--dpi-y', str(self.dpi),
'--output', save_output_name, '--format', 'png', svg_save_output_name]
_run_command(cmd)
os.remove(svg_save_output_name)
# Do we need to convert the saved file? (JPG/BMP)
if self.convert_command is not None:
logger.debug('Converting {} -> {}'.format(save_output_name, name))
cmd = [self.convert_command, save_output_name]
if self.format == 'jpg':
cmd += ['-quality', '85%']

View File

@ -0,0 +1,22 @@
kiplot:
version: 1
global:
pcb_finish: ENIG
outputs:
- name: PcbDraw
comment: "PcbDraw test top"
type: pcbdraw
dir: PcbDraw
options: &pcb_draw_ops
format: bmp
show_components: all
- name: PcbDraw2
comment: "PcbDraw test bottom"
type: pcbdraw
dir: PcbDraw
options:
<<: *pcb_draw_ops
bottom: True