# Authors: see git history # # Copyright (c) 2010 Authors # Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details. import os import re import sys from typing import List, Optional import inkex import pyembroidery from ..i18n import _ from ..svg.tags import INKSTITCH_ATTRIBS from ..threads import ThreadCatalog from .base import InkstitchExtension class ApplyThreadlist(InkstitchExtension): ''' Applies colors of a thread list to elements Count of colors and elements should fit together Use case: reapply colors to e.g. a dst file ''' def __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("-m", "--method", type=int, default=1, dest="method") self.arg_parser.add_argument("-t", "--palette", type=str, default=None, dest="palette") def effect(self) -> None: # Remove selection, we want all the elements in the document self.svg.selection.clear() if not self.get_elements(): return path = self.options.filepath self.verify_path(path) method = self.options.method # colors: [[color, cutwork_needle],[...]] if path.endswith(('col', 'inf', 'edr')): colors = self.parse_color_format(path) elif method == 1: colors = self.parse_inkstitch_threadlist(path) else: colors = self.parse_threadlist_by_catalog_number(path) self.verify_colors(colors, method) # Iterate through the color blocks to apply colors element_color = "" i = -1 for element in self.elements: if element.color != element_color: element_color = element.color i += 1 # No more colors in the list, stop here if i == len(colors): break style = element.node.get('style').replace("%s" % element_color, "%s" % colors[i][0]) element.node.set('style', style) # apply cutwork if colors[i][1] is not None: element.node.set(INKSTITCH_ATTRIBS['cutwork_needle'], colors[i][1]) def verify_path(self, path: str) -> None: 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: List[List[Optional[str]]], method: int) -> None: 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: str) -> List[List[Optional[str]]]: colors = [] with open(path) as threadlist: for line in threadlist: if line[0].isdigit(): m = re.search(r"\((#[0-9A-Fa-f]{6})\)", line) if m: colors.append([m.group(1), None]) else: # Color not found colors.append([None, None]) return colors def parse_color_format(self, path: str) -> List[List[Optional[str]]]: colors = [] threads = pyembroidery.read(path).threadlist for color in threads: if color.description is not None and color.description.startswith("Cut"): # there is a maximum of 4 needles, we can simply take the last element from the description string colors.append([color.hex_color(), color.description[-1]]) else: colors.append([color.hex_color(), None]) return colors def parse_threadlist_by_catalog_number(self, path: str) -> List[List[Optional[str]]]: palette_name = self.options.palette palette = ThreadCatalog().get_palette_by_name(palette_name) colors = [] palette_numbers = [] palette_colors = [] for color in palette: palette_numbers.append(color.number) palette_colors.append('#%s' % color.hex_digits.lower()) with open(path) as threadlist: for line in threadlist: if line[0].isdigit(): # some threadlists may add a # in front of the catalog number # let's remove it from the entire string before splitting it up thread = line.replace('#', '').split() catalog_number = set(thread[1:]).intersection(palette_numbers) if catalog_number: color_index = palette_numbers.index(next(iter(catalog_number))) colors.append([palette_colors[color_index], None]) else: # No color found colors.append([None, None]) return colors