diff --git a/pyembroidery/JefReader.py b/pyembroidery/JefReader.py index 269c0fe9..dd884d51 100644 --- a/pyembroidery/JefReader.py +++ b/pyembroidery/JefReader.py @@ -3,6 +3,7 @@ def read_jef_stitches(f, out, settings=None): + color_index = 1 while True: b = bytearray(f.read(2)) if len(b) != 2: @@ -22,7 +23,13 @@ def read_jef_stitches(f, out, settings=None): out.move(x, y) continue if ctrl == 0x01: - out.color_change(0, 0) + # PATCH: None means stop since it was color #0 + if out.threadlist[color_index] is None: + out.stop(0, 0) + del out.threadlist[color_index] + else: + out.color_change(0, 0) + color_index += 1 continue if ctrl == 0x10: break @@ -54,7 +61,11 @@ def read(f, out, settings=None): for i in range(0, count_colors): index = abs(read_int_32le(f)) - out.add_thread(jef_threads[index % len(jef_threads)]) + if index == 0: + # Patch: If we have color 0. Go ahead and set that to None. + out.threadlist.append(None) + else: + out.add_thread(jef_threads[index % len(jef_threads)]) f.seek(stitch_offset, 0) read_jef_stitches(f, out, settings) diff --git a/pyembroidery/JefWriter.py b/pyembroidery/JefWriter.py index 6dbbb665..0fdace4f 100644 --- a/pyembroidery/JefWriter.py +++ b/pyembroidery/JefWriter.py @@ -1,7 +1,6 @@ import datetime from .EmbConstant import * -from .EmbThread import build_nonrepeat_palette from .EmbThreadJef import get_thread_set from .WriteHelper import write_int_8, write_int_32le, write_string_utf8 @@ -30,7 +29,46 @@ def write(pattern, f, settings=None): date_string = settings.get("date", date_string) pattern.fix_color_count() - color_count = pattern.count_threads() + # REMOVE BUG: color_count = pattern.count_threads(). # + + # PATCH + jef_threads = get_thread_set() + last_index = None + last_thread = None + palette = [] + color_toggled = False + color_count = 0 # Color and Stop count. + index_in_threadlist = 0 + for stitch in pattern.stitches: + # Iterate all stitches. + flags = stitch[2] & COMMAND_MASK + if flags == COLOR_CHANGE or index_in_threadlist == 0: + # If color change *or* initial color unset. + thread = pattern.threadlist[index_in_threadlist] + index_in_threadlist += 1 + color_count += 1 + index_of_jefthread = thread.find_nearest_color_index(jef_threads) + if last_index == index_of_jefthread and last_thread != thread: + # Last thread and current thread pigeonhole to same jefcolor. + # We set that thread to None. And get the second closest color. + repeated_thread = jef_threads[index_of_jefthread] + repeated_index = index_of_jefthread + jef_threads[index_of_jefthread] = None + index_of_jefthread = thread.find_nearest_color_index(jef_threads) + jef_threads[repeated_index] = repeated_thread + palette.append(index_of_jefthread) + last_index = index_of_jefthread + last_thread = thread + color_toggled = False + if flags == STOP: + color_count += 1 + color_toggled = not color_toggled + if color_toggled: + palette.append(0) + else: + palette.append(last_index) + # END PATCH + offsets = 0x74 + (color_count * 8) write_int_32le(f, offsets) write_int_32le(f, 0x14) @@ -48,7 +86,7 @@ def write(pattern, f, settings=None): elif data == TRIM: if trims: point_count += 2 * command_count_max - elif data == COLOR_CHANGE: + elif data == COLOR_CHANGE or data == STOP: # PATCH: INCLUDE STOP. point_count += 2 elif data == END: break @@ -86,9 +124,12 @@ def write(pattern, f, settings=None): y_hoop_edge = 1000 - half_height write_hoop_edge_distance(f, x_hoop_edge, y_hoop_edge) - jef_threads = get_thread_set() + # REMOVE (We covered this in PATCH). + #jef_threads = get_thread_set() + # + #palette = build_nonrepeat_palette(jef_threads, pattern.threadlist) + # END REMOVE - palette = build_nonrepeat_palette(jef_threads, pattern.threadlist) for t in palette: write_int_32le(f, t) @@ -109,7 +150,7 @@ def write(pattern, f, settings=None): write_int_8(f, dx) write_int_8(f, -dy) continue - elif data == COLOR_CHANGE: + elif data == COLOR_CHANGE or data == STOP: # PATCH INCLUDE STOP. f.write(b"\x80\x01") write_int_8(f, dx) write_int_8(f, -dy) diff --git a/pyembroidery/PecWriter.py b/pyembroidery/PecWriter.py index ef58829b..3d95b174 100644 --- a/pyembroidery/PecWriter.py +++ b/pyembroidery/PecWriter.py @@ -60,7 +60,7 @@ def write_pec_header(pattern, f, threadlist): f.write(b"\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20") add_value = current_thread_count - 1 color_index_list.insert(0, add_value) - assert color_index_list[0]<255, 'to many color changes, ({0}) out of bounds (0, 255)'.format(len(color_index_list)) + assert color_index_list[0] < 255, 'too many color changes, ({0}) out of bounds (0, 255)'.format(len(color_index_list)) f.write(bytes(bytearray(color_index_list))) else: f.write(b"\x20\x20\x20\x20\x64\x20\x00\x20\x00\x20\x20\x20\xFF") diff --git a/pyembroidery/__init__.py b/pyembroidery/__init__.py index dcc4fb0d..2cf38d67 100644 --- a/pyembroidery/__init__.py +++ b/pyembroidery/__init__.py @@ -6,6 +6,7 @@ from .EmbMatrix import EmbMatrix from .EmbPattern import EmbPattern from .EmbThread import EmbThread +from .EmbCompress import compress, expand # items available in a sub-heirarchy (e.g. pyembroidery.PecGraphics.get_graphic_as_string) from .PecGraphics import get_graphic_as_string diff --git a/setup.py b/setup.py index 0f0e5475..0ca7fcaa 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setuptools.setup( name="pyembroidery", - version="1.4.28", + version="1.4.29", author="Tatarize", author_email="tatarize@gmail.com", description="Embroidery IO library", diff --git a/test/pattern_for_tests.py b/test/pattern_for_tests.py index ba6ce95e..1d50c344 100644 --- a/test/pattern_for_tests.py +++ b/test/pattern_for_tests.py @@ -59,6 +59,7 @@ def add_serp(self): } evaluate_lsystem(initial, rules, 3) # 6 + def get_big_pattern(): pattern = EmbPattern() pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red") @@ -131,6 +132,78 @@ def get_shift_pattern(): return pattern +def get_shift_stop_pattern(): + pattern = EmbPattern() + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_command(STOP) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "green") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_command(STOP) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "green") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "green") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "ivory") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "ivory") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_command(STOP) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "ivory") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "olive") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "olive") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_command(STOP) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "olive") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "olive") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "violet") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_command(STOP) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "white") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "salmon") + pattern.add_command(MATRIX_TRANSLATE, 25, 25) + pattern.add_command(MATRIX_ROTATE, 22.5) + pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "lime") + return pattern + + +def get_simple_stop(): + pattern = EmbPattern() + pattern += (0,0) + pattern += (0, 100) + pattern += (100, 100) + pattern += (100, 0) + pattern += (0, 0) + pattern.stop() + pattern += (0, 0) + pattern += (0, 100) + pattern += (100, 100) + pattern += (100, 0) + pattern += (0, 0) + return pattern + + def get_simple_pattern(): pattern = EmbPattern() pattern.add_block([(0, 0), (0, 100), (100, 100), (100, 0), (0, 0)], "red") diff --git a/test/test_convert_jef.py b/test/test_convert_jef.py index fa26e026..b9d3420a 100644 --- a/test/test_convert_jef.py +++ b/test/test_convert_jef.py @@ -168,4 +168,34 @@ def test_convert_jef_to_xxx(self): self.position_equals(t_pattern.stitches, 0, -1) print("jef->xxx: ", t_pattern.stitches) self.addCleanup(os.remove, file1) - self.addCleanup(os.remove, file2) \ No newline at end of file + self.addCleanup(os.remove, file2) + + def test_jef_stop_write_simple(self): + file = "stop.jef" + write_jef(get_simple_stop(), file) + s_pattern = read_jef(file) + self.assertEqual(s_pattern.count_stitch_commands(STOP), 1) + self.assertEqual(s_pattern.count_color_changes(), 0) + self.addCleanup(os.remove, file) + + def test_jef_stop_write_large(self): + file = "stop2.jef" + pattern = get_shift_stop_pattern() + n_pattern = pattern.get_normalized_pattern() + self.assertEqual(n_pattern.count_stitch_commands(COLOR_CHANGE), 15) + self.assertEqual(n_pattern.count_stitch_commands(STITCH), 16 * 5) + self.assertEqual(n_pattern.count_stitch_commands(STOP), 5) + + write_jef(pattern, file) + f_pattern = read_jef(file) + self.assertIsNotNone(f_pattern) + + with open(file, "rb") as f: + f.seek(0x18) + colors = f.read(1) + self.assertEqual(ord(colors), f_pattern.count_color_changes() + f_pattern.count_stitch_commands(STOP) + 1) + + self.assertEqual(f_pattern.count_stitch_commands(COLOR_CHANGE), 15) + self.assertEqual(f_pattern.count_stitch_commands(STITCH), 16 * 5) + self.assertEqual(f_pattern.count_stitch_commands(STOP), 5) + self.addCleanup(os.remove, file) \ No newline at end of file diff --git a/test/test_encoder.py b/test/test_encoder.py index 2d66c676..6cce6a06 100644 --- a/test/test_encoder.py +++ b/test/test_encoder.py @@ -110,4 +110,4 @@ def test_transcode_to_self(self): from pyembroidery.EmbEncoder import Transcoder encoder = Transcoder() encoder.transcode(pattern, pattern) - self.assertNotEquals(len(pattern.stitches), 0) + self.assertNotEqual(len(pattern.stitches), 0) diff --git a/test/test_read_hus.py b/test/test_read_hus.py index 839123d5..183169bf 100644 --- a/test/test_read_hus.py +++ b/test/test_read_hus.py @@ -3,15 +3,15 @@ import random import unittest -from EmbCompress import expand, compress +from pyembroidery import * class TestReadHus(unittest.TestCase): def test_fake_compression(self): for i in range(10): - s = random.randint(10, 1000) + s = random.randint(10, 1000) # May fail if larger. test_bytes = bytearray(random.getrandbits(8) for _ in range(s)) - compressed_bytes = compress(test_bytes) - uncompressed = bytearray(expand(compressed_bytes, len(test_bytes))) + compressed_bytes = EmbCompress.compress(test_bytes) + uncompressed = bytearray(EmbCompress.expand(compressed_bytes, len(test_bytes))) self.assertEqual(test_bytes, uncompressed)