From f3a838e856423af802de1d777a19163843cdf635 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Sat, 27 Oct 2007 00:06:53 +0100 Subject: [PATCH] Initial implementation for image device access and capture Also added new example: img_capture --- TODO | 3 -- examples/Makefile.am | 5 +- examples/img_capture.c | 100 +++++++++++++++++++++++++++++++++++++ libfprint/Makefile.am | 1 + libfprint/core.c | 9 +++- libfprint/fp_internal.h | 33 +++++++++++- libfprint/fprint.h | 12 +++++ libfprint/img.c | 106 +++++++++++++++++++++++++++++++++++++++ libfprint/imgdev.c | 108 +++++++++++++++++++++++++++++++++++++++- 9 files changed, 369 insertions(+), 8 deletions(-) create mode 100644 examples/img_capture.c create mode 100644 libfprint/img.c diff --git a/TODO b/TODO index 4ddda91..d33bc88 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,6 @@ LIBRARY ======= fingerprint data classifcation by device or device type -storage mechanism -imaging support -external imaging APIs identification external API documentation test suite against NFIQ compliance set diff --git a/examples/Makefile.am b/examples/Makefile.am index 708a378..d7d4706 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,5 +1,5 @@ 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_LDADD = ../libfprint/libfprint.la -lfprint @@ -10,3 +10,6 @@ enroll_LDADD = ../libfprint/libfprint.la -lfprint verify_SOURCES = verify.c verify_LDADD = ../libfprint/libfprint.la -lfprint +img_capture_SOURCES = img_capture.c +img_capture_LDADD = ../libfprint/libfprint.la -lfprint + diff --git a/examples/img_capture.c b/examples/img_capture.c new file mode 100644 index 0000000..6edc191 --- /dev/null +++ b/examples/img_capture.c @@ -0,0 +1,100 @@ +/* + * Example libfprint image capture program + * Copyright (C) 2007 Daniel Drake + * + * 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 +#include + +#include + +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; +} + diff --git a/libfprint/Makefile.am b/libfprint/Makefile.am index 3d84d10..5ffb8d6 100644 --- a/libfprint/Makefile.am +++ b/libfprint/Makefile.am @@ -11,6 +11,7 @@ libfprint_la_LIBADD = $(LIBUSB_LIBS) $(GLIB_LIBS) libfprint_la_SOURCES = \ core.c \ data.c \ + img.c \ imgdev.c \ $(DRIVER_SRC) diff --git a/libfprint/core.c b/libfprint/core.c index 5b2a3c7..ff8850a 100644 --- a/libfprint/core.c +++ b/libfprint/core.c @@ -193,7 +193,7 @@ API_EXPORTED struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev) fp_err("usb_open failed"); return NULL; } - + dev = g_malloc0(sizeof(*dev)); dev->drv = drv; dev->udev = udevh; @@ -242,6 +242,13 @@ API_EXPORTED const char *fp_driver_get_full_name(struct fp_driver *drv) 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, struct fp_print_data **print_data) { diff --git a/libfprint/fp_internal.h b/libfprint/fp_internal.h index c017f13..e8aeb2e 100644 --- a/libfprint/fp_internal.h +++ b/libfprint/fp_internal.h @@ -41,6 +41,10 @@ #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 { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, @@ -82,6 +86,12 @@ struct fp_dev { int __enroll_stage; }; +struct fp_img_dev { + struct fp_dev *dev; + usb_dev_handle *udev; + void *priv; +}; + struct usb_id { uint16_t vendor; uint16_t product; @@ -109,10 +119,20 @@ struct fp_driver { 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_driver driver; + uint16_t flags; /* 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; @@ -133,9 +153,20 @@ struct fp_print_data { }; 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); +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)) #if __BYTE_ORDER == __LITTLE_ENDIAN #define cpu_to_le16(x) (x) diff --git a/libfprint/fprint.h b/libfprint/fprint.h index bcc9845..128c011 100644 --- a/libfprint/fprint.h +++ b/libfprint/fprint.h @@ -25,6 +25,7 @@ struct fp_dscv_dev; struct fp_dev; struct fp_driver; struct fp_print_data; +struct fp_img; /* misc/general stuff */ 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); struct fp_driver *fp_dev_get_driver(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 */ 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); 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 */ int fp_init(void); diff --git a/libfprint/img.c b/libfprint/img.c new file mode 100644 index 0000000..664bbea --- /dev/null +++ b/libfprint/img.c @@ -0,0 +1,106 @@ +/* + * Image management functions for libfprint + * Copyright (C) 2007 Daniel Drake + * + * 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 +#include +#include +#include + +#include + +#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; +} + diff --git a/libfprint/imgdev.c b/libfprint/imgdev.c index 7071f11..be48b86 100644 --- a/libfprint/imgdev.c +++ b/libfprint/imgdev.c @@ -1,5 +1,5 @@ /* - * Core imaging functions for libfprint + * Core imaging device functions for libfprint * Copyright (C) 2007 Daniel Drake * * 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 */ +#include #include #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) { idriver->driver.type = DRIVER_IMAGING; - /* FIXME fill in primitive operations */ + idriver->driver.init = img_dev_init; + idriver->driver.exit = img_dev_exit; }