Update pyembroidery (#1683)

Embroidery formats (read)
.hus: Husqvarna Embroidery Format
.zhs: Zeng Hsing Embroidery Format

Color formats (read & write)
.col : Color format.
.edr : Color format.
.inf : Color format.

Stitch formats (read & write)
.pmv : Brother Stitch Format.

Image (write)
.png : Portable Network Graphic (line art)

G-Code
The export file format is not .txt anymore but .gcode

Bug fixes
pull/1718/head
Kaalleen 2022-06-24 17:11:52 +02:00 zatwierdzone przez GitHub
rodzic 3985b5ac71
commit ab8c87928b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 93 dodań i 38 usunięć

Wyświetl plik

@ -8,6 +8,7 @@ import re
import sys import sys
import inkex import inkex
import pyembroidery
from ..i18n import _ from ..i18n import _
from ..threads import ThreadCatalog from ..threads import ThreadCatalog
@ -22,6 +23,8 @@ class ApplyThreadlist(InkstitchExtension):
''' '''
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
InkstitchExtension.__init__(self, *args, **kwargs) InkstitchExtension.__init__(self, *args, **kwargs)
self.arg_parser.add_argument("-o", "--options", type=str, default=None, dest="page_1")
self.arg_parser.add_argument("-i", "--info", type=str, default=None, dest="page_2")
self.arg_parser.add_argument("-f", "--filepath", type=str, default="", dest="filepath") self.arg_parser.add_argument("-f", "--filepath", type=str, default="", dest="filepath")
self.arg_parser.add_argument("-m", "--method", type=int, default=1, dest="method") self.arg_parser.add_argument("-m", "--method", type=int, default=1, dest="method")
self.arg_parser.add_argument("-t", "--palette", type=str, default=None, dest="palette") self.arg_parser.add_argument("-t", "--palette", type=str, default=None, dest="palette")
@ -34,26 +37,18 @@ class ApplyThreadlist(InkstitchExtension):
return return
path = self.options.filepath path = self.options.filepath
if not os.path.exists(path): self.verify_path(path)
inkex.errormsg(_("File not found."))
sys.exit(1)
if os.path.isdir(path):
inkex.errormsg(_("The filepath specified is not a file but a dictionary.\nPlease choose a threadlist file to import."))
sys.exit(1)
method = self.options.method method = self.options.method
if method == 1:
if path.endswith(('col', 'inf', 'edr')):
colors = self.parse_color_format(path)
elif method == 1:
colors = self.parse_inkstitch_threadlist(path) colors = self.parse_inkstitch_threadlist(path)
else: else:
colors = self.parse_threadlist_by_catalog_number(path) colors = self.parse_threadlist_by_catalog_number(path)
if all(c is None for c in colors): self.verify_colors(colors, method)
inkex.errormsg(_("Couldn't find any matching colors in the file."))
if method == 1:
inkex.errormsg(_('Please try to import as "other threadlist" and specify a color palette below.'))
else:
inkex.errormsg(_("Please chose an other color palette for your design."))
sys.exit(1)
# Iterate through the color blocks to apply colors # Iterate through the color blocks to apply colors
element_color = "" element_color = ""
@ -70,6 +65,23 @@ class ApplyThreadlist(InkstitchExtension):
style = element.node.get('style').replace("%s" % element_color, "%s" % colors[i]) style = element.node.get('style').replace("%s" % element_color, "%s" % colors[i])
element.node.set('style', style) element.node.set('style', style)
def verify_path(self, path):
if not os.path.exists(path):
inkex.errormsg(_("File not found."))
sys.exit(1)
if os.path.isdir(path):
inkex.errormsg(_("The filepath specified is not a file but a dictionary.\nPlease choose a threadlist file to import."))
sys.exit(1)
def verify_colors(self, colors, method):
if all(c is None for c in colors):
inkex.errormsg(_("Couldn't find any matching colors in the file."))
if method == 1:
inkex.errormsg(_('Please try to import as "other threadlist" and specify a color palette below.'))
else:
inkex.errormsg(_("Please chose an other color palette for your design."))
sys.exit(1)
def parse_inkstitch_threadlist(self, path): def parse_inkstitch_threadlist(self, path):
colors = [] colors = []
with open(path) as threadlist: with open(path) as threadlist:
@ -83,6 +95,13 @@ class ApplyThreadlist(InkstitchExtension):
colors.append(None) colors.append(None)
return colors return colors
def parse_color_format(self, path):
colors = []
threads = pyembroidery.read(path).threadlist
for color in threads:
colors.append(color.hex_color())
return colors
def parse_threadlist_by_catalog_number(self, path): def parse_threadlist_by_catalog_number(self, path):
palette_name = self.options.palette palette_name = self.options.palette
palette = ThreadCatalog().get_palette_by_name(palette_name) palette = ThreadCatalog().get_palette_by_name(palette_name)

Wyświetl plik

@ -5,11 +5,19 @@
from lxml import etree from lxml import etree
from inkex import errormsg
from ..i18n import _
from ..stitch_plan import generate_stitch_plan from ..stitch_plan import generate_stitch_plan
class Input(object): class Input(object):
def run(self, args): def run(self, args):
embroidery_file = args[0] embroidery_file = args[0]
if args[0].endswith(('edr', 'col', 'inf')):
msg = _("Ink/Stitch cannot import color formats directly. But you can open the embroidery file and apply the color with "
"Extensions > Ink/Stitch > Thread Color Management > Apply Threadlist")
errormsg(msg)
exit(0)
stitch_plan = generate_stitch_plan(embroidery_file) stitch_plan = generate_stitch_plan(embroidery_file)
print(etree.tostring(stitch_plan).decode('utf-8')) print(etree.tostring(stitch_plan).decode('utf-8'))

Wyświetl plik

@ -9,10 +9,10 @@ import tempfile
from copy import deepcopy from copy import deepcopy
from zipfile import ZipFile from zipfile import ZipFile
from inkex import Boolean
from lxml import etree from lxml import etree
import pyembroidery import pyembroidery
from inkex import Boolean
from ..i18n import _ from ..i18n import _
from ..output import write_embroidery_file from ..output import write_embroidery_file
@ -28,7 +28,7 @@ class Zip(InkstitchExtension):
# it's kind of obnoxious that I have to do this... # it's kind of obnoxious that I have to do this...
self.formats = [] self.formats = []
for format in pyembroidery.supported_formats(): for format in pyembroidery.supported_formats():
if 'writer' in format and format['category'] == 'embroidery': if 'writer' in format and format['category'] in ['embroidery', 'color', 'image', 'stitch']:
extension = format['extension'] extension = format['extension']
self.arg_parser.add_argument('--format-%s' % extension, type=Boolean, dest=extension) self.arg_parser.add_argument('--format-%s' % extension, type=Boolean, dest=extension)
self.formats.append(extension) self.formats.append(extension)

Wyświetl plik

@ -30,7 +30,7 @@ def object_commands():
def pyembroidery_debug_formats(): def pyembroidery_debug_formats():
for format in pyembroidery.supported_formats(): for format in pyembroidery.supported_formats():
if 'writer' in format and format['category'] != 'embroidery': if 'writer' in format and format['category'] not in ['embroidery', 'image', 'color', 'stitch']:
yield format['extension'], format['description'] yield format['extension'], format['description']

Wyświetl plik

@ -10,7 +10,7 @@ from .utils import build_environment, write_inx_file
def pyembroidery_input_formats(): def pyembroidery_input_formats():
for format in pyembroidery.supported_formats(): for format in pyembroidery.supported_formats():
if 'reader' in format and format['category'] == 'embroidery': if 'reader' in format and format['category'] in ['embroidery', 'color', 'stitch']:
yield format['extension'], format['description'] yield format['extension'], format['description']

Wyświetl plik

@ -12,7 +12,13 @@ def pyembroidery_output_formats():
for format in pyembroidery.supported_formats(): for format in pyembroidery.supported_formats():
if 'writer' in format: if 'writer' in format:
description = format['description'] description = format['description']
if format['category'] != "embroidery": if format['category'] == "color":
description = "%s [COLOR]" % description
elif format['category'] == "image":
description = "%s [IMAGE]" % description
elif format['category'] == "stitch":
description = "%s [STITCH]" % description
elif format['category'] != "embroidery":
description = "%s [DEBUG]" % description description = "%s [DEBUG]" % description
yield format['extension'], description, format['mimetype'], format['category'] yield format['extension'], description, format['mimetype'], format['category']

Wyświetl plik

@ -4,8 +4,8 @@
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
import sys import sys
import inkex
import inkex
import pyembroidery import pyembroidery
from .commands import global_command from .commands import global_command
@ -33,8 +33,8 @@ def _string_to_floats(string):
return [float(num) for num in floats] return [float(num) for num in floats]
def get_origin(svg, xxx_todo_changeme): def get_origin(svg, bounding_box):
(minx, miny, maxx, maxy) = xxx_todo_changeme (minx, miny, maxx, maxy) = bounding_box
origin_command = global_command(svg, "origin") origin_command = global_command(svg, "origin")
if origin_command: if origin_command:
@ -52,7 +52,12 @@ def jump_to_stop_point(pattern, svg):
def write_embroidery_file(file_path, stitch_plan, svg, settings={}): def write_embroidery_file(file_path, stitch_plan, svg, settings={}):
# convert from pixels to millimeters
# also multiply by 10 to get tenths of a millimeter as required by pyembroidery
scale = 10 / PIXELS_PER_MM
origin = get_origin(svg, stitch_plan.bounding_box) origin = get_origin(svg, stitch_plan.bounding_box)
origin = origin * scale
pattern = pyembroidery.EmbPattern() pattern = pyembroidery.EmbPattern()
stitch = Stitch(0, 0) stitch = Stitch(0, 0)
@ -68,10 +73,6 @@ def write_embroidery_file(file_path, stitch_plan, svg, settings={}):
pattern.add_stitch_absolute(pyembroidery.END, stitch.x, stitch.y) pattern.add_stitch_absolute(pyembroidery.END, stitch.x, stitch.y)
# convert from pixels to millimeters
# also multiply by 10 to get tenths of a millimeter as required by pyembroidery
scale = 10 / PIXELS_PER_MM
settings.update({ settings.update({
# correct for the origin # correct for the origin
"translate": -origin, "translate": -origin,
@ -92,6 +93,9 @@ def write_embroidery_file(file_path, stitch_plan, svg, settings={}):
settings['max_stitch'] = float('inf') settings['max_stitch'] = float('inf')
settings['max_jump'] = float('inf') settings['max_jump'] = float('inf')
settings['explicit_trim'] = False settings['explicit_trim'] = False
elif file_path.endswith('.png'):
settings['linewidth'] = 1
settings['background'] = 'white'
try: try:
pyembroidery.write(pattern, file_path, settings) pyembroidery.write(pattern, file_path, settings)

@ -1 +1 @@
Subproject commit 2ab0085cc997762ece7b9f96aef86457a205ca82 Subproject commit 4817386d269a2724bf0c9a87d91a5103c6dffc78

Wyświetl plik

@ -3,15 +3,33 @@
<name>Apply Threadlist</name> <name>Apply Threadlist</name>
<id>org.inkstitch.apply_threadlist</id> <id>org.inkstitch.apply_threadlist</id>
<param name="extension" type="string" gui-hidden="true">apply_threadlist</param> <param name="extension" type="string" gui-hidden="true">apply_threadlist</param>
<param name="filepath" type="path" gui-text="Choose file" mode="file" filetypes="txt"/> <param name="options" type="notebook">
<param name="method" type="optiongroup" gui-text="Choose method"> <page name="options" gui-text="Options">
<option value="1">Apply Ink/Stitch threadlist</option> <param name="filepath" type="path" gui-text="Choose file" mode="file" filetypes="txt,edr,col,inf"/>
<option value="2">Apply other threadlist*</option> <param name="method" type="optiongroup" gui-text="Choose method">
</param> <option value="1">Apply Ink/Stitch threadlist</option>
<param name="palette" type="enum" gui-text="*Choose color palette"> <option value="2">Apply other threadlist*</option>
{%- for item in threadcatalog %} </param>
<item value="{{ item }}">{{ item }}</item> <param name="palette" type="enum" gui-text="*Choose color palette">
{%- endfor %} {%- for item in threadcatalog %}
<item value="{{ item }}">{{ item }}</item>
{%- endfor %}
</param>
</page>
<page name="info" gui-text="Help">
<label appearance="header">This extension applies colors from a color file to the objects in this document.</label>
<label>COL, INF, EDR</label>
<label indent="2">Select the file and apply. The chosen method is not important for these file types.</label>
<spacer />
<label>TXT</label>
<label indent="2">Import an Ink/Stitch threadlist file (created through the zip export option).</label>
<spacer />
<label indent="2">Import any other Threadlist file in txt format. Ink/Stitch will try to match the colors to the selected thread palette.
The objects in this document will be colored accordingly if color matching has been successful.</label>
<spacer />
<label>Get more information on our website</label>
<label appearance="url">https://inkstitch.org/docs/thread-color/#apply-threadlist</label>
</page>
</param> </param>
<effect> <effect>
<object-type>all</object-type> <object-type>all</object-type>

Wyświetl plik

@ -10,12 +10,12 @@
<dataloss>true</dataloss> <dataloss>true</dataloss>
</output> </output>
{%- for format, description, mimetype, category in formats %} {%- for format, description, mimetype, category in formats %}
{%- if category == "embroidery" %} {%- if category != "vector" and category != "debug" %}
<param name="format-{{ format }}" type="boolean" _gui-text=".{{ format | upper }}: {{ description }}">false</param> <param name="format-{{ format }}" type="boolean" _gui-text=".{{ format | upper }}: {{ description }}">false</param>
{%- endif %} {%- endif %}
{%- endfor %} {%- endfor %}
<param name="format-threadlist" type="boolean" gui-text=".TXT: Threadlist [COLOR]">false</param>
<param name="format-svg" type="boolean" gui-text=".SVG: Scalable Vector Graphic">false</param> <param name="format-svg" type="boolean" gui-text=".SVG: Scalable Vector Graphic">false</param>
<param name="format-threadlist" type="boolean" gui-text=".TXT: Threadlist">false</param>
<param name="extension" type="string" gui-hidden="true">zip</param> <param name="extension" type="string" gui-hidden="true">zip</param>
<script> <script>
{{ command_tag | safe }} {{ command_tag | safe }}