Fri, 24 Aug 2018 10:27:47 +0200
disabled power management, since it prevents also going monitor to sleep
1 | 1 | #!/usr/bin/env python |
2 | ||
3 | ENGRAVE_SPEED = 20 * 60 # mm/min | |
4 | TRAVEL_SPEED = 130 * 60 | |
5 | E_FACTOR = 0.1 | |
6 | INVERT_PALETTE = True | |
7 | ||
8 | DPI = 300 | |
9 | GREY_THRESHOLD = 0 | |
10 | CHANGE_DIRECTION = True | |
11 | ||
12 | ||
13 | # DO NOT CHANGE WORLD's RULES! | |
14 | INCH = 25.4 # mm | |
15 | MM_PIXEL = round(INCH / DPI, 4) | |
16 | STEPS_PIXEL = MM_PIXEL * 80 # mine is 80 steps/mm on XY | |
17 | print "Resolution: %f mm per pixel" % MM_PIXEL | |
18 | print "Steps per pixel (needs to be > 5, otherwise marlin joins lines): %f" % STEPS_PIXEL | |
19 | ||
20 | from PIL import Image | |
21 | import sys | |
22 | ||
23 | def pixel_to_bit(pixel, threshold=128): | |
24 | """Convert the pixel value to a bit.""" | |
25 | # some really weird stuff here ;-P | |
26 | ||
27 | # RGB to greyscale | |
28 | #print pixel | |
29 | #print type(pixel) | |
30 | if isinstance(pixel, tuple): | |
31 | #rgb | |
32 | pixel = pixel[0]*0.2989 + pixel[1]*0.5870 + pixel[2]*0.1140 | |
33 | threshold = 128 | |
34 | if pixel > threshold: | |
35 | return 1 | |
36 | else: | |
37 | return 0 | |
38 | ||
39 | ||
40 | # color palette | |
41 | if (pixel > 0): | |
42 | return 1 | |
43 | else: | |
44 | return 0 | |
45 | ||
46 | # | |
47 | # Open the image file and get the basic information about it. | |
48 | # | |
49 | try: | |
50 | im = Image.open(sys.argv[1]) | |
51 | except: | |
52 | print "Unable to open %s" % sys.argv[1] | |
53 | exit(-1) | |
54 | ||
55 | print "format: %s mode: %s palette: %s" % (im.format,im.mode,im.palette) | |
56 | width,height = im.size | |
57 | print "The image is %d x %d" % im.size | |
58 | ||
59 | pix = im.load() | |
60 | ||
61 | ||
62 | fo = open(sys.argv[1] + ".g", "w") | |
63 | #fo.write("G10 P1 X-30.0 Y1.5 Z0.0 R0 S0 ; Laser tool offset\n") | |
64 | #fo.write("M218 T1 X.30.0 Y1.5 ; Laser tool offset\") | |
65 | #fo.write("G28 X Y ; Home position\n") | |
66 | # G90 = absolute positioning, G91 = relative | |
67 | #fo.write("M83 ; Set extruder (laser) to relative mode\n") | |
68 | fo.write(""" | |
69 | ; Filename: %s | |
70 | ; GCode generated by bitplotter one-night-quick-hack script (marlin code flavour) | |
71 | ||
72 | G21 ; Metric | |
73 | ; We assume Z is in focus height and laser head is focus at bottom left of image! | |
74 | G92 X0 Y0 E0; set zero position - new origin | |
75 | G90 ; absolute positioning | |
76 | M82 ; Set extruder (laser) to absolute positioning | |
77 | M201 X1000 Y1000 E500 ; Set acceleration | |
78 | M203 X1000 Y1000 Z4 E10 ; Set max feedrate | |
79 | M209 S0 ; disable firmware retraction, we dont want to burn holes... | |
80 | M302 ; Allow cold extrudes - doesnt matter because we hack the extruder physically off with the M571 E mod | |
81 | M571 S1 E1 ; Activate Laser output on extrusion, but block real motor movement! | |
82 | G0 X0 Y0 F%d ; Set moving speed TRAVEL_SPEED | |
83 | G1 X0 Y0 F%d ; Set linear engraving speed ENGRAVE_SPEED | |
84 | ||
85 | """ % (sys.argv[1], TRAVEL_SPEED, ENGRAVE_SPEED) ) | |
86 | ||
87 | fo.write(";Start engraving the raster image: %dx%d points @ %d DPI = %.0fx%.0f mm" % ( | |
88 | im.size[0], im.size[1], DPI, im.size[0]*MM_PIXEL, im.size[1]*MM_PIXEL) ) | |
89 | ||
90 | INVERT_Y = MM_PIXEL * (im.size[1] -1) * (-1) | |
91 | ||
92 | DIR = 1 | |
93 | for X in range(im.size[0]): | |
94 | fo.write("; X=%d printing row: direction %i\n" % (X, DIR)) | |
95 | fo.write("G92 E0\n") | |
96 | E = 0 | |
97 | last_bit = 1 # we engrave on black pixel = 0 | |
98 | START_Y = 0 | |
99 | if DIR > 0: | |
100 | range_start = 0 | |
101 | range_stop = im.size[1] | |
102 | else: | |
103 | range_start = im.size[1] -1 | |
104 | range_stop = -1 | |
105 | ||
106 | for Y in range(range_start, range_stop, DIR): | |
107 | YMM = abs((Y * MM_PIXEL) + INVERT_Y) | |
108 | XMM = X * MM_PIXEL | |
109 | #print "X %d Y %d" % (X, Y) | |
110 | bit = pixel_to_bit(pix[X, Y], GREY_THRESHOLD) | |
111 | if last_bit == bit: | |
112 | if bit == 1: | |
113 | # nothing to do, | |
114 | continue | |
115 | else: | |
116 | # are we at the end of Y range? | |
117 | #print Y | |
118 | if (Y == (im.size[1] - 1)) or (Y == 0): | |
119 | # draw line | |
120 | if DIR > 0: | |
121 | E = E + MM_PIXEL * (Y - START_Y) | |
122 | else: | |
123 | E = E + MM_PIXEL * (START_Y - Y) | |
124 | fo.write("G1 X%.4f Y%.4f E%.4f F%d\n" % (XMM, YMM, E * E_FACTOR, ENGRAVE_SPEED)) | |
125 | else: | |
126 | # bit value has changed! | |
127 | if bit == 0: | |
128 | # jump to start of line to write | |
129 | START_Y = Y | |
130 | fo.write("G0 X%.4f Y%.4f F%d\n" % (XMM, YMM, TRAVEL_SPEED)) | |
131 | else: | |
132 | # end of line to write | |
133 | if DIR > 0: | |
134 | E = E + MM_PIXEL * (Y - START_Y) | |
135 | else: | |
136 | E = E + MM_PIXEL * (START_Y - Y) | |
137 | fo.write("G1 X%.4f Y%.4f E%.4f F%d\n" % (XMM, YMM, E * E_FACTOR, ENGRAVE_SPEED)) | |
138 | last_bit = bit | |
139 | if CHANGE_DIRECTION: | |
140 | DIR = DIR * (-1) # change y direction on every X | |
141 | ||
142 | ||
143 | fo.write("M571 S0 E0\n") | |
144 | fo.write("M501 ; undo all settings made\n") | |
145 | #fo.write("G28 X0 Y0 ; Home position\n") | |
146 | ||
147 | fo.close() |