From 6187bd393542deada5f90726d662b73565a032a4 Mon Sep 17 00:00:00 2001 From: tatarize Date: Fri, 21 Sep 2018 00:10:14 -0700 Subject: [PATCH] 1.3.0 beta, needles added. Added needles and needle information, processes them as is correct. Save routine converts to either needle_set or color_change commands where appropriate. Still rough. --- pyembroidery/BroReader.py | 2 +- pyembroidery/CsvReader.py | 39 ----- pyembroidery/CsvWriter.py | 53 ++----- pyembroidery/DatReader.py | 91 ++++++++---- pyembroidery/DsbReader.py | 5 +- pyembroidery/DstWriter.py | 2 +- pyembroidery/DszReader.py | 5 +- pyembroidery/EmbConstant.py | 163 +++++++++++++++++++-- pyembroidery/EmbEncoder.py | 270 ++++++++++++++++++++++++----------- pyembroidery/EmbPattern.py | 69 +++++---- pyembroidery/EmbThread.py | 212 ++++++++++++++++++++++++--- pyembroidery/ExpWriter.py | 3 +- pyembroidery/JefWriter.py | 2 +- pyembroidery/KsmReader.py | 2 +- pyembroidery/PecReader.py | 4 +- pyembroidery/PecWriter.py | 14 +- pyembroidery/PesWriter.py | 2 +- pyembroidery/PmvReader.py | 53 ------- pyembroidery/PmvWriter.py | 4 +- pyembroidery/PyEmbroidery.py | 5 + pyembroidery/StcReader.py | 2 +- pyembroidery/TbfReader.py | 4 +- pyembroidery/U01Reader.py | 4 +- pyembroidery/U01Writer.py | 15 +- pyembroidery/Vp3Writer.py | 13 +- pyembroidery/ZxyReader.py | 2 +- 26 files changed, 687 insertions(+), 353 deletions(-) diff --git a/pyembroidery/BroReader.py b/pyembroidery/BroReader.py index 4731219..64bce82 100644 --- a/pyembroidery/BroReader.py +++ b/pyembroidery/BroReader.py @@ -32,7 +32,7 @@ def read_bro_stitches(f, out): continue if 0xE0 < control < 0xF0: needle = control - 0xE0 - out.color_change() + out.needle_change(needle) x = signed16(read_int_16le(f)) y = signed16(read_int_16le(f)) out.move(x, -y) diff --git a/pyembroidery/CsvReader.py b/pyembroidery/CsvReader.py index fe09c48..105515d 100644 --- a/pyembroidery/CsvReader.py +++ b/pyembroidery/CsvReader.py @@ -56,42 +56,3 @@ def read(f, out, settings=None): except IndexError: pass out.add_thread(thread_add) - - -def get_command_dictionary(): - return { - "NO_COMMAND": NO_COMMAND, - "STITCH": STITCH, - "JUMP": JUMP, - "TRIM": TRIM, - "STOP": STOP, - "END": END, - "SLOW": SLOW, - "FAST": FAST, - "COLOR_CHANGE": COLOR_CHANGE, - "SEQUIN_MODE": SEQUIN_MODE, - "SEQUIN_EJECT": SEQUIN_EJECT, - "SEW_TO": SEW_TO, - "NEEDLE_AT": NEEDLE_AT, - "STITCH_BREAK": STITCH_BREAK, - "SEQUENCE_BREAK": SEQUENCE_BREAK, - "COLOR_BREAK": COLOR_BREAK, - "TIE_ON": TIE_ON, - "TIE_OFF": TIE_OFF, - "FRAME_EJECT": FRAME_EJECT, - "MATRIX_TRANSLATE": MATRIX_TRANSLATE, - "MATRIX_SCALE": MATRIX_SCALE, - "MATRIX_ROTATE": MATRIX_ROTATE, - "MATRIX_RESET": MATRIX_RESET, - "OPTION_ENABLE_TIE_ON": OPTION_ENABLE_TIE_ON, - "OPTION_ENABLE_TIE_OFF": OPTION_ENABLE_TIE_OFF, - "OPTION_DISABLE_TIE_ON": OPTION_DISABLE_TIE_ON, - "OPTION_DISABLE_TIE_OFF": OPTION_DISABLE_TIE_OFF, - "OPTION_MAX_STITCH_LENGTH": OPTION_MAX_STITCH_LENGTH, - "OPTION_MAX_JUMP_LENGTH": OPTION_MAX_JUMP_LENGTH, - "OPTION_IMPLICIT_TRIM": OPTION_IMPLICIT_TRIM, - "OPTION_EXPLICIT_TRIM": OPTION_EXPLICIT_TRIM, - "CONTINGENCY_NONE": CONTINGENCY_NONE, - "CONTINGENCY_JUMP_NEEDLE": CONTINGENCY_JUMP_NEEDLE, - "CONTINGENCY_SEW_TO": CONTINGENCY_SEW_TO, - } diff --git a/pyembroidery/CsvWriter.py b/pyembroidery/CsvWriter.py index e0db7d8..c80d15a 100644 --- a/pyembroidery/CsvWriter.py +++ b/pyembroidery/CsvWriter.py @@ -47,6 +47,8 @@ def write(pattern, f, settings=None): csv(f, ('>', 'STITCH_COUNT:', str(count_stitches))) count_threads = pattern.count_color_changes() csv(f, ('>', 'THREAD_COUNT:', str(count_threads))) + count_set_needles = pattern.count_needle_sets() + csv(f, ('>', 'NEEDLE_COUNT:', str(count_set_needles))) csv(f, ('>', 'EXTENTS_LEFT:', str(extends[0]))) csv(f, ('>', 'EXTENTS_TOP:', str(extends[1]))) csv(f, ('>', 'EXTENTS_RIGHT:', str(extends[2]))) @@ -56,7 +58,7 @@ def write(pattern, f, settings=None): stitch_counts = {} for s in pattern.stitches: - command = s[2] + command = s[2] & COMMAND_MASK if command in stitch_counts: stitch_counts[command] += 1 else: @@ -65,6 +67,7 @@ def write(pattern, f, settings=None): if len(stitch_counts) != 0: for the_key, the_value in stitch_counts.items(): try: + the_key &= COMMAND_MASK name = "COMMAND_" + names[the_key] except (IndexError, KeyError): name = "COMMAND_UNKNOWN_" + str(the_key) @@ -149,8 +152,15 @@ def write(pattern, f, settings=None): current_x = 0 current_y = 0 for i, stitch in enumerate(pattern.stitches): + command = decode_thread_change(stitch[2]) try: - name = names[stitch[2]] + name = names[command[0]] + if command[1] != -1: + name = name + " t" + str(command[1]) + if command[2] != -1: + name = name + " n" + str(command[2]) + if command[3] != -1: + name = name + " o" + str(command[3]) except (IndexError, KeyError): name = "UNKNOWN " + str(stitch[2]) if displacement: @@ -189,42 +199,3 @@ def write(pattern, f, settings=None): )) current_x = stitch[0] current_y = stitch[1] - - -def get_common_name_dictionary(): - return { - NO_COMMAND: "NO_COMMAND", - STITCH: "STITCH", - JUMP: "JUMP", - TRIM: "TRIM", - STOP: "STOP", - END: "END", - SLOW: "SLOW", - FAST: "FAST", - COLOR_CHANGE: "COLOR_CHANGE", - SEQUIN_MODE: "SEQUIN_MODE", - SEQUIN_EJECT: "SEQUIN_EJECT", - SEW_TO: "SEW_TO", - NEEDLE_AT: "NEEDLE_AT", - STITCH_BREAK: "STITCH_BREAK", - SEQUENCE_BREAK: "SEQUENCE_BREAK", - COLOR_BREAK: "COLOR_BREAK", - TIE_ON: "TIE_ON", - TIE_OFF: "TIE_OFF", - FRAME_EJECT: "FRAME_EJECT", - MATRIX_TRANSLATE: "MATRIX_TRANSLATE", - MATRIX_SCALE: "MATRIX_SCALE", - MATRIX_ROTATE: "MATRIX_ROTATE", - MATRIX_RESET: "MATRIX_RESET", - OPTION_ENABLE_TIE_ON: "OPTION_ENABLE_TIE_ON", - OPTION_ENABLE_TIE_OFF: "OPTION_ENABLE_TIE_OFF", - OPTION_DISABLE_TIE_ON: "OPTION_DISABLE_TIE_ON", - OPTION_DISABLE_TIE_OFF: "OPTION_DISABLE_TIE_OFF", - OPTION_MAX_STITCH_LENGTH: "OPTION_MAX_STITCH_LENGTH", - OPTION_MAX_JUMP_LENGTH: "OPTION_MAX_JUMP_LENGTH", - OPTION_IMPLICIT_TRIM: "OPTION_IMPLICIT_TRIM", - OPTION_EXPLICIT_TRIM: "OPTION_EXPLICIT_TRIM", - CONTINGENCY_NONE: "CONTINGENCY_NONE", - CONTINGENCY_JUMP_NEEDLE: "CONTINGENCY_JUMP_NEEDLE", - CONTINGENCY_SEW_TO: "CONTINGENCY_SEW_TO", - } diff --git a/pyembroidery/DatReader.py b/pyembroidery/DatReader.py index 015bde9..1359c41 100644 --- a/pyembroidery/DatReader.py +++ b/pyembroidery/DatReader.py @@ -1,45 +1,86 @@ +from EmbConstant import FAST, SLOW + + def read_barudan_dat(f, out): - stitched_yet = False count = 0 while True: count += 1 byte = bytearray(f.read(3)) if len(byte) != 3: break - ctrl = byte[0] - y = -byte[1] - x = byte[2] - + dy = -byte[1] + dx = byte[2] if ctrl & 0x80 == 0: # This bit should always be set, must be other dat type. return False - if ctrl & 0x40 != 0: - y = -y - if ctrl & 0x20 != 0: - x = -x - if (ctrl & 0b11111) == 0: - stitched_yet = True - out.stitch(x, y) + if (ctrl & 0x20) != 0: + dx = -dx + if (ctrl & 0x40) != 0: + dy = -dy + command = ctrl & 0b11111 + if command == 0x0: + # Stitch + out.stitch(dx, dy) continue - if (ctrl & 0b11111) == 1: - out.move(x, y) + if command == 0x01: + # Jump + out.move(dx, dy) continue - if ctrl == 0xF8: - break - if ctrl == 0xE7: + if command == 0x02: + # Fast + out.add_stitch_relative(FAST) + if dx != 0 or dy != 0: + out.stitch(dx, dy) + continue + if command == 0x03: + # Fast, Jump + out.add_stitch_relative(FAST) + if dx != 0 or dy != 0: + out.move(dx, dy) + continue + if command == 0x04: + # Slow + out.add_stitch_relative(SLOW) + if dx != 0 or dy != 0: + out.stitch(dx, dy) + continue + if command == 0x05: + # Slow, Jump + out.add_stitch_relative(SLOW) + if dx != 0 or dy != 0: + out.move(dx, dy) + continue + if command == 0x06: + # T1 Top Thread Trimming, TTrim. out.trim() + if dx != 0 or dy != 0: + out.move(dx, dy) continue - if ctrl == 0xE8: - if count > 1: - out.stop() + if command == 0x07: + # T2 Bobbin Threading + out.trim() + if dx != 0 or dy != 0: + out.move(dx, dy) continue - if 0xE9 <= ctrl < 0xF8: - needle = ctrl - 0xE8 - if stitched_yet: - out.color_change() + if command == 0x08: # ww, stop file had proper A8 rather than E8 and displacement + # C00 Stop + out.stop() + if dx != 0 or dy != 0: + out.move(dx, dy) continue - break # Uncaught Control + if 0x09 <= command <= 0x17: + # C01 - C14 + needle = command - 0x08 + out.needle_out(needle) + if dx != 0 or dy != 0: + out.move(dx, dy) + continue + if command == 0x18: + break + if ctrl == 0x2B: + break # Rare postfix data from machine. Do not read this. + break # Uncaught Command out.end() return True diff --git a/pyembroidery/DsbReader.py b/pyembroidery/DsbReader.py index 7fc61e7..3da0d7f 100644 --- a/pyembroidery/DsbReader.py +++ b/pyembroidery/DsbReader.py @@ -2,7 +2,6 @@ from .DstReader import dst_read_header def b_stitch_encoding_read(f, out): - stitched_yet = False count = 0 while True: count += 1 @@ -20,7 +19,6 @@ def b_stitch_encoding_read(f, out): x = -x if (ctrl & 0b11111) == 0: - stitched_yet = True out.stitch(x, y) continue if (ctrl & 0b11111) == 1: @@ -36,8 +34,7 @@ def b_stitch_encoding_read(f, out): continue if 0xE9 <= ctrl < 0xF8: needle = ctrl - 0xE8 - if stitched_yet: - out.color_change() + out.needle_change(needle) continue break # Uncaught Control out.end() diff --git a/pyembroidery/DstWriter.py b/pyembroidery/DstWriter.py index 3daef08..48f27fa 100644 --- a/pyembroidery/DstWriter.py +++ b/pyembroidery/DstWriter.py @@ -146,7 +146,7 @@ def write(pattern, f, settings=None): for stitch in stitches: x = stitch[0] y = stitch[1] - data = stitch[2] + data = stitch[2] & COMMAND_MASK dx = int(round(x - xx)) dy = int(round(y - yy)) xx += dx diff --git a/pyembroidery/DszReader.py b/pyembroidery/DszReader.py index 05cbd79..324a432 100644 --- a/pyembroidery/DszReader.py +++ b/pyembroidery/DszReader.py @@ -2,7 +2,6 @@ from .DstReader import dst_read_header def z_stitch_encoding_read(f, out): - stitched_yet = False count = 0 while True: count += 1 @@ -20,7 +19,6 @@ def z_stitch_encoding_read(f, out): y = -y if (ctrl & 0b11111) == 0: - stitched_yet = True out.stitch(x, y) continue if (ctrl & 0b11111) == 1: @@ -34,8 +32,7 @@ def z_stitch_encoding_read(f, out): continue if 0x83 <= ctrl <= 0x9A: needle = (ctrl - 0x83) >> 1 - if stitched_yet: - out.color_change() + out.needle_change(needle) continue break # Uncaught Control out.end() diff --git a/pyembroidery/EmbConstant.py b/pyembroidery/EmbConstant.py index a34c162..1c1958a 100644 --- a/pyembroidery/EmbConstant.py +++ b/pyembroidery/EmbConstant.py @@ -1,3 +1,11 @@ +# The commands below 0xFF are intended to denote proper commands. +# The encodings beyond this is supplying additional information. + +COMMAND_MASK = 0x000000FF +THREAD_MASK = 0x0000FF00 +NEEDLE_MASK = 0x00FF0000 +ORDER_MASK = 0xFF000000 + NO_COMMAND = -1 STITCH = 0 JUMP = 1 @@ -5,11 +13,17 @@ TRIM = 2 STOP = 3 END = 4 COLOR_CHANGE = 5 +NEEDLE_SET = 9 SEQUIN_MODE = 6 SEQUIN_EJECT = 7 SLOW = 0xB FAST = 0xC +# Assigns the change sequences, allowing the color change commands to trigger any event. +# For these can be processed in some needle, thread, order values to preset or postset the +# Underlying change sequence. +SET_CHANGE_SEQUENCE = 0x10 + # Stitch with implied contingency. SEW_TO = 0xB0 NEEDLE_AT = 0xB1 @@ -18,35 +32,156 @@ STITCH_BREAK = 0xE0 SEQUENCE_BREAK = 0xE1 COLOR_BREAK = 0xE2 + +# Middle Level commands. TIE_ON = 0xE4 TIE_OFF = 0xE5 FRAME_EJECT = 0xE9 - +# Matrix Commands. MATRIX_TRANSLATE = 0xC0 -MATRIX_SCALE = 0xC1 -MATRIX_ROTATE = 0xC2 +MATRIX_SCALE_ORIGIN = 0xC1 +MATRIX_ROTATE_ORIGIN = 0xC2 +MATRIX_SCALE = 0xC4 +MATRIX_ROTATE = 0xC5 MATRIX_RESET = 0xC3 -OPTION_ENABLE_TIE_ON = 0xD1 -OPTION_ENABLE_TIE_OFF = 0xD2 -OPTION_DISABLE_TIE_ON = 0xD3 -OPTION_DISABLE_TIE_OFF = 0xD4 OPTION_MAX_STITCH_LENGTH = 0xD5 OPTION_MAX_JUMP_LENGTH = 0xD6 OPTION_EXPLICIT_TRIM = 0xD7 OPTION_IMPLICIT_TRIM = 0xD8 -CONTINGENCY_NONE = 0xF0 -CONTINGENCY_JUMP_NEEDLE = 0xF1 -CONTINGENCY_SEW_TO = 0xF2 +CONTINGENCY_TIE_ON_NONE = 0xD3 +CONTINGENCY_TIE_ON_THREE_SMALL = 0xD1 + +CONTINGENCY_TIE_OFF_NONE = 0xD4 +CONTINGENCY_TIE_OFF_THREE_SMALL = 0xD2 + +CONTINGENCY_LONG_STITCH_NONE = 0xF0 +CONTINGENCY_LONG_STITCH_JUMP_NEEDLE = 0xF1 +CONTINGENCY_LONG_STITCH_SEW_TO = 0xF2 CONTINGENCY_SEQUIN_UTILIZE = 0xF5 CONTINGENCY_SEQUIN_JUMP = 0xF6 CONTINGENCY_SEQUIN_STITCH = 0xF7 CONTINGENCY_SEQUIN_REMOVE = 0xF8 -# Eventually the commands are supposed to be limited to 255 thereby -# allowing additional information like, color change to color in position n -# To be stored in the higher level bits. -COMMAND_MASK = 0xFF + +def encode_thread_change(command, thread=None, needle=None, order=None): + if thread is None: + thread = 0 + else: + thread += 1 + thread &= 0xFF + if needle is None: + needle = 0 + else: + needle += 1 + needle &= 0xFF + if order is None: + order = 0 + else: + order += 1 + order &= 0xFF + command &= COMMAND_MASK + return command | (order << 24) | (needle << 16) | (thread << 8) + + +def decode_thread_change(command): + flag = command & COMMAND_MASK + thread = command & THREAD_MASK + thread >>= 8 + thread -= 1 + needle = command & NEEDLE_MASK + needle >>= 16 + needle -= 1 + order = command & ORDER_MASK + order >>= 24 + order -= 1 + return flag, thread, needle, order + + +def get_command_dictionary(): + return { + "NO_COMMAND": NO_COMMAND, + "STITCH": STITCH, + "JUMP": JUMP, + "TRIM": TRIM, + "STOP": STOP, + "END": END, + "SLOW": SLOW, + "FAST": FAST, + "COLOR_CHANGE": COLOR_CHANGE, + "NEEDLE_SET": NEEDLE_SET, + "SET_CHANGE_SEQUENCE": SET_CHANGE_SEQUENCE, + "SEQUIN_MODE": SEQUIN_MODE, + "SEQUIN_EJECT": SEQUIN_EJECT, + "SEW_TO": SEW_TO, + "NEEDLE_AT": NEEDLE_AT, + "STITCH_BREAK": STITCH_BREAK, + "SEQUENCE_BREAK": SEQUENCE_BREAK, + "COLOR_BREAK": COLOR_BREAK, + "TIE_ON": TIE_ON, + "TIE_OFF": TIE_OFF, + "FRAME_EJECT": FRAME_EJECT, + "MATRIX_TRANSLATE": MATRIX_TRANSLATE, + "MATRIX_SCALE_ORIGIN": MATRIX_SCALE_ORIGIN, + "MATRIX_ROTATE_ORIGIN": MATRIX_ROTATE_ORIGIN, + "MATRIX_SCALE": MATRIX_SCALE, + "MATRIX_ROTATE": MATRIX_ROTATE, + "MATRIX_RESET": MATRIX_RESET, + "CONTINGENCY_TIE_ON_THREE_SMALL": CONTINGENCY_TIE_ON_THREE_SMALL, + "CONTINGENCY_TIE_OFF_THREE_SMALL": CONTINGENCY_TIE_OFF_THREE_SMALL, + "CONTINGENCY_TIE_ON_NONE": CONTINGENCY_TIE_ON_NONE, + "CONTINGENCY_TIE_OFF_NONE": CONTINGENCY_TIE_OFF_NONE, + "OPTION_MAX_STITCH_LENGTH": OPTION_MAX_STITCH_LENGTH, + "OPTION_MAX_JUMP_LENGTH": OPTION_MAX_JUMP_LENGTH, + "OPTION_IMPLICIT_TRIM": OPTION_IMPLICIT_TRIM, + "OPTION_EXPLICIT_TRIM": OPTION_EXPLICIT_TRIM, + "CONTINGENCY_LONG_STITCH_NONE": CONTINGENCY_LONG_STITCH_NONE, + "CONTINGENCY_LONG_STITCH_JUMP_NEEDLE": CONTINGENCY_LONG_STITCH_JUMP_NEEDLE, + "CONTINGENCY_LONG_STITCH_SEW_TO": CONTINGENCY_LONG_STITCH_SEW_TO, + } + + +def get_common_name_dictionary(): + return { + NO_COMMAND: "NO_COMMAND", + STITCH: "STITCH", + JUMP: "JUMP", + TRIM: "TRIM", + STOP: "STOP", + END: "END", + SLOW: "SLOW", + FAST: "FAST", + COLOR_CHANGE: "COLOR_CHANGE", + NEEDLE_SET: "NEEDLE_SET", + SET_CHANGE_SEQUENCE: "SET_CHANGE_SEQUENCE", + SEQUIN_MODE: "SEQUIN_MODE", + SEQUIN_EJECT: "SEQUIN_EJECT", + SEW_TO: "SEW_TO", + NEEDLE_AT: "NEEDLE_AT", + STITCH_BREAK: "STITCH_BREAK", + SEQUENCE_BREAK: "SEQUENCE_BREAK", + COLOR_BREAK: "COLOR_BREAK", + TIE_ON: "TIE_ON", + TIE_OFF: "TIE_OFF", + FRAME_EJECT: "FRAME_EJECT", + MATRIX_TRANSLATE: "MATRIX_TRANSLATE", + MATRIX_SCALE: "MATRIX_SCALE", + MATRIX_ROTATE: "MATRIX_ROTATE", + MATRIX_SCALE_ORIGIN: "MATRIX_SCALE_ORIGIN", + MATRIX_ROTATE_ORIGIN: "MATRIX_ROTATE_ORIGIN", + MATRIX_RESET: "MATRIX_RESET", + CONTINGENCY_TIE_ON_THREE_SMALL: "CONTINGENCY_TIE_ON_THREE_SMALL", + CONTINGENCY_TIE_OFF_THREE_SMALL: "CONTINGENCY_TIE_OFF_THREE_SMALL", + CONTINGENCY_TIE_ON_NONE: "CONTINGENCY_TIE_ON_NONE", + CONTINGENCY_TIE_OFF_NONE: "CONTINGENCY_TIE_OFF_NONE", + OPTION_MAX_STITCH_LENGTH: "OPTION_MAX_STITCH_LENGTH", + OPTION_MAX_JUMP_LENGTH: "OPTION_MAX_JUMP_LENGTH", + OPTION_IMPLICIT_TRIM: "OPTION_IMPLICIT_TRIM", + OPTION_EXPLICIT_TRIM: "OPTION_EXPLICIT_TRIM", + CONTINGENCY_LONG_STITCH_NONE: "CONTINGENCY_LONG_STITCH_NONE", + CONTINGENCY_LONG_STITCH_JUMP_NEEDLE: "CONTINGENCY_LONG_STITCH_JUMP_NEEDLE", + CONTINGENCY_LONG_STITCH_SEW_TO: "CONTINGENCY_LONG_STITCH_SEW_TO" + } diff --git a/pyembroidery/EmbEncoder.py b/pyembroidery/EmbEncoder.py index 2376eb3..e42fda0 100644 --- a/pyembroidery/EmbEncoder.py +++ b/pyembroidery/EmbEncoder.py @@ -10,20 +10,33 @@ class Transcoder: self.max_stitch = settings.get("max_stitch", float('inf')) self.max_jump = settings.get("max_jump", float('inf')) self.full_jump = settings.get("full_jump", False) + self.needle_count = settings.get("needle_count", 1) + self.thread_change_command = settings.get("thread_change_command", COLOR_CHANGE) strip_sequins = settings.get("strip_sequins", True) + # deprecated, use sequin_contingency. if strip_sequins: - self.sequin_contingency = CONTINGENCY_SEQUIN_UTILIZE - else: self.sequin_contingency = CONTINGENCY_SEQUIN_JUMP + else: + self.sequin_contingency = CONTINGENCY_SEQUIN_UTILIZE self.sequin_contingency = settings.get("sequin_contingency", self.sequin_contingency) self.strip_speeds = settings.get("strip_speeds", True) - self.explicit_trim = settings.get("explicit_trim", True) + self.explicit_trim = settings.get("explicit_trim", False) + + self.tie_on_contingency = settings.get("tie_on", CONTINGENCY_TIE_ON_NONE) + if self.tie_on_contingency is True: + self.tie_on_contingency = CONTINGENCY_TIE_ON_THREE_SMALL + if self.tie_on_contingency is False: + self.tie_on_contingency = CONTINGENCY_TIE_ON_NONE + + self.tie_off_contingency = settings.get("tie_off", CONTINGENCY_TIE_OFF_NONE) + if self.tie_off_contingency is True: + self.tie_off_contingency = CONTINGENCY_TIE_OFF_THREE_SMALL + if self.tie_off_contingency is False: + self.tie_off_contingency = CONTINGENCY_TIE_OFF_NONE - self.has_tie_on = settings.get("tie_on", False) - self.has_tie_off = settings.get("tie_off", False) self.long_stitch_contingency = \ - settings.get("long_stitch_contingency", CONTINGENCY_JUMP_NEEDLE) + settings.get("long_stitch_contingency", CONTINGENCY_LONG_STITCH_JUMP_NEEDLE) self.matrix = get_identity() translate = settings.get("translate", None) @@ -56,15 +69,20 @@ class Transcoder: self.source_pattern = None self.destination_pattern = None self.position = 0 - self.color_index = -1 + self.order_index = -1 + self.change_sequence = {} self.stitch = None self.state_trimmed = True self.state_sequin_mode = False + self.state_jumping = False self.needle_x = 0 self.needle_y = 0 - self.state_jumping = False def transcode(self, source_pattern, destination_pattern): + if source_pattern is destination_pattern: + # both objects are same. Source is copy, destination is cleared. + source_pattern = destination_pattern.copy() + destination_pattern.clear() self.source_pattern = source_pattern self.destination_pattern = destination_pattern self.transcode_metadata() @@ -93,24 +111,86 @@ class Transcoder: self.needle_x = 0 self.needle_y = 0 self.position = 0 - self.color_index = -1 + self.order_index = -1 + self.change_sequence = {} + + lookahead_index = 0 + current_index = 0 + self.change_sequence[0] = [None, None, None, None] + + for self.position, self.stitch in enumerate(source): + command = self.stitch[2] + flags = command & COMMAND_MASK + + if current_index == 0: + if flags == STITCH or flags == SEW_TO or flags == NEEDLE_AT or flags == SEQUIN_EJECT: + current_index = 1 + + if flags != SET_CHANGE_SEQUENCE and flags != NEEDLE_SET \ + and flags != COLOR_CHANGE and flags != COLOR_BREAK: + continue + + if flags == SET_CHANGE_SEQUENCE: + try: + current = self.change_sequence[lookahead_index] + except KeyError: + current = [None, None, None, None] + self.change_sequence[lookahead_index] = current + lookahead_index += 1 + else: + try: + current = self.change_sequence[current_index] + except KeyError: + current = [None, None, None, None] + self.change_sequence[current_index] = current + current_index += 1 + if current_index > lookahead_index: + lookahead_index = current_index + decode_change = decode_thread_change(command) + thread = decode_change[1] + needle = decode_change[2] + if flags == COLOR_CHANGE: + current[0] = COLOR_CHANGE + elif flags == NEEDLE_SET: + current[0] = NEEDLE_SET + if thread != -1: + current[1] = thread + current[3] = self.source_pattern.get_thread_or_filler(thread) + if needle != -1: + current[2] = needle + # TODO: account for contingency where threadset has repeated + # threads and not explicit values set within the commands. + + thread_index = 0 + needle_index = 1 + for order, s in self.change_sequence.items(): + if s[0] is None: + s[0] = self.thread_change_command + if s[1] is None: + s[1] = thread_index + thread_index += 1 + if s[2] is None: + s[2] = needle_index + # self.needle_count + needle_index += 1 + if s[3] is None: + s[3] = self.source_pattern.get_thread_or_filler(s[1]) flags = NO_COMMAND for self.position, self.stitch in enumerate(source): p = point_in_matrix_space(self.matrix, self.stitch) x = p[0] y = p[1] - flags = self.stitch[2] + flags = self.stitch[2] & COMMAND_MASK if flags == NO_COMMAND: continue - elif flags == STITCH: if self.state_trimmed: + self.declare_not_trimmed() self.jump_to_within_stitchrange(x, y) self.stitch_at(x, y) - if self.has_tie_on: - self.tie_on() + self.tie_on() elif self.state_jumping: self.needle_to(x, y) self.state_jumping = False @@ -118,10 +198,10 @@ class Transcoder: self.stitch_with_contingency(x, y) elif flags == NEEDLE_AT: if self.state_trimmed: + self.declare_not_trimmed() self.jump_to_within_stitchrange(x, y) self.stitch_at(x, y) - if self.has_tie_on: - self.tie_on() + self.tie_on() elif self.state_jumping: self.needle_to(x, y) self.state_jumping = False @@ -129,10 +209,10 @@ class Transcoder: self.needle_to(x, y) elif flags == SEW_TO: if self.state_trimmed: + self.declare_not_trimmed() self.jump_to_within_stitchrange(x, y) self.stitch_at(x, y) - if self.has_tie_on: - self.tie_on() + self.tie_on() elif self.state_jumping: self.needle_to(x, y) self.state_jumping = False @@ -165,17 +245,17 @@ class Transcoder: self.toggle_sequins() elif flags == SEQUIN_EJECT: if self.state_trimmed: + self.declare_not_trimmed() self.jump_to_within_stitchrange(x, y) self.stitch_at(x, y) - if self.has_tie_on: - self.tie_on() + self.tie_on() if not self.state_sequin_mode: self.toggle_sequins() self.sequin_at(x, y) elif flags == COLOR_CHANGE: self.tie_off_trim_color_change() - # If we are told to do something we do it. - # Even if it's the first command and makes no sense. + elif flags == NEEDLE_SET: + self.tie_off_trim_color_change() elif flags == STOP: self.stop_here() elif flags == SLOW: @@ -185,16 +265,15 @@ class Transcoder: elif flags == END: self.end_here() break - # On-the-fly Settings Commands. - elif flags == OPTION_ENABLE_TIE_ON: - self.has_tie_on = True - elif flags == OPTION_ENABLE_TIE_OFF: - self.has_tie_off = True - elif flags == OPTION_DISABLE_TIE_ON: - self.has_tie_on = False - elif flags == OPTION_DISABLE_TIE_OFF: - self.has_tie_off = False + elif flags == CONTINGENCY_TIE_ON_THREE_SMALL: + self.tie_on_contingency = CONTINGENCY_TIE_ON_THREE_SMALL + elif flags == CONTINGENCY_TIE_OFF_THREE_SMALL: + self.tie_off_contingency = CONTINGENCY_TIE_OFF_THREE_SMALL + elif flags == CONTINGENCY_TIE_ON_NONE: + self.tie_on_contingency = CONTINGENCY_TIE_ON_NONE + elif flags == CONTINGENCY_TIE_OFF_NONE: + self.tie_off_contingency = CONTINGENCY_TIE_OFF_NONE elif flags == OPTION_MAX_JUMP_LENGTH: x = self.stitch[0] self.max_jump = x @@ -205,12 +284,12 @@ class Transcoder: self.explicit_trim = True elif flags == OPTION_IMPLICIT_TRIM: self.explicit_trim = False - elif flags == CONTINGENCY_NONE: - self.long_stitch_contingency = CONTINGENCY_NONE - elif flags == CONTINGENCY_JUMP_NEEDLE: - self.long_stitch_contingency = CONTINGENCY_JUMP_NEEDLE - elif flags == CONTINGENCY_SEW_TO: - self.long_stitch_contingency = CONTINGENCY_SEW_TO + elif flags == CONTINGENCY_LONG_STITCH_NONE: + self.long_stitch_contingency = CONTINGENCY_LONG_STITCH_NONE + elif flags == CONTINGENCY_LONG_STITCH_JUMP_NEEDLE: + self.long_stitch_contingency = CONTINGENCY_LONG_STITCH_JUMP_NEEDLE + elif flags == CONTINGENCY_LONG_STITCH_SEW_TO: + self.long_stitch_contingency = CONTINGENCY_LONG_STITCH_SEW_TO elif flags == CONTINGENCY_SEQUIN_REMOVE: if self.state_sequin_mode: # if sequin_mode, turn it off. self.toggle_sequins() @@ -228,12 +307,26 @@ class Transcoder: elif flags == MATRIX_TRANSLATE: m = get_translate(self.stitch[0], self.stitch[1]) self.matrix = matrix_multiply(self.matrix, m) - elif flags == MATRIX_SCALE: + elif flags == MATRIX_SCALE_ORIGIN: m = get_scale(self.stitch[0], self.stitch[1]) self.matrix = matrix_multiply(self.matrix, m) - elif flags == MATRIX_ROTATE: + elif flags == MATRIX_ROTATE_ORIGIN: m = get_rotate(self.stitch[0]) self.matrix = matrix_multiply(self.matrix, m) + elif flags == MATRIX_SCALE: + pos = point_in_matrix_space(self.matrix, (self.needle_x, self.needle_y)) + m0 = get_translate(-pos[0], -pos[1]) + m1 = get_scale(self.stitch[0], self.stitch[1]) + m2 = get_translate(pos[0], pos[1]) + m = post_matrix_cat((m0, m1, m2)) + self.matrix = matrix_multiply(self.matrix, m) + elif flags == MATRIX_ROTATE: + pos = point_in_matrix_space(self.matrix, (self.needle_x, self.needle_y)) + m0 = get_translate(-pos[0], -pos[1]) + m1 = get_rotate(self.stitch[0]) + m2 = get_translate(pos[0], pos[1]) + m = post_matrix_cat((m0, m1, m2)) + self.matrix = matrix_multiply(self.matrix, m) elif flags == MATRIX_RESET: self.matrix = get_identity() if flags != END: @@ -244,10 +337,12 @@ class Transcoder: self.needle_y = y def declare_not_trimmed(self): - if self.state_trimmed: - self.state_trimmed = False - if self.color_index == -1: - self.color_index = 0 + self.state_trimmed = False + if self.order_index == -1: + self.next_change_sequence() + + def add_thread_change(self, command, thread=None, needle=None, order=None): + self.add(encode_thread_change(command, thread, needle, order)) def add(self, flags, x=None, y=None): if x is None: @@ -279,27 +374,23 @@ class Transcoder: def color_break(self): """Implements color break. Should add color changes add needed only.""" - if self.color_index < 0: + if self.order_index < 0: return # We haven't stitched anything, colorbreak happens, before start. Ignore. if not self.state_trimmed: - if self.has_tie_off: - self.tie_off() + self.tie_off() if self.explicit_trim: self.trim_here() if not self.lookahead_stitch(): return # No more stitching will happen, colorchange unneeded. - self.add(COLOR_CHANGE) - self.color_index += 1 + self.next_change_sequence() self.state_trimmed = True def tie_off_trim_color_change(self): if not self.state_trimmed: - if self.has_tie_off: - self.tie_off() + self.tie_off() if self.explicit_trim: self.trim_here() - self.add(COLOR_CHANGE) - self.color_index += 1 + self.next_change_sequence() self.state_trimmed = True def tie_off_and_trim_if_needed(self): @@ -307,37 +398,38 @@ class Transcoder: self.tie_off_and_trim() def tie_off_and_trim(self): - if self.has_tie_off: - self.tie_off() + self.tie_off() self.trim_here() def tie_off(self): - try: - b = point_in_matrix_space( - self.matrix, - self.source_pattern.stitches[self.position - 1], - ) - flags = b[2] - if flags == STITCH or flags == NEEDLE_AT or \ - flags == SEW_TO or flags == SEQUIN_EJECT: - self.lock_stitch(self.needle_x, self.needle_y, - b[0], b[1], self.max_stitch) - except IndexError: - pass # must be an island stitch. jump-stitch-jump + if self.tie_off_contingency == CONTINGENCY_TIE_OFF_THREE_SMALL: + try: + b = point_in_matrix_space( + self.matrix, + self.source_pattern.stitches[self.position - 1], + ) + flags = b[2] + if flags == STITCH or flags == NEEDLE_AT or \ + flags == SEW_TO or flags == SEQUIN_EJECT: + self.lock_stitch(self.needle_x, self.needle_y, + b[0], b[1], self.max_stitch) + except IndexError: + pass # must be an island stitch. jump-stitch-jump def tie_on(self): - try: - b = point_in_matrix_space( - self.matrix, - self.source_pattern.stitches[self.position + 1] - ) - flags = b[2] - if flags == STITCH or flags == NEEDLE_AT or \ - flags == SEW_TO or flags == SEQUIN_EJECT: - self.lock_stitch(self.needle_x, self.needle_y, - b[0], b[1], self.max_stitch) - except IndexError: - pass # must be an island stitch. jump-stitch-jump + if self.tie_on_contingency == CONTINGENCY_TIE_ON_THREE_SMALL: + try: + b = point_in_matrix_space( + self.matrix, + self.source_pattern.stitches[self.position + 1] + ) + flags = b[2] + if flags == STITCH or flags == NEEDLE_AT or \ + flags == SEW_TO or flags == SEQUIN_EJECT: + self.lock_stitch(self.needle_x, self.needle_y, + b[0], b[1], self.max_stitch) + except IndexError: + pass # must be an island stitch. jump-stitch-jump def trim_here(self): if self.state_sequin_mode: @@ -383,9 +475,9 @@ class Transcoder: self.update_needle_position(new_x, new_y) def stitch_with_contingency(self, new_x, new_y): - if self.long_stitch_contingency == CONTINGENCY_SEW_TO: + if self.long_stitch_contingency == CONTINGENCY_LONG_STITCH_SEW_TO: self.sew_to(new_x, new_y) - elif self.long_stitch_contingency == CONTINGENCY_JUMP_NEEDLE: + elif self.long_stitch_contingency == CONTINGENCY_LONG_STITCH_JUMP_NEEDLE: self.needle_to(new_x, new_y) else: self.stitch_at(new_x, new_y) @@ -421,7 +513,6 @@ class Transcoder: Should have already been checked for constraints.""" self.add(STITCH, new_x, new_y) self.update_needle_position(new_x, new_y) - self.declare_not_trimmed() def sequin_at(self, new_x, new_y): """Sequin Ejects at position with the proper Sequin Contingency @@ -444,7 +535,6 @@ class Transcoder: elif contingency == CONTINGENCY_SEQUIN_STITCH: self.add(STITCH, new_x, new_y) self.update_needle_position(new_x, new_y) - self.declare_not_trimmed() def slow_command_here(self): if not self.strip_speeds: @@ -462,9 +552,14 @@ class Transcoder: self.add(END) self.state_trimmed = True - def color_change_here(self): - self.add(COLOR_CHANGE) - self.color_index += 1 + def next_change_sequence(self): + self.order_index += 1 + change = self.change_sequence[self.order_index] + if self.thread_change_command == COLOR_CHANGE: + if self.order_index != 0: + self.add_thread_change(COLOR_CHANGE, change[1], change[2]) + elif self.thread_change_command == NEEDLE_SET: + self.add_thread_change(NEEDLE_SET, change[1], change[2]) self.state_trimmed = True def position_will_exceed_constraint(self, length=None, new_x=None, new_y=None): @@ -598,6 +693,13 @@ def get_rotate(theta): 0, 0, 1 +def post_matrix_cat(matrix_list): + m = get_identity() + for mx in matrix_list: + m = matrix_multiply(m, mx) + return m + + def matrix_multiply(a, b): return [ a[0] * b[0] + a[1] * b[3] + a[2] * b[6], diff --git a/pyembroidery/EmbPattern.py b/pyembroidery/EmbPattern.py index 62d17ed..2c79328 100644 --- a/pyembroidery/EmbPattern.py +++ b/pyembroidery/EmbPattern.py @@ -1,5 +1,3 @@ -import random - from .EmbThread import EmbThread from .EmbEncoder import Transcoder as Normalizer from .EmbConstant import * @@ -14,6 +12,22 @@ class EmbPattern: self._previousX = 0 # type: float self._previousY = 0 # type: float + def copy(self): + emb_pattern = EmbPattern() + emb_pattern.stitches = self.stitches[:] + emb_pattern.threadlist = self.threadlist[:] + emb_pattern.extras.update(self.extras) + emb_pattern._previousX = self._previousX + emb_pattern._previousY = self._previousY + return emb_pattern + + def clear(self): + self.stitches = [] + self.threadlist = [] + self.extras = {} + self._previousX = 0 + self._previousY = 0 + def move(self, dx=0, dy=0): """Move dx, dy""" self.add_stitch_relative(JUMP, dx, dy) @@ -42,6 +56,11 @@ class EmbPattern: """Color Change dx, dy""" self.add_stitch_relative(COLOR_CHANGE, dx, dy) + def needle_change(self, needle=0, dx=0, dy=0): + """Needle change, needle, dx, dy""" + cmd = encode_thread_change(NEEDLE_SET, None, needle) + self.add_stitch_relative(cmd, dx, dy) + def sequin_eject(self, dx=0, dy=0): """Eject Sequin dx, dy""" self.add_stitch_relative(SEQUIN_EJECT, dx, dy) @@ -92,7 +111,7 @@ class EmbPattern: def count_stitch_commands(self, command): count = 0 for stitch in self.stitches: - flags = stitch[2] + flags = stitch[2] & COMMAND_MASK if flags == command: count += 1 return count @@ -100,6 +119,9 @@ class EmbPattern: def count_color_changes(self): return self.count_stitch_commands(COLOR_CHANGE) + def count_needle_sets(self): + return self.count_stitch_commands(NEEDLE_SET) + def count_stitches(self): return len(self.stitches) @@ -109,7 +131,7 @@ class EmbPattern: @staticmethod def get_random_thread(): thread = EmbThread() - thread.color = 0xFF000000 | random.randint(0, 0xFFFFFF) + thread.set("random") thread.description = "Random" return thread @@ -119,12 +141,15 @@ class EmbPattern: else: return self.threadlist[index] + def get_thread(self, index): + return self.threadlist[index] + def get_as_stitchblock(self): stitchblock = [] thread = self.get_thread_or_filler(0) thread_index = 1 for stitch in self.stitches: - flags = stitch[2] + flags = stitch[2] & COMMAND_MASK if flags == STITCH: stitchblock.append(stitch) else: @@ -141,7 +166,7 @@ class EmbPattern: last_pos = 0 last_command = NO_COMMAND for pos, stitch in enumerate(self.stitches): - command = stitch[2] + command = stitch[2] & COMMAND_MASK if command == last_command or last_command == NO_COMMAND: last_command = command continue @@ -154,7 +179,8 @@ class EmbPattern: thread_index = 0 last_pos = 0 for pos, stitch in enumerate(self.stitches): - if stitch[2] != COLOR_CHANGE: + command = stitch[2] & COMMAND_MASK + if command != COLOR_CHANGE: continue thread = self.get_thread_or_filler(thread_index) thread_index += 1 @@ -186,7 +212,7 @@ class EmbPattern: stitch[0] += dx stitch[1] += dy - def fix_color_count(self): + def fix_color_count(self): # TODO: FIX COLOR COUNT is basically part of the encoder now. """Ensure the there are threads for all color blocks.""" thread_index = 0 init_color = True @@ -247,7 +273,7 @@ class EmbPattern: while i < ie: i += 1 stitch = self.stitches[i] - command = stitch[2] + command = stitch[2] & COMMAND_MASK if command == STITCH or command == SEQUIN_EJECT: trimmed = False elif command == COLOR_CHANGE or command == TRIM: @@ -284,7 +310,8 @@ class EmbPattern: while i < ie: i += 1 stitch = self.stitches[i] - if stitch[2] == JUMP: + command = stitch[2] & COMMAND_MASK + if command == JUMP: if stitch_break: continue new_pattern.add_command(STITCH_BREAK) @@ -306,7 +333,7 @@ class EmbPattern: return stable_pattern def get_normalized_pattern(self, encode_settings=None): - """Encodes""" + """Encodes pattern typically for saving.""" normal_pattern = EmbPattern() transcoder = Normalizer(encode_settings) transcoder.transcode(self, normal_pattern) @@ -317,23 +344,3 @@ class EmbPattern: All commands will be translated by the given amount, including absolute location commands.""" self.add_stitch_relative(MATRIX_TRANSLATE, x, y, ) - - def append_enable_tie_on(self, x=0, y=0): - """Appends enable tie on. - All starts of new stitching will be tied on""" - self.add_stitch_relative(OPTION_ENABLE_TIE_ON, x, y) - - def append_enable_tie_off(self, x=0, y=0): - """Appends enable tie off. - All ends of stitching will be tied off""" - self.add_stitch_relative(OPTION_ENABLE_TIE_OFF, x, y) - - def append_disable_tie_on(self, x=0, y=0): - """Appends disable tie on. - New stitching will no longer be tied on""" - self.add_stitch_relative(OPTION_DISABLE_TIE_ON, x, y) - - def append_disable_tie_off(self, x=0, y=0): - """Appends enable tie off. - Ends of stitching will no longer be tied off""" - self.add_stitch_relative(OPTION_DISABLE_TIE_OFF, x, y) diff --git a/pyembroidery/EmbThread.py b/pyembroidery/EmbThread.py index 30abbbe..7f7eeba 100644 --- a/pyembroidery/EmbThread.py +++ b/pyembroidery/EmbThread.py @@ -24,6 +24,22 @@ def find_nearest_color_index(find_color, values): return closest_index +def color_rgb(r, g, b): + return int(0xFF000000 | + ((r & 255) << 16) | + ((g & 255) << 8) | + (b & 255)) + + +def color_hex(hex_string): + h = hex_string.lstrip('#') + size = len(h) + if size == 6 or size == 8: + return int(h[:6], 16) + elif size == 4 or size == 3: + return int(h[2] + h[2] + h[1] + h[1] + h[0] + h[0], 16) + + def color_distance_red_mean( r1, g1, b1, r2, g2, b2): @@ -50,37 +66,33 @@ class EmbThread: # description, catalog_number, details, brand, chart, weight def set_color(self, r, g, b): - self.color = 0xFF000000 | ( - (r & 255) << 16) | ( - (g & 255) << 8) | ( - b & 255) + self.color = color_rgb(r, g, b) def get_opaque_color(self): return 0xFF000000 | self.color def get_red(self): - return (self.color >> 16) & 0xFF + red = self.color >> 16 + return red & 0xFF def get_green(self): - return (self.color >> 8) & 0xFF + green = self.color >> 8 + return green & 0xFF def get_blue(self): - return self.color & 0xFF + blue = self.color + return blue & 0xFF def find_nearest_color_index(self, values): - return find_nearest_color_index(self.color, values) + return find_nearest_color_index(int(self.color), values) def hex_color(self): return "#%02x%02x%02x" % ( - self.get_red(), self.get_green(), self.get_blue()) + self.get_red(), self.get_green(), self.get_blue() + ) def set_hex_color(self, hex_string): - h = hex_string.lstrip('#') - size = len(h) - if size == 6 or size == 8: - self.color = int(h[:6], 16) - elif size == 4 or size == 3: - self.color = int(h[2] + h[2] + h[1] + h[1] + h[0] + h[0], 16) + self.color = color_hex(hex_string) def set(self, thread): if isinstance(thread, EmbThread): @@ -93,6 +105,8 @@ class EmbThread: self.weight = thread.weight elif isinstance(thread, int): self.color = thread + elif isinstance(thread,long): + self.color = int(thread) elif isinstance(thread, dict): if "name" in thread: self.description = thread["name"] @@ -112,11 +126,7 @@ class EmbThread: if isinstance(color, int): self.color = color elif isinstance(color, str): - if color == "random": - import random - self.color = 0xFF000000 | random.randint(0, 0xFFFFFF) - if color[0:1] == "#": - self.set_hex_color(color[1:]) + self.color = self.parse_string_color(color) elif isinstance(color, tuple) or isinstance(color, list): self.color = (color[0] & 0xFF) << 16 | \ (color[1] & 0xFF) << 8 | \ @@ -127,3 +137,165 @@ class EmbThread: self.catalog_number = thread["id"] if "catalog" in thread: self.catalog_number = thread["catalog"] + elif isinstance(thread, str): + self.color = self.parse_string_color(thread) + + @staticmethod + def parse_string_color(color): + if color == "random": + import random + return 0xFF000000 | random.randint(0, 0xFFFFFF) + if color[0:1] == "#": + return color_hex(color[1:]) + color_dict = { + "aliceblue": color_rgb(240, 248, 255), + "antiquewhite": color_rgb(250, 235, 215), + "aqua": color_rgb(0, 255, 255), + "aquamarine": color_rgb(127, 255, 212), + "azure": color_rgb(240, 255, 255), + "beige": color_rgb(245, 245, 220), + "bisque": color_rgb(255, 228, 196), + "black": color_rgb(0, 0, 0), + "blanchedalmond": color_rgb(255, 235, 205), + "blue": color_rgb(0, 0, 255), + "blueviolet": color_rgb(138, 43, 226), + "brown": color_rgb(165, 42, 42), + "burlywood": color_rgb(222, 184, 135), + "cadetblue": color_rgb(95, 158, 160), + "chartreuse": color_rgb(127, 255, 0), + "chocolate": color_rgb(210, 105, 30), + "coral": color_rgb(255, 127, 80), + "cornflowerblue": color_rgb(100, 149, 237), + "cornsilk": color_rgb(255, 248, 220), + "crimson": color_rgb(220, 20, 60), + "cyan": color_rgb(0, 255, 255), + "darkblue": color_rgb(0, 0, 139), + "darkcyan": color_rgb(0, 139, 139), + "darkgoldenrod": color_rgb(184, 134, 11), + "darkgray": color_rgb(169, 169, 169), + "darkgreen": color_rgb(0, 100, 0), + "darkgrey": color_rgb(169, 169, 169), + "darkkhaki": color_rgb(189, 183, 107), + "darkmagenta": color_rgb(139, 0, 139), + "darkolivegreen": color_rgb(85, 107, 47), + "darkorange": color_rgb(255, 140, 0), + "darkorchid": color_rgb(153, 50, 204), + "darkred": color_rgb(139, 0, 0), + "darksalmon": color_rgb(233, 150, 122), + "darkseagreen": color_rgb(143, 188, 143), + "darkslateblue": color_rgb(72, 61, 139), + "darkslategray": color_rgb(47, 79, 79), + "darkslategrey": color_rgb(47, 79, 79), + "darkturquoise": color_rgb(0, 206, 209), + "darkviolet": color_rgb(148, 0, 211), + "deeppink": color_rgb(255, 20, 147), + "deepskyblue": color_rgb(0, 191, 255), + "dimgray": color_rgb(105, 105, 105), + "dimgrey": color_rgb(105, 105, 105), + "dodgerblue": color_rgb(30, 144, 255), + "firebrick": color_rgb(178, 34, 34), + "floralwhite": color_rgb(255, 250, 240), + "forestgreen": color_rgb(34, 139, 34), + "fuchsia": color_rgb(255, 0, 255), + "gainsboro": color_rgb(220, 220, 220), + "ghostwhite": color_rgb(248, 248, 255), + "gold": color_rgb(255, 215, 0), + "goldenrod": color_rgb(218, 165, 32), + "gray": color_rgb(128, 128, 128), + "grey": color_rgb(128, 128, 128), + "green": color_rgb(0, 128, 0), + "greenyellow": color_rgb(173, 255, 47), + "honeydew": color_rgb(240, 255, 240), + "hotpink": color_rgb(255, 105, 180), + "indianred": color_rgb(205, 92, 92), + "indigo": color_rgb(75, 0, 130), + "ivory": color_rgb(255, 255, 240), + "khaki": color_rgb(240, 230, 140), + "lavender": color_rgb(230, 230, 250), + "lavenderblush": color_rgb(255, 240, 245), + "lawngreen": color_rgb(124, 252, 0), + "lemonchiffon": color_rgb(255, 250, 205), + "lightblue": color_rgb(173, 216, 230), + "lightcoral": color_rgb(240, 128, 128), + "lightcyan": color_rgb(224, 255, 255), + "lightgoldenrodyellow": color_rgb(250, 250, 210), + "lightgray": color_rgb(211, 211, 211), + "lightgreen": color_rgb(144, 238, 144), + "lightgrey": color_rgb(211, 211, 211), + "lightpink": color_rgb(255, 182, 193), + "lightsalmon": color_rgb(255, 160, 122), + "lightseagreen": color_rgb(32, 178, 170), + "lightskyblue": color_rgb(135, 206, 250), + "lightslategray": color_rgb(119, 136, 153), + "lightslategrey": color_rgb(119, 136, 153), + "lightsteelblue": color_rgb(176, 196, 222), + "lightyellow": color_rgb(255, 255, 224), + "lime": color_rgb(0, 255, 0), + "limegreen": color_rgb(50, 205, 50), + "linen": color_rgb(250, 240, 230), + "magenta": color_rgb(255, 0, 255), + "maroon": color_rgb(128, 0, 0), + "mediumaquamarine": color_rgb(102, 205, 170), + "mediumblue": color_rgb(0, 0, 205), + "mediumorchid": color_rgb(186, 85, 211), + "mediumpurple": color_rgb(147, 112, 219), + "mediumseagreen": color_rgb(60, 179, 113), + "mediumslateblue": color_rgb(123, 104, 238), + "mediumspringgreen": color_rgb(0, 250, 154), + "mediumturquoise": color_rgb(72, 209, 204), + "mediumvioletred": color_rgb(199, 21, 133), + "midnightblue": color_rgb(25, 25, 112), + "mintcream": color_rgb(245, 255, 250), + "mistyrose": color_rgb(255, 228, 225), + "moccasin": color_rgb(255, 228, 181), + "navajowhite": color_rgb(255, 222, 173), + "navy": color_rgb(0, 0, 128), + "oldlace": color_rgb(253, 245, 230), + "olive": color_rgb(128, 128, 0), + "olivedrab": color_rgb(107, 142, 35), + "orange": color_rgb(255, 165, 0), + "orangered": color_rgb(255, 69, 0), + "orchid": color_rgb(218, 112, 214), + "palegoldenrod": color_rgb(238, 232, 170), + "palegreen": color_rgb(152, 251, 152), + "paleturquoise": color_rgb(175, 238, 238), + "palevioletred": color_rgb(219, 112, 147), + "papayawhip": color_rgb(255, 239, 213), + "peachpuff": color_rgb(255, 218, 185), + "peru": color_rgb(205, 133, 63), + "pink": color_rgb(255, 192, 203), + "plum": color_rgb(221, 160, 221), + "powderblue": color_rgb(176, 224, 230), + "purple": color_rgb(128, 0, 128), + "red": color_rgb(255, 0, 0), + "rosybrown": color_rgb(188, 143, 143), + "royalblue": color_rgb(65, 105, 225), + "saddlebrown": color_rgb(139, 69, 19), + "salmon": color_rgb(250, 128, 114), + "sandybrown": color_rgb(244, 164, 96), + "seagreen": color_rgb(46, 139, 87), + "seashell": color_rgb(255, 245, 238), + "sienna": color_rgb(160, 82, 45), + "silver": color_rgb(192, 192, 192), + "skyblue": color_rgb(135, 206, 235), + "slateblue": color_rgb(106, 90, 205), + "slategray": color_rgb(112, 128, 144), + "slategrey": color_rgb(112, 128, 144), + "snow": color_rgb(255, 250, 250), + "springgreen": color_rgb(0, 255, 127), + "steelblue": color_rgb(70, 130, 180), + "tan": color_rgb(210, 180, 140), + "teal": color_rgb(0, 128, 128), + "thistle": color_rgb(216, 191, 216), + "tomato": color_rgb(255, 99, 71), + "turquoise": color_rgb(64, 224, 208), + "violet": color_rgb(238, 130, 238), + "wheat": color_rgb(245, 222, 179), + "white": color_rgb(255, 255, 255), + "whitesmoke": color_rgb(245, 245, 245), + "yellow": color_rgb(255, 255, 0), + "yellowgreen": color_rgb(154, 205, 50) + } + if color in color_dict: + return color_dict[color] + return 0xFF000000 # Failed, so black. diff --git a/pyembroidery/ExpWriter.py b/pyembroidery/ExpWriter.py index 5992c4c..76102f7 100644 --- a/pyembroidery/ExpWriter.py +++ b/pyembroidery/ExpWriter.py @@ -1,5 +1,6 @@ from .EmbConstant import * +HAS_THREADS = False SEQUIN_CONTINGENCY = CONTINGENCY_SEQUIN_JUMP FULL_JUMP = True MAX_JUMP_DISTANCE = 127 @@ -13,7 +14,7 @@ def write(pattern, f, settings=None): for stitch in stitches: x = stitch[0] y = stitch[1] - data = stitch[2] + data = stitch[2] & COMMAND_MASK dx = int(round(x - xx)) dy = int(round(y - yy)) xx += dx diff --git a/pyembroidery/JefWriter.py b/pyembroidery/JefWriter.py index 6166ac6..c3855f8 100644 --- a/pyembroidery/JefWriter.py +++ b/pyembroidery/JefWriter.py @@ -85,7 +85,7 @@ def write(pattern, f, settings=None): for stitch in pattern.stitches: x = stitch[0] y = stitch[1] - data = stitch[2] + data = stitch[2] & COMMAND_MASK dx = int(round(x - xx)) dy = int(round(y - yy)) xx += dx diff --git a/pyembroidery/KsmReader.py b/pyembroidery/KsmReader.py index 10e0b25..0879152 100644 --- a/pyembroidery/KsmReader.py +++ b/pyembroidery/KsmReader.py @@ -39,7 +39,7 @@ def read_ksm_stitches(f, out): continue if 0x0B <= ctrl <= 0x12: needle = ctrl - 0x0A - out.color_change() + out.needle_change(needle) trimmed = True continue if ctrl == 0x05: diff --git a/pyembroidery/PecReader.py b/pyembroidery/PecReader.py index 82b8147..d4973c0 100644 --- a/pyembroidery/PecReader.py +++ b/pyembroidery/PecReader.py @@ -47,13 +47,13 @@ def read_pec(f, out, pes_chart=None): def read_pec_graphics(f, out, size, stride, count, values): - # TODO: Breaking Change PEC GRAPHIC names to pec_graphic_0... v = values[:] v.insert(0, None) for i in range(0, count): graphic = bytearray(f.read(size)) if f is not None: - out.metadata(i, (graphic, stride, v[i])) + name = "pec_graphic_" + str(i) + out.metadata(name, (graphic, stride, v[i])) def process_pec_colors(colorbytes, out, values): diff --git a/pyembroidery/PecWriter.py b/pyembroidery/PecWriter.py index eca44cb..ef0ad7e 100644 --- a/pyembroidery/PecWriter.py +++ b/pyembroidery/PecWriter.py @@ -120,12 +120,12 @@ def encode_long_form(value): return value -def flag_jump(longForm): - return longForm | (JUMP_CODE << 8) +def flag_jump(long_form): + return long_form | (JUMP_CODE << 8) -def flag_trim(longForm): - return longForm | (TRIM_CODE << 8) +def flag_trim(long_form): + return long_form | (TRIM_CODE << 8) def pec_encode(pattern, f): @@ -138,7 +138,7 @@ def pec_encode(pattern, f): for stitch in stitches: x = stitch[0] y = stitch[1] - data = stitch[2] + data = stitch[2] & COMMAND_MASK dx = int(round(x - xx)) dy = int(round(y - yy)) xx += dx @@ -188,10 +188,6 @@ def pec_encode(pattern, f): f.write(b'\x01') color_two = not color_two elif data == STOP: - # if jumping: - # f.write(b'\x00\x00') - # jumping = False - # f.write(b'\x80\x01\x00\x00') pass elif data == END: if jumping: diff --git a/pyembroidery/PesWriter.py b/pyembroidery/PesWriter.py index 99a9442..81b3b68 100644 --- a/pyembroidery/PesWriter.py +++ b/pyembroidery/PesWriter.py @@ -310,7 +310,7 @@ def get_as_segments_blocks(pattern, chart, adjust_x, adjust_y): stitched_y = 0 for command_block in pattern.get_as_command_blocks(): block = [] - command = command_block[0][2] + command = command_block[0][2] & COMMAND_MASK if command == JUMP: block.append([stitched_x - adjust_x, stitched_y - adjust_y]) last_pos = command_block[-1] diff --git a/pyembroidery/PmvReader.py b/pyembroidery/PmvReader.py index 139fb7d..e4e467e 100644 --- a/pyembroidery/PmvReader.py +++ b/pyembroidery/PmvReader.py @@ -44,59 +44,6 @@ def read_pmv_stitches(f, out, settings=None): dx = x out.stitch_abs(px + x, y) # This is a hybrid relative, absolute value. px += dx - # stitches.append((x, y)) - out.end() - # f.seek(0x10, 1) # 16 bytes - # block_end = read_int_16le(f) - # if block_end != 256: - # return - # steps = [] - # dunno0 = read_int_8(f) - # dunno1 = read_int_8(f) - # length_steps = read_int_8(f) - # steps_size = read_int_8(f) - # for i in range(0, steps_size): - # x = read_int_16le(f) - # y = read_int_16le(f) - # if x is None or y is None: - # break - # steps.append((x, y)) - # width_units = read_int_8(f) - # steps2_size = read_int_8(f) - # steps2 = [] - # for i in range(0, steps2_size): - # x = read_int_16le(f) - # y = read_int_16le(f) - # if x is None or y is None: - # break - # steps2.append((x, y)) - # dunno4 = read_int_16le(f) # seems to be 0x12. - # f.seek(0x10, 1) # 16 bytes - # # EOF - This should be End of File. - # none_bytes = read_int_8(f) - # if none_bytes is None: - # pass - # - # extends = find_extends(stitches) - # print(f) - # print("Stitches: Total ", len(stitches), " : ", stitches) - # print("Unknown0:", dunno0) - # print("Unknown1:", dunno1) - # print("Length Position:", length_steps) - # print("Length Lookup: ", len(steps), " : ", steps) - # print("Length value:", steps[length_steps]) - # length_max = extends[2] - extends[0] - # width_max = extends[3] - extends[1] - # print("Max Length:", length_max) - # print("Max dx+:", extends[2]) - # print("Max dx-:", extends[0]) - # print("Width Position:", width_units) - # print("Width Lookup:", len(steps2), " : ", steps2) - # print("Width value:", steps2[width_units]) - # print("Max Width:", width_max) - # - # print("Unknown4:", dunno4) - out.end() diff --git a/pyembroidery/PmvWriter.py b/pyembroidery/PmvWriter.py index 1280e8d..bfd6f04 100644 --- a/pyembroidery/PmvWriter.py +++ b/pyembroidery/PmvWriter.py @@ -55,7 +55,7 @@ def write(pattern, f, settings=None): point_index += 1 if point_index >= point_count: break - data = stitch[2] + data = stitch[2] & COMMAND_MASK x = stitch[0] y = stitch[1] x *= scale_x @@ -122,7 +122,7 @@ def write_width_lookup_table(f, width_range): return steps = 15 write_int_8(f, steps) - second_max = other_step = 28000.0 / float(width_range) + second_max = 28000.0 / float(width_range) second_step = second_max / float(steps - 1) for i in range(0, steps): width_at_step = 50 * i diff --git a/pyembroidery/PyEmbroidery.py b/pyembroidery/PyEmbroidery.py index 02c3f19..a7f7cf1 100644 --- a/pyembroidery/PyEmbroidery.py +++ b/pyembroidery/PyEmbroidery.py @@ -495,6 +495,11 @@ def write_embroidery(writer, pattern, stream, settings=None): settings["sequin_contingency"] = writer.SEQUIN_CONTINGENCY except AttributeError: pass + if not ("thread_change_command" in settings): + try: + settings["thread_change_command"] = writer.THREAD_CHANGE_COMMAND + except AttributeError: + pass pattern = pattern.get_normalized_pattern(settings) if isinstance(stream, str): diff --git a/pyembroidery/StcReader.py b/pyembroidery/StcReader.py index 124cbe6..a68220d 100644 --- a/pyembroidery/StcReader.py +++ b/pyembroidery/StcReader.py @@ -22,7 +22,7 @@ def stc_stitch_encoding_read(f, out): break else: needle = ctrl - 2 - out.color_change() + out.needle_change(needle) out.end() diff --git a/pyembroidery/TbfReader.py b/pyembroidery/TbfReader.py index 667f76e..15b802d 100644 --- a/pyembroidery/TbfReader.py +++ b/pyembroidery/TbfReader.py @@ -27,7 +27,7 @@ def read(f, out, settings=None): out.stitch(signed8(x), -signed8(y)) continue elif ctrl == 0x81: - if count > 1: + if count > 1: # This might rather be a needle change. out.color_change() elif ctrl == 0x90: if x == 0 and y == 0: @@ -44,5 +44,5 @@ def read(f, out, settings=None): elif ctrl == 0x8F: break else: - print("odd.") + break # Dunno why it got here. out.end() diff --git a/pyembroidery/U01Reader.py b/pyembroidery/U01Reader.py index bd84800..e397075 100644 --- a/pyembroidery/U01Reader.py +++ b/pyembroidery/U01Reader.py @@ -68,8 +68,8 @@ def read_u01_stitches(f, out): continue if 0x09 <= command <= 0x17: # C01 - C14 - if count > 1: - out.color_change() + needle = command - 0x08 + out.needle_change(needle) if dx != 0 or dy != 0: out.move(dx, dy) continue diff --git a/pyembroidery/U01Writer.py b/pyembroidery/U01Writer.py index aafcb16..d26047d 100644 --- a/pyembroidery/U01Writer.py +++ b/pyembroidery/U01Writer.py @@ -1,6 +1,7 @@ from .EmbConstant import * from .WriteHelper import write_int_16le, write_int_32le +THREAD_CHANGE_COMMAND = NEEDLE_SET SEQUIN_CONTINGENCY = CONTINGENCY_SEQUIN_JUMP STRIP_SPEEDS = False FULL_JUMP = False @@ -30,14 +31,12 @@ def write(pattern, f, settings=None): f.write(b'\x00') xx = 0 yy = 0 - needle = 1 - f.write(b'\xE9\x00\x00') # Needle to C1 trigger_fast = False trigger_slow = False for stitch in stitches: x = stitch[0] y = stitch[1] - data = stitch[2] + data = stitch[2] & COMMAND_MASK dx = int(round(x - xx)) dy = int(round(y - yy)) xx += dx @@ -78,10 +77,12 @@ def write(pattern, f, settings=None): elif data == TRIM: cmd |= 0x07 f.write(bytes(bytearray([cmd, delta_y, delta_x]))) - elif data == COLOR_CHANGE: - needle %= 7 - needle += 1 - cmd = cmd + 8 + needle + elif data == NEEDLE_SET: + decoded = decode_thread_change(stitch[2]) + needle = decoded[2] + needle %= 15 + cmd |= 0x08 + cmd += needle f.write(bytes(bytearray([cmd, delta_y, delta_x]))) elif data == END: f.write(b'\xF8\x00\x00') diff --git a/pyembroidery/Vp3Writer.py b/pyembroidery/Vp3Writer.py index 7dc7003..d33b572 100644 --- a/pyembroidery/Vp3Writer.py +++ b/pyembroidery/Vp3Writer.py @@ -29,11 +29,11 @@ def vp3_write_length_and_bytes(stream, bytestring): def vp3_patch_byte_offset(stream, offset): - currentPos = stream.tell() + current_pos = stream.tell() stream.seek(offset, 0) # Absolute position seek. - position = currentPos - offset - 4 # 4 bytes int32 + position = current_pos - offset - 4 # 4 bytes int32 write_int_32be(stream, position) - stream.seek(currentPos, 0) # Absolute position seek. + stream.seek(current_pos, 0) # Absolute position seek. def get_as_colorblocks(pattern): @@ -41,7 +41,8 @@ def get_as_colorblocks(pattern): last_pos = 0 end = len(pattern.stitches) for pos, stitch in enumerate(pattern.stitches): - if stitch[2] != COLOR_CHANGE: + command = stitch[2] & COMMAND_MASK + if command != COLOR_CHANGE: continue thread = pattern.get_thread_or_filler(thread_index) thread_index += 1 @@ -213,7 +214,7 @@ def write_stitches_block(f, stitches, first_pos_x, first_pos_y): # Embroidermodder code has # vp3_write_string(f, "\x00"); # The 0, x, 0 bytes come before placeholders - # Given this consisistency, it's doubtful this is a string. + # Given this consistency, it's doubtful this is a string. # Those aren't f.write(b'\x00\x01\x00') placeholder_distance_to_end_of_stitches_block_010 = f.tell() @@ -226,7 +227,7 @@ def write_stitches_block(f, stitches, first_pos_x, first_pos_y): for stitch in stitches: x = stitch[0] y = stitch[1] - flags = stitch[2] + flags = stitch[2] & COMMAND_MASK if flags == END: f.write(b'\x80\x03') break diff --git a/pyembroidery/ZxyReader.py b/pyembroidery/ZxyReader.py index 1853d97..59b42d9 100644 --- a/pyembroidery/ZxyReader.py +++ b/pyembroidery/ZxyReader.py @@ -25,8 +25,8 @@ def read_zxy_stitches(f, out): if ctrl & 0x20: if b[1] == 0xFF: break - out.color_change() needle = b[2] + out.needle_change(needle) out.end()