rlm@0
|
1 (ns laser.rasterize)
|
rlm@0
|
2
|
rlm@0
|
3 (import '(java.io File))
|
rlm@0
|
4 (import '(org.apache.commons.io FileUtils))
|
rlm@0
|
5 (import '(javax.imageio ImageIO) )
|
rlm@0
|
6 (import '(javax.swing JFrame))
|
rlm@0
|
7 (import '(java.awt Color BorderLayout))
|
rlm@0
|
8 (import '(ij ImagePlus IJ))
|
rlm@0
|
9 (import '(java.lang Math))
|
rlm@2
|
10 (import '(java.awt Graphics2D Panel))
|
rlm@0
|
11 (import '(ij Macro))
|
rlm@0
|
12
|
rlm@0
|
13 (import '(java.io BufferedReader InputStreamReader))
|
rlm@0
|
14 (import '(java.awt.image BufferedImage))
|
rlm@0
|
15
|
rlm@0
|
16 (use 'clojure.contrib.str-utils)
|
rlm@0
|
17
|
rlm@0
|
18 (use 'clojure.contrib.combinatorics)
|
rlm@0
|
19
|
rlm@0
|
20
|
rlm@0
|
21 (use 'clojure.contrib.repl-utils)
|
rlm@0
|
22
|
rlm@0
|
23 (set! *print-length* 20)
|
rlm@0
|
24
|
rlm@0
|
25
|
rlm@0
|
26 (def img "/home/r/graster/test.png")
|
rlm@0
|
27
|
rlm@1
|
28
|
rlm@1
|
29 (def feed 120)
|
rlm@1
|
30 (def dpi [500, 500])
|
rlm@1
|
31 (def on_range [0.0, 0.5])
|
rlm@1
|
32 (def overshoot 0.5)
|
rlm@1
|
33 (def offset [1.0, 1.0])
|
rlm@1
|
34 (def tiles [1, 1])
|
rlm@1
|
35 (def tile_size [false, false])
|
rlm@1
|
36 (def tile_spacing [0.125, 0.125])
|
rlm@1
|
37 (def feed 120)
|
rlm@1
|
38 (def cut_feed 20)
|
rlm@1
|
39 (def corner_radius 0)
|
rlm@1
|
40
|
rlm@1
|
41
|
rlm@5
|
42 (defn preserve-meta [f]
|
rlm@5
|
43 (fn [& x] (with-meta
|
rlm@5
|
44 (apply f x)
|
rlm@5
|
45 (meta (last x)))))
|
rlm@2
|
46
|
rlm@1
|
47
|
rlm@1
|
48
|
rlm@0
|
49 (defn frame-hash
|
rlm@0
|
50 "yields a convienent representation for the pixles in an image.
|
rlm@0
|
51 Because of the size of the structvre generated, this must only be used
|
rlm@0
|
52 in a transient way so that java can do it's garbage collection."
|
rlm@0
|
53 [#^java.lang.String image-name]
|
rlm@0
|
54 (let [image+ (ImagePlus. image-name)]
|
rlm@0
|
55 (with-meta
|
rlm@0
|
56 (let [buf (.. image+ getBufferedImage)
|
rlm@0
|
57 color (.getColorModel buf)]
|
rlm@0
|
58 (apply hash-map
|
rlm@0
|
59 (interleave
|
rlm@0
|
60 (doall (for [x (range (.getWidth image+)) y (range (.getHeight image+))]
|
rlm@0
|
61 (vector x y)))
|
rlm@0
|
62 (doall (for [x (range (.getWidth image+)) y (range (.getHeight image+))]
|
rlm@0
|
63 (let [data (.getRGB buf x y)]
|
rlm@0
|
64 (hash-map :r (bit-shift-right (bit-and 0xff0000 data) 16)
|
rlm@0
|
65 :g (bit-shift-right (bit-and 0x00ff00 data) 8)
|
rlm@0
|
66 :b (bit-and 0x0000ff data))))))))
|
rlm@0
|
67 {:width (.getWidth image+) :height (.getHeight image+)})))
|
rlm@0
|
68
|
rlm@0
|
69
|
rlm@5
|
70
|
rlm@5
|
71
|
rlm@5
|
72
|
rlm@5
|
73
|
rlm@5
|
74
|
rlm@1
|
75 (def white {:r 255, :g 255, :b 255})
|
rlm@1
|
76 (def black {:r 0, :g 0, :b 0})
|
rlm@1
|
77
|
rlm@1
|
78 (def expt #(Math/pow %1 %2))
|
rlm@1
|
79
|
rlm@1
|
80 (defn rgb-euclidian
|
rlm@1
|
81 [{r1 :r g1 :g b1 :b} {r2 :r g2 :g b2 :b} ]
|
rlm@1
|
82 (expt (+ (expt (- r1 r2) 2)
|
rlm@1
|
83 (expt (- g1 g2) 2)
|
rlm@1
|
84 (expt (- b1 b2) 2)) 0.5))
|
rlm@1
|
85
|
rlm@1
|
86 (defn b&w
|
rlm@1
|
87 "turn everything strictly black or white"
|
rlm@1
|
88 [window]
|
rlm@1
|
89 (with-meta
|
rlm@1
|
90 (zipmap
|
rlm@1
|
91 (keys window)
|
rlm@1
|
92 (map (fn [rgb]
|
rlm@1
|
93 (if (> (rgb-euclidian rgb white) (rgb-euclidian rgb black))
|
rlm@1
|
94 black white))
|
rlm@1
|
95 (vals window))) (meta window)))
|
rlm@1
|
96
|
rlm@1
|
97
|
rlm@1
|
98
|
rlm@3
|
99 (defn raster-preamble []
|
rlm@3
|
100 (str-join \newline
|
rlm@3
|
101 ["M63 P0\nG61"
|
rlm@3
|
102 (str \F feed)
|
rlm@3
|
103 "M101"
|
rlm@3
|
104 "M3 S1"]))
|
rlm@3
|
105
|
rlm@4
|
106 (defn raster-epilogue []
|
rlm@4
|
107 (str-join \newline
|
rlm@4
|
108 ["M63 PO"
|
rlm@4
|
109 "M5"
|
rlm@4
|
110 "M2"]))
|
rlm@3
|
111
|
rlm@1
|
112
|
rlm@4
|
113 (defn raster-comment [string]
|
rlm@4
|
114 (str "(" (re-gsub #"[()]" "" string) ")"))
|
rlm@1
|
115
|
rlm@4
|
116 (defn filter-keys [fun m]
|
rlm@4
|
117 (select-keys m (filter fun (keys m))))
|
rlm@6
|
118
|
rlm@5
|
119 (def filter-keys (preserve-meta filter-keys))
|
rlm@2
|
120
|
rlm@4
|
121 (defn filter-vals [fun m]
|
rlm@5
|
122 (into {} (filter (comp fun val) m)))
|
rlm@6
|
123
|
rlm@5
|
124 (def filter-vals (preserve-meta filter-vals))
|
rlm@1
|
125
|
rlm@0
|
126 (defn frame-hash->bufferedImage
|
rlm@0
|
127 [frame-hash]
|
rlm@0
|
128 (let [data (meta frame-hash)
|
rlm@0
|
129 image (BufferedImage. (:width data) (:height data) BufferedImage/TYPE_INT_BGR)]
|
rlm@0
|
130
|
rlm@0
|
131 (doall (for [element frame-hash]
|
rlm@0
|
132 (let [coord (key element)
|
rlm@0
|
133 rgb (val element)
|
rlm@0
|
134 packed-RGB
|
rlm@0
|
135 (+ (bit-shift-left (:r rgb) 16)
|
rlm@0
|
136 (bit-shift-left (:g rgb) 8)
|
rlm@0
|
137 (:b rgb))]
|
rlm@0
|
138 (.setRGB image (first coord) (last coord) packed-RGB))))
|
rlm@0
|
139 image))
|
rlm@5
|
140
|
rlm@5
|
141 (defmulti display "Creates a JFrame and displays a buffered image" class)
|
rlm@0
|
142
|
rlm@5
|
143 (defn- makePanel [image] (proxy [Panel] [] (paint [g] (.drawImage g image 0 0 nil))))
|
rlm@0
|
144
|
rlm@6
|
145 (defn select-row [x window]
|
rlm@6
|
146 (filter-keys (comp (partial = x) first) window))
|
rlm@6
|
147
|
rlm@6
|
148
|
rlm@0
|
149
|
rlm@5
|
150 (defmethod display
|
rlm@5
|
151 BufferedImage [image]
|
rlm@5
|
152 (let [panel (makePanel image)
|
rlm@5
|
153 frame (JFrame. "Oh Yeah!")]
|
rlm@5
|
154 (.add frame panel)
|
rlm@5
|
155 (.pack frame)
|
rlm@5
|
156 (.setVisible frame true )
|
rlm@5
|
157 (.setSize frame(.getWidth image) (.getHeight image))))
|
rlm@5
|
158
|
rlm@5
|
159 (defmethod display
|
rlm@5
|
160 ImagePlus [image]
|
rlm@5
|
161 (display (.getBufferedImage image)))
|
rlm@5
|
162
|
rlm@5
|
163 (defmethod display
|
rlm@5
|
164 clojure.lang.PersistentHashMap [frame-hash]
|
rlm@5
|
165 (display (frame-hash->bufferedImage frame-hash)))
|
rlm@5
|
166
|
rlm@5
|
167 (defmethod display
|
rlm@5
|
168 clojure.lang.PersistentArrayMap [frame-hash]
|
rlm@5
|
169 (display (frame-hash->bufferedImage frame-hash)))
|
rlm@5
|
170
|
rlm@5
|
171
|
rlm@5
|
172
|
rlm@5
|
173
|
rlm@5
|
174
|
rlm@7
|
175 ;this is a sequence of rows
|
rlm@7
|
176
|
rlm@7
|
177 ;(defn span [row]
|
rlm@7
|
178 ; (let [sorted-row (sort #(< (first %1) (first %2)) row)]
|
rlm@7
|
179 ; (vector (first sorted-row) (last sorted-row))))
|
rlm@7
|
180
|
rlm@7
|
181
|
rlm@7
|
182 (defn row->gcode [[x-dpi y-dpi] row]
|
rlm@7
|
183 (let [[x1 y1] (first row)
|
rlm@7
|
184 [x2 y2] (last row)]
|
rlm@7
|
185 (str (format "GO X%.3f Y%.3f\n"
|
rlm@7
|
186 (float (* x1 (/ x-dpi)))
|
rlm@7
|
187 (float (* y1 (/ y-dpi))))
|
rlm@7
|
188
|
rlm@7
|
189 (format "G1 X%.3f Y%.3f\n"
|
rlm@7
|
190 (float (* x2 (/ x-dpi)))
|
rlm@7
|
191 (float (* y2 (/ y-dpi)))))))
|
rlm@7
|
192
|
rlm@7
|
193 (defn gather-row [row]
|
rlm@7
|
194 (let [base [[(first (first row)) (first (first row))]]]
|
rlm@7
|
195 ; (println base)
|
rlm@7
|
196 (reduce
|
rlm@7
|
197 (fn colapse [collection new-n]
|
rlm@7
|
198
|
rlm@7
|
199 (let [collection (apply vector collection)
|
rlm@7
|
200 prevoius (last (last collection))
|
rlm@7
|
201 range-start (first (last collection))]
|
rlm@7
|
202 ; (println new-n)
|
rlm@7
|
203 ; (println prevoius)
|
rlm@7
|
204 ; (println range-start)
|
rlm@7
|
205 (if (<= new-n (+ prevoius 1))
|
rlm@7
|
206 (do ;(println "join")
|
rlm@7
|
207 ;(println (butlast collection))
|
rlm@7
|
208 (conj (apply vector (butlast collection)) (vector range-start new-n)))
|
rlm@7
|
209 (conj collection (vector new-n new-n)))))
|
rlm@7
|
210
|
rlm@7
|
211 base
|
rlm@7
|
212 (map first row))))
|
rlm@7
|
213
|
rlm@7
|
214
|
rlm@7
|
215
|
rlm@7
|
216 (defn row->gmask [[x-dpi y-dpi] forward? row]
|
rlm@7
|
217
|
rlm@7
|
218 (let [start (float (* (/ x-dpi) (first (first row))))]
|
rlm@7
|
219
|
rlm@7
|
220 (let [preamble (if forward?
|
rlm@7
|
221 (str
|
rlm@7
|
222 (format "0 0 0 %.3f\n" start)
|
rlm@7
|
223 (format "0 0 1 %.3f\n" start)))
|
rlm@7
|
224 body
|
rlm@7
|
225 (for [[x y] (gather-row row)]
|
rlm@7
|
226 (let [x (float (* x (/ x-dpi)))
|
rlm@7
|
227 y (float (* y (/ x-dpi)))]
|
rlm@7
|
228 (if forward?
|
rlm@7
|
229 (str (format "0 0 1 %.3f\n" x)
|
rlm@7
|
230 (format "0 1 1 %.3f\n" y))
|
rlm@7
|
231
|
rlm@7
|
232 (str (format "0 0 0 %.3f\n" x)
|
rlm@7
|
233 (format "0 1 0 %.3f\n" y)))))]
|
rlm@7
|
234
|
rlm@7
|
235 (str preamble (str-join "" body)))))
|
rlm@7
|
236
|
rlm@7
|
237
|
rlm@7
|
238
|
rlm@7
|
239 (defn make-rows [pic]
|
rlm@7
|
240
|
rlm@7
|
241 (map (partial sort #(< (first %1) (first %2)))
|
rlm@7
|
242 (partition-by last
|
rlm@7
|
243 (sort (fn [[x1 y1][x2 y2]] (> y2 y1))
|
rlm@7
|
244 (map first (filter-vals (partial = black) pic))))))
|
rlm@7
|
245
|
rlm@7
|
246
|
rlm@7
|
247
|
rlm@7
|
248
|
rlm@7
|
249 ;sequence of numbers indicating width
|
rlm@7
|
250 (def mega
|
rlm@7
|
251
|
rlm@7
|
252 ;sequence of rows
|
rlm@7
|
253
|
rlm@7
|
254 (map (partial sort #(< (first %1) (first %2)))
|
rlm@7
|
255 (partition-by last
|
rlm@7
|
256 (sort (fn [[x1 y1][x2 y2]] (> y2 y1))
|
rlm@7
|
257 (map first (filter-vals (partial = black) pic))))))
|
rlm@7
|
258
|
rlm@7
|
259
|
rlm@7
|
260
|
rlm@7
|
261
|
rlm@7
|
262 (defn generate-gmask [pic]
|
rlm@7
|
263
|
rlm@7
|
264 (str "1 0 0 0\n"
|
rlm@7
|
265 (str-join "" (map (fn [[index row]] (row->gmask dpi (even? index) row)) (indexed (make-rows pic))))))
|
rlm@7
|
266
|
rlm@7
|
267
|
rlm@7
|
268 (defn generate-gcode [pic]
|
rlm@7
|
269 (str-join "" (map (partial row->gcode dpi) (make-rows pic))))
|
rlm@7
|
270
|
rlm@7
|
271
|
rlm@7
|
272
|