1313
1414# from cura.CuraApplication import CuraApplication
1515from cura .Snapshot import Snapshot
16+ from cura .CuraApplication import CuraApplication
1617from cura .Utils .Threading import call_on_qt_thread
1718# from cura.UI import PrintInformation
1819from PyQt5 .QtCore import QBuffer
@@ -62,16 +63,19 @@ def __init__(self):
6263 super ().__init__ (add_to_recent_files = False )
6364 self ._application = Application .getInstance ()
6465
66+ @call_on_qt_thread
6567 def _createSnapshot (self , * args ):
66- # must be called from the main thread because of OpenGL
6768 Logger .log ("d" , "Creating thumbnail image..." )
69+ if not CuraApplication .getInstance ().isVisible :
70+ Logger .log ("w" , "Can't create snapshot when renderer not initialized." )
71+ return None
6872 try :
69- self . _snapshot = Snapshot .snapshot (width = 300 , height = 300 ).convertToFormat (QImage .Format_Indexed8 )
73+ ss = Snapshot .snapshot (width = 300 , height = 300 ).convertToFormat (QImage .Format_Indexed8 )
7074 except Exception :
7175 Logger .logException ("w" , "Failed to create snapshot image" )
72- self ._snapshot = None # Failing to create thumbnail should not fail creation of UFP
76+ return None
77+ return ss
7378
74- @call_on_qt_thread
7579 def write (self , stream , nodes , mode = MeshWriter .OutputMode .TextMode ):
7680 """Writes the g-code for the entire scene to a stream.
7781
@@ -98,87 +102,93 @@ def write(self, stream, nodes, mode = MeshWriter.OutputMode.TextMode):
98102 gcode_dict = getattr (scene , "gcode_dict" )
99103 gcode_list = gcode_dict .get (active_build_plate , None )
100104
101- # Get some vars (I cannot find the correct value)
102105 printTemp = None
103106 bedTemp = None
104107 for x in gcode_list :
105108 if ("M190" in x or "M140" in x ) and bedTemp is None :
106- for y in re .findall (r"(M140|M190) S(\d+)" , x ):
107- #Logger.log("d","Bed:" + y[1])
109+ for y in re .findall (r"(M190|M140) S(\d+)" , x ):
108110 bedTemp = y [1 ]
109- break
111+ break ;
110112 if ("M109" in x or "M104" in x ) and printTemp is None :
111113 for y in re .findall (r"(M109|M104) S(\d+)" , x ):
112- #Logger.log("d","Extruder:" + y[1])
113114 printTemp = y [1 ]
114- break
115- if printTemp is not None and bedTemp is not None :
116- break
115+ break ;
116+ if not (printTemp is None or bedTemp is None ):
117+ break ;
118+
117119 print_info = Application .getInstance ().getPrintInformation ()
118120 feature_times = print_info .getFeaturePrintTimes ()
119121 estiTime = 0 #in Seconds
120122 for x in feature_times :
121- #Logger.log("d",x+":"+str(int(feature_times[x])) + " Seconds")
122123 estiTime += int (feature_times [x ])
124+
123125 # Generate snapshot
124- self . _createSnapshot ()
125- if self ._snapshot :
126- Logger . log ( "d" , "Snapshot created." )
126+ base64_bytes = b""
127+ ss = self ._createSnapshot ()
128+ if ss :
127129 thumbnail_buffer = QBuffer ()
128130 thumbnail_buffer .open (QBuffer .ReadWrite )
129- thumbnail_image = self ._snapshot
130- thumbnail_image .save (thumbnail_buffer , "PNG" )
131+ ss .save (thumbnail_buffer , "PNG" )
131132 base64_bytes = base64 .b64encode (thumbnail_buffer .data ())
132133 thumbnail_buffer .close ()
133- else :
134- base64_bytes = b""
134+
135135 # Start header
136- stream .write (";Header Start\n \n " )
137136 gcode_buffer = ""
138137 header_buffer = False
139- model_line_count = 0
138+ model_line_count = 22
140139 if gcode_list is not None :
141140 has_settings = False
142- for gcode in gcode_list :
143- if gcode [:len (self ._setting_keyword )] == self ._setting_keyword :
144- has_settings = True
145- # Move FLAVOR/TIME/... block to top
146- if "FLAVOR" not in gcode :
147- model_line_count += len (gcode .splitlines ()) # Add lines to model_line_count for header
148- gcode_buffer += gcode + "\n " # Add extra newline for each layer, for readability of gcode
141+ is_gcode_file = False
142+ for line , gcode in enumerate (gcode_list ):
143+ if line is 0 and len (re .findall (r"\n" , gcode )) is 1 :
144+ is_gcode_file = True
145+
146+ if is_gcode_file :
147+ gcode_buffer += gcode
148+
149149 else :
150- # Split header lines and write to buffer
151- header_buffer = gcode .splitlines (keepends = True )
152- # Combine everything
153- stream .write (header_buffer [0 ]) # FLAVOR
154- stream .write (header_buffer [1 ]) # TIME
155- stream .write (header_buffer [2 ]) # Filament used
156- stream .write (header_buffer [3 ]) # Layer height
157- stream .write ("\n \n ;header_type: 3dp\n " )
158- if base64_bytes :
159- stream .write (";thumbnail: data:image/png;base64," )
160- stream .write (base64_bytes .decode ("ascii" ))
161- stream .write ("\n " )
162- stream .write (";file_total_lines: %s\n " % model_line_count )
163- stream .write (";estimated_time(s): %s\n " % estiTime )
164- stream .write (";nozzle_temperature(°C): %s\n " % printTemp )
165- stream .write (";build_plate_temperature(°C): %s\n " % bedTemp )
166- stream .write (header_buffer [7 ].replace ("MAXX:" ,"max_x(mm): " )) # max_x
167- stream .write (header_buffer [8 ].replace ("MAXY:" ,"max_y(mm): " )) # max_y
168- stream .write (header_buffer [9 ].replace ("MAXZ:" ,"max_z(mm): " )) # max_z
169- stream .write (header_buffer [4 ].replace ("MINX:" ,"min_x(mm): " )) # min_x
170- stream .write (header_buffer [5 ].replace ("MINY:" ,"min_y(mm): " )) # min_y
171- stream .write (header_buffer [6 ].replace ("MINZ:" ,"min_z(mm): " )) # min_z
172- stream .write ("\n ;Header End\n \n " )
173- # Add some useful comments, conform Luban generated code, and/or what I deem usefull
174- gcode_buffer = re .sub (r"(M190 S\d+)" ,r"\1 ;Wait for Bed Temperature" , gcode_buffer )
175- gcode_buffer = re .sub (r"(M109 S\d+)" ,r"\1 ;Wait for Hotend Temperature" , gcode_buffer )
176- gcode_buffer = re .sub (r"(G92 E0)" ,r"\1 ;Reset the extruder's origin/length" , gcode_buffer )
150+ if gcode [:len (self ._setting_keyword )] == self ._setting_keyword :
151+ has_settings = True
152+ if ";FLAVOR:" not in gcode :
153+ model_line_count += len (gcode .splitlines ()) + 1
154+ gcode_buffer += gcode + "\n "
155+ else :
156+ # Split header lines and write to buffer
157+ header_buffer = gcode .splitlines (keepends = True )
158+
159+ if not is_gcode_file :
160+ if not has_settings :
161+ settings = self ._serialiseSettings (Application .getInstance ().getGlobalContainerStack ())
162+ model_line_count += len (settings .splitlines ())
163+ # Combine everything
164+ stream .write (";Header Start\n \n " )
165+ stream .write (header_buffer [0 ]) # FLAVOR
166+ stream .write (header_buffer [1 ]) # TIME
167+ stream .write (header_buffer [2 ]) # Filament used
168+ stream .write (header_buffer [3 ]) # Layer height
169+ stream .write ("\n ;header_type: 3dp\n " )
170+ if base64_bytes :
171+ stream .write (";thumbnail: data:image/png;base64," )
172+ stream .write (base64_bytes .decode ("ascii" ))
173+ stream .write ("\n " )
174+ stream .write (";file_total_lines: %s\n " % model_line_count )
175+ stream .write (";estimated_time(s): %s\n " % estiTime )
176+ stream .write (";nozzle_temperature(°C): %s\n " % printTemp )
177+ stream .write (";build_plate_temperature(°C): %s\n " % bedTemp )
178+ stream .write (header_buffer [7 ].replace ("MAXX:" ,"max_x(mm): " )) # max_x
179+ stream .write (header_buffer [8 ].replace ("MAXY:" ,"max_y(mm): " )) # max_y
180+ stream .write (header_buffer [9 ].replace ("MAXZ:" ,"max_z(mm): " )) # max_z
181+ stream .write (header_buffer [4 ].replace ("MINX:" ,"min_x(mm): " )) # min_x
182+ stream .write (header_buffer [5 ].replace ("MINY:" ,"min_y(mm): " )) # min_y
183+ stream .write (header_buffer [6 ].replace ("MINZ:" ,"min_z(mm): " )) # min_z
184+ stream .write ("\n ;Header End\n \n " )
185+
177186 stream .write (gcode_buffer )
187+
178188 # Serialise the current container stack and put it at the end of the file.
179- if not has_settings :
180- settings = self ._serialiseSettings (Application .getInstance ().getGlobalContainerStack ())
189+ if not has_settings and not is_gcode_file :
181190 stream .write (settings )
191+
182192 return True
183193
184194 self .setInformation (catalog .i18nc ("@warning:status" , "Please prepare G-code before exporting." ))
0 commit comments