From a8400ae0541d3663823fb84f5912f98ba0feda11 Mon Sep 17 00:00:00 2001 From: Piotr Piastucki Date: Sun, 29 Nov 2020 22:45:54 +0100 Subject: [PATCH] elan: Add support for touch devices Introduce a subclass for Elan touch devices along with a bunch of changes making the devices usable. In order to support touch devices the following changes were made: * capture just a few frames and select the middle one * preserve the original dimensions of the frame * resize the frame due to its low resolution (96x96) * apply simple sharpening filter to the resized frame to improve minutiae extraction * reduce bz3_threshold to 9 to make matching work reasonably Some changes which might be specific to the 0x0c28 model: * increase the number of calibration loops * add dummy handling for 0xaf code in CAPTURE_READ_DATA --- libfprint/drivers/aes3k.c | 2 +- libfprint/drivers/elan.c | 143 ++++++++++++++++----------------- libfprint/drivers/elan.h | 62 ++++++++++---- libfprint/drivers/elan_touch.c | 101 +++++++++++++++++++++++ libfprint/fpi-image.c | 34 +++++++- libfprint/fpi-image.h | 3 +- libfprint/meson.build | 5 +- meson.build | 3 +- 8 files changed, 260 insertions(+), 93 deletions(-) create mode 100644 libfprint/drivers/elan_touch.c diff --git a/libfprint/drivers/aes3k.c b/libfprint/drivers/aes3k.c index bab6815b..ffc9d7b1 100644 --- a/libfprint/drivers/aes3k.c +++ b/libfprint/drivers/aes3k.c @@ -121,7 +121,7 @@ img_cb (FpiUsbTransfer *transfer, FpDevice *device, /* FIXME: this is an ugly hack to make the image big enough for NBIS * to process reliably */ - img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor); + img = fpi_image_resize (tmp, cls->enlarge_factor, cls->enlarge_factor, FALSE); g_object_unref (tmp); fpi_image_device_image_captured (dev, img); diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c index cb7e88f5..86b9487f 100644 --- a/libfprint/drivers/elan.c +++ b/libfprint/drivers/elan.c @@ -41,6 +41,10 @@ #include "drivers_api.h" #include "elan.h" +static void elan_cmd_done (FpiSsm *ssm); +static void elan_cmd_read (FpiSsm *ssm, + FpDevice *dev); + static unsigned char elan_get_pixel (struct fpi_frame_asmbl_ctx *ctx, struct fpi_frame *frame, unsigned int x, @@ -56,36 +60,6 @@ static struct fpi_frame_asmbl_ctx assembling_ctx = { .get_pixel = elan_get_pixel, }; -struct _FpiDeviceElan -{ - FpImageDevice parent; - - /* device config */ - unsigned short dev_type; - unsigned short fw_ver; - void (*process_frame) (unsigned short *raw_frame, - GSList ** frames); - /* end device config */ - - /* commands */ - const struct elan_cmd *cmd; - int cmd_timeout; - /* end commands */ - - /* state */ - gboolean active; - gboolean deactivating; - unsigned char *last_read; - unsigned char calib_atts_left; - unsigned char calib_status; - unsigned short *background; - unsigned char frame_width; - unsigned char frame_height; - unsigned char raw_frame_height; - int num_frames; - GSList *frames; - /* end state */ -}; G_DEFINE_TYPE (FpiDeviceElan, fpi_device_elan, FP_TYPE_IMAGE_DEVICE); static int @@ -95,7 +69,7 @@ cmp_short (const void *a, const void *b) } static void -elan_dev_reset_state (FpiDeviceElan *elandev) +elan_dev_reset_state (FpiDeviceElanClass *elandev) { G_DEBUG_HERE (); @@ -113,7 +87,7 @@ elan_dev_reset_state (FpiDeviceElan *elandev) } static void -elan_save_frame (FpiDeviceElan *self, unsigned short *frame) +elan_save_frame (FpiDeviceElanClass *self, unsigned short *frame) { G_DEBUG_HERE (); @@ -151,7 +125,7 @@ elan_save_frame (FpiDeviceElan *self, unsigned short *frame) } static void -elan_save_background (FpiDeviceElan *elandev) +elan_save_background (FpiDeviceElanClass *elandev) { G_DEBUG_HERE (); @@ -198,7 +172,7 @@ elan_save_background (FpiDeviceElan *elandev) * ======== 0 \___> ======== 0 */ static int -elan_save_img_frame (FpiDeviceElan *elandev) +elan_save_img_frame (FpiDeviceElanClass *elandev) { G_DEBUG_HERE (); @@ -304,27 +278,35 @@ elan_process_frame_thirds (unsigned short *raw_frame, *frames = g_slist_prepend (*frames, frame); } -static void -elan_submit_image (FpImageDevice *dev) +static FpImage * +elan_assemble_image (FpiDeviceElanClass *self, GSList *raw_frames, unsigned int image_width) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); - GSList *raw_frames; - GSList *frames = NULL; FpImage *img; - - G_DEBUG_HERE (); - - raw_frames = g_slist_nth (self->frames, ELAN_SKIP_LAST_FRAMES); + GSList *frames = NULL; assembling_ctx.frame_width = self->frame_width; assembling_ctx.frame_height = self->frame_height; - assembling_ctx.image_width = self->frame_width * 3 / 2; + assembling_ctx.image_width = image_width; + g_slist_foreach (raw_frames, (GFunc) self->process_frame, &frames); fpi_do_movement_estimation (&assembling_ctx, frames); img = fpi_assemble_frames (&assembling_ctx, frames); img->flags |= FPI_IMAGE_PARTIAL; - g_slist_free_full (frames, g_free); + return img; +} + +static void +elan_submit_image (FpImageDevice *dev) +{ + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); + GSList *raw_frames; + FpImage *img; + + G_DEBUG_HERE (); + + raw_frames = g_slist_nth (self->frames, ELAN_SKIP_LAST_FRAMES); + img = self->assemble_image (self, raw_frames, self->frame_width * 3 / 2); fpi_image_device_image_captured (dev, img); } @@ -341,7 +323,7 @@ elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev, gpointer user_data, GError *error) { FpiSsm *ssm = transfer->ssm; - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -371,7 +353,7 @@ elan_cmd_cb (FpiUsbTransfer *transfer, FpDevice *dev, static void elan_cmd_read (FpiSsm *ssm, FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); FpiUsbTransfer *transfer; GCancellable *cancellable = NULL; int response_len = self->cmd->response_len; @@ -419,7 +401,7 @@ elan_run_cmd (FpiSsm *ssm, const struct elan_cmd *cmd, int cmd_timeout) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); FpiUsbTransfer *transfer; GCancellable *cancellable = NULL; @@ -478,7 +460,7 @@ static void stop_capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -506,7 +488,7 @@ elan_stop_capture (FpiDeviceElan *self) { G_DEBUG_HERE (); - elan_dev_reset_state (self); + elan_dev_reset_state (FPI_DEVICE_ELAN_GET_CLASS (self)); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), stop_capture_run_state, STOP_CAPTURE_NUM_STATES); @@ -526,7 +508,7 @@ static void capture_run_state (FpiSsm *ssm, FpDevice *dev) { FpImageDevice *idev = FP_IMAGE_DEVICE (dev); - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); int r; switch (fpi_ssm_get_cur_state (ssm)) @@ -547,6 +529,13 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) fpi_image_device_report_finger_status (idev, TRUE); elan_run_cmd (ssm, dev, &get_image_cmd, ELAN_CMD_TIMEOUT); } + else if (self->last_read && self->last_read[0] == 0xaf) + { + /* 0xaf - no idea what it means, but it is returned quite often + * hence it needs to be handled somehow instead of just reporting FP_DEVICE_ERROR_PROTO + * to make the reader usable */ + fpi_ssm_mark_completed (ssm); + } else { /* XXX: The timeout is emulated incorrectly, resulting in a zero byte read. */ @@ -563,7 +552,7 @@ capture_run_state (FpiSsm *ssm, FpDevice *dev) { fpi_ssm_mark_failed (ssm, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL)); } - else if (self->num_frames < ELAN_MAX_FRAMES) + else if (self->num_frames < self->max_frames) { /* quickly stop if finger is removed */ self->cmd_timeout = ELAN_FINGER_TIMEOUT; @@ -581,7 +570,7 @@ static void capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) { FpImageDevice *dev = FP_IMAGE_DEVICE (_dev); - FpiDeviceElan *self = FPI_DEVICE_ELAN (_dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -590,14 +579,14 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && fpi_ssm_get_cur_state (ssm) == CAPTURE_WAIT_FINGER)) { - if (self->num_frames >= ELAN_MIN_FRAMES) + if (self->num_frames >= self->min_frames) { - elan_submit_image (dev); + self->submit_image (dev); } else { fp_dbg ("swipe too short: want >= %d frames, got %d", - ELAN_MIN_FRAMES, self->num_frames); + self->min_frames, self->num_frames); fpi_image_device_retry_scan (dev, FP_DEVICE_RETRY_TOO_SHORT); } g_clear_error (&error); @@ -611,7 +600,7 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error) * Doing this between captures appears to make it at least less likely for * devices to end up in a bad state. */ - elan_stop_capture (self); + elan_stop_capture (FPI_DEVICE_ELAN (dev)); } static void @@ -619,7 +608,7 @@ elan_capture (FpiDeviceElan *self) { G_DEBUG_HERE (); - elan_dev_reset_state (self); + elan_dev_reset_state (FPI_DEVICE_ELAN_GET_CLASS (self)); FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), capture_run_state, CAPTURE_NUM_STATES); @@ -629,7 +618,7 @@ elan_capture (FpiDeviceElan *self) /* this function needs to have elandev->background and elandev->last_read to be * the calibration mean */ static int -elan_need_calibration (FpiDeviceElan *elandev) +elan_need_calibration (FpiDeviceElanClass *elandev) { G_DEBUG_HERE (); @@ -675,7 +664,7 @@ enum calibrate_states { }; static gboolean -elan_supports_calibration (FpiDeviceElan *elandev) +elan_supports_calibration (FpiDeviceElanClass *elandev) { if (elandev->dev_type == ELAN_0C42) return TRUE; @@ -686,7 +675,7 @@ elan_supports_calibration (FpiDeviceElan *elandev) static void calibrate_run_state (FpiSsm *ssm, FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -790,12 +779,13 @@ static void elan_calibrate (FpiDeviceElan *self) { G_DEBUG_HERE (); + FpiDeviceElanClass *klass = FPI_DEVICE_ELAN_GET_CLASS (self); - elan_dev_reset_state (self); + elan_dev_reset_state (klass); - g_return_if_fail (!self->active); - self->active = TRUE; - self->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; + g_return_if_fail (!klass->active); + klass->active = TRUE; + klass->calib_atts_left = ELAN_CALIBRATION_ATTEMPTS; FpiSsm *ssm = fpi_ssm_new (FP_DEVICE (self), calibrate_run_state, CALIBRATE_NUM_STATES); @@ -815,7 +805,7 @@ enum activate_states { static void activate_run_state (FpiSsm *ssm, FpDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -859,8 +849,8 @@ activate_run_state (FpiSsm *ssm, FpDevice *dev) self->frame_height++; self->raw_frame_height = self->frame_height; } - if (self->frame_height > ELAN_MAX_FRAME_HEIGHT) - self->frame_height = ELAN_MAX_FRAME_HEIGHT; + if (self->frame_height > self->max_frame_height) + self->frame_height = self->max_frame_height; fp_dbg ("sensor dimensions, WxH: %dx%d", self->frame_width, self->raw_frame_height); fpi_ssm_next_state (ssm); @@ -887,7 +877,7 @@ activate_complete (FpiSsm *ssm, FpDevice *dev, GError *error) static void elan_activate (FpImageDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); elan_dev_reset_state (self); @@ -903,7 +893,7 @@ static void dev_init (FpImageDevice *dev) { GError *error = NULL; - FpiDeviceElan *self; + FpiDeviceElanClass *self; G_DEBUG_HERE (); @@ -913,7 +903,7 @@ dev_init (FpImageDevice *dev) return; } - self = FPI_DEVICE_ELAN (dev); + self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); /* common params */ self->dev_type = fpi_device_get_driver_data (FP_DEVICE (dev)); @@ -934,7 +924,7 @@ static void dev_deinit (FpImageDevice *dev) { GError *error = NULL; - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -970,7 +960,7 @@ dev_change_state (FpImageDevice *dev, FpiImageDeviceState state) static void dev_deactivate (FpImageDevice *dev) { - FpiDeviceElan *self = FPI_DEVICE_ELAN (dev); + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); G_DEBUG_HERE (); @@ -1007,4 +997,11 @@ fpi_device_elan_class_init (FpiDeviceElanClass *klass) img_class->change_state = dev_change_state; img_class->bz3_threshold = 24; + + klass->min_frames = ELAN_MIN_FRAMES; + klass->max_frames = ELAN_MAX_FRAMES; + klass->max_frame_height = ELAN_MAX_FRAME_HEIGHT; + klass->assemble_image = elan_assemble_image; + klass->submit_image = elan_submit_image; + } diff --git a/libfprint/drivers/elan.h b/libfprint/drivers/elan.h index 989778e6..6a989df2 100644 --- a/libfprint/drivers/elan.h +++ b/libfprint/drivers/elan.h @@ -44,14 +44,17 @@ /* times to retry reading calibration status during one session * generally prevents calibration from looping indefinitely */ -#define ELAN_CALIBRATION_ATTEMPTS 10 +#define ELAN_CALIBRATION_ATTEMPTS 50 /* min and max frames in a capture */ #define ELAN_MIN_FRAMES 7 #define ELAN_MAX_FRAMES 30 +#define ELAN_TOUCH_MIN_FRAMES 2 +#define ELAN_TOUCH_MAX_FRAMES 8 /* crop frames to this height to improve stitching */ #define ELAN_MAX_FRAME_HEIGHT 50 +#define ELAN_TOUCH_MAX_FRAME_HEIGHT 96 /* number of frames to drop at the end of capture because frames captured * while the finger is being lifted can be bad */ @@ -70,8 +73,49 @@ #define ELAN_CMD_TIMEOUT 10000 #define ELAN_FINGER_TIMEOUT 200 -G_DECLARE_FINAL_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, - FpImageDevice); +G_DECLARE_DERIVABLE_TYPE (FpiDeviceElan, fpi_device_elan, FPI, DEVICE_ELAN, + FpImageDevice); + +#define FPI_TYPE_DEVICE_ELAN (fpi_device_elan_get_type ()) + +struct _FpiDeviceElanClass +{ + FpImageDeviceClass parent; + + /* device config */ + unsigned short dev_type; + unsigned short fw_ver; + void (*process_frame) (unsigned short *raw_frame, + GSList ** frames); + /* end device config */ + + /* commands */ + const struct elan_cmd *cmd; + int cmd_timeout; + /* end commands */ + + /* state */ + gboolean active; + gboolean deactivating; + unsigned char *last_read; + unsigned char calib_atts_left; + unsigned char calib_status; + unsigned short *background; + unsigned char frame_width; + unsigned char frame_height; + unsigned char raw_frame_height; + int num_frames; + GSList *frames; + unsigned int max_frame_height; + unsigned int min_frames; + unsigned int max_frames; + void (*submit_image) (FpImageDevice *dev); + FpImage * (*assemble_image) (FpiDeviceElanClass *self, + GSList *raw_frames, + unsigned int image_width); + + /* end state */ +}; struct elan_cmd { @@ -201,7 +245,7 @@ static const FpIdEntry elan_id_table[] = { {.vid = ELAN_VEND_ID, .pid = 0x0c25, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c26, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c27, .driver_data = ELAN_ALL_DEV}, - {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, +// {.vid = ELAN_VEND_ID, .pid = 0x0c28, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c29, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c2a, .driver_data = ELAN_ALL_DEV}, {.vid = ELAN_VEND_ID, .pid = 0x0c2b, .driver_data = ELAN_ALL_DEV}, @@ -217,13 +261,3 @@ static const FpIdEntry elan_id_table[] = { {.vid = ELAN_VEND_ID, .pid = 0x0c4d, .driver_data = ELAN_ALL_DEV}, {.vid = 0, .pid = 0, .driver_data = 0}, }; - -static void elan_cmd_done (FpiSsm *ssm); -static void elan_cmd_read (FpiSsm *ssm, - FpDevice *dev); - -static void elan_calibrate (FpiDeviceElan *self); -static void elan_capture (FpiDeviceElan *self); - -static void dev_change_state (FpImageDevice *dev, - FpiImageDeviceState state); diff --git a/libfprint/drivers/elan_touch.c b/libfprint/drivers/elan_touch.c new file mode 100644 index 00000000..5abe08a2 --- /dev/null +++ b/libfprint/drivers/elan_touch.c @@ -0,0 +1,101 @@ +/* + * Elan driver for libfprint + * + * Copyright (C) 2017 Igor Filatov + * Copyright (C) 2018 Sébastien Béchet + * + * 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 + */ + +/* + * The algorithm which libfprint uses to match fingerprints doesn't like small + * images like the ones these drivers produce. There's just not enough minutiae + * (recognizable print-specific points) on them for a reliable match. This means + * that unless another matching algo is found/implemented, these readers will + * not work as good with libfprint as they do with vendor drivers. + * + * To get bigger images the driver expects you to swipe the finger over the + * reader. This works quite well for readers with a rectangular 144x64 sensor. + * Worse than real swipe readers but good enough for day-to-day use. It needs + * a steady and relatively slow swipe. There are also square 96x96 sensors and + * I don't know whether they are in fact usable or not because I don't have one. + * I imagine they'd be less reliable because the resulting image is even + * smaller. If they can't be made usable with libfprint, I might end up dropping + * them because it's better than saying they work when they don't. + */ + +#define FP_COMPONENT "elan_touch" + +#include "drivers_api.h" +#include "elan.h" + +struct _FpiDeviceElanTouch +{ + FpiDeviceElan parent; +}; +G_DECLARE_FINAL_TYPE (FpiDeviceElanTouch, fpi_device_elan_touch, FPI, + DEVICE_ELAN_TOUCH, FpiDeviceElan); +G_DEFINE_TYPE (FpiDeviceElanTouch, fpi_device_elan_touch, FPI_TYPE_DEVICE_ELAN); + +static const FpIdEntry id_table[] = { + { .vid = 0x04f3, .pid = 0x0c28 }, + { .vid = 0, .pid = 0, .driver_data = 0 }, +}; + +static void +elan_touch_submit_image (FpImageDevice *dev) +{ + FpiDeviceElanClass *self = FPI_DEVICE_ELAN_GET_CLASS (FPI_DEVICE_ELAN (dev)); + GSList *raw_frames = NULL; + FpImage *img, *tmp; + + G_DEBUG_HERE (); + + // Prefer the middle frame + raw_frames = g_slist_prepend (raw_frames, g_slist_nth_data (self->frames, g_slist_length (self->frames) / 2)); + tmp = self->assemble_image (self, raw_frames, self->frame_width); + /* Make the image big enough for NBIS to process reliably */ + img = fpi_image_resize (tmp, 2, 2, TRUE); + g_object_unref (tmp); + + g_slist_free (raw_frames); + fpi_image_device_image_captured (dev, img); +} + +static void +fpi_device_elan_touch_init (FpiDeviceElanTouch *self) +{ +} + +static void +fpi_device_elan_touch_class_init (FpiDeviceElanTouchClass *klass) +{ + FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass); + FpiDeviceElanClass *elan_class = FPI_DEVICE_ELAN_CLASS (klass); + FpImageDeviceClass *img_class = FP_IMAGE_DEVICE_CLASS (klass); + + dev_class->id = "elan_touch"; + dev_class->full_name = "ElanTech Fingerprint Sensor"; + dev_class->id_table = id_table; + dev_class->scan_type = FP_SCAN_TYPE_PRESS; + + /* Low due to low image quality. */ + img_class->bz3_threshold = 9; + + elan_class->min_frames = ELAN_TOUCH_MIN_FRAMES; + elan_class->max_frames = ELAN_TOUCH_MAX_FRAMES; + elan_class->max_frame_height = ELAN_TOUCH_MAX_FRAME_HEIGHT; + elan_class->submit_image = elan_touch_submit_image; +} diff --git a/libfprint/fpi-image.c b/libfprint/fpi-image.c index 47aac8d7..6272b562 100644 --- a/libfprint/fpi-image.c +++ b/libfprint/fpi-image.c @@ -111,14 +111,24 @@ fpi_mean_sq_diff_norm (const guint8 *buf1, FpImage * fpi_image_resize (FpImage *orig_img, guint w_factor, - guint h_factor) + guint h_factor, + gboolean enhance) { int new_width = orig_img->width * w_factor; int new_height = orig_img->height * h_factor; - pixman_image_t *orig, *resized; + pixman_image_t *orig, *resized, *enhanced; pixman_transform_t transform; FpImage *newimg; + static const pixman_fixed_t kernel[] = { + #define D(f) (pixman_double_to_fixed (f) + 0x0001) + pixman_int_to_fixed (3), + pixman_int_to_fixed (3), + D (-1.0), D (-2.0), D (-1.0), + D (-2.0), D (13.0), D (-2.0), + D (-1.0), D (-2.0), D (-1.0), + }; + orig = pixman_image_create_bits (PIXMAN_a8, orig_img->width, orig_img->height, (uint32_t *) orig_img->data, orig_img->width); resized = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width); @@ -136,6 +146,26 @@ fpi_image_resize (FpImage *orig_img, new_width, new_height /* width height */ ); + if (enhance) + { + enhanced = pixman_image_create_bits (PIXMAN_a8, new_width, new_height, NULL, new_width); + pixman_transform_init_identity (&transform); + pixman_image_set_transform (resized, &transform); + pixman_image_set_filter (resized, PIXMAN_FILTER_CONVOLUTION, kernel, 11); + + pixman_image_composite32 (PIXMAN_OP_SRC, + resized, /* src */ + NULL, /* mask */ + enhanced, /* dst */ + 0, 0, /* src x y */ + 0, 0, /* mask x y */ + 0, 0, /* dst x y */ + new_width, new_height /* width height */ + ); + pixman_image_unref (resized); + resized = enhanced; + } + newimg = fp_image_new (new_width, new_height); newimg->flags = orig_img->flags; diff --git a/libfprint/fpi-image.h b/libfprint/fpi-image.h index fcd62b8e..ec4c909c 100644 --- a/libfprint/fpi-image.h +++ b/libfprint/fpi-image.h @@ -80,5 +80,6 @@ gint fpi_mean_sq_diff_norm (const guint8 *buf1, #if HAVE_PIXMAN FpImage *fpi_image_resize (FpImage *orig, guint w_factor, - guint h_factor); + guint h_factor, + gboolean enhance); #endif diff --git a/libfprint/meson.build b/libfprint/meson.build index 96cfe9b5..ea187637 100644 --- a/libfprint/meson.build +++ b/libfprint/meson.build @@ -150,7 +150,10 @@ foreach driver: drivers drivers_sources += [ 'drivers/vfs0050.c' ] endif if driver == 'elan' - drivers_sources += [ 'drivers/elan.c' ] + drivers_sources += [ 'drivers/elan.c', 'drivers/elan_touch.c' ] + endif + if driver == 'elan_touch' + drivers_sources += [ 'drivers/elan_touch.c' ] endif if driver == 'virtual_image' drivers_sources += [ 'drivers/virtual-image.c' ] diff --git a/meson.build b/meson.build index abfc5c49..1648e70f 100644 --- a/meson.build +++ b/meson.build @@ -106,6 +106,7 @@ default_drivers = [ 'vcom5s', 'synaptics', 'elan', + 'elan_touch', 'uru4000', 'upektc', 'upeksonly', @@ -137,7 +138,7 @@ foreach driver: drivers error('NSS is required for the URU4000/URU4500 driver') endif endif - if driver == 'aes3500' or driver == 'aes4000' + if driver == 'aes3500' or driver == 'aes4000' or driver == 'elan_touch' imaging_dep = dependency('pixman-1', required: false) if not imaging_dep.found() error('pixman is required for imaging support') -- GitLab