Initial implementation for image device access and capture

Also added new example: img_capture
This commit is contained in:
Daniel Drake 2007-10-27 00:06:53 +01:00
parent 0aac3706d7
commit f3a838e856
9 changed files with 369 additions and 8 deletions

3
TODO
View file

@ -1,9 +1,6 @@
LIBRARY LIBRARY
======= =======
fingerprint data classifcation by device or device type fingerprint data classifcation by device or device type
storage mechanism
imaging support
external imaging APIs
identification identification
external API documentation external API documentation
test suite against NFIQ compliance set test suite against NFIQ compliance set

View file

@ -1,5 +1,5 @@
INCLUDES = -I$(top_srcdir) INCLUDES = -I$(top_srcdir)
noinst_PROGRAMS = verify_live enroll verify noinst_PROGRAMS = verify_live enroll verify img_capture
verify_live_SOURCES = verify_live.c verify_live_SOURCES = verify_live.c
verify_live_LDADD = ../libfprint/libfprint.la -lfprint verify_live_LDADD = ../libfprint/libfprint.la -lfprint
@ -10,3 +10,6 @@ enroll_LDADD = ../libfprint/libfprint.la -lfprint
verify_SOURCES = verify.c verify_SOURCES = verify.c
verify_LDADD = ../libfprint/libfprint.la -lfprint verify_LDADD = ../libfprint/libfprint.la -lfprint
img_capture_SOURCES = img_capture.c
img_capture_LDADD = ../libfprint/libfprint.la -lfprint

100
examples/img_capture.c Normal file
View file

@ -0,0 +1,100 @@
/*
* Example libfprint image capture program
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <libfprint/fprint.h>
struct fp_dscv_dev *discover_device(struct fp_dscv_dev **discovered_devs)
{
struct fp_dscv_dev *ddev = NULL;
int i;
for (i = 0; ddev = discovered_devs[i]; i++) {
struct fp_driver *drv = fp_dscv_dev_get_driver(ddev);
printf("Found device claimed by %s driver\n",
fp_driver_get_full_name(drv));
return ddev;
}
return ddev;
}
int main(void)
{
int r = 1;
struct fp_dscv_dev *ddev;
struct fp_dscv_dev **discovered_devs;
struct fp_dev *dev;
struct fp_img_dev *imgdev;
struct fp_img *img = NULL;
r = fp_init();
if (r < 0) {
fprintf(stderr, "Failed to initialize libfprint\n");
exit(1);
}
discovered_devs = fp_discover_devs();
if (!discovered_devs) {
fprintf(stderr, "Could not discover devices\n");
exit(1);
}
ddev = discover_device(discovered_devs);
if (!ddev) {
fprintf(stderr, "No devices detected.\n");
exit(1);
}
dev = fp_dev_open(ddev);
fp_dscv_devs_free(discovered_devs);
if (!dev) {
fprintf(stderr, "Could not open device.\n");
exit(1);
}
imgdev = fp_dev_to_img_dev(dev);
if (!imgdev) {
fprintf(stderr, "could not get image dev, is this an imaging "
"device?\n");
goto out_close;
}
printf("Opened device. It's now time to scan your finger.\n\n");
r = fp_imgdev_capture(imgdev, 0, &img);
if (r) {
fprintf(stderr, "image capture failed, code %d\n", r);
goto out_close;
}
r = fp_img_save_to_file(img, "finger.pgm");
if (r) {
fprintf(stderr, "img save failed, code %d\n", r);
goto out_close;
}
r = 0;
out_close:
fp_dev_close(dev);
return r;
}

View file

@ -11,6 +11,7 @@ libfprint_la_LIBADD = $(LIBUSB_LIBS) $(GLIB_LIBS)
libfprint_la_SOURCES = \ libfprint_la_SOURCES = \
core.c \ core.c \
data.c \ data.c \
img.c \
imgdev.c \ imgdev.c \
$(DRIVER_SRC) $(DRIVER_SRC)

View file

@ -242,6 +242,13 @@ API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv)
return drv->full_name; return drv->full_name;
} }
API_EXPORTED struct fp_img_dev *fp_dev_to_img_dev(struct fp_dev *dev)
{
if (dev->drv->type != DRIVER_IMAGING)
return NULL;
return dev->priv;
}
API_EXPORTED int fp_enroll_finger(struct fp_dev *dev, API_EXPORTED int fp_enroll_finger(struct fp_dev *dev,
struct fp_print_data **print_data) struct fp_print_data **print_data)
{ {

View file

@ -41,6 +41,10 @@
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
enum fpi_log_level { enum fpi_log_level {
LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG,
LOG_LEVEL_INFO, LOG_LEVEL_INFO,
@ -82,6 +86,12 @@ struct fp_dev {
int __enroll_stage; int __enroll_stage;
}; };
struct fp_img_dev {
struct fp_dev *dev;
usb_dev_handle *udev;
void *priv;
};
struct usb_id { struct usb_id {
uint16_t vendor; uint16_t vendor;
uint16_t product; uint16_t product;
@ -109,10 +119,20 @@ struct fp_driver {
int (*verify)(struct fp_dev *dev, struct fp_print_data *data); int (*verify)(struct fp_dev *dev, struct fp_print_data *data);
}; };
/* flags for fp_img_driver.flags */
#define FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE (1 << 0)
struct fp_img_driver { struct fp_img_driver {
struct fp_driver driver; struct fp_driver driver;
uint16_t flags;
/* Device operations */ /* Device operations */
int (*init)(struct fp_img_dev *dev, unsigned long driver_data);
void (*exit)(struct fp_img_dev *dev);
int (*await_finger_on)(struct fp_img_dev *dev);
int (*await_finger_off)(struct fp_img_dev *dev);
int (*capture)(struct fp_img_dev *dev, gboolean unconditional,
struct fp_img **image);
}; };
extern struct fp_driver upekts_driver; extern struct fp_driver upekts_driver;
@ -133,9 +153,20 @@ struct fp_print_data {
}; };
struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length); struct fp_print_data *fpi_print_data_new(struct fp_dev *dev, size_t length);
unsigned char *fpi_print_data_get_buffer(struct fp_print_data *data);
int fpi_print_data_compatible(struct fp_dev *dev, struct fp_print_data *data); int fpi_print_data_compatible(struct fp_dev *dev, struct fp_print_data *data);
struct fp_img {
int width;
int height;
size_t length;
unsigned char data[0];
};
struct fp_img *fpi_img_new(size_t length);
struct fp_img *fpi_img_new_dims(int width, int height);
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize);
gboolean fpi_img_is_sane(struct fp_img *img);
#define bswap16(x) (((x & 0xff) << 8) | (x >> 8)) #define bswap16(x) (((x & 0xff) << 8) | (x >> 8))
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le16(x) (x) #define cpu_to_le16(x) (x)

View file

@ -25,6 +25,7 @@ struct fp_dscv_dev;
struct fp_dev; struct fp_dev;
struct fp_driver; struct fp_driver;
struct fp_print_data; struct fp_print_data;
struct fp_img;
/* misc/general stuff */ /* misc/general stuff */
enum fp_finger { enum fp_finger {
@ -50,6 +51,7 @@ struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev);
void fp_dev_close(struct fp_dev *dev); void fp_dev_close(struct fp_dev *dev);
struct fp_driver *fp_dev_get_driver(struct fp_dev *dev); struct fp_driver *fp_dev_get_driver(struct fp_dev *dev);
int fp_dev_get_nr_enroll_stages(struct fp_dev *dev); int fp_dev_get_nr_enroll_stages(struct fp_dev *dev);
struct fp_img_dev *fp_dev_to_img_dev(struct fp_dev *dev);
/* Drivers */ /* Drivers */
const char *fp_driver_get_name(struct fp_driver *drv); const char *fp_driver_get_name(struct fp_driver *drv);
@ -86,6 +88,16 @@ int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger,
int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger); int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger);
void fp_print_data_free(struct fp_print_data *data); void fp_print_data_free(struct fp_print_data *data);
/* Imaging devices */
int fp_imgdev_capture(struct fp_img_dev *imgdev, int unconditional,
struct fp_img **image);
/* Image handling */
int fp_img_get_height(struct fp_img *img);
int fp_img_get_width(struct fp_img *img);
unsigned char *fp_img_get_data(struct fp_img *img);
int fp_img_save_to_file(struct fp_img *img, char *path);
/* Library */ /* Library */
int fp_init(void); int fp_init(void);

106
libfprint/img.c Normal file
View file

@ -0,0 +1,106 @@
/*
* Image management functions for libfprint
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "fp_internal.h"
struct fp_img *fpi_img_new(size_t length)
{
struct fp_img *img = g_malloc(sizeof(*img) + length);
memset(img, 0, sizeof(*img));
fp_dbg("length=%zd", length);
img->length = length;
return img;
}
struct fp_img *fpi_img_new_dims(int width, int height)
{
struct fp_img *img = fpi_img_new(width * height);
img->width = width;
img->height = height;
return img;
}
gboolean fpi_img_is_sane(struct fp_img *img)
{
/* basic checks */
if (!img->length || !img->width || !img->height)
return FALSE;
/* buffer is big enough? */
if ((img->length * img->height) < img->length)
return FALSE;
return TRUE;
}
struct fp_img *fpi_img_resize(struct fp_img *img, size_t newsize)
{
return g_realloc(img, sizeof(*img) + newsize);
}
API_EXPORTED int fp_img_get_height(struct fp_img *img)
{
return img->height;
}
API_EXPORTED int fp_img_get_width(struct fp_img *img)
{
return img->width;
}
API_EXPORTED unsigned char *fp_img_get_data(struct fp_img *img)
{
return img->data;
}
API_EXPORTED int fp_img_save_to_file(struct fp_img *img, char *path)
{
FILE *fd = fopen(path, "w");
size_t write_size = img->width * img->height;
int r;
if (!fd) {
fp_dbg("could not open '%s' for writing: %d", path, errno);
return -errno;
}
r = fprintf(fd, "P5 %d %d 255\n", img->width, img->height);
if (r < 0) {
fp_err("pgm header write failed, error %d", r);
return r;
}
r = fwrite(img->data, 1, write_size, fd);
if (r < write_size) {
fp_err("short write (%d)", r);
return -EIO;
}
fclose(fd);
fp_dbg("written to '%s'", path);
return 0;
}

View file

@ -1,5 +1,5 @@
/* /*
* Core imaging functions for libfprint * Core imaging device functions for libfprint
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
@ -17,13 +17,117 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <errno.h>
#include <glib.h> #include <glib.h>
#include "fp_internal.h" #include "fp_internal.h"
#define driver_to_img_driver(drv) \
container_of((drv), struct fp_img_driver, driver)
static int img_dev_init(struct fp_dev *dev, unsigned long driver_data)
{
struct fp_img_dev *imgdev = g_malloc0(sizeof(*imgdev));
struct fp_img_driver *imgdrv = driver_to_img_driver(dev->drv);
int r = 0;
imgdev->dev = dev;
dev->priv = imgdev;
dev->nr_enroll_stages = 1;
/* for consistency in driver code, allow udev access through imgdev */
imgdev->udev = dev->udev;
if (imgdrv->init) {
r = imgdrv->init(imgdev, driver_data);
if (r)
goto err;
}
return 0;
err:
g_free(imgdev);
return r;
}
static void img_dev_exit(struct fp_dev *dev)
{
struct fp_img_dev *imgdev = dev->priv;
struct fp_img_driver *imgdrv = driver_to_img_driver(dev->drv);
if (imgdrv->exit)
imgdrv->exit(imgdev);
g_free(imgdev);
}
API_EXPORTED int fp_imgdev_capture(struct fp_img_dev *imgdev,
int unconditional, struct fp_img **image)
{
struct fp_driver *drv = imgdev->dev->drv;
struct fp_img_driver *imgdrv = driver_to_img_driver(drv);
int r;
if (!image) {
fp_err("no image pointer given");
return -EINVAL;
}
if (!imgdrv->capture) {
fp_err("img driver %s has no capture func", drv->name);
return -ENOTSUP;
}
if (unconditional) {
if (!(imgdrv->flags & FP_IMGDRV_SUPPORTS_UNCONDITIONAL_CAPTURE)) {
fp_dbg("requested unconditional capture, but driver %s does not "
"support it", drv->name);
return -ENOTSUP;
}
}
fp_dbg("%s will handle capture request", drv->name);
if (!unconditional && imgdrv->await_finger_on) {
r = imgdrv->await_finger_on(imgdev);
if (r) {
fp_err("await_finger_on failed with error %d", r);
return r;
}
}
r = imgdrv->capture(imgdev, unconditional, image);
if (r) {
fp_err("capture failed with error %d", r);
return r;
}
if (!unconditional && imgdrv->await_finger_off) {
r = imgdrv->await_finger_off(imgdev);
if (r) {
fp_err("await_finger_off failed with error %d", r);
return r;
}
}
if (r == 0) {
if (*image == NULL) {
fp_err("capture succeeded but no image returned?");
return -ENODATA;
}
if (!fpi_img_is_sane(*image)) {
fp_err("image is not sane!");
return -EIO;
}
}
return r;
}
void fpi_img_driver_setup(struct fp_img_driver *idriver) void fpi_img_driver_setup(struct fp_img_driver *idriver)
{ {
idriver->driver.type = DRIVER_IMAGING; idriver->driver.type = DRIVER_IMAGING;
/* FIXME fill in primitive operations */ idriver->driver.init = img_dev_init;
idriver->driver.exit = img_dev_exit;
} }