summaryrefslogtreecommitdiff
path: root/lib/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'lib/extensions')
-rw-r--r--lib/extensions/__init__.py6
-rw-r--r--lib/extensions/png_realistic.py32
-rw-r--r--lib/extensions/png_simple.py72
-rw-r--r--lib/extensions/thread_list.py78
-rw-r--r--lib/extensions/zip.py93
5 files changed, 232 insertions, 49 deletions
diff --git a/lib/extensions/__init__.py b/lib/extensions/__init__.py
index e38eeb43..901fe02c 100644
--- a/lib/extensions/__init__.py
+++ b/lib/extensions/__init__.py
@@ -46,6 +46,8 @@ from .output import Output
from .palette_split_text import PaletteSplitText
from .palette_to_text import PaletteToText
from .params import Params
+from .png_realistic import PngRealistic
+from .png_simple import PngSimple
from .preferences import Preferences
from .print_pdf import Print
from .redwork import Redwork
@@ -61,6 +63,7 @@ from .stitch_plan_preview_undo import StitchPlanPreviewUndo
from .stroke_to_lpe_satin import StrokeToLpeSatin
from .tartan import Tartan
from .test_swatches import TestSwatches
+from .thread_list import ThreadList
from .troubleshoot import Troubleshoot
from .unlink_clone import UnlinkClone
from .update_svg import UpdateSvg
@@ -110,6 +113,8 @@ __all__ = extensions = [About,
PaletteSplitText,
PaletteToText,
Params,
+ PngRealistic,
+ PngSimple,
Preferences,
Print,
Redwork,
@@ -125,6 +130,7 @@ __all__ = extensions = [About,
StrokeToLpeSatin,
Tartan,
TestSwatches,
+ ThreadList,
Troubleshoot,
UnlinkClone,
UpdateSvg,
diff --git a/lib/extensions/png_realistic.py b/lib/extensions/png_realistic.py
new file mode 100644
index 00000000..24ebce55
--- /dev/null
+++ b/lib/extensions/png_realistic.py
@@ -0,0 +1,32 @@
+# Authors: see git history
+#
+# Copyright (c) 2024 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+import sys
+
+from ..stitch_plan import stitch_groups_to_stitch_plan
+from ..svg import render_stitch_plan
+from ..threads import ThreadCatalog
+from .base import InkstitchExtension
+from .png_simple import write_png_output
+
+
+class PngRealistic(InkstitchExtension):
+ def effect(self):
+ if not self.get_elements():
+ return
+
+ self.metadata = self.get_inkstitch_metadata()
+ collapse_len = self.metadata['collapse_len_mm']
+ min_stitch_len = self.metadata['min_stitch_len_mm']
+ stitch_groups = self.elements_to_stitch_groups(self.elements)
+ stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
+ ThreadCatalog().match_and_apply_palette(stitch_plan, self.get_inkstitch_metadata()['thread-palette'])
+
+ layer = render_stitch_plan(self.svg, stitch_plan, True, visual_commands=False, render_jumps=False)
+
+ write_png_output(self.svg, layer)
+
+ # don't let inkex output the SVG!
+ sys.exit(0)
diff --git a/lib/extensions/png_simple.py b/lib/extensions/png_simple.py
new file mode 100644
index 00000000..7902b43b
--- /dev/null
+++ b/lib/extensions/png_simple.py
@@ -0,0 +1,72 @@
+# Authors: see git history
+#
+# Copyright (c) 2024 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+import sys
+from tempfile import TemporaryDirectory
+
+from inkex.units import convert_unit
+
+from ..stitch_plan import stitch_groups_to_stitch_plan
+from ..svg import render_stitch_plan
+from ..threads import ThreadCatalog
+from ..utils.svg_data import get_pagecolor
+from .base import InkstitchExtension
+from .utils.inkex_command import inkscape
+
+
+class PngSimple(InkstitchExtension):
+ def __init__(self, *args, **kwargs):
+ InkstitchExtension.__init__(self)
+
+ self.arg_parser.add_argument('--notebook', type=str, default='')
+ self.arg_parser.add_argument('--line_width', type=str, default='', dest='line_width')
+
+ def effect(self):
+ if not self.get_elements():
+ return
+
+ self.metadata = self.get_inkstitch_metadata()
+ collapse_len = self.metadata['collapse_len_mm']
+ min_stitch_len = self.metadata['min_stitch_len_mm']
+ stitch_groups = self.elements_to_stitch_groups(self.elements)
+ stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
+ ThreadCatalog().match_and_apply_palette(stitch_plan, self.get_inkstitch_metadata()['thread-palette'])
+
+ line_width = convert_unit(f"{self.options.line_width}mm", self.svg.document_unit)
+ layer = render_stitch_plan(self.svg, stitch_plan, False, visual_commands=False,
+ render_jumps=False, line_width=line_width)
+
+ write_png_output(self.svg, layer)
+
+ # don't let inkex output the SVG!
+ sys.exit(0)
+
+
+def write_png_output(svg, layer):
+ with TemporaryDirectory() as tempdir:
+ # Inkex's command functionality also writes files to temp directories like this.
+ temp_svg_path = f"{tempdir}/temp.svg"
+ temp_png_path = f"{tempdir}/temp.png"
+ with open(temp_svg_path, "wb") as f:
+ f.write(svg.tostring())
+
+ generate_png(svg, layer, temp_svg_path, temp_png_path)
+
+ # inkscape will read the file contents from stdout and copy
+ # to the destination file that the user chose
+ with open(temp_png_path, 'rb') as output_file:
+ sys.stdout.buffer.write(output_file.read())
+
+
+def generate_png(svg, layer, input_path, output_path):
+ inkscape(input_path, actions="; ".join([
+ f"export-id:{layer.get_id()}",
+ "export-id-only",
+ "export-type:png",
+ f"export-dpi:{96*8}",
+ f"export-filename:{output_path}",
+ f"export-background:{get_pagecolor(svg.namedview)}",
+ "export-do" # Inkscape docs say this should be implicit at the end, but it doesn't seem to be.
+ ]))
diff --git a/lib/extensions/thread_list.py b/lib/extensions/thread_list.py
new file mode 100644
index 00000000..5603107a
--- /dev/null
+++ b/lib/extensions/thread_list.py
@@ -0,0 +1,78 @@
+# Authors: see git history
+#
+# Copyright (c) 2024 Authors
+# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
+
+import sys
+
+from ..i18n import _
+from ..stitch_plan import stitch_groups_to_stitch_plan
+from ..threads import ThreadCatalog
+from .base import InkstitchExtension
+
+
+class ThreadList(InkstitchExtension):
+ def __init__(self, *args, **kwargs):
+ InkstitchExtension.__init__(self)
+
+ def effect(self):
+ if not self.get_elements():
+ return
+
+ self.metadata = self.get_inkstitch_metadata()
+ collapse_len = self.metadata['collapse_len_mm']
+ min_stitch_len = self.metadata['min_stitch_len_mm']
+ stitch_groups = self.elements_to_stitch_groups(self.elements)
+ stitch_plan = stitch_groups_to_stitch_plan(stitch_groups, collapse_len=collapse_len, min_stitch_len=min_stitch_len)
+ ThreadCatalog().match_and_apply_palette(stitch_plan, self.get_inkstitch_metadata()['thread-palette'])
+
+ thread_list = get_threadlist(stitch_plan, self.get_base_file_name())
+
+ # inkscape will read the file contents from stdout and copy
+ # to the destination file that the user chose
+ sys.stdout.write(thread_list)
+
+ # don't let inkex output the SVG!
+ sys.exit(0)
+
+
+def get_threadlist(stitch_plan, design_name):
+ width = round(stitch_plan.dimensions_mm[0], 2)
+ height = round(stitch_plan.dimensions_mm[1], 2)
+
+ thread_used = []
+
+ thread_output = "%s\n" % _("Design Details")
+ thread_output += "==============================\n\n"
+
+ thread_output += _("Title")
+ thread_output += f": {design_name}\n"
+
+ thread_output += _("Size")
+ thread_output += f" (mm): {width}, {height}"
+
+ thread_output += _("Stitches")
+ thread_output += f": {stitch_plan.num_stitches}\n"
+
+ thread_output += _("Colors")
+ thread_output += f": {stitch_plan.num_colors}\n\n"
+
+ thread_output += _("Thread Order")
+ thread_output += "\n===========================\n\n"
+
+ for i, color_block in enumerate(stitch_plan):
+ thread = color_block.color
+
+ thread_output += str(i + 1) + " "
+ string = f"{thread.name} #{thread.number} - {thread.manufacturer} (#{thread.hex_digits.lower()})"
+ thread_output += string + "\n"
+ thread_used.append(string)
+
+ thread_output += "\n"
+ thread_output += _("Thread Used") + "\n"
+ thread_output += "===========================" + "\n\n"
+
+ for thread in set(thread_used):
+ thread_output += thread + "\n"
+
+ return thread_output
diff --git a/lib/extensions/zip.py b/lib/extensions/zip.py
index 9a13ca2d..1c33c080 100644
--- a/lib/extensions/zip.py
+++ b/lib/extensions/zip.py
@@ -10,6 +10,7 @@ from copy import deepcopy
from zipfile import ZipFile
from inkex import Boolean, errormsg
+from inkex.units import convert_unit
from lxml import etree
import pyembroidery
@@ -17,10 +18,12 @@ import pyembroidery
from ..i18n import _
from ..output import write_embroidery_file
from ..stitch_plan import stitch_groups_to_stitch_plan
-from ..svg import PIXELS_PER_MM
+from ..svg import PIXELS_PER_MM, render_stitch_plan
from ..threads import ThreadCatalog
from ..utils.geometry import Point
from .base import InkstitchExtension
+from .png_simple import generate_png
+from .thread_list import get_threadlist
class Zip(InkstitchExtension):
@@ -41,6 +44,11 @@ class Zip(InkstitchExtension):
self.formats.append('svg')
self.arg_parser.add_argument('--format-threadlist', type=Boolean, default=False, dest='threadlist')
self.formats.append('threadlist')
+ self.arg_parser.add_argument('--format-png_realistic', type=Boolean, default=False, dest='png_realistic')
+ self.formats.append('png_realistic')
+ self.arg_parser.add_argument('--format-png_simple', type=Boolean, default=False, dest='png_simple')
+ self.arg_parser.add_argument('--png_simple_line_width', type=float, default=0.3, dest='line_width')
+ self.formats.append('png_simple')
self.arg_parser.add_argument('--x-repeats', type=int, default=1, dest='x_repeats', )
self.arg_parser.add_argument('--y-repeats', type=int, default=1, dest='y_repeats',)
@@ -64,23 +72,7 @@ class Zip(InkstitchExtension):
base_file_name = self._get_file_name()
path = tempfile.mkdtemp()
- files = []
-
- for format in self.formats:
- if getattr(self.options, format):
- output_file = os.path.join(path, "%s.%s" % (base_file_name, format))
- if format == 'svg':
- document = deepcopy(self.document.getroot())
- with open(output_file, 'w', encoding='utf-8') as svg:
- svg.write(etree.tostring(document).decode('utf-8'))
- elif format == 'threadlist':
- output_file = os.path.join(path, "%s_%s.txt" % (base_file_name, _("threadlist")))
- output = open(output_file, 'w', encoding='utf-8')
- output.write(self.get_threadlist(stitch_plan, base_file_name))
- output.close()
- else:
- write_embroidery_file(output_file, stitch_plan, self.document.getroot())
- files.append(output_file)
+ files = self.generate_output_files(stitch_plan, path, base_file_name)
if not files:
errormsg(_("No embroidery file formats selected."))
@@ -123,34 +115,37 @@ class Zip(InkstitchExtension):
offsets.append(Point(x * dx, y * dy))
return stitch_plan.make_offsets(offsets)
- def get_threadlist(self, stitch_plan, design_name):
- thread_used = []
-
- thread_output = "%s\n" % _("Design Details")
- thread_output += "==============\n\n"
-
- thread_output += "%s: %s\n" % (_("Title"), design_name)
- thread_output += "%s (mm): %.2f x %.2f\n" % (_("Size"), stitch_plan.dimensions_mm[0], stitch_plan.dimensions_mm[1])
- thread_output += "%s: %s\n" % (_("Stitches"), stitch_plan.num_stitches)
- thread_output += "%s: %s\n\n" % (_("Colors"), stitch_plan.num_colors)
-
- thread_output += "%s\n" % _("Thread Order")
- thread_output += "============\n\n"
-
- for i, color_block in enumerate(stitch_plan):
- thread = color_block.color
-
- thread_output += str(i + 1) + " "
- string = "%s #%s - %s (#%s)" % (thread.name, thread.number, thread.manufacturer, thread.hex_digits.lower())
- thread_output += string + "\n"
-
- thread_used.append(string)
-
- thread_output += "\n"
- thread_output += _("Thread Used") + "\n"
- thread_output += "============" + "\n\n"
-
- for thread in set(thread_used):
- thread_output += thread + "\n"
-
- return "%s" % thread_output
+ def generate_output_files(self, stitch_plan, path, base_file_name):
+ files = []
+ for format in self.formats:
+ if getattr(self.options, format):
+ output_file = os.path.join(path, "%s.%s" % (base_file_name, format))
+ if format == 'svg':
+ document = deepcopy(self.document.getroot())
+ with open(output_file, 'w', encoding='utf-8') as svg:
+ svg.write(etree.tostring(document).decode('utf-8'))
+ elif format == 'threadlist':
+ output_file = os.path.join(path, "%s_%s.txt" % (base_file_name, _("threadlist")))
+ with open(output_file, 'w', encoding='utf-8') as output:
+ output.write(get_threadlist(stitch_plan, base_file_name))
+ elif format == 'png_realistic':
+ output_file = os.path.join(path, f"{base_file_name}_realistic.png")
+ layer = render_stitch_plan(self.svg, stitch_plan, True, visual_commands=False, render_jumps=False)
+ self.generate_png_output(output_file, layer)
+ elif format == 'png_simple':
+ output_file = os.path.join(path, f"{base_file_name}_simple.png")
+ line_width = convert_unit(f"{self.options.line_width}mm", self.svg.document_unit)
+ layer = render_stitch_plan(self.svg, stitch_plan, False, visual_commands=False,
+ render_jumps=False, line_width=line_width)
+ self.generate_png_output(output_file, layer)
+ else:
+ write_embroidery_file(output_file, stitch_plan, self.document.getroot())
+ files.append(output_file)
+ return files
+
+ def generate_png_output(self, output_file, layer):
+ with tempfile.TemporaryDirectory() as tempdir:
+ temp_svg_path = f"{tempdir}/temp.svg"
+ with open(temp_svg_path, "wb") as f:
+ f.write(self.svg.tostring())
+ generate_png(self.svg, layer, temp_svg_path, output_file)