diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/extensions/__init__.py | 2 | ||||
| -rw-r--r-- | lib/extensions/base.py | 9 | ||||
| -rw-r--r-- | lib/extensions/embroider.py | 3 | ||||
| -rw-r--r-- | lib/extensions/input.py | 6 | ||||
| -rw-r--r-- | lib/extensions/output.py | 51 | ||||
| -rw-r--r-- | lib/extensions/zip.py | 88 | ||||
| -rw-r--r-- | lib/utils/io.py | 21 |
7 files changed, 174 insertions, 6 deletions
diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py index ebdd2fc9..6d3e00d8 100644 --- a/lib/extensions/__init__.py +++ b/lib/extensions/__init__.py @@ -4,3 +4,5 @@ from params import Params from print_pdf import Print from simulate import Simulate from input import Input +from output import Output +from zip import Zip diff --git a/lib/extensions/base.py b/lib/extensions/base.py index 4589132f..831b6dc6 100644 --- a/lib/extensions/base.py +++ b/lib/extensions/base.py @@ -200,6 +200,15 @@ class InkstitchExtension(inkex.Effect): def get_inkstitch_metadata(self): return InkStitchMetadata(self.document) + def get_base_file_name(self): + svg_filename = self.document.getroot().get(inkex.addNS('docname', 'sodipodi'), "embroidery.svg") + + if svg_filename.endswith('.svg'): + svg_filename = svg_filename[:-4] + + return svg_filename + + def parse(self): """Override inkex.Effect to add Ink/Stitch xml namespace""" diff --git a/lib/extensions/embroider.py b/lib/extensions/embroider.py index a213be64..1e994e27 100644 --- a/lib/extensions/embroider.py +++ b/lib/extensions/embroider.py @@ -44,8 +44,7 @@ class Embroider(InkstitchExtension): if self.options.output_file: output_path = os.path.join(self.options.path, self.options.output_file) else: - svg_filename = self.document.getroot().get(inkex.addNS('docname', 'sodipodi'), "embroidery.svg") - csv_filename = svg_filename.replace('.svg', '.%s' % self.options.output_format) + csv_filename = '%s.%s' % (self.get_base_file_name(), self.options.output_format) output_path = os.path.join(self.options.path, csv_filename) def add_suffix(path, suffix): diff --git a/lib/extensions/input.py b/lib/extensions/input.py index 251859c5..21248dd9 100644 --- a/lib/extensions/input.py +++ b/lib/extensions/input.py @@ -14,6 +14,7 @@ from ..svg import PIXELS_PER_MM, render_stitch_plan from ..svg.tags import INKSCAPE_LABEL from ..i18n import _ from ..stitch_plan import StitchPlan +from ..utils.io import save_stdout class Input(object): @@ -25,6 +26,9 @@ class Input(object): def affect(self, args): + # libembroidery likes to dump a bunch of debugging stuff to stdout + save_stdout() + embroidery_file = args[0] pattern = embPattern_create() embPattern_read(pattern, embroidery_file) @@ -65,4 +69,4 @@ class Input(object): # Note: this is NOT the same as centering the design in the canvas! layer.set('transform', 'translate(%s,%s)' % (extents[0], extents[1])) - print etree.tostring(svg) + print >> sys.real_stdout, etree.tostring(svg) diff --git a/lib/extensions/output.py b/lib/extensions/output.py new file mode 100644 index 00000000..f4b153e6 --- /dev/null +++ b/lib/extensions/output.py @@ -0,0 +1,51 @@ +import sys +import traceback +import os +import inkex +import tempfile + +from .base import InkstitchExtension +from ..i18n import _ +from ..output import write_embroidery_file +from ..stitch_plan import patches_to_stitch_plan +from ..svg import render_stitch_plan, PIXELS_PER_MM +from ..utils.io import save_stdout + +class Output(InkstitchExtension): + def __init__(self, *args, **kwargs): + InkstitchExtension.__init__(self) + self.OptionParser.add_option("-c", "--collapse_len_mm", + action="store", type="float", + dest="collapse_length_mm", default=3.0, + help="max collapse length (mm)") + self.OptionParser.add_option("-f", "--format", + dest="file_extension", + help="file extension to output (example: DST)") + + def effect(self): + if not self.get_elements(): + return + + patches = self.elements_to_patches(self.elements) + stitch_plan = patches_to_stitch_plan(patches, self.options.collapse_length_mm * PIXELS_PER_MM) + + # libembroidery wants to write to an actual file rather than stdout + temp_file = tempfile.NamedTemporaryFile(suffix=".%s" % self.options.file_extension, delete=False) + + # in windows, failure to close here will keep the file locked + temp_file.close() + + # libembroidery likes to debug log things to stdout. No way to disable it. + save_stdout() + write_embroidery_file(temp_file.name, stitch_plan, self.document.getroot()) + + # inkscape will read the file contents from stdout and copy + # to the destination file that the user chose + with open(temp_file.name) as output_file: + sys.real_stdout.write(output_file.read()) + + # clean up the temp file + os.remove(temp_file.name) + + # don't let inkex output the SVG! + sys.exit(0) diff --git a/lib/extensions/zip.py b/lib/extensions/zip.py new file mode 100644 index 00000000..ca12efdd --- /dev/null +++ b/lib/extensions/zip.py @@ -0,0 +1,88 @@ +import sys +import traceback +import os +import inkex +import tempfile +from zipfile import ZipFile +from libembroidery import * + +from .base import InkstitchExtension +from ..i18n import _ +from ..output import write_embroidery_file +from ..stitch_plan import patches_to_stitch_plan +from ..svg import render_stitch_plan, PIXELS_PER_MM +from ..utils.io import save_stdout + + +class Zip(InkstitchExtension): + def __init__(self, *args, **kwargs): + InkstitchExtension.__init__(self) + self.OptionParser.add_option("-c", "--collapse_len_mm", + action="store", type="float", + dest="collapse_length_mm", default=3.0, + help="max collapse length (mm)") + + # it's kind of obnoxious that I have to do this... + self.formats = [] + formatList = embFormatList_create() + curFormat = formatList + while(curFormat): + # extension includes the dot, so we'll remove it + extension = embFormat_extension(curFormat)[1:] + description = embFormat_description(curFormat) + writer_state = embFormat_writerState(curFormat) + + if writer_state.strip() and embFormat_type(curFormat) != EMBFORMAT_OBJECTONLY: + self.OptionParser.add_option('--format-%s' % extension, type="inkbool", dest=extension) + self.formats.append(extension) + curFormat = curFormat.next + + def effect(self): + if not self.get_elements(): + return + + patches = self.elements_to_patches(self.elements) + stitch_plan = patches_to_stitch_plan(patches, self.options.collapse_length_mm * PIXELS_PER_MM) + + base_file_name = self.get_base_file_name() + path = tempfile.mkdtemp() + + files = [] + + # libembroidery likes to debug log things to stdout. No way to disable it. + save_stdout() + for format in self.formats: + if getattr(self.options, format): + output_file = os.path.join(path, "%s.%s" % (base_file_name, format)) + write_embroidery_file(output_file, stitch_plan, self.document.getroot()) + files.append(output_file) + + # I'd love to do restore_stderr() here, but if I do, libembroidery's + # stuff still prints out and corrupts the zip! That's because it uses + # C's buffered stdout, so it hasn't actually written anything to the + # real standard output yet. + + if not files: + self.errormsg(_("No embroidery file formats selected.")) + + temp_file = tempfile.NamedTemporaryFile(suffix=".zip", delete=False) + + # in windows, failure to close here will keep the file locked + temp_file.close() + + with ZipFile(temp_file.name, "w") as zip_file: + for file in files: + zip_file.write(file, os.path.basename(file)) + + # inkscape will read the file contents from stdout and copy + # to the destination file that the user chose + with open(temp_file.name) as output_file: + sys.real_stdout.write(output_file.read()) + + os.remove(temp_file.name) + for file in files: + os.remove(file) + os.rmdir(path) + + # don't let inkex output the SVG! + sys.exit(0) diff --git a/lib/utils/io.py b/lib/utils/io.py index be1fdf24..e5a246f3 100644 --- a/lib/utils/io.py +++ b/lib/utils/io.py @@ -7,12 +7,27 @@ def save_stderr(): # GTK likes to spam stderr, which inkscape will show in a dialog. null = open(os.devnull, 'w') sys.stderr_dup = os.dup(sys.stderr.fileno()) + sys.real_stderr = os.fdopen(sys.stderr_dup, 'w') os.dup2(null.fileno(), 2) - sys.stderr_backup = sys.stderr sys.stderr = StringIO() def restore_stderr(): os.dup2(sys.stderr_dup, 2) - sys.stderr_backup.write(sys.stderr.getvalue()) - sys.stderr = sys.stderr_backup + sys.real_stderr.write(sys.stderr.getvalue()) + sys.stderr = sys.real_stderr + +# It's probably possible to generalize this code, but when I tried, +# the result was incredibly unreadable. +def save_stdout(): + null = open(os.devnull, 'w') + sys.stdout_dup = os.dup(sys.stdout.fileno()) + sys.real_stdout = os.fdopen(sys.stdout_dup, 'w') + os.dup2(null.fileno(), 1) + sys.stdout = StringIO() + + +def restore_stdout(): + os.dup2(sys.stdout_dup, 1) + sys.real_stdout.write(sys.stdout.getvalue()) + sys.stdout = sys.real_stdout |
