Blob Blame History Raw
From 0063288d48791b181d794615e5694f9d3c8c1007 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Wed, 11 Dec 2019 19:55:47 +0100
Subject: [PATCH 107/181] fp-image, fp-print: Move private methods to own code
 units

---
 libfprint/fp-image.c         | 128 +-----------------
 libfprint/fp-print-private.h |  46 +++++++
 libfprint/fp-print.c         | 247 +---------------------------------
 libfprint/fpi-image.c        | 150 +++++++++++++++++++++
 libfprint/fpi-print.c        | 249 +++++++++++++++++++++++++++++++++++
 libfprint/meson.build        |   2 +
 6 files changed, 452 insertions(+), 370 deletions(-)
 create mode 100644 libfprint/fp-print-private.h
 create mode 100644 libfprint/fpi-image.c
 create mode 100644 libfprint/fpi-print.c

diff --git a/libfprint/fp-image.c b/libfprint/fp-image.c
index 16837a8..ac70d68 100644
--- a/libfprint/fp-image.c
+++ b/libfprint/fp-image.c
@@ -18,15 +18,13 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#define FP_COMPONENT "image"
+
 #include "fpi-image.h"
 #include "fpi-log.h"
 
 #include <nbis.h>
 
-#if HAVE_PIXMAN
-#include <pixman.h>
-#endif
-
 /**
  * SECTION: fp-image
  * @title: FpImage
@@ -36,15 +34,6 @@
  * this object allows accessing this data.
  */
 
-/**
- * SECTION: fpi-image
- * @title: Internal FpImage
- * @short_description: Internal image handling routines
- *
- * Internal image handling routines. Also see the public <ulink
- * url="libfprint-FpImage.html">FpImage routines</ulink>.
- */
-
 G_DEFINE_TYPE (FpImage, fp_image, G_TYPE_OBJECT)
 
 enum {
@@ -479,78 +468,6 @@ fp_image_detect_minutiae_finish (FpImage      *self,
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
-
-
-/**
- * fpi_std_sq_dev:
- * @buf: buffer (usually bitmap, one byte per pixel)
- * @size: size of @buffer
- *
- * Calculates the squared standard deviation of the individual
- * pixels in the buffer, as per the following formula:
- * |[<!-- -->
- *    mean = sum (buf[0..size]) / size
- *    sq_dev = sum ((buf[0.size] - mean) ^ 2)
- * ]|
- * This function is usually used to determine whether image
- * is empty.
- *
- * Returns: the squared standard deviation for @buffer
- */
-gint
-fpi_std_sq_dev (const guint8 *buf,
-                gint          size)
-{
-  guint64 res = 0, mean = 0;
-  gint i;
-
-  for (i = 0; i < size; i++)
-    mean += buf[i];
-
-  mean /= size;
-
-  for (i = 0; i < size; i++)
-    {
-      int dev = (int) buf[i] - mean;
-      res += dev * dev;
-    }
-
-  return res / size;
-}
-
-/**
- * fpi_mean_sq_diff_norm:
- * @buf1: buffer (usually bitmap, one byte per pixel)
- * @buf2: buffer (usually bitmap, one byte per pixel)
- * @size: buffer size of smallest buffer
- *
- * This function calculates the normalized mean square difference of
- * two buffers, usually two lines, as per the following formula:
- * |[<!-- -->
- *    sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
- * ]|
- *
- * This functions is usually used to get numerical difference
- * between two images.
- *
- * Returns: the normalized mean squared difference between @buf1 and @buf2
- */
-gint
-fpi_mean_sq_diff_norm (const guint8 *buf1,
-                       const guint8 *buf2,
-                       gint          size)
-{
-  int res = 0, i;
-
-  for (i = 0; i < size; i++)
-    {
-      int dev = (int) buf1[i] - (int) buf2[i];
-      res += dev * dev;
-    }
-
-  return res / size;
-}
-
 /**
  * fp_minutia_get_coords:
  * @min: A #FpMinutia
@@ -568,44 +485,3 @@ fp_minutia_get_coords (FpMinutia *min, gint *x, gint *y)
   if (y)
     *y = min->y;
 }
-
-#if HAVE_PIXMAN
-FpImage *
-fpi_image_resize (FpImage *orig_img,
-                  guint    w_factor,
-                  guint    h_factor)
-{
-  int new_width = orig_img->width * w_factor;
-  int new_height = orig_img->height * h_factor;
-  pixman_image_t *orig, *resized;
-  pixman_transform_t transform;
-  FpImage *newimg;
-
-  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);
-
-  pixman_transform_init_identity (&transform);
-  pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
-  pixman_image_set_transform (orig, &transform);
-  pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
-  pixman_image_composite32 (PIXMAN_OP_SRC,
-                            orig, /* src */
-                            NULL, /* mask */
-                            resized, /* dst */
-                            0, 0, /* src x y */
-                            0, 0, /* mask x y */
-                            0, 0, /* dst x y */
-                            new_width, new_height /* width height */
-                           );
-
-  newimg = fp_image_new (new_width, new_height);
-  newimg->flags = orig_img->flags;
-
-  memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
-
-  pixman_image_unref (orig);
-  pixman_image_unref (resized);
-
-  return newimg;
-}
-#endif
diff --git a/libfprint/fp-print-private.h b/libfprint/fp-print-private.h
new file mode 100644
index 0000000..f5822b3
--- /dev/null
+++ b/libfprint/fp-print-private.h
@@ -0,0 +1,46 @@
+/*
+ * FPrint Print handling
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
+ *
+ * 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 "fpi-print.h"
+#include "fpi-image.h"
+
+#include <nbis.h>
+
+struct _FpPrint
+{
+  GInitiallyUnowned parent_instance;
+
+  FpPrintType       type;
+
+  gchar            *driver;
+  gchar            *device_id;
+  gboolean          device_stored;
+
+  FpImage          *image;
+
+  /* Metadata */
+  FpFinger   finger;
+  gchar     *username;
+  gchar     *description;
+  GDate     *enroll_date;
+
+  GVariant  *data;
+  GPtrArray *prints;
+};
diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c
index f724c77..30fdf1a 100644
--- a/libfprint/fp-print.c
+++ b/libfprint/fp-print.c
@@ -18,12 +18,10 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-#include "fpi-print.h"
-#include "fpi-image.h"
-#include "fpi-log.h"
-#include "fpi-device.h"
+#define FP_COMPONENT "print"
 
-#include <nbis.h>
+#include "fp-print-private.h"
+#include "fpi-log.h"
 
 /**
  * SECTION: fp-print
@@ -42,28 +40,6 @@
  * #FpPrint routines.
  */
 
-struct _FpPrint
-{
-  GInitiallyUnowned parent_instance;
-
-  FpPrintType       type;
-
-  gchar            *driver;
-  gchar            *device_id;
-  gboolean          device_stored;
-
-  FpImage          *image;
-
-  /* Metadata */
-  FpFinger   finger;
-  gchar     *username;
-  gchar     *description;
-  GDate     *enroll_date;
-
-  GVariant  *data;
-  GPtrArray *prints;
-};
-
 G_DEFINE_TYPE (FpPrint, fp_print, G_TYPE_INITIALLY_UNOWNED)
 
 enum {
@@ -540,223 +516,6 @@ fp_print_set_enroll_date (FpPrint     *print,
   g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_ENROLL_DATE]);
 }
 
-
-
-/**
- * fpi_print_add_print:
- * @print: A #FpPrint
- * @add: Print to append to @print
- *
- * Appends the single #FP_PRINT_NBIS print from @add to the collection of
- * prints in @print. Both print objects need to be of type #FP_PRINT_NBIS
- * for this to work.
- */
-void
-fpi_print_add_print (FpPrint *print, FpPrint *add)
-{
-  g_return_if_fail (print->type == FP_PRINT_NBIS);
-  g_return_if_fail (add->type == FP_PRINT_NBIS);
-
-  g_assert (add->prints->len == 1);
-  g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
-}
-
-/**
- * fpi_print_set_type:
- * @print: A #FpPrint
- * @type: The newly type of the print data
- *
- * This function can only be called exactly once. Drivers should
- * call it after creating a new print, or to initialize the template
- * print passed during enrollment.
- */
-void
-fpi_print_set_type (FpPrint    *print,
-                    FpPrintType type)
-{
-  g_return_if_fail (FP_IS_PRINT (print));
-  /* We only allow setting this once! */
-  g_return_if_fail (print->type == FP_PRINT_UNDEFINED);
-
-  print->type = type;
-  if (print->type == FP_PRINT_NBIS)
-    {
-      g_assert_null (print->prints);
-      print->prints = g_ptr_array_new_with_free_func (g_free);
-    }
-  g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_FPI_TYPE]);
-}
-
-/**
- * fpi_print_set_device_stored:
- * @print: A #FpPrint
- * @device_stored: Whether the print is stored on the device or not
- *
- * Drivers must set this to %TRUE for any print that is really a handle
- * for data that is stored on the device itself.
- */
-void
-fpi_print_set_device_stored (FpPrint *print,
-                             gboolean device_stored)
-{
-  g_return_if_fail (FP_IS_PRINT (print));
-
-  print->device_stored = device_stored;
-  g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_DEVICE_STORED]);
-}
-
-/* XXX: This is the old version, but wouldn't it be smarter to instead
- * use the highest quality mintutiae? Possibly just using bz_prune from
- * upstream? */
-static void
-minutiae_to_xyt (struct fp_minutiae *minutiae,
-                 int                 bwidth,
-                 int                 bheight,
-                 struct xyt_struct  *xyt)
-{
-  int i;
-  struct fp_minutia *minutia;
-  struct minutiae_struct c[MAX_FILE_MINUTIAE];
-
-  /* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
-  int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
-
-  for (i = 0; i < nmin; i++)
-    {
-      minutia = minutiae->list[i];
-
-      lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
-                            minutia, bwidth, bheight);
-      c[i].col[3] = sround (minutia->reliability * 100.0);
-
-      if (c[i].col[2] > 180)
-        c[i].col[2] -= 360;
-    }
-
-  qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
-         sort_x_y);
-
-  for (i = 0; i < nmin; i++)
-    {
-      xyt->xcol[i]     = c[i].col[0];
-      xyt->ycol[i]     = c[i].col[1];
-      xyt->thetacol[i] = c[i].col[2];
-    }
-  xyt->nrows = nmin;
-}
-
-/**
- * fpi_print_add_from_image:
- * @print: A #FpPrint
- * @image: A #FpImage
- * @error: Return location for error
- *
- * Extracts the minutiae from the given image and adds it to @print of
- * type #FP_PRINT_NBIS.
- *
- * The @image will be kept so that API users can get retrieve it e.g.
- * for debugging purposes.
- *
- * Returns: %TRUE on success
- */
-gboolean
-fpi_print_add_from_image (FpPrint *print,
-                          FpImage *image,
-                          GError **error)
-{
-  GPtrArray *minutiae;
-  struct fp_minutiae _minutiae;
-  struct xyt_struct *xyt;
-
-  if (print->type != FP_PRINT_NBIS || !image)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_INVALID_DATA,
-                   "Cannot add print data from image!");
-      return FALSE;
-    }
-
-  minutiae = fp_image_get_minutiae (image);
-  if (!minutiae || minutiae->len == 0)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_INVALID_DATA,
-                   "No minutiae found in image or not yet detected!");
-      return FALSE;
-    }
-
-  _minutiae.num = minutiae->len;
-  _minutiae.list = (struct fp_minutia **) minutiae->pdata;
-  _minutiae.alloc = minutiae->len;
-
-  xyt = g_new0 (struct xyt_struct, 1);
-  minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
-  g_ptr_array_add (print->prints, xyt);
-
-  g_clear_object (&print->image);
-  print->image = g_object_ref (image);
-  g_object_notify_by_pspec (G_OBJECT (print), properties[PROP_IMAGE]);
-
-  return TRUE;
-}
-
-/**
- * fpi_print_bz3_match:
- * @template: A #FpPrint containing one or more prints
- * @print: A newly scanned #FpPrint to test
- * @bz3_threshold: The BZ3 match threshold
- * @error: Return location for error
- *
- * Match the newly scanned @print (containing exactly one print) against the
- * prints contained in @template which will have been stored during enrollment.
- *
- * Both @template and @print need to be of type #FP_PRINT_NBIS for this to
- * work.
- *
- * Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
- */
-FpiMatchResult
-fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
-{
-  struct xyt_struct *pstruct;
-  gint probe_len;
-  gint i;
-
-  /* XXX: Use a different error type? */
-  if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS)
-    {
-      *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
-                                         "It is only possible to match NBIS type print data");
-      return FPI_MATCH_ERROR;
-    }
-
-  if (print->prints->len != 1)
-    {
-      *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
-                                         "New print contains more than one print!");
-      return FPI_MATCH_ERROR;
-    }
-
-  pstruct = g_ptr_array_index (print->prints, 0);
-  probe_len = bozorth_probe_init (pstruct);
-
-  for (i = 0; i < template->prints->len; i++)
-    {
-      struct xyt_struct *gstruct;
-      gint score;
-      gstruct = g_ptr_array_index (template->prints, i);
-      score = bozorth_to_gallery (probe_len, pstruct, gstruct);
-      fp_dbg ("score %d", score);
-
-      if (score >= bz3_threshold)
-        return FPI_MATCH_SUCCESS;
-    }
-
-  return FPI_MATCH_FAIL;
-}
-
 /**
  * fp_print_compatible:
  * @self: A #FpPrint
diff --git a/libfprint/fpi-image.c b/libfprint/fpi-image.c
new file mode 100644
index 0000000..8344037
--- /dev/null
+++ b/libfprint/fpi-image.c
@@ -0,0 +1,150 @@
+/*
+ * FPrint Image - Private APIs
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
+ *
+ * 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
+ */
+
+#define FP_COMPONENT "image"
+
+#include "fpi-image.h"
+#include "fpi-log.h"
+
+#include <nbis.h>
+
+#if HAVE_PIXMAN
+#include <pixman.h>
+#endif
+
+/**
+ * SECTION: fpi-image
+ * @title: Internal FpImage
+ * @short_description: Internal image handling routines
+ *
+ * Internal image handling routines. Also see the public <ulink
+ * url="libfprint-FpImage.html">FpImage routines</ulink>.
+ */
+
+/**
+ * fpi_std_sq_dev:
+ * @buf: buffer (usually bitmap, one byte per pixel)
+ * @size: size of @buffer
+ *
+ * Calculates the squared standard deviation of the individual
+ * pixels in the buffer, as per the following formula:
+ * |[<!-- -->
+ *    mean = sum (buf[0..size]) / size
+ *    sq_dev = sum ((buf[0.size] - mean) ^ 2)
+ * ]|
+ * This function is usually used to determine whether image
+ * is empty.
+ *
+ * Returns: the squared standard deviation for @buffer
+ */
+gint
+fpi_std_sq_dev (const guint8 *buf,
+                gint          size)
+{
+  guint64 res = 0, mean = 0;
+  gint i;
+
+  for (i = 0; i < size; i++)
+    mean += buf[i];
+
+  mean /= size;
+
+  for (i = 0; i < size; i++)
+    {
+      int dev = (int) buf[i] - mean;
+      res += dev * dev;
+    }
+
+  return res / size;
+}
+
+/**
+ * fpi_mean_sq_diff_norm:
+ * @buf1: buffer (usually bitmap, one byte per pixel)
+ * @buf2: buffer (usually bitmap, one byte per pixel)
+ * @size: buffer size of smallest buffer
+ *
+ * This function calculates the normalized mean square difference of
+ * two buffers, usually two lines, as per the following formula:
+ * |[<!-- -->
+ *    sq_diff = sum ((buf1[0..size] - buf2[0..size]) ^ 2) / size
+ * ]|
+ *
+ * This functions is usually used to get numerical difference
+ * between two images.
+ *
+ * Returns: the normalized mean squared difference between @buf1 and @buf2
+ */
+gint
+fpi_mean_sq_diff_norm (const guint8 *buf1,
+                       const guint8 *buf2,
+                       gint          size)
+{
+  int res = 0, i;
+
+  for (i = 0; i < size; i++)
+    {
+      int dev = (int) buf1[i] - (int) buf2[i];
+      res += dev * dev;
+    }
+
+  return res / size;
+}
+
+#if HAVE_PIXMAN
+FpImage *
+fpi_image_resize (FpImage *orig_img,
+                  guint    w_factor,
+                  guint    h_factor)
+{
+  int new_width = orig_img->width * w_factor;
+  int new_height = orig_img->height * h_factor;
+  pixman_image_t *orig, *resized;
+  pixman_transform_t transform;
+  FpImage *newimg;
+
+  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);
+
+  pixman_transform_init_identity (&transform);
+  pixman_transform_scale (NULL, &transform, pixman_int_to_fixed (w_factor), pixman_int_to_fixed (h_factor));
+  pixman_image_set_transform (orig, &transform);
+  pixman_image_set_filter (orig, PIXMAN_FILTER_BILINEAR, NULL, 0);
+  pixman_image_composite32 (PIXMAN_OP_SRC,
+                            orig, /* src */
+                            NULL, /* mask */
+                            resized, /* dst */
+                            0, 0, /* src x y */
+                            0, 0, /* mask x y */
+                            0, 0, /* dst x y */
+                            new_width, new_height /* width height */
+                           );
+
+  newimg = fp_image_new (new_width, new_height);
+  newimg->flags = orig_img->flags;
+
+  memcpy (newimg->data, pixman_image_get_data (resized), new_width * new_height);
+
+  pixman_image_unref (orig);
+  pixman_image_unref (resized);
+
+  return newimg;
+}
+#endif
diff --git a/libfprint/fpi-print.c b/libfprint/fpi-print.c
new file mode 100644
index 0000000..a407dd9
--- /dev/null
+++ b/libfprint/fpi-print.c
@@ -0,0 +1,249 @@
+/*
+ * FPrint Print handling - Private APIs
+ * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
+ * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
+ *
+ * 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
+ */
+
+#define FP_COMPONENT "print"
+#include "fpi-log.h"
+
+#include "fp-print-private.h"
+#include "fpi-device.h"
+
+/**
+ * SECTION: fpi-print
+ * @title: Internal FpPrint
+ * @short_description: Internal fingerprint handling routines
+ *
+ * Interaction with prints and their storage. See also the public
+ * #FpPrint routines.
+ */
+
+/**
+ * fpi_print_add_print:
+ * @print: A #FpPrint
+ * @add: Print to append to @print
+ *
+ * Appends the single #FP_PRINT_NBIS print from @add to the collection of
+ * prints in @print. Both print objects need to be of type #FP_PRINT_NBIS
+ * for this to work.
+ */
+void
+fpi_print_add_print (FpPrint *print, FpPrint *add)
+{
+  g_return_if_fail (print->type == FP_PRINT_NBIS);
+  g_return_if_fail (add->type == FP_PRINT_NBIS);
+
+  g_assert (add->prints->len == 1);
+  g_ptr_array_add (print->prints, g_memdup (add->prints->pdata[0], sizeof (struct xyt_struct)));
+}
+
+/**
+ * fpi_print_set_type:
+ * @print: A #FpPrint
+ * @type: The newly type of the print data
+ *
+ * This function can only be called exactly once. Drivers should
+ * call it after creating a new print, or to initialize the template
+ * print passed during enrollment.
+ */
+void
+fpi_print_set_type (FpPrint    *print,
+                    FpPrintType type)
+{
+  g_return_if_fail (FP_IS_PRINT (print));
+  /* We only allow setting this once! */
+  g_return_if_fail (print->type == FP_PRINT_UNDEFINED);
+
+  print->type = type;
+  if (print->type == FP_PRINT_NBIS)
+    {
+      g_assert_null (print->prints);
+      print->prints = g_ptr_array_new_with_free_func (g_free);
+    }
+  g_object_notify (G_OBJECT (print), "fp-type");
+}
+
+/**
+ * fpi_print_set_device_stored:
+ * @print: A #FpPrint
+ * @device_stored: Whether the print is stored on the device or not
+ *
+ * Drivers must set this to %TRUE for any print that is really a handle
+ * for data that is stored on the device itself.
+ */
+void
+fpi_print_set_device_stored (FpPrint *print,
+                             gboolean device_stored)
+{
+  g_return_if_fail (FP_IS_PRINT (print));
+
+  print->device_stored = device_stored;
+  g_object_notify (G_OBJECT (print), "device-stored");
+}
+
+/* XXX: This is the old version, but wouldn't it be smarter to instead
+ * use the highest quality mintutiae? Possibly just using bz_prune from
+ * upstream? */
+static void
+minutiae_to_xyt (struct fp_minutiae *minutiae,
+                 int                 bwidth,
+                 int                 bheight,
+                 struct xyt_struct  *xyt)
+{
+  int i;
+  struct fp_minutia *minutia;
+  struct minutiae_struct c[MAX_FILE_MINUTIAE];
+
+  /* struct xyt_struct uses arrays of MAX_BOZORTH_MINUTIAE (200) */
+  int nmin = min (minutiae->num, MAX_BOZORTH_MINUTIAE);
+
+  for (i = 0; i < nmin; i++)
+    {
+      minutia = minutiae->list[i];
+
+      lfs2nist_minutia_XYT (&c[i].col[0], &c[i].col[1], &c[i].col[2],
+                            minutia, bwidth, bheight);
+      c[i].col[3] = sround (minutia->reliability * 100.0);
+
+      if (c[i].col[2] > 180)
+        c[i].col[2] -= 360;
+    }
+
+  qsort ((void *) &c, (size_t) nmin, sizeof (struct minutiae_struct),
+         sort_x_y);
+
+  for (i = 0; i < nmin; i++)
+    {
+      xyt->xcol[i]     = c[i].col[0];
+      xyt->ycol[i]     = c[i].col[1];
+      xyt->thetacol[i] = c[i].col[2];
+    }
+  xyt->nrows = nmin;
+}
+
+/**
+ * fpi_print_add_from_image:
+ * @print: A #FpPrint
+ * @image: A #FpImage
+ * @error: Return location for error
+ *
+ * Extracts the minutiae from the given image and adds it to @print of
+ * type #FP_PRINT_NBIS.
+ *
+ * The @image will be kept so that API users can get retrieve it e.g.
+ * for debugging purposes.
+ *
+ * Returns: %TRUE on success
+ */
+gboolean
+fpi_print_add_from_image (FpPrint *print,
+                          FpImage *image,
+                          GError **error)
+{
+  GPtrArray *minutiae;
+  struct fp_minutiae _minutiae;
+  struct xyt_struct *xyt;
+
+  if (print->type != FP_PRINT_NBIS || !image)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_INVALID_DATA,
+                   "Cannot add print data from image!");
+      return FALSE;
+    }
+
+  minutiae = fp_image_get_minutiae (image);
+  if (!minutiae || minutiae->len == 0)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   G_IO_ERROR_INVALID_DATA,
+                   "No minutiae found in image or not yet detected!");
+      return FALSE;
+    }
+
+  _minutiae.num = minutiae->len;
+  _minutiae.list = (struct fp_minutia **) minutiae->pdata;
+  _minutiae.alloc = minutiae->len;
+
+  xyt = g_new0 (struct xyt_struct, 1);
+  minutiae_to_xyt (&_minutiae, image->width, image->height, xyt);
+  g_ptr_array_add (print->prints, xyt);
+
+  g_clear_object (&print->image);
+  print->image = g_object_ref (image);
+  g_object_notify (G_OBJECT (print), "image");
+
+  return TRUE;
+}
+
+/**
+ * fpi_print_bz3_match:
+ * @template: A #FpPrint containing one or more prints
+ * @print: A newly scanned #FpPrint to test
+ * @bz3_threshold: The BZ3 match threshold
+ * @error: Return location for error
+ *
+ * Match the newly scanned @print (containing exactly one print) against the
+ * prints contained in @template which will have been stored during enrollment.
+ *
+ * Both @template and @print need to be of type #FP_PRINT_NBIS for this to
+ * work.
+ *
+ * Returns: Whether the prints match, @error will be set if #FPI_MATCH_ERROR is returned
+ */
+FpiMatchResult
+fpi_print_bz3_match (FpPrint *template, FpPrint *print, gint bz3_threshold, GError **error)
+{
+  struct xyt_struct *pstruct;
+  gint probe_len;
+  gint i;
+
+  /* XXX: Use a different error type? */
+  if (template->type != FP_PRINT_NBIS || print->type != FP_PRINT_NBIS)
+    {
+      *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
+                                         "It is only possible to match NBIS type print data");
+      return FPI_MATCH_ERROR;
+    }
+
+  if (print->prints->len != 1)
+    {
+      *error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
+                                         "New print contains more than one print!");
+      return FPI_MATCH_ERROR;
+    }
+
+  pstruct = g_ptr_array_index (print->prints, 0);
+  probe_len = bozorth_probe_init (pstruct);
+
+  for (i = 0; i < template->prints->len; i++)
+    {
+      struct xyt_struct *gstruct;
+      gint score;
+      gstruct = g_ptr_array_index (template->prints, i);
+      score = bozorth_to_gallery (probe_len, pstruct, gstruct);
+      fp_dbg ("score %d", score);
+
+      if (score >= bz3_threshold)
+        return FPI_MATCH_SUCCESS;
+    }
+
+  return FPI_MATCH_FAIL;
+}
diff --git a/libfprint/meson.build b/libfprint/meson.build
index 9eb4849..8cb8609 100644
--- a/libfprint/meson.build
+++ b/libfprint/meson.build
@@ -9,7 +9,9 @@ libfprint_sources = [
 libfprint_private_sources = [
     'fpi-assembling.c',
     'fpi-device.c',
+    'fpi-image.c',
     'fpi-image-device.c',
+    'fpi-print.c',
     'fpi-ssm.c',
     'fpi-usb-transfer.c',
     'fpi-byte-reader.c',
-- 
2.24.1