Fix breakage due to changed method names in pyfprint.
[pyfprint_demo.git] / pyfprint_demo.py
blobdb4013417e2f2ac17f965f3eaaf755e490bce850
1 #!/usr/bin/env python
3 import sys
5 try:
6 import pygtk
7 pygtk.require("2.4")
8 except:
9 pass
10 try:
11 import gtk
12 import gobject
13 import gtk.glade
14 except:
15 sys.exit(1)
17 import pyfprint
18 import thread
20 fingers_short = ['lt','li','lm','lr','ll','rt','ri','rm','rr','rl']
21 fingers_int = [ pyfprint.Fingers['LEFT_THUMB'],
22 pyfprint.Fingers['LEFT_INDEX'],
23 pyfprint.Fingers['LEFT_MIDDLE'],
24 pyfprint.Fingers['LEFT_RING'],
25 pyfprint.Fingers['LEFT_LITTLE'],
26 pyfprint.Fingers['RIGHT_THUMB'],
27 pyfprint.Fingers['RIGHT_INDEX'],
28 pyfprint.Fingers['RIGHT_MIDDLE'],
29 pyfprint.Fingers['RIGHT_RING'],
30 pyfprint.Fingers['RIGHT_LITTLE']
33 fingers_s_to_i = dict(zip(fingers_short, fingers_int))
34 fingers_i_to_s = dict(zip(fingers_int, fingers_short))
36 def pixbuf_new_from_fprint_image(img):
37 d = img.rgb_data()
38 buf = gtk.gdk.pixbuf_new_from_data(d, gtk.gdk.COLORSPACE_RGB, False, 8,
39 img.width(), img.height(),img.width()*3)
40 return buf
42 def pixmap_from_fprint_image(cm,img):
43 d = img.data()
44 x = img.width()
45 y = img.height()
47 pm = gtk.gdk.Pixmap(None, x,y, 24)
48 pm.set_colormap(cm)
49 gc = pm.new_gc()
50 pm.draw_gray_image(gc, 0,0, x,y,gtk.gdk.RGB_DITHER_NONE,d,-1)
51 return pm
53 class ScanDialog(gtk.Dialog):
54 def __init__(self, parent, device):
55 self.dev = device
56 gtk.Dialog.__init__(self, "Scan finger", parent,
57 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, None)
58 self.set_has_separator(False)
59 self.text_label = gtk.Label("Scan your finger now")
60 self.vbox.pack_start(self.text_label)
61 self.vbox.show_all()
63 def enroll(self):
64 thread.start_new_thread(self.enroll_runner, (None,))
65 gtk.Dialog.run(self)
66 return (self.fp, self.fp_img)
68 def enroll_runner(self, void_arg):
69 (self.fp, self.fp_img) = self.dev.enroll_finger()
70 self.response(1)
72 def verify(self, finger):
73 thread.start_new_thread(self.verify_runner, (finger,))
74 gtk.Dialog.run(self)
75 return (self.match, self.fp_img)
77 def verify_runner(self, finger):
78 (self.match, self.fp_img) = self.dev.verify_finger(finger)
79 self.response(1)
81 def identify(self, prints):
82 thread.start_new_thread(self.identify_runner, (prints,))
83 gtk.Dialog.run(self)
84 return (self.off, self.fp, self.fp_img)
86 def identify_runner(self, prints):
87 (self.off, self.fp, self.fp_img) = self.dev.identify_finger(prints)
88 self.response(1)
90 def capture_image(self, wait_for_finger):
91 thread.start_new_thread(self.capture_runner, (wait_for_finger,))
92 gtk.Dialog.run(self)
93 return self.fp_img
95 def capture_runner(self, wait):
96 self.fp_img = self.dev.capture_image(wait_for_finger = wait)
97 self.response(1)
100 class PyfprintTab:
101 def __init__(self, glade_xml, parent, dev, load_prints_cb):
102 self.wTree = glade_xml
103 self.dev = dev
104 self.parent = parent
105 self.load_prints_cb = load_prints_cb
107 self.connect_signals()
109 def change_dev(self, new_dev):
110 self.dev = new_dev
112 def load_prints(self, prints):
113 pass
115 class PyfprintIdentifyTab(PyfprintTab):
116 def connect_signals(self):
117 dic = { "on_identify_button_clicked": self.identify,
119 self.wTree.signal_autoconnect(dic)
121 def identify(self, widget):
122 status = self.wTree.get_widget("identify_status")
123 img = self.wTree.get_widget("identify_img")
124 bx = self.get_checkboxes()
125 vps = []
126 for b in bx:
127 if b[0].get_active():
128 vps.append(self.prints[b[1]])
129 dlg = ScanDialog(self.parent, self.dev)
130 (off, fp, fp_img) = dlg.identify(vps)
131 dlg.destroy()
132 if fp != None:
133 pi = fp.finger()
134 status.set_label("<b>Status: </b> Matched finger " + fingers_i_to_s[pi] +".")
135 else:
136 status.set_label("<b>Status: </b> Did not match any finger.")
138 pm = pixmap_from_fprint_image(self.parent.get_colormap(), fp_img)
139 img.set_from_pixmap(pm, None)
141 def get_checkboxes(self, fingers = None):
142 ret = []
143 if fingers == None:
144 fingers = fingers_short
145 for f in fingers:
146 w = "identify_" + f
147 ret.append((self.wTree.get_widget(w), f))
148 return ret
150 def load_prints(self, prints):
151 bx = self.get_checkboxes()
152 for x in bx:
153 x[0].set_sensitive(False)
154 x[0].set_active(False)
155 self.prints = dict()
156 ps = []
157 for p in prints:
158 pi = p.finger()
159 ps.append(fingers_i_to_s[pi])
160 self.prints[fingers_i_to_s[pi]] = p
161 bx = self.get_checkboxes(ps)
162 for x in bx:
163 x[0].set_sensitive(True)
164 x[0].set_active(True)
166 class EnrollDialog(gtk.Dialog):
167 def __init__(self, parent, fp_img):
168 gtk.Dialog.__init__(self, "Enrolled finger", parent,
169 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
170 (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
171 gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
173 self.fp_img = fp_img
175 pixbuf = pixbuf_new_from_fprint_image(self.fp_img)
176 self.img = gtk.Image()
177 self.img.set_from_pixbuf(pixbuf)
178 self.vbox.pack_start(self.img)
180 self.vbox.show_all()
182 def run(self):
183 gobject.timeout_add(1500, self.show_binarized)
184 return gtk.Dialog.run(self)
186 def show_binarized(self):
187 pixbuf = pixbuf_new_from_fprint_image(self.fp_img.binarize())
188 self.img.set_from_pixbuf(pixbuf)
189 return False #Don't run again from timeout_add()
191 class PyfprintEnrollTab(PyfprintTab):
192 def connect_signals(self):
193 dic = { "on_enroll_button_clicked": self.enroll,
194 "on_delete_print_button_clicked": self.delete_print,
196 self.wTree.signal_autoconnect(dic)
198 def load_prints(self, prints):
199 for i in fingers_int:
200 self.set_enrolled(i, False)
201 self.prints = dict()
202 for p in prints:
203 pi = p.finger()
204 self.set_enrolled(pi, True)
205 self.prints[pi] = p
207 def set_enrolled(self, finger, enrolled):
208 label_name = "enrolled_yes_no_" + fingers_i_to_s[finger]
209 delete_name = "delete_print_button_" + fingers_i_to_s[finger]
210 text = "Not enrolled"
211 if enrolled:
212 text = "Enrolled"
213 self.wTree.get_widget(label_name).set_text(text)
214 self.wTree.get_widget(delete_name).set_sensitive(enrolled)
216 def enroll(self, widget):
217 fs = gtk.glade.get_widget_name(widget).rsplit("_", 1)[1]
218 dlg = ScanDialog(self.parent, self.dev)
219 (fp, img) = dlg.enroll()
220 dlg.destroy()
221 dlg = EnrollDialog(self.parent, img)
222 status = dlg.run()
223 dlg.destroy()
224 if status == gtk.RESPONSE_ACCEPT:
225 fp.save_to_disk(fingers_s_to_i[fs])
226 self.load_prints_cb()
228 def delete_print(self, widget):
229 fs = gtk.glade.get_widget_name(widget).rsplit("_", 1)[1]
230 f = fingers_s_to_i[fs]
231 self.prints[f].delete_from_disk()
232 self.load_prints_cb()
235 class PyfprintVerifyTab(PyfprintTab):
236 def connect_signals(self):
237 dic = { "on_verify_button_clicked" : self.verify,
238 "on_verify_img_ctrl_changed": self.update_verify_img,
239 "on_save_verify_image": self.save_verify_image,
241 self.wTree.signal_autoconnect(dic)
243 def load_prints(self, prints):
244 self.print_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
245 for p in prints:
246 pi = p.finger()
247 self.print_store.append((fingers_i_to_s[pi], p))
248 ver_combo = self.wTree.get_widget("verify_finger_combo")
249 ver_combo.set_model(self.print_store)
250 ver_combo.set_active(0)
252 def verify(self, widget):
253 status = self.wTree.get_widget("verify_status")
254 combo = self.wTree.get_widget("verify_finger_combo")
255 sel = combo.get_active()
256 f = self.print_store[sel][1]
258 status.set_text("<b>Status: </b> Ready for scan")
259 status.set_use_markup(True)
260 dlg = ScanDialog(self.parent, self.dev)
261 (ok, fp_img) = dlg.verify(f)
262 dlg.destroy()
263 if ok == True:
264 status.set_label("<b>Status: </b> Finger matches")
265 elif ok == False:
266 status.set_label("<b>Status: </b> Finger does not match")
267 elif ok == None:
268 status.set_label("<b>Status: </b> Scan failed")
270 min_cnt = len(fp_img.minutiae())
272 l = status.get_label()
273 l += "\nFound " + str(min_cnt) + " minutiae."
274 status.set_label(l)
276 self.ver_fp_img = fp_img
277 self.update_verify_img()
279 def update_verify_img(self, null = None):
280 img = self.wTree.get_widget("verify_img")
281 bin = self.wTree.get_widget("verify_img_ctrl_bin")
282 minutiae = self.wTree.get_widget("verify_show_minutiae")
284 if bin.get_active():
285 fp_img = self.ver_fp_img.binarize()
286 else:
287 self.ver_fp_img.standardize()
288 fp_img = self.ver_fp_img
290 pm = pixmap_from_fprint_image(self.parent.get_colormap(), fp_img)
292 if minutiae.get_active():
293 self.draw_minutiae(pm, self.ver_fp_img.minutiae())
295 img.set_from_pixmap(pm, None)
297 def draw_minutiae(self, pm, minutiae):
298 ml = []
299 for x in minutiae:
300 ml.append((x.x,x.y))
301 ml.append((x.x-2,x.y))
302 ml.append((x.x-1,x.y))
303 ml.append((x.x+1,x.y))
304 ml.append((x.x+2,x.y))
305 ml.append((x.x,x.y-2))
306 ml.append((x.x,x.y-1))
307 ml.append((x.x,x.y+1))
308 ml.append((x.x,x.y+2))
309 red = pm.get_colormap().alloc_color("red")
310 gc = pm.new_gc(foreground = red)
311 pm.draw_points(gc, ml)
313 def save_verify_image(self, widget):
314 img = self.wTree.get_widget("verify_img")
315 dlg = gtk.FileChooserDialog(title = "Save print image", parent = self.parent,
316 action = gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (
317 gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
318 gtk.STOCK_SAVE, gtk.RESPONSE_ACCEPT))
319 dlg.set_current_name("fingerprint.png")
320 dlg.set_do_overwrite_confirmation(True)
321 r = dlg.run()
322 if r != gtk.RESPONSE_ACCEPT:
323 dlg.destroy()
324 return
325 f = dlg.get_filename()
326 dlg.destroy()
328 pm = img.get_pixmap()[0]
329 (width, height) = pm.get_size()
330 cm = pm.get_colormap()
332 buf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False,8,width,height)
333 buf.get_from_drawable(pm, cm, 0,0,0,0,width,height)
334 buf.save(f, "png")
336 class PyfprintCaptureImageTab(PyfprintTab):
337 def connect_signals(self):
338 dic = { "on_capture_image_button_clicked" : self.capture,
340 self.wTree.signal_autoconnect(dic)
342 def capture(self, widget):
343 img = self.wTree.get_widget("capture_img")
344 wt = self.wTree.get_widget("cap_wait_check")
345 dlg = ScanDialog(self.parent, self.dev)
346 fp_img = dlg.capture_image(wt.get_active())
347 dlg.destroy()
348 pm = pixmap_from_fprint_image(self.parent.get_colormap(), fp_img)
349 img.set_from_pixmap(pm, None)
351 class PyfprintDemo:
352 """This is the pyfprint demo application"""
354 def __init__(self):
355 #Set the Glade file
356 self.gladefile = "pyfprint_demo.glade"
357 self.wTree = gtk.glade.XML(self.gladefile)
359 #Get the Main Window, and connect the "destroy" event
360 self.window = self.wTree.get_widget("MainWindow")
361 if (self.window):
362 self.window.connect("destroy", gtk.main_quit)
364 #Create our dictionary and connect it
365 dic = { "gtk_main_quit" : gtk.main_quit,
366 "on_devices_combo_changed": self.change_device,
368 self.wTree.signal_autoconnect(dic)
370 devs_combo = self.wTree.get_widget("devices_combo")
371 cell = gtk.CellRendererText()
372 devs_combo.pack_start(cell, True)
373 devs_combo.add_attribute(cell, 'text', 0)
375 self.tabs = []
376 self.tabs.append(PyfprintEnrollTab(self.wTree, self.window, None, self.load_prints))
377 self.tabs.append(PyfprintVerifyTab(self.wTree, self.window, None, self.load_prints))
378 self.tabs.append(PyfprintIdentifyTab(self.wTree, self.window, None, self.load_prints))
379 self.tabs.append(PyfprintCaptureImageTab(self.wTree, self.window, None, self.load_prints))
381 self.init_pyfprint(devs_combo)
383 def __del__(self):
384 #FIXME: why isn't this called?
385 self.exit_pyfprint()
387 def init_pyfprint(self, devs_combo):
388 pyfprint.fp_init()
390 self.devs = pyfprint.discover_devices()
391 dev_list = gtk.ListStore(gobject.TYPE_STRING)
392 for x in range(len(self.devs)):
393 dev_list.append([self.devs[x].driver().full_name()])
394 devs_combo.set_model(dev_list)
395 devs_combo.set_active(0) #open the first device found
397 def exit_pyfprint(self, x = None):
398 try:
399 self.dev.close()
400 except(AttributeError):
401 pass
402 pyfprint.fp_exit()
404 def load_prints(self):
405 loaded_prints = pyfprint.discover_prints()
406 compat_prints = []
407 for p in loaded_prints:
408 if self.dev.is_compatible(p):
409 compat_prints.append(p)
410 map((lambda x: x.load_prints(compat_prints)), self.tabs)
412 def change_device(self, widget):
413 try:
414 self.dev.close()
415 except (AttributeError):
416 pass
417 self.dev = self.devs[widget.get_active()]
418 self.dev.open()
419 map((lambda x: x.change_dev(self.dev)), self.tabs)
420 self.load_prints()
424 if __name__ == "__main__":
425 gtk.gdk.threads_init()
427 hwg = PyfprintDemo()
428 gtk.main()
429 hwg.dev.close()