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
):
38 buf
= gtk
.gdk
.pixbuf_new_from_data(d
, gtk
.gdk
.COLORSPACE_RGB
, False, 8,
39 img
.width(), img
.height(),img
.width()*3)
42 def pixmap_from_fprint_image(cm
,img
):
47 pm
= gtk
.gdk
.Pixmap(None, x
,y
, 24)
50 pm
.draw_gray_image(gc
, 0,0, x
,y
,gtk
.gdk
.RGB_DITHER_NONE
,d
,-1)
53 class ScanDialog(gtk
.Dialog
):
54 def __init__(self
, parent
, 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
)
64 thread
.start_new_thread(self
.enroll_runner
, (None,))
66 return (self
.fp
, self
.fp_img
)
68 def enroll_runner(self
, void_arg
):
69 (self
.fp
, self
.fp_img
) = self
.dev
.enroll_finger()
72 def verify(self
, finger
):
73 thread
.start_new_thread(self
.verify_runner
, (finger
,))
75 return (self
.match
, self
.fp_img
)
77 def verify_runner(self
, finger
):
78 (self
.match
, self
.fp_img
) = self
.dev
.verify_finger(finger
)
81 def identify(self
, prints
):
82 thread
.start_new_thread(self
.identify_runner
, (prints
,))
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
)
90 def capture_image(self
, wait_for_finger
):
91 thread
.start_new_thread(self
.capture_runner
, (wait_for_finger
,))
95 def capture_runner(self
, wait
):
96 self
.fp_img
= self
.dev
.capture_image(wait_for_finger
= wait
)
101 def __init__(self
, glade_xml
, parent
, dev
, load_prints_cb
):
102 self
.wTree
= glade_xml
105 self
.load_prints_cb
= load_prints_cb
107 self
.connect_signals()
109 def change_dev(self
, new_dev
):
112 def load_prints(self
, prints
):
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()
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
)
134 status
.set_label("<b>Status: </b> Matched finger " + fingers_i_to_s
[pi
] +".")
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):
144 fingers
= fingers_short
147 ret
.append((self
.wTree
.get_widget(w
), f
))
150 def load_prints(self
, prints
):
151 bx
= self
.get_checkboxes()
153 x
[0].set_sensitive(False)
154 x
[0].set_active(False)
159 ps
.append(fingers_i_to_s
[pi
])
160 self
.prints
[fingers_i_to_s
[pi
]] = p
161 bx
= self
.get_checkboxes(ps
)
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
))
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
)
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)
204 self
.set_enrolled(pi
, True)
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"
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()
221 dlg
= EnrollDialog(self
.parent
, img
)
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
)
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
)
264 status
.set_label("<b>Status: </b> Finger matches")
266 status
.set_label("<b>Status: </b> Finger does not match")
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."
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")
285 fp_img
= self
.ver_fp_img
.binarize()
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
):
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)
322 if r
!= gtk
.RESPONSE_ACCEPT
:
325 f
= dlg
.get_filename()
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
)
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())
348 pm
= pixmap_from_fprint_image(self
.parent
.get_colormap(), fp_img
)
349 img
.set_from_pixmap(pm
, None)
352 """This is the pyfprint demo application"""
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")
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)
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
)
384 #FIXME: why isn't this called?
387 def init_pyfprint(self
, devs_combo
):
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):
400 except(AttributeError):
404 def load_prints(self
):
405 loaded_prints
= pyfprint
.discover_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
):
415 except (AttributeError):
417 self
.dev
= self
.devs
[widget
.get_active()]
419 map((lambda x
: x
.change_dev(self
.dev
)), self
.tabs
)
424 if __name__
== "__main__":
425 gtk
.gdk
.threads_init()