Browse Source

add sparkmaker wow conversion script

Thomas Buck 1 year ago
parent
commit
226057263b
2 changed files with 188 additions and 0 deletions
  1. 4
    0
      tools/README.md
  2. 184
    0
      tools/convert_sparkmaker.py

+ 4
- 0
tools/README.md View File

@@ -26,3 +26,7 @@ Machine size is hardcoded in the script.
26 26
 
27 27
 Simple G-Code sender using pySerial to access serial port.
28 28
 For use with Marlin and possibly other RepRap compatible firmwares.
29
+
30
+## convert_sparkmaker.py
31
+
32
+Convert PrusaSlicer `.sl1` files to Sparkmaker `.wow` files.

+ 184
- 0
tools/convert_sparkmaker.py View File

@@ -0,0 +1,184 @@
1
+#!/usr/bin/env python
2
+
3
+import sys
4
+import os
5
+from zipfile import ZipFile
6
+import re
7
+import pprint
8
+import png
9
+
10
+###############################################################################
11
+
12
+screen_size = (854, 480)
13
+max_height = 120
14
+initial_params = {
15
+    'layer_height': 0.1,
16
+    'first_layer_height': 0.1,
17
+    'exposure_time': 15.0,
18
+    'first_exposure_time': 120.0,
19
+    'lift_height': 5.0,
20
+    'lift_speed': 30.0,
21
+    'sink_speed': 100.0
22
+}
23
+
24
+###############################################################################
25
+
26
+def read_prusaslicer_ini(f, params):
27
+    lines = f.decode("utf-8").split("\n")
28
+
29
+    for l in lines:
30
+        if l.startswith("exposure_time"):
31
+            params["exposure_time"] = float(l.split(" = ")[1])
32
+        elif l.startswith("initial_exposure_time"):
33
+            params["first_exposure_time"] = float(l.split(" = ")[1])
34
+        elif l.startswith("layer_height"):
35
+            params["layer_height"] = float(l.split(" = ")[1])
36
+        elif l.startswith("initial_layer_height"):
37
+            params["first_layer_height"] = float(l.split(" = ")[1])
38
+
39
+def read_config_ini(f, params):
40
+    lines = f.decode("utf-8").split("\n")
41
+
42
+    for l in lines:
43
+        if l.startswith("expTimeFirst"):
44
+            params["first_exposure_time"] = float(l.split(" = ")[1])
45
+        elif l.startswith("expTime"):
46
+            params["exposure_time"] = float(l.split(" = ")[1])
47
+        elif l.startswith("layerHeight"):
48
+            params["layer_height"] = float(l.split(" = ")[1])
49
+
50
+def read_sl1(f):
51
+    params = initial_params
52
+
53
+    files = f.namelist()
54
+    if "prusaslicer.ini" in files:
55
+        read_prusaslicer_ini(f.read("prusaslicer.ini"), params)
56
+    else:
57
+        print("No prusaslicer.ini found in file")
58
+        if "config.ini" in files:
59
+            read_config_ini(f.read("config.ini"), params)
60
+        else:
61
+            print("No config.ini found in file")
62
+            sys.exit(1)
63
+
64
+    imgs = [x for x in files if x.endswith(".png")]
65
+    imgs = [x for x in imgs if not x.startswith("thumbnail/")]
66
+
67
+    if len(imgs) <= 0:
68
+        print("No slices found in file. Aborting.")
69
+        sys.exit(1)
70
+
71
+    res = re.findall('(\D*)\d*.*', imgs[0])[0]
72
+    print("Internal name: \"" + res + "\"")
73
+    print("Found " + str(len(imgs)) + " slices")
74
+
75
+    images = []
76
+    for img in imgs:
77
+        images.append(f.read(img))
78
+
79
+    return params, images
80
+
81
+###############################################################################
82
+
83
+def write_image(f, img):
84
+    p = png.Reader(bytes = img)
85
+    width, height, rows, info = p.read()
86
+
87
+    if width != screen_size[0]:
88
+        print("Error: layer has wrong width " + str(width) + " != " + str(screen_size[0]))
89
+        sys.exit(1)
90
+
91
+    if height != screen_size[1]:
92
+        print("Error: layer has wrong height " + str(height) + " != " + str(screen_size[1]))
93
+        sys.exit(1)
94
+
95
+    if (not info['greyscale']) or info['alpha']:
96
+        print("Error: invalid image encoding")
97
+        sys.exit(1)
98
+
99
+    data = [0] * int(width * height / 8)
100
+
101
+    y = 0 # width is 854
102
+    x = 0 # height is 480
103
+    for row in rows:
104
+        for v in row:
105
+            if v > 0x7F:
106
+                data[int(height / 8) * y + int(x / 8)] |= (1 << x % 8)
107
+            y += 1
108
+        x += 1
109
+        y = 0
110
+
111
+    for d in data:
112
+        f.write(d.to_bytes(1, 'big'))
113
+
114
+def write_wow(f, params, imgs):
115
+    def write(s):
116
+        #print(s)
117
+        f.write((s + "\n").encode())
118
+
119
+    write("G21;")
120
+    write("G91;")
121
+    write("M17;")
122
+    write("M106 S0;")
123
+    write("G28 Z0;")
124
+
125
+    first_layer = True
126
+
127
+    for i in range(0, len(imgs)):
128
+        write(";L:" + str(int(i)) + ";")
129
+        write("M106 S0;")
130
+
131
+        lift_up = params['lift_height']
132
+        lift_down = -(lift_up - params['layer_height'])
133
+        exposure_time = params['exposure_time']
134
+        if first_layer:
135
+            lift_down = -(lift_up - params['first_layer_height'])
136
+            exposure_time = params['first_exposure_time']
137
+            first_layer = False
138
+
139
+        write("G1 Z" + str(lift_up) + " F" + str(params['lift_speed']) + ";")
140
+        write("G1 Z" + str(lift_down) + " F" + str(params['sink_speed']) + ";")
141
+        write("{{")
142
+        write_image(f, imgs[i])
143
+        write("}}")
144
+        write("M106 S255;")
145
+        write("G4 S" + str(exposure_time) + ";")
146
+        write("G4 S1;")
147
+
148
+    object_height = params['layer_height'] * (len(imgs) - 1) + params['first_layer_height']
149
+    final_move = max_height - object_height
150
+
151
+    write("M106 S0;")
152
+    write("G1 Z" + str(final_move) + " F25;")
153
+    write("M18;")
154
+
155
+###############################################################################
156
+
157
+def main():
158
+    if len(sys.argv) < 2:
159
+        print("Usage:")
160
+        print("    " + sys.argv[0] + " input.sl1 [output.wow]")
161
+        sys.exit(1)
162
+
163
+    in_file_name = sys.argv[1]
164
+
165
+    out_file_name = "print.wow"
166
+    if len(sys.argv) >= 3:
167
+        out_file_name = sys.argv[2]
168
+
169
+    if os.path.exists(out_file_name):
170
+        print("File already exists: \"" + out_file_name + "\". Aborting.")
171
+        sys.exit(1)
172
+
173
+    with ZipFile(in_file_name, 'r') as sl1:
174
+        params, imgs = read_sl1(sl1)
175
+
176
+    print("Using following parameters:")
177
+    pprint.pprint(params)
178
+    print("Writing output to \"" + out_file_name + "\"")
179
+
180
+    with open(out_file_name, 'wb') as wow:
181
+        write_wow(wow, params, imgs)
182
+
183
+if __name__ == '__main__':
184
+    main()

Loading…
Cancel
Save