pull/76/head
tatarize 2019-08-26 12:55:28 -07:00 zatwierdzone przez GitHub
rodzic 5cb7ffe9a7
commit 4aa63ed7b9
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
12 zmienionych plików z 330 dodań i 17 usunięć

Wyświetl plik

@ -89,13 +89,13 @@ def encode_record(x, y, flags):
y += 1
if y != 0:
raise ValueError("The dy value given to the writer exceeds maximum allowed.")
elif flags is COLOR_CHANGE:
elif flags == COLOR_CHANGE:
b2 = 0b11000011
elif flags is STOP:
elif flags == STOP:
b2 = 0b11000011
elif flags is END:
elif flags == END:
b2 = 0b11110011
elif flags is SEQUIN_MODE:
elif flags == SEQUIN_MODE:
b2 = 0b01000011
return bytes(bytearray([b0, b1, b2]))

Wyświetl plik

@ -0,0 +1,187 @@
def expand(data, uncompressed_size=None):
compress = EmbCompress()
return compress.decompress(data, uncompressed_size)
class Huffman:
def __init__(self, lengths=None, value=0):
self.default_value = value
self.lengths = lengths
self.table = None
self.table_width = 0
def build_table(self):
"""Build an index huffman table based on the lengths. lowest index value wins in a tie."""
self.table_width = max(self.lengths)
self.table = []
size = (1 << self.table_width)
for bit_length in range(1, self.table_width + 1):
size /= 2
for len_index in range(0, len(self.lengths)):
length = self.lengths[len_index]
if length == bit_length:
self.table += [len_index] * size
def lookup(self, byte_lookup):
"""lookup into the index, returns value and length
must be requested with 2 bytes."""
if self.table is None:
return self.default_value, 0
v = self.table[byte_lookup >> (16 - self.table_width)]
return v, self.lengths[v]
class EmbCompress:
def __init__(self):
self.bit_position = 0
self.input_data = None
self.block_elements = None
self.character_huffman = None
self.distance_huffman = None
def get_bits(self, start_pos_in_bits, length):
end_pos_in_bits = start_pos_in_bits + length - 1
start_pos_in_bytes = int(start_pos_in_bits / 8)
end_pos_in_bytes = int(end_pos_in_bits / 8)
value = 0
for i in range(start_pos_in_bytes, end_pos_in_bytes + 1):
value <<= 8
try:
value |= self.input_data[i] & 0xFF
except IndexError:
pass
unused_bits_right_of_sample = (8 - (end_pos_in_bits + 1) % 8) % 8
mask_sample_bits = (1 << length) - 1
original = (value >> unused_bits_right_of_sample) & mask_sample_bits
return original
def pop(self, bit_count):
value = self.peek(bit_count)
self.slide(bit_count)
return value
def peek(self, bit_count):
return self.get_bits(self.bit_position, bit_count)
def slide(self, bit_count):
self.bit_position += bit_count
def read_variable_length(self):
m = self.pop(3)
if m != 7:
return m
for q in range(0, 13): # max read is 16 bit, 3 bits already used. It can't exceed 16-3
s = self.pop(1)
if s == 1:
m += 1
else:
break
return m
def load_character_length_huffman(self):
count = self.pop(5)
if count == 0:
v = self.pop(5)
huffman = Huffman(value=v)
else:
huffman_code_lengths = [0] * count
index = 0
while index < count:
if index == 3: # Special index 3, skip up to 3 elements.
index += self.pop(2)
huffman_code_lengths[index] = self.read_variable_length()
index += 1
huffman = Huffman(huffman_code_lengths, 8)
huffman.build_table()
return huffman
def load_character_huffman(self, length_huffman):
count = self.pop(9)
if count == 0:
v = self.pop(9)
huffman = Huffman(value=v)
else:
huffman_code_lengths = [0] * count
index = 0
while index < count:
h = length_huffman.lookup(self.peek(16))
c = h[0]
self.slide(h[1])
if c == 0: # C == 0, skip 1.
c = 1
index += c
elif c == 1: # C == 1, skip 3 + read(4)
c = 3 + self.pop(4)
index += c
elif c == 2: # C == 2, skip 20 + read(9)
c = 20 + self.pop(9)
index += c
else:
c -= 2
huffman_code_lengths[index] = c
index += 1
huffman = Huffman(huffman_code_lengths)
huffman.build_table()
return huffman
def load_distance_huffman(self):
count = self.pop(5)
if count == 0:
v = self.pop(5)
huffman = Huffman(value=v)
else:
index = 0
lengths = [0] * count
for i in range(0, count):
lengths[index] = self.read_variable_length()
index += 1
huffman = Huffman(lengths)
huffman.build_table()
return huffman
def load_block(self):
self.block_elements = self.pop(16)
character_length_huffman = self.load_character_length_huffman()
self.character_huffman = self.load_character_huffman(character_length_huffman)
self.distance_huffman = self.load_distance_huffman()
def get_token(self):
if self.block_elements <= 0:
self.load_block()
self.block_elements -= 1
h = self.character_huffman.lookup(self.peek(16))
self.slide(h[1])
return h[0]
def get_position(self):
h = self.distance_huffman.lookup(self.peek(16))
self.slide(h[1])
if h[0] == 0:
return 0
v = h[0] - 1
v = (1 << v) + self.pop(v)
return v
def decompress(self, input_data, uncompressed_size=None):
self.input_data = input_data
output_data = []
self.block_elements = -1
bits_total = (len(input_data) * 8)
while bits_total > self.bit_position and (uncompressed_size is None or len(output_data) <= uncompressed_size):
character = self.get_token()
if character <= 255: # literal.
output_data.append(character)
elif character == 510:
break # END
else:
length = character - 253 # Min length is 3. 256-253=3.
back = self.get_position() + 1
position = len(output_data) - back
if back > length:
# Entire lookback is already within output data.
output_data += output_data[position:position + length]
else:
# Will read & write the same data at some point.
for i in range(position, position + length):
output_data.append(output_data[i])
return output_data

Wyświetl plik

@ -6,6 +6,8 @@ THREAD_MASK = 0x0000FF00
NEEDLE_MASK = 0x00FF0000
ORDER_MASK = 0xFF000000
FLAGS_MASK = 0x0000FF00
NO_COMMAND = -1
STITCH = 0
JUMP = 1
@ -65,3 +67,5 @@ CONTINGENCY_SEQUIN_UTILIZE = 0xF5
CONTINGENCY_SEQUIN_JUMP = 0xF6
CONTINGENCY_SEQUIN_STITCH = 0xF7
CONTINGENCY_SEQUIN_REMOVE = 0xF8
ALTERNATIVE = 0x100 # Generic flag for an alternative form.

Wyświetl plik

@ -75,6 +75,7 @@ class Transcoder:
self.state_jumping = False
self.needle_x = 0
self.needle_y = 0
self.high_flags = 0
def transcode(self, source_pattern, destination_pattern):
if source_pattern is destination_pattern:
@ -198,6 +199,7 @@ class Transcoder:
x = round(x)
y = round(y)
flags = self.stitch[2] & COMMAND_MASK
self.high_flags = self.stitch[2] & FLAGS_MASK
if flags == NO_COMMAND:
continue
@ -351,13 +353,17 @@ class Transcoder:
self.state_trimmed = False
def add_thread_change(self, command, thread=None, needle=None, order=None):
self.add(encode_thread_change(command, thread, needle, order))
x = self.needle_x
y = self.needle_y
cmd = encode_thread_change(command, thread, needle, order)
self.destination_pattern.stitches.append([x, y, cmd])
def add(self, flags, x=None, y=None):
if x is None:
x = self.needle_x
if y is None:
y = self.needle_y
flags |= self.high_flags
self.destination_pattern.stitches.append([x, y, flags])
def lookahead_stitch(self):
@ -615,7 +621,7 @@ class Transcoder:
# we need the gap stitches only, not start or end stitch.
qx += step_size_x
qy += step_size_y
stitch = [qx, qy, data]
stitch = [qx, qy, data | self.high_flags]
transcode.append(stitch)
self.update_needle_position(stitch[0], stitch[1])

Wyświetl plik

@ -0,0 +1,46 @@
from .EmbThread import EmbThread
def get_thread_set():
return [
EmbThreadHus("#000000", "Black", "026"),
EmbThreadHus("#0000e7", "Blue", "005"),
EmbThreadHus("#00c600", "Green", "002"),
EmbThreadHus("#ff0000", "Red", "014"),
EmbThreadHus("#840084", "Purple", "008"),
EmbThreadHus("#ffff00", "Yellow", "020"),
EmbThreadHus("#848484", "Grey", "024"),
EmbThreadHus("#8484e7", "Light Blue", "006"),
EmbThreadHus("#00ff84", "Light Green", "003"),
EmbThreadHus("#ff7b31", "Orange", "017"),
EmbThreadHus("#ff8ca5", "Pink", "011"),
EmbThreadHus("#845200", "Brown", "028"),
EmbThreadHus("#ffffff", "White", "022"),
EmbThreadHus("#000084", "Dark Blue", "004"),
EmbThreadHus("#008400", "Dark Green", "001"),
EmbThreadHus("#7b0000", "Dark Red", "013"),
EmbThreadHus("#ff6384", "Light Red", "015"),
EmbThreadHus("#522952", "Dark Purple", "007"),
EmbThreadHus("#ff00ff", "Light Purple", "009"),
EmbThreadHus("#ffde00", "Dark Yellow", "019"),
EmbThreadHus("#ffff9c", "Light Yellow", "021"),
EmbThreadHus("#525252", "Dark Grey", "025"),
EmbThreadHus("#d6d6d6", "Light Grey", "023"),
EmbThreadHus("#ff5208", "Dark Orange", "016"),
EmbThreadHus("#ff9c5a", "Light Orange", "018"),
EmbThreadHus("#ff52b5", "Dark Pink", "010"),
EmbThreadHus("#ffc6de", "Light Pink", "012"),
EmbThreadHus("#523100", "Dark Brown", "027"),
EmbThreadHus("#b5a584", "Light Brown", "029")
]
class EmbThreadHus(EmbThread):
def __init__(self, color, description, catalog_number=None):
EmbThread.__init__(self)
self.set(color)
self.description = description
self.catalog_number = catalog_number
self.brand = "Hus"
self.chart = "Hus"

Wyświetl plik

@ -19,7 +19,7 @@ def write(pattern, f, settings=None):
dy = int(round(y - yy))
xx += dx
yy += dy
if data is STITCH:
if data == STITCH:
# consider bounds checking the delta_x, delta_y and raising ValueError if exceeds.
delta_x = dx & 0xFF
delta_y = -dy & 0xFF

Wyświetl plik

@ -0,0 +1,59 @@
from .EmbCompress import expand
from .EmbThreadHus import get_thread_set
from .ReadHelper import signed8, signed16, read_int_32le, read_int_16le, read_string_8
def read(f, out, settings=None):
magic_code = read_int_32le(f)
number_of_stitches = read_int_32le(f)
number_of_colors = read_int_32le(f)
extend_pos_x = signed16(read_int_16le(f))
extend_pos_y = signed16(read_int_16le(f))
extend_neg_x = signed16(read_int_16le(f))
extend_neg_y = signed16(read_int_16le(f))
command_offset = read_int_32le(f)
x_offset = read_int_32le(f)
y_offset = read_int_32le(f)
string_value = read_string_8(f, 8)
unknown_16_bit = read_int_16le(f)
hus_thread_set = get_thread_set()
for i in range(0, number_of_colors):
index = read_int_16le(f)
out.add_thread(hus_thread_set[index])
f.seek(command_offset, 0)
command_compressed = bytearray(f.read(x_offset - command_offset))
f.seek(x_offset, 0)
x_compressed = bytearray(f.read(y_offset - x_offset))
f.seek(y_offset, 0)
y_compressed = bytearray(f.read())
command_decompressed = expand(command_compressed, number_of_stitches)
x_decompressed = expand(x_compressed, number_of_stitches)
y_decompressed = expand(y_compressed, number_of_stitches)
stitch_count = min(len(command_decompressed), len(x_decompressed), len(y_decompressed))
for i in range(0, stitch_count):
cmd = command_decompressed[i]
x = signed8(x_decompressed[i])
y = -signed8(y_decompressed[i])
if cmd == 0x80: # STITCH
out.stitch(x, y)
elif cmd == 0x81: # JUMP
out.move(x, y)
elif cmd == 0x84: # COLOR_CHANGE
out.color_change(x, y)
elif cmd == 0x88: # TRIM
if x != 0 or y != 0:
out.move(x, y)
out.trim()
elif cmd == 0x90: # END
break
else: # UNMAPPED COMMAND
break
out.end()

Wyświetl plik

@ -132,7 +132,7 @@ def pec_encode(pattern, f):
dy = int(round(y - yy))
xx += dx
yy += dy
if data is STITCH:
if data == STITCH:
if jumping and dx != 0 and dy != 0:
f.write(b'\x00\x00')
jumping = False

Wyświetl plik

@ -18,6 +18,7 @@ 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.JefReader as JefReader
import pyembroidery.JefWriter as JefWriter
@ -462,6 +463,14 @@ def supported_formats():
"stitch_z_travel": (5.0, 10.0),
},
})
yield ({
"description": "Husqvarna Embroidery Format",
"extension": "hus",
"extensions": ("hus",),
"mimetype": "application/x-hus",
"category": "embroidery",
"reader": HusReader
})
def convert(filename_from, filename_to, settings=None):

Wyświetl plik

@ -31,35 +31,35 @@ def read_signed(stream, n):
def read_sint_8(stream):
byte = bytearray(stream.read(1))
if len(byte) is 1:
if len(byte) == 1:
return signed8(byte[0])
return None
def read_int_8(stream):
byte = bytearray(stream.read(1))
if len(byte) is 1:
if len(byte) == 1:
return byte[0]
return None
def read_int_16le(stream):
byte = bytearray(stream.read(2))
if len(byte) is 2:
if len(byte) == 2:
return (byte[0] & 0xFF) + ((byte[1] & 0xFF) << 8)
return None
def read_int_16be(stream):
byte = bytearray(stream.read(2))
if len(byte) is 2:
if len(byte) == 2:
return (byte[1] & 0xFF) + ((byte[0] & 0xFF) << 8)
return None
def read_int_24le(stream):
b = bytearray(stream.read(3))
if len(b) is 3:
if len(b) == 3:
return (b[0] & 0xFF) + ((b[1] & 0xFF) << 8) + \
((b[2] & 0xFF) << 16)
return None
@ -67,7 +67,7 @@ def read_int_24le(stream):
def read_int_24be(stream):
b = bytearray(stream.read(3))
if len(b) is 3:
if len(b) == 3:
return (b[2] & 0xFF) + ((b[1] & 0xFF) << 8) + \
((b[0] & 0xFF) << 16)
return None
@ -75,7 +75,7 @@ def read_int_24be(stream):
def read_int_32le(stream):
b = bytearray(stream.read(4))
if len(b) is 4:
if len(b) == 4:
return (b[0] & 0xFF) + ((b[1] & 0xFF) << 8) + \
((b[2] & 0xFF) << 16) + ((b[3] & 0xFF) << 24)
return None
@ -83,7 +83,7 @@ def read_int_32le(stream):
def read_int_32be(stream):
b = bytearray(stream.read(4))
if len(b) is 4:
if len(b) == 4:
return (b[3] & 0xFF) + ((b[2] & 0xFF) << 8) + \
((b[1] & 0xFF) << 16) + ((b[0] & 0xFF) << 24)
return None

Wyświetl plik

@ -57,6 +57,7 @@ def read(f, out, settings=None):
vp3_read_colorblock(f, out, center_x, center_y)
if (i + 1) < count_colors: # Don't add the color change on the final read.
out.color_change()
out.end()
def vp3_read_colorblock(f, out, center_x, center_y):

Wyświetl plik

@ -224,6 +224,7 @@ def write_stitches_block(f, stitches, first_pos_x, first_pos_y):
x = stitch[0]
y = stitch[1]
flags = stitch[2] & COMMAND_MASK
alt = stitch[2] & FLAGS_MASK
if flags == END:
f.write(b'\x80\x03') # Write a trim at end of file.
break
@ -248,7 +249,7 @@ def write_stitches_block(f, stitches, first_pos_x, first_pos_y):
last_x += dx
last_y += dy
if flags == STITCH:
if -127 <= dx <= 127 and -127 <= dy <= 127:
if -127 <= dx <= 127 and -127 <= dy <= 127 and alt == 0:
write_int_8(f, dx)
write_int_8(f, dy)
else: