kopia lustrzana https://github.com/EmbroidePy/pyembroidery
1731 wiersze
60 KiB
Python
1731 wiersze
60 KiB
Python
import os
|
|
|
|
import pyembroidery.A10oReader as A10oReader
|
|
import pyembroidery.A100Reader as A100Reader
|
|
|
|
# import pyembroidery.ArtReader as ArtReader
|
|
import pyembroidery.BroReader as BroReader
|
|
import pyembroidery.ColReader as ColReader
|
|
import pyembroidery.ColWriter as ColWriter
|
|
import pyembroidery.CsvReader as CsvReader
|
|
import pyembroidery.CsvWriter as CsvWriter
|
|
import pyembroidery.DatReader as DatReader
|
|
import pyembroidery.DsbReader as DsbReader
|
|
import pyembroidery.DstReader as DstReader
|
|
import pyembroidery.DstWriter as DstWriter
|
|
import pyembroidery.DszReader as DszReader
|
|
import pyembroidery.EdrReader as EdrReader
|
|
import pyembroidery.EdrWriter as EdrWriter
|
|
import pyembroidery.EmdReader as EmdReader
|
|
import pyembroidery.ExpReader as ExpReader
|
|
import pyembroidery.ExpWriter as ExpWriter
|
|
import pyembroidery.ExyReader as ExyReader
|
|
import pyembroidery.FxyReader as FxyReader
|
|
import pyembroidery.GcodeReader as GcodeReader
|
|
import pyembroidery.GcodeWriter as GcodeWriter
|
|
import pyembroidery.GtReader as GtReader
|
|
import pyembroidery.HusReader as HusReader
|
|
import pyembroidery.InbReader as InbReader
|
|
import pyembroidery.InfReader as InfReader
|
|
import pyembroidery.InfWriter as InfWriter
|
|
import pyembroidery.JefReader as JefReader
|
|
import pyembroidery.JefWriter as JefWriter
|
|
import pyembroidery.JpxReader as JpxReader
|
|
import pyembroidery.JsonReader as JsonReader
|
|
import pyembroidery.JsonWriter as JsonWriter
|
|
import pyembroidery.KsmReader as KsmReader
|
|
import pyembroidery.MaxReader as MaxReader
|
|
import pyembroidery.MitReader as MitReader
|
|
import pyembroidery.NewReader as NewReader
|
|
import pyembroidery.PcdReader as PcdReader
|
|
import pyembroidery.PcmReader as PcmReader
|
|
import pyembroidery.PcqReader as PcqReader
|
|
import pyembroidery.PcsReader as PcsReader
|
|
import pyembroidery.PecReader as PecReader
|
|
import pyembroidery.PecWriter as PecWriter
|
|
import pyembroidery.PesReader as PesReader
|
|
import pyembroidery.PesWriter as PesWriter
|
|
import pyembroidery.PhbReader as PhbReader
|
|
import pyembroidery.PhcReader as PhcReader
|
|
import pyembroidery.PmvReader as PmvReader
|
|
import pyembroidery.PmvWriter as PmvWriter
|
|
import pyembroidery.PngWriter as PngWriter
|
|
import pyembroidery.SewReader as SewReader
|
|
import pyembroidery.ShvReader as ShvReader
|
|
import pyembroidery.SpxReader as SpxReader
|
|
import pyembroidery.StcReader as StcReader
|
|
import pyembroidery.StxReader as StxReader
|
|
import pyembroidery.SvgWriter as SvgWriter
|
|
import pyembroidery.TapReader as TapReader
|
|
import pyembroidery.TbfReader as TbfReader
|
|
import pyembroidery.TxtWriter as TxtWriter
|
|
import pyembroidery.U01Reader as U01Reader
|
|
import pyembroidery.U01Writer as U01Writer
|
|
import pyembroidery.Vp3Reader as Vp3Reader
|
|
import pyembroidery.Vp3Writer as Vp3Writer
|
|
import pyembroidery.XxxReader as XxxReader
|
|
import pyembroidery.XxxWriter as XxxWriter
|
|
|
|
import pyembroidery.ZhsReader as ZhsReader
|
|
import pyembroidery.ZxyReader as ZxyReader
|
|
|
|
from .EmbEncoder import Transcoder as Normalizer
|
|
from .EmbFunctions import *
|
|
from .EmbThread import EmbThread
|
|
|
|
|
|
class EmbPattern:
|
|
def __init__(self, *args, **kwargs):
|
|
self.stitches = [] # type: list
|
|
self.threadlist = [] # type: list
|
|
self.extras = {} # type: dict
|
|
# filename, name, category, author, keywords, comments, are typical
|
|
self._previousX = 0 # type: float
|
|
self._previousY = 0 # type: float
|
|
len_args = len(args)
|
|
if len_args >= 1:
|
|
arg0 = args[0]
|
|
if isinstance(arg0, EmbPattern):
|
|
self.stitches = arg0.stitches[:]
|
|
self.threadlist = arg0.threadlist[:]
|
|
self.extras.update(arg0.extras)
|
|
self._previousX = arg0._previousX
|
|
self._previousY = arg0._previousY
|
|
return
|
|
if len(args) >= 2:
|
|
settings = args[1]
|
|
elif "settings" in kwargs:
|
|
settings = kwargs["settings"]
|
|
else:
|
|
settings = kwargs
|
|
if isinstance(arg0, str):
|
|
EmbPattern.static_read(arg0, settings=settings, pattern=self)
|
|
|
|
def __ne__(self, other):
|
|
return not self.__eq__(other)
|
|
|
|
def __eq__(self, other):
|
|
if not isinstance(other, EmbPattern):
|
|
return False
|
|
if self.stitches != other.stitches:
|
|
return False
|
|
if self.threadlist != other.threadlist:
|
|
return False
|
|
if self.extras != other.extras:
|
|
return False
|
|
return True
|
|
|
|
def __str__(self):
|
|
if "name" in self.extras:
|
|
return "EmbPattern %s (commands: %3d, threads: %3d)" % (
|
|
self.extras["name"],
|
|
len(self.stitches),
|
|
len(self.threadlist),
|
|
)
|
|
return "EmbPattern (commands: %3d, threads: %3d)" % (
|
|
len(self.stitches),
|
|
len(self.threadlist),
|
|
)
|
|
|
|
def __len__(self):
|
|
return len(self.stitches)
|
|
|
|
def __getitem__(self, item):
|
|
if isinstance(item, str):
|
|
return self.extras[item]
|
|
return self.stitches[item]
|
|
|
|
def __setitem__(self, key, value):
|
|
if isinstance(key, str):
|
|
self.extras[key] = value
|
|
else:
|
|
self.stitches[key] = value
|
|
|
|
def __copy__(self):
|
|
return self.copy()
|
|
|
|
def __deepcopy__(self):
|
|
return self.copy()
|
|
|
|
def __iadd__(self, other):
|
|
if isinstance(other, EmbPattern):
|
|
self.add_pattern(other)
|
|
elif isinstance(other, EmbThread) or isinstance(other, str):
|
|
self.add_thread(other)
|
|
for i in range(0, len(self.stitches)):
|
|
data = self.stitches[i][2] & COMMAND_MASK
|
|
if data == STITCH or data == SEW_TO or data == NEEDLE_AT:
|
|
self.color_change()
|
|
break # Only add color change if stitching exists.
|
|
elif isinstance(other, int):
|
|
self.add_command(other)
|
|
elif isinstance(other, list) or isinstance(other, tuple): # tuple or list
|
|
if len(other) == 0:
|
|
return
|
|
v = other[0]
|
|
if isinstance(v, list) or isinstance(
|
|
v, tuple
|
|
): # tuple or list of tuple or lists
|
|
for v in other:
|
|
x = v[0]
|
|
y = v[1]
|
|
try:
|
|
cmd = v[2]
|
|
except IndexError:
|
|
cmd = STITCH
|
|
self.add_stitch_absolute(cmd, x, y)
|
|
elif isinstance(v, complex): # tuple or list of complex
|
|
for v in other:
|
|
x = v.real
|
|
y = v.imag
|
|
self.add_stitch_absolute(STITCH, x, y)
|
|
elif isinstance(v, int) or isinstance(
|
|
v, float
|
|
): # tuple or list of numbers.
|
|
i = 0
|
|
ie = len(other)
|
|
while i < ie:
|
|
self.add_stitch_absolute(STITCH, other[i], other[i + 1])
|
|
i += 2
|
|
elif isinstance(v, str):
|
|
self.extras[v] = other[1]
|
|
else:
|
|
raise ValueError()
|
|
return self
|
|
|
|
def __add__(self, other):
|
|
p = self.copy()
|
|
p.add_pattern(other)
|
|
return p
|
|
|
|
def __radd__(self, other):
|
|
p = other.copy()
|
|
p.add_pattern(self)
|
|
return p
|
|
|
|
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 read(self, filename, **settings):
|
|
EmbPattern.static_read(filename, settings=settings, pattern=self)
|
|
|
|
def write(self, filename, **settings):
|
|
EmbPattern.static_write(self, filename, settings=settings)
|
|
|
|
def move(self, dx=0, dy=0, position=None):
|
|
"""Move dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(JUMP, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, JUMP, dx, dy)
|
|
|
|
def move_abs(self, x, y, position=None):
|
|
"""Move absolute x, y"""
|
|
if position is None:
|
|
self.add_stitch_absolute(JUMP, x, y)
|
|
else:
|
|
self.insert(position, JUMP, x, y)
|
|
|
|
def stitch(self, dx=0, dy=0, position=None):
|
|
"""Stitch dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(STITCH, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, STITCH, dx, dy)
|
|
|
|
def stitch_abs(self, x, y, position=None):
|
|
"""Stitch absolute x, y"""
|
|
if position is None:
|
|
self.add_stitch_absolute(STITCH, x, y)
|
|
else:
|
|
self.insert(position, STITCH, x, y)
|
|
|
|
def stop(self, dx=0, dy=0, position=None):
|
|
"""Stop dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(STOP, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, STOP, dx, dy)
|
|
|
|
def trim(self, dx=0, dy=0, position=None):
|
|
"""Trim dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(TRIM, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, TRIM, dx, dy)
|
|
|
|
def color_change(self, dx=0, dy=0, position=None):
|
|
"""Color Change dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(COLOR_CHANGE, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, COLOR_CHANGE, dx, dy)
|
|
|
|
def needle_change(self, needle=0, dx=0, dy=0, position=None):
|
|
"""Needle change, needle, dx, dy"""
|
|
cmd = encode_thread_change(NEEDLE_SET, None, needle)
|
|
if position is None:
|
|
self.add_stitch_relative(cmd, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, cmd, dx, dy)
|
|
|
|
def sequin_eject(self, dx=0, dy=0, position=None):
|
|
"""Eject Sequin dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(SEQUIN_EJECT, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, SEQUIN_EJECT, dx, dy)
|
|
|
|
def sequin_mode(self, dx=0, dy=0, position=None):
|
|
"""Eject Sequin dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(SEQUIN_MODE, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, SEQUIN_MODE, dx, dy)
|
|
|
|
def end(self, dx=0, dy=0, position=None):
|
|
"""End Design dx, dy"""
|
|
if position is None:
|
|
self.add_stitch_relative(END, dx, dy)
|
|
else:
|
|
self.insert_stitch_relative(position, END, dx, dy)
|
|
|
|
def add_thread(self, thread):
|
|
"""Adds thread to design.
|
|
Note: this has no effect on stitching and can be done at any point."""
|
|
if isinstance(thread, EmbThread):
|
|
self.threadlist.append(thread)
|
|
else:
|
|
thread_object = EmbThread()
|
|
thread_object.set(thread)
|
|
self.threadlist.append(thread_object)
|
|
|
|
def metadata(self, name, data):
|
|
"""Adds select metadata to design.
|
|
Note: this has no effect on stitching and can be done at any point."""
|
|
self.extras[name] = data
|
|
|
|
def get_metadata(self, name, default=None):
|
|
return self.extras.get(name, default)
|
|
|
|
def bounds(self):
|
|
"""Returns the bounds of the stitch data:
|
|
min_x, min_y, max_x, max_y"""
|
|
min_x = float("inf")
|
|
min_y = float("inf")
|
|
max_x = -float("inf")
|
|
max_y = -float("inf")
|
|
|
|
for stitch in self.stitches:
|
|
if stitch[0] > max_x:
|
|
max_x = stitch[0]
|
|
if stitch[0] < min_x:
|
|
min_x = stitch[0]
|
|
if stitch[1] > max_y:
|
|
max_y = stitch[1]
|
|
if stitch[1] < min_y:
|
|
min_y = stitch[1]
|
|
return min_x, min_y, max_x, max_y
|
|
|
|
extends = bounds
|
|
extents = bounds
|
|
|
|
def count_stitch_commands(self, command):
|
|
count = 0
|
|
for stitch in self.stitches:
|
|
flags = stitch[2] & COMMAND_MASK
|
|
if flags == command:
|
|
count += 1
|
|
return count
|
|
|
|
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)
|
|
|
|
def count_threads(self):
|
|
return len(self.threadlist)
|
|
|
|
@staticmethod
|
|
def get_random_thread():
|
|
thread = EmbThread()
|
|
thread.set("random")
|
|
thread.description = "Random"
|
|
return thread
|
|
|
|
def get_thread_or_filler(self, index):
|
|
if len(self.threadlist) <= index:
|
|
return self.get_random_thread()
|
|
else:
|
|
return self.threadlist[index]
|
|
|
|
def get_thread(self, index):
|
|
return self.threadlist[index]
|
|
|
|
def get_match_commands(self, command):
|
|
for stitch in self.stitches:
|
|
flags = stitch[2] & COMMAND_MASK
|
|
if flags == command:
|
|
yield stitch
|
|
|
|
def get_as_stitchblock(self):
|
|
stitchblock = []
|
|
thread = self.get_thread_or_filler(0)
|
|
thread_index = 1
|
|
for stitch in self.stitches:
|
|
flags = stitch[2] & COMMAND_MASK
|
|
if flags == STITCH:
|
|
stitchblock.append(stitch)
|
|
else:
|
|
if len(stitchblock) > 0:
|
|
yield (stitchblock, thread)
|
|
stitchblock = []
|
|
if flags == COLOR_CHANGE:
|
|
thread = self.get_thread_or_filler(thread_index)
|
|
thread_index += 1
|
|
if len(stitchblock) > 0:
|
|
yield (stitchblock, thread)
|
|
|
|
def get_as_command_blocks(self):
|
|
last_pos = 0
|
|
last_command = NO_COMMAND
|
|
for pos, stitch in enumerate(self.stitches):
|
|
command = stitch[2] & COMMAND_MASK
|
|
if command == last_command or last_command == NO_COMMAND:
|
|
last_command = command
|
|
continue
|
|
last_command = command
|
|
yield self.stitches[last_pos:pos]
|
|
last_pos = pos
|
|
yield self.stitches[last_pos:]
|
|
|
|
def get_as_colorblocks(self):
|
|
"""
|
|
Returns a generator for colorblocks. Color blocks defined with color_breaks will have
|
|
the command omitted whereas color blocks delimited with color_change will end with the
|
|
color_change command, and if delimited with needle_set, the blocks will begin the new
|
|
color block with the needle_set.
|
|
"""
|
|
thread_index = 0
|
|
colorblock_start = 0
|
|
|
|
for pos, stitch in enumerate(self.stitches):
|
|
command = stitch[2] & COMMAND_MASK
|
|
if command == COLOR_BREAK:
|
|
if colorblock_start != pos:
|
|
thread = self.get_thread_or_filler(thread_index)
|
|
thread_index += 1
|
|
yield self.stitches[colorblock_start:pos], thread
|
|
colorblock_start = pos + 1
|
|
continue
|
|
if command == COLOR_CHANGE:
|
|
thread = self.get_thread_or_filler(thread_index)
|
|
thread_index += 1
|
|
yield self.stitches[colorblock_start : pos + 1], thread
|
|
colorblock_start = pos + 1
|
|
continue
|
|
if command == NEEDLE_SET and colorblock_start != pos:
|
|
thread = self.get_thread_or_filler(thread_index)
|
|
thread_index += 1
|
|
yield self.stitches[colorblock_start:pos], thread
|
|
colorblock_start = pos
|
|
continue
|
|
|
|
if colorblock_start != len(self.stitches):
|
|
thread = self.get_thread_or_filler(thread_index)
|
|
yield self.stitches[colorblock_start:], thread
|
|
|
|
def get_as_stitches(self):
|
|
"""pos, x, y, command, v1, v2, v3"""
|
|
for pos, stitch in enumerate(self.stitches):
|
|
decode = decode_embroidery_command(stitch[2])
|
|
command = decode[0]
|
|
thread = decode[1]
|
|
needle = decode[2]
|
|
order = decode[3]
|
|
yield pos, stitch[0], stitch[1], command, thread, needle, order
|
|
|
|
def get_unique_threadlist(self):
|
|
return set(self.threadlist)
|
|
|
|
def get_singleton_threadlist(self):
|
|
singleton = []
|
|
last_thread = None
|
|
for thread in self.threadlist:
|
|
if thread != last_thread:
|
|
singleton.append(thread)
|
|
last_thread = thread
|
|
return singleton
|
|
|
|
def move_center_to_origin(self):
|
|
extends = self.bounds()
|
|
cx = round((extends[2] - extends[0]) / 2.0)
|
|
cy = round((extends[3] - extends[1]) / 2.0)
|
|
self.translate(-cx, -cy)
|
|
|
|
def translate(self, dx, dy):
|
|
for stitch in self.stitches:
|
|
stitch[0] += dx
|
|
stitch[1] += dy
|
|
|
|
def transform(self, matrix):
|
|
for stitch in self.stitches:
|
|
matrix.apply(stitch)
|
|
|
|
def fix_color_count(self):
|
|
"""Ensure that there are threads for all color blocks."""
|
|
thread_index = 0
|
|
init_color = True
|
|
for stitch in self.stitches:
|
|
data = stitch[2] & COMMAND_MASK
|
|
if data == STITCH or data == SEW_TO or data == NEEDLE_AT:
|
|
if init_color:
|
|
thread_index += 1
|
|
init_color = False
|
|
elif data == COLOR_CHANGE or data == COLOR_BREAK or data == NEEDLE_SET:
|
|
init_color = True
|
|
while len(self.threadlist) < thread_index:
|
|
self.add_thread(self.get_thread_or_filler(len(self.threadlist)))
|
|
|
|
def add_stitch_absolute(self, cmd, x=0, y=0):
|
|
"""Add a command at the absolute location: x, y"""
|
|
self.stitches.append([x, y, cmd])
|
|
self._previousX = x
|
|
self._previousY = y
|
|
|
|
def add_stitch_relative(self, cmd, dx=0, dy=0):
|
|
"""Add a command relative to the previous location"""
|
|
x = self._previousX + dx
|
|
y = self._previousY + dy
|
|
self.add_stitch_absolute(cmd, x, y)
|
|
|
|
def insert_stitch_relative(self, position, cmd, dx=0, dy=0):
|
|
"""Insert a relative stitch into the pattern. The stitch is relative to the stitch before it.
|
|
If inserting at position 0, it's relative to 0,0. If appending, add is called, updating the positioning.
|
|
"""
|
|
if position < 0:
|
|
position += len(self.stitches) # I need positive positions.
|
|
if position == 0:
|
|
self.stitches.insert(0, [dx, dy, cmd]) # started (0,0)
|
|
elif (
|
|
position == len(self.stitches) or position is None
|
|
): # This is properly just an add.
|
|
self.add_stitch_relative(cmd, dx, dy)
|
|
elif 0 < position < len(self.stitches):
|
|
p = self.stitches[position - 1]
|
|
x = p[0] + dx
|
|
y = p[1] + dy
|
|
self.stitches.insert(position, [x, y, cmd])
|
|
|
|
def insert(self, position, cmd, x=0, y=0):
|
|
"""Insert a stitch or command"""
|
|
self.stitches.insert(position, [x, y, cmd])
|
|
|
|
def prepend_command(self, cmd, x=0, y=0):
|
|
"""Prepend a command, without treating parameters as locations"""
|
|
self.stitches.insert(0, [x, y, cmd])
|
|
|
|
def add_command(self, cmd, x=0, y=0):
|
|
"""Add a command, without treating parameters as locations
|
|
that require an update"""
|
|
self.stitches.append([x, y, cmd])
|
|
|
|
def add_block(self, block, thread=None):
|
|
if thread is not None:
|
|
self.add_thread(thread)
|
|
if block is None:
|
|
return
|
|
|
|
if isinstance(block, list) or isinstance(block, tuple):
|
|
if len(block) == 0:
|
|
return
|
|
v = block[0]
|
|
if isinstance(v, list) or isinstance(v, tuple):
|
|
for v in block:
|
|
x = v[0]
|
|
y = v[1]
|
|
try:
|
|
cmd = v[2]
|
|
except IndexError:
|
|
cmd = STITCH
|
|
self.add_stitch_absolute(cmd, x, y)
|
|
elif isinstance(v, complex):
|
|
for v in block:
|
|
x = v.real
|
|
y = v.imag
|
|
self.add_stitch_absolute(STITCH, x, y)
|
|
elif isinstance(v, int) or isinstance(v, float):
|
|
i = 0
|
|
ie = len(block)
|
|
while i < ie:
|
|
self.add_stitch_absolute(STITCH, block[i], block[i + 1])
|
|
i += 2
|
|
self.add_command(COLOR_BREAK)
|
|
|
|
def add_stitchblock(self, stitchblock):
|
|
threadlist = self.threadlist
|
|
block = stitchblock[0]
|
|
thread = stitchblock[1]
|
|
if len(threadlist) == 0 or thread is not threadlist[-1]:
|
|
threadlist.append(thread)
|
|
self.add_stitch_relative(COLOR_BREAK)
|
|
else:
|
|
self.add_stitch_relative(SEQUENCE_BREAK)
|
|
|
|
for stitch in block:
|
|
try:
|
|
self.add_stitch_absolute(stitch.command, stitch.x, stitch.y)
|
|
except AttributeError:
|
|
self.add_stitch_absolute(stitch[2], stitch[0], stitch[1])
|
|
|
|
def add_pattern(self, pattern, dx=None, dy=None, sx=None, sy=None, rotate=None):
|
|
"""
|
|
add_pattern merges the given pattern with the current pattern. It accounts for some edge conditions but
|
|
not all of them.
|
|
|
|
If there is an end command on the current pattern, that is removed.
|
|
If the color ending the current pattern is equal to the color starting the next those color blocks are merged.
|
|
Any prepended thread change command to the merging pattern is suppressed.
|
|
|
|
:param pattern: pattern to add to current pattern
|
|
:param dx: position change of the added pattern x
|
|
:param dy: position change of the added pattern y
|
|
:param sx: scale of the added pattern x
|
|
:param sy: scale of the added pattern y
|
|
:param rotate: rotation of the added pattern
|
|
:return:
|
|
"""
|
|
if isinstance(pattern, str):
|
|
pattern = EmbPattern(pattern)
|
|
if self.stitches[-1][2] == END:
|
|
self.stitches = self.stitches[:-1] # Remove END, if exists
|
|
if dx is not None or dy is not None:
|
|
if dx is None:
|
|
dx = 0
|
|
if dy is None:
|
|
dy = 0
|
|
self.add_command(MATRIX_TRANSLATE, dx, dy)
|
|
if sx is not None or sx is not None:
|
|
if sx is None:
|
|
sx = sy
|
|
if sy is None:
|
|
sy = sx
|
|
self.add_command(MATRIX_SCALE, sx, sy)
|
|
if rotate is not None:
|
|
self.add_command(MATRIX_ROTATE, rotate)
|
|
# Add the new thread only if it's different from the last one
|
|
self.fix_color_count()
|
|
|
|
if len(pattern.threadlist) > 0:
|
|
if pattern.threadlist[0] == self.threadlist[-1]:
|
|
self.threadlist.extend(pattern.threadlist[1:])
|
|
else:
|
|
self.threadlist.extend(pattern.threadlist)
|
|
self.color_change()
|
|
join_position = len(self.stitches)
|
|
self.stitches.extend(pattern.stitches)
|
|
|
|
for i in range(join_position, len(self.stitches)):
|
|
data = self.stitches[i][2] & COMMAND_MASK
|
|
if data == STITCH or data == SEW_TO or data == NEEDLE_AT:
|
|
break
|
|
elif data == COLOR_CHANGE or data == COLOR_BREAK or data == NEEDLE_SET:
|
|
self.stitches[i][2] = NO_COMMAND
|
|
self.extras.update(pattern.extras)
|
|
|
|
def interpolate_duplicate_color_as_stop(self):
|
|
"""Processes a pattern replacing any duplicate colors in the threadlist as a stop."""
|
|
thread_index = 0
|
|
init_color = True
|
|
last_change = None
|
|
for position, stitch in enumerate(self.stitches):
|
|
data = stitch[2] & COMMAND_MASK
|
|
if data == STITCH or data == SEW_TO or data == NEEDLE_AT:
|
|
if init_color:
|
|
try:
|
|
if (
|
|
last_change is not None
|
|
and thread_index != 0
|
|
and self.threadlist[thread_index - 1]
|
|
== self.threadlist[thread_index]
|
|
):
|
|
del self.threadlist[thread_index]
|
|
self.stitches[last_change][2] = STOP
|
|
else:
|
|
thread_index += 1
|
|
except IndexError: # Non-existent threads cannot double
|
|
return
|
|
init_color = False
|
|
elif data == COLOR_CHANGE or data == COLOR_BREAK or data == NEEDLE_SET:
|
|
init_color = True
|
|
last_change = position
|
|
|
|
def interpolate_stop_as_duplicate_color(self, thread_change_command=COLOR_CHANGE):
|
|
"""Processes a pattern replacing any stop as a duplicate color, and color_change
|
|
or another specified thread_change_command"""
|
|
thread_index = 0
|
|
for position, stitch in enumerate(self.stitches):
|
|
data = stitch[2] & COMMAND_MASK
|
|
if data == STITCH or data == SEW_TO or data == NEEDLE_AT:
|
|
continue
|
|
elif data == COLOR_CHANGE or data == COLOR_BREAK or data == NEEDLE_SET:
|
|
thread_index += 1
|
|
elif data == STOP:
|
|
try:
|
|
self.threadlist.insert(thread_index, self.threadlist[thread_index])
|
|
self.stitches[position][2] = thread_change_command
|
|
thread_index += 1
|
|
except IndexError: # There are no colors to duplicate
|
|
return
|
|
|
|
def interpolate_frame_eject(self):
|
|
"""Processes a pattern replacing jump-stop-jump/jump-stop-end sequences with FRAME_EJECT."""
|
|
mode = 0
|
|
stop_x = None
|
|
stop_y = None
|
|
sequence_start_position = None
|
|
position = 0
|
|
ie = len(self.stitches)
|
|
while position < ie:
|
|
stitch = self.stitches[position]
|
|
data = stitch[2] & COMMAND_MASK
|
|
if (
|
|
data == STITCH
|
|
or data == SEW_TO
|
|
or data == NEEDLE_AT
|
|
or data == COLOR_CHANGE
|
|
or data == COLOR_BREAK
|
|
or data == NEEDLE_SET
|
|
):
|
|
if mode == 3:
|
|
del self.stitches[sequence_start_position:position]
|
|
position = sequence_start_position
|
|
self.stitches.insert(position, [stop_x, stop_y, FRAME_EJECT])
|
|
ie = len(self.stitches)
|
|
mode = 0
|
|
elif data == JUMP:
|
|
if mode == 2:
|
|
mode = 3
|
|
if mode == 0:
|
|
sequence_start_position = position
|
|
mode = 1
|
|
elif data == STOP:
|
|
if mode == 1:
|
|
mode = 2
|
|
stop_x = stitch[0]
|
|
stop_y = stitch[1]
|
|
position += 1
|
|
if mode >= 2: # Frame_eject at end.
|
|
del self.stitches[sequence_start_position:position]
|
|
position = sequence_start_position
|
|
self.stitches.insert(position, [stop_x, stop_y, FRAME_EJECT])
|
|
|
|
def interpolate_trims(
|
|
self, jumps_to_require_trim=None, distance_to_require_trim=None, clipping=True
|
|
):
|
|
"""Processes a pattern adding trims according to the given criteria."""
|
|
i = -1
|
|
ie = len(self.stitches) - 1
|
|
|
|
x = 0
|
|
y = 0
|
|
jump_count = 0
|
|
jump_start = 0
|
|
jump_dx = 0
|
|
jump_dy = 0
|
|
jumping = False
|
|
trimmed = True
|
|
while i < ie:
|
|
i += 1
|
|
stitch = self.stitches[i]
|
|
dx = stitch[0] - x
|
|
dy = stitch[1] - y
|
|
x = stitch[0]
|
|
y = stitch[1]
|
|
command = stitch[2] & COMMAND_MASK
|
|
if command == STITCH or command == SEQUIN_EJECT:
|
|
trimmed = False
|
|
jumping = False
|
|
elif command == COLOR_CHANGE or command == NEEDLE_SET or command == TRIM:
|
|
trimmed = True
|
|
jumping = False
|
|
if command == JUMP:
|
|
if not jumping:
|
|
jump_dx = 0
|
|
jump_dy = 0
|
|
jump_count = 0
|
|
jump_start = i
|
|
jumping = True
|
|
jump_count += 1
|
|
jump_dx += dx
|
|
jump_dy += dy
|
|
if not trimmed:
|
|
if (
|
|
jump_count == jumps_to_require_trim
|
|
or distance_to_require_trim is not None
|
|
and (
|
|
abs(jump_dy) > distance_to_require_trim
|
|
or abs(jump_dx) > distance_to_require_trim
|
|
)
|
|
):
|
|
self.trim(position=jump_start)
|
|
jump_start += 1 # We inserted a position, start jump has moved.
|
|
i += 1
|
|
ie += 1
|
|
trimmed = True
|
|
if (
|
|
clipping and jump_dx == 0 and jump_dy == 0
|
|
): # jump displacement is 0, clip trim command.
|
|
del self.stitches[jump_start : i + 1]
|
|
i = jump_start - 1
|
|
ie = len(self.stitches) - 1
|
|
|
|
def get_pattern_interpolate_trim(self, jumps_to_require_trim):
|
|
"""Gets a processed pattern with untrimmed jumps merged
|
|
and trims added if merged jumps are beyond the given value.
|
|
The expectation is that it has core commands and not
|
|
middle-level commands"""
|
|
new_pattern = EmbPattern()
|
|
i = -1
|
|
ie = len(self.stitches) - 1
|
|
count = 0
|
|
trimmed = True
|
|
while i < ie:
|
|
i += 1
|
|
stitch = self.stitches[i]
|
|
command = stitch[2] & COMMAND_MASK
|
|
if command == STITCH or command == SEQUIN_EJECT:
|
|
trimmed = False
|
|
elif command == COLOR_CHANGE or command == NEEDLE_SET or command == TRIM:
|
|
trimmed = True
|
|
if trimmed or stitch[2] != JUMP:
|
|
new_pattern.add_stitch_absolute(stitch[2], stitch[0], stitch[1])
|
|
continue
|
|
while i < ie and command == JUMP:
|
|
i += 1
|
|
stitch = self.stitches[i]
|
|
command = stitch[2]
|
|
count += 1
|
|
if command != JUMP:
|
|
i -= 1
|
|
stitch = self.stitches[i]
|
|
if count >= jumps_to_require_trim:
|
|
new_pattern.trim()
|
|
count = 0
|
|
new_pattern.add_stitch_absolute(stitch[2], stitch[0], stitch[1])
|
|
new_pattern.threadlist.extend(self.threadlist)
|
|
new_pattern.extras.update(self.extras)
|
|
return new_pattern
|
|
|
|
def get_pattern_merge_jumps(self):
|
|
"""Returns a pattern with all multiple jumps merged."""
|
|
new_pattern = EmbPattern()
|
|
i = -1
|
|
ie = len(self.stitches) - 1
|
|
stitch_break = False
|
|
while i < ie:
|
|
i += 1
|
|
stitch = self.stitches[i]
|
|
command = stitch[2] & COMMAND_MASK
|
|
if command == JUMP:
|
|
if stitch_break:
|
|
continue
|
|
new_pattern.add_command(STITCH_BREAK)
|
|
stitch_break = True
|
|
continue
|
|
new_pattern.add_stitch_absolute(stitch[2], stitch[0], stitch[1])
|
|
new_pattern.threadlist.extend(self.threadlist)
|
|
new_pattern.extras.update(self.extras)
|
|
return new_pattern
|
|
|
|
def get_stable_pattern(self):
|
|
"""Gets a stabilized version of the pattern."""
|
|
stable_pattern = EmbPattern()
|
|
for stitchblock in self.get_as_stitchblock():
|
|
stable_pattern.add_stitchblock(stitchblock)
|
|
stable_pattern.extras.update(self.extras)
|
|
return stable_pattern
|
|
|
|
def get_normalized_pattern(self, encode_settings=None):
|
|
"""Encodes pattern typically for saving."""
|
|
normal_pattern = EmbPattern()
|
|
transcoder = Normalizer(encode_settings)
|
|
transcoder.transcode(self, normal_pattern)
|
|
return normal_pattern
|
|
|
|
def append_translation(self, x, y):
|
|
"""Appends translation to the pattern.
|
|
All commands will be translated by the given amount,
|
|
including absolute location commands."""
|
|
self.add_stitch_relative(MATRIX_TRANSLATE, x, y)
|
|
|
|
@staticmethod
|
|
def supported_formats():
|
|
"""Generates dictionary entries for supported formats. Each entry will
|
|
always have description, extension, mimetype, and category. Reader
|
|
will provide the reader, if one exists, writer will provide the writer,
|
|
if one exists.
|
|
|
|
Metadata gives a list of metadata read and/or written by that type.
|
|
|
|
Options provides accepted options by the format and their accepted values.
|
|
"""
|
|
# yield ({
|
|
# "description": "Art Embroidery Format",
|
|
# "extension": "art",
|
|
# "extensions": ("art",),
|
|
# "mimetype": "application/x-art",
|
|
# "category": "embroidery",
|
|
# "reader": ArtReader,
|
|
# "metadata": ("name")
|
|
# })
|
|
yield (
|
|
{
|
|
"description": "Brother Embroidery Format",
|
|
"extension": "pec",
|
|
"extensions": ("pec",),
|
|
"mimetype": "application/x-pec",
|
|
"category": "embroidery",
|
|
"reader": PecReader,
|
|
"writer": PecWriter,
|
|
"metadata": ("name"),
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Brother Embroidery Format",
|
|
"extension": "pes",
|
|
"extensions": ("pes",),
|
|
"mimetype": "application/x-pes",
|
|
"category": "embroidery",
|
|
"reader": PesReader,
|
|
"writer": PesWriter,
|
|
"versions": ("1", "6", "1t", "6t"),
|
|
"metadata": ("name", "author", "category", "keywords", "comments"),
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Melco Expanded Embroidery Format",
|
|
"extension": "exp",
|
|
"extensions": ("exp",),
|
|
"mimetype": "application/x-exp",
|
|
"category": "embroidery",
|
|
"reader": ExpReader,
|
|
"writer": ExpWriter,
|
|
}
|
|
)
|
|
# yield (
|
|
# {
|
|
# "description": "Melco Condensed Embroidery Format",
|
|
# "extension": "cnd",
|
|
# "extensions": ("cnd",),
|
|
# "mimetype": "application/x-cnd",
|
|
# "category": "embroidery",
|
|
# "reader": CndReader,
|
|
# }
|
|
# )
|
|
yield (
|
|
{
|
|
"description": "Tajima Embroidery Format",
|
|
"extension": "dst",
|
|
"extensions": ("dst",),
|
|
"mimetype": "application/x-dst",
|
|
"category": "embroidery",
|
|
"reader": DstReader,
|
|
"writer": DstWriter,
|
|
"read_options": {
|
|
"trim_distance": (None, 3.0, 50.0),
|
|
"trim_at": (2, 3, 4, 5, 6, 7, 8),
|
|
"clipping": (True, False),
|
|
},
|
|
"write_options": {"trim_at": (2, 3, 4, 5, 6, 7, 8)},
|
|
"versions": ("default", "extended"),
|
|
"metadata": ("name", "author", "copyright"),
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Janome Embroidery Format",
|
|
"extension": "jef",
|
|
"extensions": ("jef",),
|
|
"mimetype": "application/x-jef",
|
|
"category": "embroidery",
|
|
"reader": JefReader,
|
|
"writer": JefWriter,
|
|
"read_options": {
|
|
"trim_distance": (None, 3.0, 50.0),
|
|
"trims": (True, False),
|
|
"trim_at": (2, 3, 4, 5, 6, 7, 8),
|
|
"clipping": (True, False),
|
|
},
|
|
"write_options": {
|
|
"trims": (True, False),
|
|
"trim_at": (2, 3, 4, 5, 6, 7, 8),
|
|
},
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "vp3",
|
|
"extensions": ("vp3",),
|
|
"mimetype": "application/x-vp3",
|
|
"category": "embroidery",
|
|
"reader": Vp3Reader,
|
|
"writer": Vp3Writer,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Scalable Vector Graphics",
|
|
"extension": "svg",
|
|
"extensions": ("svg", "svgz"),
|
|
"mimetype": "image/svg+xml",
|
|
"category": "vector",
|
|
"writer": SvgWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Comma-separated values",
|
|
"extension": "csv",
|
|
"extensions": ("csv",),
|
|
"mimetype": "text/csv",
|
|
"category": "debug",
|
|
"reader": CsvReader,
|
|
"writer": CsvWriter,
|
|
"versions": ("default", "delta", "full"),
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Singer Embroidery Format",
|
|
"extension": "xxx",
|
|
"extensions": ("xxx",),
|
|
"mimetype": "application/x-xxx",
|
|
"category": "embroidery",
|
|
"reader": XxxReader,
|
|
"writer": XxxWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Janome Embroidery Format",
|
|
"extension": "sew",
|
|
"extensions": ("sew",),
|
|
"mimetype": "application/x-sew",
|
|
"category": "embroidery",
|
|
"reader": SewReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Barudan Embroidery Format",
|
|
"extension": "u01",
|
|
"extensions": ("u00", "u01", "u02"),
|
|
"mimetype": "application/x-u01",
|
|
"category": "embroidery",
|
|
"reader": U01Reader,
|
|
"writer": U01Writer,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Husqvarna Viking Embroidery Format",
|
|
"extension": "shv",
|
|
"extensions": ("shv",),
|
|
"mimetype": "application/x-shv",
|
|
"category": "embroidery",
|
|
"reader": ShvReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Toyota Embroidery Format",
|
|
"extension": "10o",
|
|
"extensions": ("10o",),
|
|
"mimetype": "application/x-10o",
|
|
"category": "embroidery",
|
|
"reader": A10oReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Toyota Embroidery Format",
|
|
"extension": "100",
|
|
"extensions": ("100",),
|
|
"mimetype": "application/x-100",
|
|
"category": "embroidery",
|
|
"reader": A100Reader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Bits & Volts Embroidery Format",
|
|
"extension": "bro",
|
|
"extensions": ("bro",),
|
|
"mimetype": "application/x-Bro",
|
|
"category": "embroidery",
|
|
"reader": BroReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Sunstar or Barudan Embroidery Format",
|
|
"extension": "dat",
|
|
"extensions": ("dat",),
|
|
"mimetype": "application/x-dat",
|
|
"category": "embroidery",
|
|
"reader": DatReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Tajima(Barudan) Embroidery Format",
|
|
"extension": "dsb",
|
|
"extensions": ("dsb",),
|
|
"mimetype": "application/x-dsb",
|
|
"category": "embroidery",
|
|
"reader": DsbReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "ZSK USA Embroidery Format",
|
|
"extension": "dsz",
|
|
"extensions": ("dsz",),
|
|
"mimetype": "application/x-dsz",
|
|
"category": "embroidery",
|
|
"reader": DszReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Elna Embroidery Format",
|
|
"extension": "emd",
|
|
"extensions": ("emd",),
|
|
"mimetype": "application/x-emd",
|
|
"category": "embroidery",
|
|
"reader": EmdReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Eltac Embroidery Format",
|
|
"extension": "exy", # e??, e01
|
|
"extensions": ("e00", "e01", "e02"),
|
|
"mimetype": "application/x-exy",
|
|
"category": "embroidery",
|
|
"reader": ExyReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Fortron Embroidery Format",
|
|
"extension": "fxy", # f??, f01
|
|
"extensions": ("f00", "f01", "f02"),
|
|
"mimetype": "application/x-fxy",
|
|
"category": "embroidery",
|
|
"reader": FxyReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Gold Thread Embroidery Format",
|
|
"extension": "gt",
|
|
"extensions": ("gt",),
|
|
"mimetype": "application/x-exy",
|
|
"category": "embroidery",
|
|
"reader": GtReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Inbro Embroidery Format",
|
|
"extension": "inb",
|
|
"extensions": ("inb",),
|
|
"mimetype": "application/x-inb",
|
|
"category": "embroidery",
|
|
"reader": InbReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Tajima Embroidery Format",
|
|
"extension": "tbf",
|
|
"extensions": ("tbf",),
|
|
"mimetype": "application/x-tbf",
|
|
"category": "embroidery",
|
|
"reader": TbfReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "ksm",
|
|
"extensions": ("ksm",),
|
|
"mimetype": "application/x-ksm",
|
|
"category": "embroidery",
|
|
"reader": KsmReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Happy Embroidery Format",
|
|
"extension": "tap",
|
|
"extensions": ("tap",),
|
|
"mimetype": "application/x-tap",
|
|
"category": "embroidery",
|
|
"reader": TapReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "spx",
|
|
"extensions": ("spx"),
|
|
"mimetype": "application/x-spx",
|
|
"category": "embroidery",
|
|
"reader": SpxReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Data Stitch Embroidery Format",
|
|
"extension": "stx",
|
|
"extensions": ("stx",),
|
|
"mimetype": "application/x-stx",
|
|
"category": "embroidery",
|
|
"reader": StxReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Brother Embroidery Format",
|
|
"extension": "phb",
|
|
"extensions": ("phb",),
|
|
"mimetype": "application/x-phb",
|
|
"category": "embroidery",
|
|
"reader": PhbReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Brother Embroidery Format",
|
|
"extension": "phc",
|
|
"extensions": ("phc",),
|
|
"mimetype": "application/x-phc",
|
|
"category": "embroidery",
|
|
"reader": PhcReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Ameco Embroidery Format",
|
|
"extension": "new",
|
|
"extensions": ("new",),
|
|
"mimetype": "application/x-new",
|
|
"category": "embroidery",
|
|
"reader": NewReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "max",
|
|
"extensions": ("max",),
|
|
"mimetype": "application/x-max",
|
|
"category": "embroidery",
|
|
"reader": MaxReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Mitsubishi Embroidery Format",
|
|
"extension": "mit",
|
|
"extensions": ("mit",),
|
|
"mimetype": "application/x-mit",
|
|
"category": "embroidery",
|
|
"reader": MitReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "pcd",
|
|
"extensions": ("pcd",),
|
|
"mimetype": "application/x-pcd",
|
|
"category": "embroidery",
|
|
"reader": PcdReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "pcq",
|
|
"extensions": ("pcq",),
|
|
"mimetype": "application/x-pcq",
|
|
"category": "embroidery",
|
|
"reader": PcqReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "pcm",
|
|
"extensions": ("pcm",),
|
|
"mimetype": "application/x-pcm",
|
|
"category": "embroidery",
|
|
"reader": PcmReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Pfaff Embroidery Format",
|
|
"extension": "pcs",
|
|
"extensions": ("pcs",),
|
|
"mimetype": "application/x-pcs",
|
|
"category": "embroidery",
|
|
"reader": PcsReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Janome Embroidery Format",
|
|
"extension": "jpx",
|
|
"extensions": ("jpx",),
|
|
"mimetype": "application/x-jpx",
|
|
"category": "embroidery",
|
|
"reader": JpxReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Gunold Embroidery Format",
|
|
"extension": "stc",
|
|
"extensions": ("stc",),
|
|
"mimetype": "application/x-stc",
|
|
"category": "embroidery",
|
|
"reader": StcReader,
|
|
}
|
|
)
|
|
yield ({
|
|
"description": "Zeng Hsing Embroidery Format",
|
|
"extension": "zhs",
|
|
"extensions": ("zhs",),
|
|
"mimetype": "application/x-zhs",
|
|
"category": "embroidery",
|
|
"reader": ZhsReader
|
|
})
|
|
yield (
|
|
{
|
|
"description": "ZSK TC Embroidery Format",
|
|
"extension": "zxy",
|
|
"extensions": ("z00", "z01", "z02"),
|
|
"mimetype": "application/x-zxy",
|
|
"category": "embroidery",
|
|
"reader": ZxyReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Brother Stitch Format",
|
|
"extension": "pmv",
|
|
"extensions": ("pmv",),
|
|
"mimetype": "application/x-pmv",
|
|
"category": "stitch",
|
|
"reader": PmvReader,
|
|
"writer": PmvWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "PNG Format, Portable Network Graphics",
|
|
"extension": "png",
|
|
"extensions": ("png",),
|
|
"mimetype": "image/png",
|
|
"category": "image",
|
|
"writer": PngWriter,
|
|
"write_options": {
|
|
"background": (0x000000, 0xFFFFFF),
|
|
"linewidth": (1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
|
|
},
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "txt Format, Text File",
|
|
"extension": "txt",
|
|
"extensions": ("txt",),
|
|
"mimetype": "text/plain",
|
|
"category": "debug",
|
|
"writer": TxtWriter,
|
|
"versions": ("default", "embroidermodder"),
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "gcode Format, Text File",
|
|
"extension": "gcode",
|
|
"extensions": ("gcode", "g-code", "ngc", "nc", ".g"),
|
|
"mimetype": "text/plain",
|
|
"category": "embroidery",
|
|
"reader": GcodeReader,
|
|
"writer": GcodeWriter,
|
|
"write_options": {
|
|
"stitch_z_travel": (5.0, 10.0),
|
|
},
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Husqvarna Embroidery Format",
|
|
"extension": "hus",
|
|
"extensions": ("hus",),
|
|
"mimetype": "application/x-hus",
|
|
"category": "embroidery",
|
|
"reader": HusReader,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Edr Color Format",
|
|
"extension": "edr",
|
|
"extensions": ("edr",),
|
|
"mimetype": "application/x-edr",
|
|
"category": "color",
|
|
"reader": EdrReader,
|
|
"writer": EdrWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Col Color Format",
|
|
"extension": "col",
|
|
"extensions": ("col",),
|
|
"mimetype": "application/x-col",
|
|
"category": "color",
|
|
"reader": ColReader,
|
|
"writer": ColWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Inf Color Format",
|
|
"extension": "inf",
|
|
"extensions": ("inf",),
|
|
"mimetype": "application/x-inf",
|
|
"category": "color",
|
|
"reader": InfReader,
|
|
"writer": InfWriter,
|
|
}
|
|
)
|
|
yield (
|
|
{
|
|
"description": "Json Export",
|
|
"extension": "json",
|
|
"extensions": ("json",),
|
|
"mimetype": "application/json",
|
|
"category": "debug",
|
|
"reader": JsonReader,
|
|
"writer": JsonWriter,
|
|
}
|
|
)
|
|
|
|
@staticmethod
|
|
def convert(filename_from, filename_to, settings=None):
|
|
pattern = EmbPattern.static_read(filename_from, settings)
|
|
if pattern is None:
|
|
return
|
|
EmbPattern.static_write(pattern, filename_to, settings)
|
|
|
|
@staticmethod
|
|
def get_extension_by_filename(filename):
|
|
"""extracts the extension from a filename"""
|
|
return os.path.splitext(filename)[1][1:]
|
|
|
|
@staticmethod
|
|
def read_embroidery(reader, f, settings=None, pattern=None):
|
|
"""Reads fileobject or filename with reader."""
|
|
if reader is None:
|
|
return None
|
|
if pattern is None:
|
|
pattern = EmbPattern()
|
|
|
|
if EmbPattern.is_str(f):
|
|
text_mode = False
|
|
try:
|
|
text_mode = reader.READ_FILE_IN_TEXT_MODE
|
|
except AttributeError:
|
|
pass
|
|
if text_mode:
|
|
try:
|
|
with open(f, "r") as stream:
|
|
reader.read(stream, pattern, settings)
|
|
stream.close()
|
|
except IOError:
|
|
pass
|
|
else:
|
|
try:
|
|
with open(f, "rb") as stream:
|
|
reader.read(stream, pattern, settings)
|
|
stream.close()
|
|
except IOError:
|
|
pass
|
|
else:
|
|
reader.read(f, pattern, settings)
|
|
return pattern
|
|
|
|
@staticmethod
|
|
def read_dst(f, settings=None, pattern=None):
|
|
"""Reads fileobject as DST file"""
|
|
return EmbPattern.read_embroidery(DstReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_pec(f, settings=None, pattern=None):
|
|
"""Reads fileobject as PEC file"""
|
|
return EmbPattern.read_embroidery(PecReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_pes(f, settings=None, pattern=None):
|
|
"""Reads fileobject as PES file"""
|
|
return EmbPattern.read_embroidery(PesReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_exp(f, settings=None, pattern=None):
|
|
"""Reads fileobject as EXP file"""
|
|
return EmbPattern.read_embroidery(ExpReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_vp3(f, settings=None, pattern=None):
|
|
"""Reads fileobject as VP3 file"""
|
|
return EmbPattern.read_embroidery(Vp3Reader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_jef(f, settings=None, pattern=None):
|
|
"""Reads fileobject as JEF file"""
|
|
return EmbPattern.read_embroidery(JefReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_u01(f, settings=None, pattern=None):
|
|
"""Reads fileobject as U01 file"""
|
|
return EmbPattern.read_embroidery(U01Reader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_csv(f, settings=None, pattern=None):
|
|
"""Reads fileobject as CSV file"""
|
|
return EmbPattern.read_embroidery(CsvReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_gcode(f, settings=None, pattern=None):
|
|
"""Reads fileobject as GCode file"""
|
|
return EmbPattern.read_embroidery(GcodeReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def read_xxx(f, settings=None, pattern=None):
|
|
"""Reads fileobject as XXX file"""
|
|
return EmbPattern.read_embroidery(XxxReader, f, settings, pattern)
|
|
|
|
@staticmethod
|
|
def static_read(filename, settings=None, pattern=None):
|
|
"""Reads file, assuming type by extension"""
|
|
extension = EmbPattern.get_extension_by_filename(filename)
|
|
extension = extension.lower()
|
|
for file_type in EmbPattern.supported_formats():
|
|
if file_type["extension"] != extension:
|
|
continue
|
|
reader = file_type.get("reader", None)
|
|
return EmbPattern.read_embroidery(reader, filename, settings, pattern)
|
|
return None
|
|
|
|
@staticmethod
|
|
def write_embroidery(writer, pattern, stream, settings=None):
|
|
if pattern is None:
|
|
return
|
|
if settings is None:
|
|
settings = {}
|
|
else:
|
|
settings = settings.copy()
|
|
try:
|
|
encode = writer.ENCODE
|
|
except AttributeError:
|
|
encode = True
|
|
|
|
if settings.get("encode", encode):
|
|
if not ("max_jump" in settings):
|
|
try:
|
|
settings["max_jump"] = writer.MAX_JUMP_DISTANCE
|
|
except AttributeError:
|
|
pass
|
|
if not ("max_stitch" in settings):
|
|
try:
|
|
settings["max_stitch"] = writer.MAX_STITCH_DISTANCE
|
|
except AttributeError:
|
|
pass
|
|
if not ("full_jump" in settings):
|
|
try:
|
|
settings["full_jump"] = writer.FULL_JUMP
|
|
except AttributeError:
|
|
pass
|
|
if not ("round" in settings):
|
|
try:
|
|
settings["round"] = writer.ROUND
|
|
except AttributeError:
|
|
pass
|
|
if not ("writes_speeds" in settings):
|
|
try:
|
|
settings["writes_speeds"] = writer.WRITES_SPEEDS
|
|
except AttributeError:
|
|
pass
|
|
if not ("sequin_contingency" in settings):
|
|
try:
|
|
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
|
|
if not ("translate" in settings):
|
|
try:
|
|
settings["translate"] = writer.TRANSLATE
|
|
except AttributeError:
|
|
pass
|
|
if not ("scale" in settings):
|
|
try:
|
|
settings["scale"] = writer.SCALE
|
|
except AttributeError:
|
|
pass
|
|
if not ("rotate" in settings):
|
|
try:
|
|
settings["rotate"] = writer.ROTATE
|
|
except AttributeError:
|
|
pass
|
|
pattern = pattern.get_normalized_pattern(settings)
|
|
|
|
if EmbPattern.is_str(stream):
|
|
text_mode = False
|
|
try:
|
|
text_mode = writer.WRITE_FILE_IN_TEXT_MODE
|
|
except AttributeError:
|
|
pass
|
|
if text_mode:
|
|
try:
|
|
with open(stream, "w") as stream:
|
|
writer.write(pattern, stream, settings)
|
|
except IOError:
|
|
pass
|
|
else:
|
|
try:
|
|
with open(stream, "wb") as stream:
|
|
writer.write(pattern, stream, settings)
|
|
except IOError:
|
|
pass
|
|
else:
|
|
writer.write(pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_dst(pattern, stream, settings=None):
|
|
"""Writes fileobject as DST file"""
|
|
EmbPattern.write_embroidery(DstWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_pec(pattern, stream, settings=None):
|
|
"""Writes fileobject as PEC file"""
|
|
EmbPattern.write_embroidery(PecWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_pes(pattern, stream, settings=None):
|
|
"""Writes fileobject as PES file"""
|
|
EmbPattern.write_embroidery(PesWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_exp(pattern, stream, settings=None):
|
|
"""Writes fileobject as EXP file"""
|
|
EmbPattern.write_embroidery(ExpWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_vp3(pattern, stream, settings=None):
|
|
"""Writes fileobject as Vp3 file"""
|
|
EmbPattern.write_embroidery(Vp3Writer, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_jef(pattern, stream, settings=None):
|
|
"""Writes fileobject as JEF file"""
|
|
EmbPattern.write_embroidery(JefWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_u01(pattern, stream, settings=None):
|
|
"""Writes fileobject as U01 file"""
|
|
EmbPattern.write_embroidery(U01Writer, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_csv(pattern, stream, settings=None):
|
|
"""Writes fileobject as CSV file"""
|
|
EmbPattern.write_embroidery(CsvWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_txt(pattern, stream, settings=None):
|
|
"""Writes fileobject as CSV file"""
|
|
EmbPattern.write_embroidery(TxtWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_gcode(pattern, stream, settings=None):
|
|
"""Writes fileobject as Gcode file"""
|
|
EmbPattern.write_embroidery(GcodeWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_xxx(pattern, stream, settings=None):
|
|
"""Writes fileobject as XXX file"""
|
|
EmbPattern.write_embroidery(XxxWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_svg(pattern, stream, settings=None):
|
|
"""Writes fileobject as DST file"""
|
|
EmbPattern.write_embroidery(SvgWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def write_png(pattern, stream, settings=None):
|
|
"""Writes fileobject as PNG file"""
|
|
EmbPattern.write_embroidery(PngWriter, pattern, stream, settings)
|
|
|
|
@staticmethod
|
|
def static_write(pattern, filename, settings=None):
|
|
"""Writes file, assuming type by extension"""
|
|
extension = EmbPattern.get_extension_by_filename(filename)
|
|
extension = extension.lower()
|
|
|
|
for file_type in EmbPattern.supported_formats():
|
|
if file_type["extension"] != extension:
|
|
continue
|
|
writer = file_type.get("writer", None)
|
|
if writer is None:
|
|
continue
|
|
EmbPattern.write_embroidery(writer, pattern, filename, settings)
|
|
|
|
@staticmethod
|
|
def is_str(obj):
|
|
try:
|
|
return isinstance(obj, basestring)
|
|
except NameError:
|
|
return isinstance(obj, str)
|