[PcbDraw][PCB_Print] Removed all PcbDraw convert.py usage
- Currently not needed
This commit is contained in:
parent
700bf5bff3
commit
1df9d1da46
|
|
@ -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)}")
|
||||
|
|
@ -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]))
|
||||
|
|
@ -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}'")
|
||||
|
|
@ -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())
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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%']
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue