1
+ # Cura PostProcessingPlugin
2
+ # Author: Daniuel Spannbauer
3
+ # Date: November 3, 2019
4
+
5
+ # Description: This plugin generates and inserts code including a image of the
6
+ # slices part.
7
+
8
+
9
+ from UM .Mesh .MeshWriter import MeshWriter
10
+ from UM .MimeTypeDatabase import MimeTypeDatabase , MimeType
11
+ from cura .Snapshot import Snapshot
12
+ from cura .Utils .Threading import call_on_qt_thread
13
+ from UM .Logger import Logger
14
+ from UM .Scene .SceneNode import SceneNode #For typing.
15
+ from UM .PluginRegistry import PluginRegistry
16
+ from UM .i18n import i18nCatalog
17
+ catalog = i18nCatalog ("cura" )
18
+
19
+ import re
20
+ from io import StringIO , BufferedIOBase #To write the g-code to a temporary buffer, and for typing.
21
+ from typing import cast , List
22
+
23
+
24
+ def getValue (line , key , default = None ):
25
+ if key not in line :
26
+ return default
27
+ else :
28
+ subPart = line [line .find (key ) + len (key ):]
29
+ m = re .search ('^-?[0-9]+\\ .?[0-9]*' , subPart )
30
+ #if m is None:
31
+ # pass
32
+ #return default
33
+ try :
34
+ return float (m .group (0 ))
35
+ except :
36
+ return default
37
+
38
+
39
+
40
+ class ChituCodeWriter (MeshWriter ):
41
+ def __init__ (self ):
42
+ super ().__init__ (add_to_recent_files = False )
43
+ self ._snapshot = None
44
+ MimeTypeDatabase .addMimeType (
45
+ MimeType (
46
+ name = "text/chitu-g-code" ,
47
+ comment = "chitu additionals" ,
48
+ suffixes = ["gcode" ]
49
+ )
50
+ )
51
+
52
+ @call_on_qt_thread
53
+ def write (self ,stream : BufferedIOBase , nodes : List [SceneNode ], mode = MeshWriter .OutputMode .BinaryMode ) -> bool :
54
+ Logger .log ("i" , "starting ChituCodeWriter." )
55
+ if mode != MeshWriter .OutputMode .TextMode :
56
+ Logger .log ("e" , "ChituCodeWriter does not support non-text mode." )
57
+ self .setInformation (catalog .i18nc ("@error:not supported" , "ChituCodeWriter does not support non-text mode." ))
58
+ return False
59
+ gcode_textio = StringIO () #We have to convert the g-code into bytes.
60
+ gcode_writer = cast (MeshWriter , PluginRegistry .getInstance ().getPluginObject ("GCodeWriter" ))
61
+ success = gcode_writer .write (gcode_textio , None )
62
+
63
+ if not success :
64
+ self .setInformation (gcode_writer .getInformation ())
65
+ return False
66
+ result = self .modify (gcode_textio .getvalue ())
67
+ stream .write (result )
68
+ Logger .log ("i" , "ChituWriter done" )
69
+ return True
70
+
71
+ def modify (self ,in_data ):
72
+ self ._createSnapshot ()
73
+ temp_in_data = self .generate_image_code (self ._snapshot )
74
+ temp_in_data += "\n "
75
+ temp_in_data += in_data
76
+ time_data = self .insert_time_infos (temp_in_data )
77
+ return time_data
78
+
79
+
80
+ def insert_time_infos (self , gcode_data ):
81
+ return_data = ""
82
+ for line in gcode_data .split ("\n " ):
83
+ if line .startswith (';TIME:' ):
84
+ return_data += 'M2100 T%d\n ' % int (getValue (line , ';TIME:' , 0 ))
85
+ elif line .startswith (';TIME_ELAPSED:' ):
86
+ return_data += 'M2101 T%d\n ' % int (getValue (line , ';TIME_ELAPSED:' , 0 ))
87
+ else :
88
+ if line .endswith ("\n " ):
89
+ return_data += line
90
+ else :
91
+ return_data += line + "\n "
92
+ return return_data
93
+
94
+
95
+ def _createSnapshot (self , * args ):
96
+ Logger .log ("i" , "Creating chitu thumbnail image ..." )
97
+ try :
98
+ self ._snapshot = Snapshot .snapshot (width = 300 , height = 300 )
99
+ except Exception :
100
+ Logger .logException ("w" , "Failed to create snapshot image" )
101
+ self ._snapshot = None
102
+
103
+
104
+
105
+ def generate_image_code (self , image ,startX = 0 , startY = 0 , endX = 300 , endY = 300 ):
106
+ MAX_PIC_WIDTH_HEIGHT = 320
107
+ width = image .width ()
108
+ height = image .height ()
109
+ if endX > width :
110
+ endX = width
111
+ if endY > height :
112
+ endY = height
113
+ scale = 1.0
114
+ max_edge = endY - startY
115
+ if max_edge < endX - startX :
116
+ max_edge = endX - startX
117
+ if max_edge > MAX_PIC_WIDTH_HEIGHT :
118
+ scale = MAX_PIC_WIDTH_HEIGHT / max_edge
119
+ if scale != 1.0 :
120
+ width = int (width * scale )
121
+ height = int (height * scale )
122
+ startX = int (startX * scale )
123
+ startY = int (startY * scale )
124
+ endX = int (endX * scale )
125
+ endY = int (endY * scale )
126
+ image = image .scaled (width , height )
127
+ res_list = []
128
+ for i in range (startY , endY ):
129
+ for j in range (startX , endX ):
130
+ res_list .append (image .pixel (j , i ))
131
+
132
+ index_pixel = 0
133
+ pixel_num = 0
134
+ pixel_data = ''
135
+ pixel_string = ""
136
+ pixel_string += ('M4010 X%d Y%d\n ' % (endX - startX , endY - startY ))
137
+ last_color = - 1
138
+ mask = 32
139
+ unmask = ~ mask
140
+ same_pixel = 1
141
+ color = 0
142
+ for j in res_list :
143
+ a = j >> 24 & 255
144
+ if not a :
145
+ r = g = b = 255
146
+ else :
147
+ r = j >> 16 & 255
148
+ g = j >> 8 & 255
149
+ b = j & 255
150
+ color = (r >> 3 << 11 | g >> 2 << 5 | b >> 3 ) & unmask
151
+ if last_color == - 1 :
152
+ last_color = color
153
+ elif last_color == color and same_pixel < 4095 :
154
+ same_pixel += 1
155
+ elif same_pixel >= 2 :
156
+ pixel_data += '%04x' % (last_color | mask )
157
+ pixel_data += '%04x' % (12288 | same_pixel )
158
+ pixel_num += same_pixel
159
+ last_color = color
160
+ same_pixel = 1
161
+ else :
162
+ pixel_data += '%04x' % last_color
163
+ last_color = color
164
+ pixel_num += 1
165
+ if len (pixel_data ) >= 180 :
166
+ pixel_string += ("M4010 I%d T%d '%s'\n " % (index_pixel , pixel_num , pixel_data ))
167
+ pixel_data = ''
168
+ index_pixel += pixel_num
169
+ pixel_num = 0
170
+
171
+ if same_pixel >= 2 :
172
+ pixel_data += '%04x' % (last_color | mask )
173
+ pixel_data += '%04x' % (12288 | same_pixel )
174
+ pixel_num += same_pixel
175
+ last_color = color
176
+ same_pixel = 1
177
+ else :
178
+ pixel_data += '%04x' % last_color
179
+ last_color = color
180
+ pixel_num += 1
181
+ pixel_string += ("M4010 I%d T%d '%s'\n " % (index_pixel , pixel_num , pixel_data ))
182
+ return pixel_string
183
+
0 commit comments