暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

convert_sparkmaker.py 6.1KB

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