2 ############################################################################
3 # Copyright (C) 2008 by Lukas Sandström #
6 # This program is free software; you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation; either version 2 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program; if not, write to the #
18 # Free Software Foundation, Inc., #
19 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
20 ############################################################################
22 import pyfprint_swig
as pyf
25 # exceptions, especially for RETRY_* errors
26 # constants for fingers
30 # Image(img) for devices which don't support imaging? Is img NULL?
39 """Call this before doing anything else."""
40 _init_ok
= (pyf
.fp_init() == 0)
42 raise "fprint initialization failed."
45 """pyfprint can't be used after this is called."""
50 """Enumeration of the different fingers, used when using Fprint.save_to_disk()."""
51 LEFT_THUMB
= pyf
.LEFT_THUMB
,
52 LEFT_INDEX
= pyf
.LEFT_INDEX
,
53 LEFT_MIDDLE
= pyf
.LEFT_MIDDLE
,
54 LEFT_RING
= pyf
.LEFT_RING
,
55 LEFT_LITTLE
= pyf
.LEFT_LITTLE
,
56 RIGHT_THUMB
= pyf
.RIGHT_THUMB
,
57 RIGHT_INDEX
= pyf
.RIGHT_INDEX
,
58 RIGHT_MIDDLE
= pyf
.RIGHT_MIDDLE
,
59 RIGHT_RING
= pyf
.RIGHT_RING
,
60 RIGHT_LITTLE
= pyf
.RIGHT_LITTLE
64 """Provides access to a fingerprint reading device. Don't construct this
65 directly, use discover_devices() instead."""
66 def __init__(self
, dev_ptr
= None, dscv_ptr
= None, DscvList
= None):
67 """For internal use only."""
70 self
.DscvList
= DscvList
71 if dscv_ptr
and DscvList
== None:
72 raise "Programming error? Device contructed with dscv without DscvList."
75 """Closes the device. No more methods, except open(), may be called after this."""
77 pyf
.fp_dev_close(self
.dev
)
81 """Connects to the device."""
83 raise "Device already open"
84 self
.dev
= pyf
.fp_dev_open(self
.dscv
)
86 raise "device open failed"
90 Return a Driver instance.
92 open() is not required before this method.
95 return Driver(pyf
.fp_dev_get_driver(self
.dev
))
97 return Driver(pyf
.fp_dscv_dev_get_driver(self
.dscv
))
99 def get_devtype(self
):
101 Return an integer representing the type of device.
103 open() is not required before this method.
106 return pyf
.fp_dev_get_devtype(self
.dev
)
108 return pyf
.fp_dscv_dev_get_devtype(self
.dev
)
110 def get_nr_enroll_stages(self
):
112 Return how many times enroll_finger needs to be called
113 before the finger is successfully enrolled.
116 return pyf
.fp_dev_get_nr_enroll_stages(self
.dev
)
117 raise "Device not open"
119 def is_compatible(self
, fprint
):
121 Checks whether the passed fprint is compatible with the device.
123 open() is not required before this method.
127 return pyf
.fp_dev_supports_print_data(self
.dev
, fprint
.data_ptr
) == 1
129 return pyf
.fp_dev_supports_dscv_print(self
.dev
, fprint
.dscv_ptr
) == 1
130 raise "No print found"
133 return pyf
.fp_dscv_dev_supports_print_data(self
.dscv
, fprint
.data_ptr
) == 1
135 return pyf
.fp_dscv_dev_supports_dscv_print(self
.dscv
, fprint
.dscv_ptr
) == 1
136 raise "No print found"
137 raise "No device found"
139 def get_supports_imaging(self
):
140 """If true, the device can return an image of the finger."""
142 return pyf
.fp_dev_supports_imaging(self
.dev
) == 1
143 raise "Device not open"
145 def get_img_width(self
):
146 """Return the width of the images scanned by the device, in pixels."""
148 return pyf
.fp_dev_get_img_width(self
.dev
)
149 raise "Device not open"
151 def get_img_height(self
):
152 """Return the height of the images scanned by the device, in pixels."""
154 return pyf
.fp_dev_get_img_height(self
.dev
)
155 raise "Device not open"
157 def capture_image(self
, wait_for_finger
):
158 """FIXME: check that the dev supports imaging, or check -ENOTSUP"""
160 raise "Device not open"
163 if wait_for_finger
== True:
166 (r
, img
) = pyf
.pyfp_dev_img_capture(self
.dev
, unconditional
)
168 raise "image_capture failed. error: " + r
171 def enroll_finger(self
):
172 """FIXME: docstring, error handling"""
174 raise "Device not open"
175 (r
, fprint
, img
) = pyf
.pyfp_enroll_finger_img(self
.dev
)
177 raise "Internal I/O error while enrolling"
179 if r
== pyf
.FP_ENROLL_COMPLETE
:
180 _dbg("enroll complete")
181 return (Fprint(data_ptr
= fprint
), img
)
182 if r
== pyf
.FP_ENROLL_FAIL
:
183 print "Failed. Enrollmet process reset."
184 if r
== pyf
.FP_ENROLL_PASS
:
187 if r
== pyf
.FP_ENROLL_RETRY
:
190 if r
== pyf
.FP_ENROLL_RETRY_TOO_SHORT
:
191 _dbg("enroll RETRY_SHORT")
193 if r
== pyf
.FP_ENROLL_RETRY_CENTER_FINGER
:
194 _dbg("enroll RETRY_CENTER")
196 if r
== pyf
.FP_ENROLL_RETRY_REMOVE_FINGER
:
197 _dbg("enroll RETRY_REMOVE")
201 def verify_finger(self
, fprint
):
203 Compare the finger on the device with the supplied Fprint.
204 Return true if the finger and the Fprint matches.
207 raise "Device not open"
208 (r
, img
) = pyf
.pyfp_verify_finger_img(self
.dev
, fprint
._get
_print
_data
_ptr
())
212 if r
== pyf
.FP_VERIFY_NO_MATCH
:
214 if r
== pyf
.FP_VERIFY_MATCH
:
216 if r
== pyf
.FP_VERIFY_RETRY
:
218 if r
== pyf
.FP_VERIFY_RETRY_TOO_SHORT
:
220 if r
== pyf
.FP_VERIFY_RETRY_CENTER_FINGER
:
222 if r
== pyf
.FP_VERIFY_RETRY_REMOVE_FINGER
:
226 def supports_identification(self
):
227 """Return True if the device supports the identify_finger method."""
229 raise "Device not open"
230 return pyf
.fp_dev_supports_identification(self
.dev
) == 1
232 def identify_finger(self
, fprints
):
234 FIXME: error handling
236 Match the finger on the reader against a list of Fprints.
238 Return a tuple: (list_offset, Fprint, Image) if a match is found,
239 (None, None, Image) otherwise.
241 Image is None if the device doesn't support imaging.
245 raise "Device not open"
246 gallery
= pyf
.pyfp_print_data_array(len(fprints
))
248 if not self
.is_compatible(x
):
249 raise "can't verify uncompatible print"
250 gallery
.append(x
._get
_print
_data
_ptr
())
251 (r
, offset
, img
) = pyf
.pyfp_identify_finger_img(self
.dev
, gallery
.list)
253 raise "identification error"
255 if r
== pyf
.FP_VERIFY_NO_MATCH
:
256 return (None, None, img
)
257 if r
== pyf
.FP_VERIFY_MATCH
:
258 return (offset
, fprints
[offset
], img
)
259 if r
== pyf
.FP_VERIFY_RETRY
:
261 if r
== pyf
.FP_VERIFY_RETRY_TOO_SHORT
:
263 if r
== pyf
.FP_VERIFY_RETRY_CENTER_FINGER
:
265 if r
== pyf
.FP_VERIFY_RETRY_REMOVE_FINGER
:
269 def load_print_from_disk(self
, finger
):
271 Load a stored fingerprint from the users home directory.
273 - finger should be a value from Fingers.
278 raise "Device not open"
279 (r
, print_ptr
) = pyf
.fp_print_data_load(self
.dev
, finger
)
281 raise "could not load print from disk"
282 return Fprint(data_ptr
= print_ptr
)
284 def delete_stored_finger(self
, finger
):
286 Delete a fingerprint stored in the users home directory
288 - finger should be a value from Fingers.
291 raise "Device not open"
292 r
= pyf
.fp_print_data_delete(self
.dev
, finger
)
294 raise "delete failed"
296 class Minutia(pyf
.fp_minutia
):
297 """A single point of interest in a fingerprint."""
298 def __init__(self
, minutia_ptr
, img
):
300 self
.ptr
= minutia_ptr
301 pyf
.fp_minutia
.__init
__(self
, minutia_ptr
)
304 """An image returned from the fingerprint reader."""
305 def __init__(self
, img_ptr
, bin
= False):
306 """Private method."""
314 pyf
.fp_img_free(self
.img
)
316 def get_height(self
):
317 """The height of the image in pixels."""
318 return pyf
.fp_img_get_height(self
.img
)
320 """The width of the image in pixels."""
321 return pyf
.fp_img_get_width(self
.img
)
326 Return a vector containing one byte per pixel, representing a grayscale image.
328 return pyf
.pyfp_img_get_data(self
.img
)
330 def get_rgb_data(self
):
333 Return a vector containing three bytes per pixel, representing a gray RGB image.
335 return pyf
.pyfp_img_get_rgb_data(self
.img
)
337 def save_to_file(self
, path
):
338 r
= pyf
.fp_img_save_to_file(self
.img
, path
)
342 def standardize(self
):
343 pyf
.fp_img_standardize(self
.img
)
351 i
= pyf
.fp_img_binarize(self
.img
)
353 raise "Binarize failed"
354 return Image(img_ptr
= i
, bin
= True)
356 def get_minutiae(self
):
360 raise "Cannot find minutiae in binarized image"
363 (min_list
, nr
) = pyf
.fp_img_get_minutiae(self
.img
)
366 l
.append(Minutia(img
= self
, minutia_ptr
= pyf
.pyfp_deref_minutiae(min_list
, n
)))
371 """Provides access to some information about a libfprint driver."""
372 def __init__(self
, swig_drv_ptr
):
374 self
.drv
= swig_drv_ptr
381 """Return the driver name."""
382 return pyf
.fp_driver_get_name(self
.drv
)
384 def get_full_name(self
):
385 """A longer, more desciptive version of the driver name."""
386 return pyf
.fp_driver_get_full_name(self
.drv
)
388 def get_driver_id(self
):
389 """Return an integer uniqly identifying the driver."""
390 return pyf
.fp_driver_get_driver_id(self
.drv
)
393 def __init__(self
, serial_data
= None, data_ptr
= None, dscv_ptr
= None, DscvList
= None):
395 The only parameter that should be used is serial_data, which
396 should be data previously aquired from get_data(), in the form of a string.
397 All other parameters are for internal use only.
399 # data_ptr is a SWIG pointer to a struct pf_print_data
400 # dscv_ptr is a SWIG pointer to a struct pf_dscv_print
401 # DscvList is a class instance used to free the allocated pf_dscv_print's
402 # with pf_dscv_prints_free when they're all unused.
403 # serial_data is a string as returned by get_data()
405 self
.data_ptr
= data_ptr
406 self
.dscv_ptr
= dscv_ptr
407 self
.DscvList
= DscvList
410 self
.data_ptr
= pyf
.fp_print_data_from_data(serial_data
)
413 if dscv_ptr
!= None and DscvList
== None:
414 raise "Programming error: Fprint constructed with dscv_prt with DscvList == None"
418 pyf
.fp_print_data_free(self
.data_ptr
)
419 # The dscv_ptr is freed when all the dscv prints have been garbage collected
421 def _get_print_data_ptr(self
):
422 if not self
.data_ptr
:
423 self
._data
_from
_dscv
()
426 def get_driver_id(self
):
427 """Return an integer identifing the driver used to scan this print."""
429 return pyf
.fp_print_data_get_driver_id(self
.data_ptr
)
431 return pyf
.fp_dscv_print_get_driver_id(self
.dscv_ptr
)
434 def get_devtype(self
):
435 """Return an integer representing the type of device used to scan this print."""
437 return pyf
.fp_print_data_get_devtype(self
.data_ptr
)
439 return pyf
.fp_dscv_print_get_devtype(self
.dscv_ptr
)
442 def get_finger(self
):
444 If the Fprint was returned from discover_prints(), return
445 the Finger the Fprint represents. Otherwise raise an exception.
447 if not self
.dscv_ptr
:
448 raise "get_finger needs a discovered print"
449 return pyf
.fp_dscv_print_get_finger(self
.dscv_ptr
)
451 def delete_from_disk(self
):
453 If the Fprint was returned from discover_prints(), delete it
454 from the users home directory. Otherwise raise an exception.
456 if not self
.dscv_ptr
:
457 raise "delete needs a discovered print"
458 return pyf
.fp_dscv_print_delete(self
.dscv_ptr
)
460 def save_to_disk(self
, finger
):
461 """Save the print to the users home directory.
463 - finger is a member of Fingers, indicating which
466 r
= pyf
.fp_print_data_save(self
.data_ptr
, finger
)
470 def _data_from_dscv(self
):
473 if not self
.dscv_ptr
:
475 (r
, ptr
) = pyf
.fp_print_data_from_dscv_print(self
.dscv_ptr
)
477 raise "print data from dscv failed"
482 Return a serialized dataset representing the fprint.
483 This data could be stored away, and later passed to the
484 contructor of Fprint.
486 if not self
.data_ptr
:
488 s
= pyf
.pyfp_print_get_data(self
.data_ptr
)
490 raise "serialization failed"
493 class DiscoveredPrints(list):
495 A list of stored fingerprints available from the users
498 def __init__(self
, dscv_devs_list
):
499 self
.ptr
= dscv_devs_list
502 x
= pyf
.pyfp_deref_dscv_print_ptr(dscv_devs_list
, i
)
505 self
.append(Fprint(dscv_ptr
= x
, DscvList
= self
))
508 pyf
.pf_dscv_prints_free(self
.ptr
)
510 def discover_prints():
511 """Look for fingerprints in the users home directory ;)"""
515 prints
= pyf
.fp_discover_prints()
518 print "Print discovery failed"
519 return DiscoveredPrints(prints
)
522 class DiscoveredDevices(list):
523 """A list of available devices."""
524 def __init__(self
, dscv_devs_list
):
525 self
.swig_list_ptr
= dscv_devs_list
528 x
= pyf
.pyfp_deref_dscv_dev_ptr(dscv_devs_list
, i
)
531 self
.append(Device(dscv_ptr
= x
, DscvList
= self
))
535 pyf
.fp_dscv_devs_free(self
.swig_list_ptr
)
537 def find_compatible(self
, fprint
):
539 Return a Device that is compatible with the fprint,
540 or None if no compatible device is found.
543 if n
.is_compatible(fprint
):
547 def discover_devices():
548 """Return a list of available devices."""
552 devs
= pyf
.fp_discover_devs()
555 raise "Device discovery failed"
556 return DiscoveredDevices(devs
)