summaryrefslogtreecommitdiff
path: root/lib/extensions/apply_threadlist.py
blob: 2779a90120759a76dc97ad5f068b0c8eda86b230 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 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

import inkex
import pyembroidery

from ..i18n import _
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):
        # 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

        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])
            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):
        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))
                    else:
                        # Color not found
                        colors.append(None)
        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):
        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 catalof 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])
                    else:
                        # No color found
                        colors.append(None)
        return colors

    def find_elements(self, xpath):
        svg = self.document.getroot()
        elements = svg.xpath(xpath, namespaces=inkex.NSS)
        return elements