Don't touch me! - Interfacing with a Fingerprint Reader
| | In this installment of the "Some Assembly Required" column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the Microsoft Fingerprint Reader and the GrFinger SDK from Griaule. |
| Scott Hanselman Difficulty: Intermediate Time Required: 1-3 hours Cost: $50-$100 Hardware: Microsoft FingerPrint Reader |
Scott Hanselman
Summary: In this installment of the "Some Assembly Required" column, Scott Hanselman creates a Family Fingerprint Manager using .NET 2.0 that interfaces with the Microsoft Fingerprint Reader and the GrFinger SDK from Griaule.
The Microsoft Fingerprint Reader

I love my Microsoft Fingerprint Reader and when I got it I knew I had to hack it write some software for it. Since there's already a lot of great security software out there like the Digital Persona software that Microsoft shipped with it as well as 3rd party software like GrFinger's Desktop Identity, I wanted to write something a little different.
My wife and I made a New Year's Resolution to be more prepared for emergencies and the like in the wake of Hurricane Katrina. I figured, since we've moved all our identification and important papers into the a safety deposit box, why not a copy of our fingerprints as well?
There are do-it-yourself-at-home fingerprinting kits one can buy, but I had this nice Fingerprint Reader lying around....:)
Interfacing with the Reader
Griaule Software out of Brazil has a nice, clean COM API SDK that abstracts away the fingerprint hardware supporting a number of readers including Microsoft's. You can download a trial of their SDK software and use it for 90 days. They also include an open-source driver for the Microsoft Fingerprint Reader so you don't have to use the Digital Persona standard stuff if you don't want to. They've got an excellent sample code section with details on how to interface with a read using VB.NET, C#, Java, VB6, even Excel.
I started by adding references to their COM APIs and generating an interop assembly as seen in the picture at left. The AxGrFinger control library includes a small control that you can drag on to your WinForms design surface that exposes a number of Fingerprint-related events like FingerDown and ImageRequired that make interfacing with the hardware incredibly easy.
I created a PictureBox on my WinForm that would display the fingerprint being acquired along with ten other PictureBoxes, one for each finger. The large picture box will appear only when an image is being acquired then disappear after we copy the large acquired image into one of the smaller "fingertip" images.
The large PictureBox is passed in to a utility class along with a reference to the AxGrFinger control. As the image is acquired a valid "Handle to a Device Context" or HDC (remember those?) is passed into the CapRawImageToHandle method on the AxGrFinger control. When that handle comes back, we just update the large picture box and it displays the newly received image. Once the image has move into the world of WinForms, it's considerably easier to manipulate using the System.Drawing APIs.
' Display fingerprint image on screen
Public Sub PrintBiometricDisplay()
' handle to finger image
Dim handle As System.Drawing.Image = Nothing
' screen HDC
Dim hdc As Integer = GetDC(0)
' get raw image
_GrFingerX.CapRawImageToHandle(raw.img, raw.width, raw.height, hdc, handle)
' draw image on picture box
If Not (handle Is Nothing) Then
_pbPic.Image = handle
_pbPic.Update()
End If
' release screen HDC
ReleaseDC(0, hdc)
End Sub
The images from the large picture box are of very high quality and are copied into the smaller fingers one at a time.
Loading and Saving the Fingerprints
There's ten fingerprints (assuming you have ten fingers) to save, but should we save them as one file or ten? I decided that folks would probably want one file per family member using File|Open and File|Save method, but they'd want to reserve the right to export all the fingers as individual (PNG) images.
I created a very simple in-memory representation of a Fingerprint Database like this. It's actually slightly more complex with custom constructors as such in the actual code, but this is the general idea. I'm going to be storing the high-quality image as a byte array rather than a System.Drawing.Bitmap or Image because a byte array is very easily serialized as XML.
Public Class Fingerprints
Public FingerImages(10) As FingerImage
Public Sub New()
For i As Integer = 0 To 10
FingerImages(i) = New FingerImage()
Next i
End Sub
Public Sub AddFingerImage(ByVal finger As String, ByVal image() As Byte)
Dim i As Int32 = Int32.Parse(finger)
FingerImages(i - 1) = New FingerImage(image, finger)
End Sub
Public Function GetImageFromFinger(ByVal finger As String) As Byte()
For Each fi As FingerImage In Me.FingerImages
If (fi.Finger = finger) Then
Return fi.Image
End If
Next
Return Nothing
End Function
End Class
Public Class FingerImage
Public _image() As Byte
Public _finger As String
End Class
Each per-person finger database, like scott.finger for example, will be saved as XML similar to the example below. The byte[] is automatically turned into a BASE64'ed string by the XmlSerializer. This might be considered inelegant by some, but disk space is cheap, and the code was fantastically simple. An easy enhancement would ZIP up the file, but the savings would only be about 30-40%.
<?xml version="1.0"?>
<Fingerprints xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FingerImages>
<FingerImage>
<Image>iVBOR...big opaque BASE64'ed image</Image>
<Finger>L1</Finger>
</FingerImage>
</FingerPrints>
Loading the fingers back into the Form is the exact opposite of saving. We use a standard Windows File Dialog with the filter set to show only .finger files. The file is deserialized using the XmlSerializer and the images are loaded back into the appropriate PictureBox.
Private Sub MenuLoad_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MenuLoad.Click
Dim OpenFileDialog1 As New OpenFileDialog
'' open "load" dialog
OpenFileDialog1.Filter = "FINGER files (*.finger)|*.finger|All files (*.*)|*.*"
OpenFileDialog1.FilterIndex = 1
OpenFileDialog1.RestoreDirectory = True
OpenFileDialog1.CheckFileExists = True
'' load image
If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
Dim x As New XmlSerializer(GetType(Fingerprints))
Dim newdb As Fingerprints
Using fs As FileStream = File.OpenRead(OpenFileDialog1.FileName)
newdb = CType(x.Deserialize(fs), Fingerprints)
End Using
For Each item As Control In Me.Controls
If IsFingerprintPictureBox(item) Then
Dim pic As PictureBox = CType(item, PictureBox)
Dim b As Byte() = newdb.GetImageFromFinger(pic.Tag)
If (Not b Is Nothing) Then
pic.Image = Image.FromStream(New MemoryStream(b))
End If
End If
Next
End If
End Sub
I used the Tag Property of the PictureBox to store the name of the finger. The name is also stored in the .finger file and used to correlate the fingers and PictureBoxes.
The export works similarly, except I save the contents of each PictureBox to the selected directory using the given name as a basefilename. For example, if the user said they wanted to export to Foo.png, I'd create 10 files with names like Foo.l1.png, Foo.r2.png, etc. You can see how easy it is to change image formats using System.Drawing.Image.
For Each item As Control In Me.Controls
If IsFingerprintPictureBox(item) Then
Dim pic As PictureBox = CType(item, PictureBox)
If Not pic.Image Is Nothing Then
Dim filename As String = Path.Combine(Path.GetDirectoryName(ExportFileDialog1.FileName), (Path.GetFileNameWithoutExtension(ExportFileDialog1.FileName) & "." & pic.Name & ".png"))
Using m As New MemoryStream
pic.Image.Save(filename, Imaging.ImageFormat.Png)
End Using
End If
End If
Next
To get this sample to work, you'll need a Microsoft Fingerprint Reader (or other compatible reader) and the Griaule SDK installed. I recommend you uninstall the Digital Persona drivers that came with the Fingerprint Reader otherwise this application may compete for the same hardware if the Digital Persona software is running in the background.
Conclusion
There's a number of fun things that could be extended, added, and improved on with this project. Here are some ideas to get you started:
- Adding a PDF export feature using an open-source .NET PDF Library
- ...or export to Word using Office Automation and the Microsoft Office Interop Assemblies.
- Add security by using DPAPI or encrypt the Fingerprint files directly.
- Add compression by zipping the .finger files up programmatically.
Have fun and have no fear when faced with the words - Some Assembly Required!
If you do extend this application, be sure to release the source. Thanks again to Griaule for the use of their SDK.
Scott Hanselman is the Chief Architect at the Corillian Corporation, an eFinance enabler. He has thirteen years experience developing software in C, C++, VB, COM, and most recently in VB.NET and C#. Scott is proud to be both a Microsoft RD and Architecture MVP. He is co-author of Professional ASP.NET 2.0 with Bill Evjen, available on BookPool.com and Amazon. His thoughts on the Zen of .NET, Programming and Web Services can be found on his blog at http://www.computerzen.com.