├── .github └── stale.yml ├── .gitignore ├── LICENSE ├── README.md ├── Unosquare.Labs.LibFprint.Tests ├── Program.cs └── Unosquare.Labs.LibFprint.Tests.csproj ├── Unosquare.Labs.LibFprint.sln ├── Unosquare.Labs.LibFprint ├── EnrollResult.cs ├── EnrollStageResult.cs ├── Extensions.cs ├── FingerprintDevice.cs ├── FingerprintDeviceManager.cs ├── FingerprintGallery.cs ├── Interop.Types.cs ├── Interop.cs ├── PgmFormatReader.cs ├── Unosquare.Labs.LibFprint.csproj └── fprint.h ├── appveyor.yml ├── docfx.json └── toc.yml /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | (This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.) 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | {description} 474 | Copyright (C) {year} {fullname} 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | {signature of Ty Coon}, 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | 506 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Analytics](https://ga-beacon.appspot.com/UA-8535255-2/unosquare/libfprint-cs/)](https://github.com/igrigorik/ga-beacon) 2 | [![Build Status](https://travis-ci.org/unosquare/libfprint-cs.svg?branch=master)](https://travis-ci.org/unosquare/libfprint-cs) 3 | [![Build status](https://ci.appveyor.com/api/projects/status/jxi3ixge0p8jx9e8/branch/master?svg=true)](https://ci.appveyor.com/project/geoperez/libfprint-cs/branch/master) 4 | 5 | # libfprint-cs 6 | 7 | **WE ARE LOOKING FOR A NEW HOME FOR THIS PROJECT. APPLY AT:** https://adoptoposs.org/p/c905cc68-9a61-4b69-bf52-b27bda1fd6b3 8 | 9 | The long-awaited C# (.net/mono) wrapper for the great fingerprint reader interfacing library libfprint 10 | *Note: A few people have reported a System.DllNotFoundException being thrown at runtime. This is a Linux project. There is no libfprint.dll for Windows* 11 | 12 | From the libfprint website: 13 |
14 | libfprint is an open source software library designed to make it easy for application developers to add support for consumer fingerprint readers to their software. 15 |
16 | 17 | This wrapper makes interfacing with your fingerprint reader extremely easy. 18 | 19 | ## Simple guidelines 20 | 27 | 28 | ## Super quick code example 29 | 30 | ```cs 31 | using (var manager = FingerprintDeviceManager.Instance) 32 | { 33 | manager.Initialize(); 34 | using (var gallery = new FingerprintGallery()) 35 | { 36 | var device = manager.DiscoverDevices().FirstOrDefault(); 37 | device.Open(); 38 | var enrollResult = device.EnrollFingerprint("enroll.pgm"); 39 | if (enrollResult.IsEnrollComplete) 40 | { 41 | var isVerified = device.VerifyFingerprint(enrollResult, "verify.pgm"); 42 | if (isVerified) 43 | { 44 | gallery.Add("username_gose_here", enrollResult); 45 | } 46 | } 47 | 48 | var identified = device.IdentifyFingerprint(gallery, "identify.pgm"); 49 | } 50 | } 51 | ``` 52 | 53 | ## Getting it to run on the Raspberry Pi (Raspbian) 54 | 55 | Raspbian has a fairly outdated libfprint-dev package (0.4.0). The following script will remove the installed libfprint-dev, install dependencies, pull code from 0.5.1, build it, and install the library. 56 | 57 | ```shell 58 | sudo apt-get remove -y libfprint-dev 59 | sudo apt-get autoremove -y 60 | sudo apt-get install -y libusb-1.0-0-dev 61 | sudo apt-get install -y libnss3-dev 62 | sudo apt-get install -y libgtk2.0-dev 63 | 64 | wget http://people.freedesktop.org/~hadess/libfprint-0.5.1.tar.xz 65 | tar xf libfprint-0.5.1.tar.xz 66 | rm libfprint-0.5.1.tar.xz 67 | cd libfprint-0.5.1 68 | ./configure 69 | make 70 | sudo make install 71 | sudo make clean 72 | cd .. 73 | sudo cp /usr/local/lib/libfprint.so libfprint.so 74 | sudo find / -iname "libfprint.so" 75 | ``` 76 | 77 | You will also obviously want to install mono for any of the above to work . . . 78 | ```shell 79 | sudo apt-get install mono-complete 80 | ``` 81 | 82 | ## Futures 83 | 84 | The identification logic seems to be fairly slow when we start adding many fingerprints. Maybe using this library for imaging and then using something like SourceAFIS for identification would work better... 85 | 86 | ## Thanks 87 | 88 | Thanks to the libfprint developers! 89 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint.Tests/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Unosquare.Labs.LibFprint.Tests 5 | { 6 | public class MainClass 7 | { 8 | public static void Main(string[] args) 9 | { 10 | // The device manager discovers devices. It's a singleton and is used to detect connected devices 11 | // it also create references to the fingerprint scanners 12 | using var manager = FingerprintDeviceManager.Instance; 13 | // We always need to call this method to make sure the library is initialized 14 | manager.Initialize(); 15 | Console.WriteLine("Initialized Device Manager."); 16 | 17 | // Now we call the device discovery method 18 | var devices = manager.DiscoverDevices(); 19 | 20 | // Let's do stuff with each of the discovered devices (typically only 1) 21 | foreach (var device in devices) 22 | { 23 | var thread = new Thread(() => 24 | { 25 | 26 | // Before we do anything, we need to open the device. 27 | device.Open(); 28 | 29 | // Now we print some info about the device. 30 | Console.ForegroundColor = ConsoleColor.Cyan; 31 | Console.WriteLine(); 32 | Console.WriteLine("Device {0} - {1}", device.DriverName, device.DriverFullName); 33 | Console.WriteLine(" Enroll Stages: {0}", device.EnrollStagesCount); 34 | Console.WriteLine(" Supports Imaging: {0}", device.SupportsImaging); 35 | Console.WriteLine(" Supports Ident: {0}", device.SupportsIdentification); 36 | Console.WriteLine(" Imaging Dimensions: {0}x{1}", device.ImageWidth, device.ImageHeight); 37 | 38 | // We will enroll a few fingerprints into the gallery. 39 | using var gallery = new FingerprintGallery(); 40 | var enrollCount = 0; 41 | while (enrollCount < 5) 42 | { 43 | Console.ForegroundColor = ConsoleColor.Green; 44 | Console.WriteLine(" >> ENROLL: Enroll count: {0}. Enroll a new finger now . . .", enrollCount); 45 | 46 | // Call the enrollment method 47 | var enrollResult = device.EnrollFingerprint("enroll.pgm"); 48 | if (enrollResult.IsEnrollComplete) 49 | { 50 | 51 | Console.ForegroundColor = ConsoleColor.Green; 52 | Console.WriteLine(" >> VERIFY: Now, verify your scan just to make sure . . ."); 53 | 54 | // Although not necessary, we are adding verification just to make sure 55 | var isVerified = device.VerifyFingerprint(enrollResult, "verify.pgm"); 56 | if (isVerified) 57 | { 58 | enrollCount++; 59 | var printName = "The print " + enrollCount; 60 | gallery.Add(printName, enrollResult); 61 | } 62 | else 63 | { 64 | Console.ForegroundColor = ConsoleColor.Red; 65 | Console.WriteLine("Could not verify. Try again!"); 66 | Console.WriteLine(); 67 | } 68 | } 69 | else 70 | { 71 | Console.ForegroundColor = ConsoleColor.Red; 72 | Console.WriteLine("Try Again -- Error Code {0} - {1}", enrollResult.ResultCode, enrollResult.Result); 73 | Console.WriteLine(); 74 | // HACK: for some reason we needed the Reset method to be called. Otherwise the reader would blink rapidly and get stuck 75 | device.Reset(); 76 | } 77 | } 78 | 79 | Console.ForegroundColor = ConsoleColor.Gray; 80 | Console.WriteLine(); 81 | 82 | // Now, let's try some identification in the gallery we created earlier 83 | // with enrollment and verification operations 84 | while (true) 85 | { 86 | Console.ForegroundColor = ConsoleColor.Green; 87 | Console.WriteLine(" >> IDENTIFY: Press finger against scanner to identify . . ."); 88 | 89 | // Let's try to identify a fingerprint and getting it's key back. 90 | // a null key means the FP was not identified. 91 | var identified = device.IdentifyFingerprint(gallery, "identify.pgm"); 92 | if (identified == null) 93 | { 94 | Console.ForegroundColor = ConsoleColor.Red; 95 | Console.WriteLine("Could not identify."); 96 | Console.WriteLine(); 97 | } 98 | else 99 | { 100 | Console.ForegroundColor = ConsoleColor.Blue; 101 | Console.WriteLine("Fingerprint was identified: {0}.", identified); 102 | Console.WriteLine(); 103 | } 104 | } 105 | }) 106 | { IsBackground = true }; 107 | 108 | 109 | Console.ForegroundColor = ConsoleColor.DarkYellow; 110 | Console.WriteLine("Press A to abort the thread . . ."); 111 | 112 | thread.Start(); 113 | 114 | while (true) 115 | { 116 | if (Console.ReadKey(true).Key == ConsoleKey.A) 117 | { 118 | thread.Abort(); 119 | var terminationTimeout = DateTime.Now.AddSeconds(10); 120 | while (thread.IsAlive) 121 | { 122 | Console.ForegroundColor = ConsoleColor.DarkYellow; 123 | Console.WriteLine("Waiting for thread termination. {0.00} seconds to terminate forcefully.", terminationTimeout.Subtract(DateTime.Now).TotalSeconds); 124 | thread.Abort(); 125 | 126 | if (DateTime.Now > terminationTimeout) 127 | { 128 | Console.ForegroundColor = ConsoleColor.Red; 129 | Console.WriteLine("Termination timeout reached. Forcefully disposing the device."); 130 | } 131 | 132 | Thread.Sleep(1000); 133 | } 134 | 135 | break; 136 | } 137 | 138 | Console.ForegroundColor = ConsoleColor.Red; 139 | Console.WriteLine("Press A to abort the thread . . ."); 140 | } 141 | 142 | // We release unmanaged resources for the device. 143 | device.Dispose(); 144 | } 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint.Tests/Unosquare.Labs.LibFprint.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp3.0 4 | Copyright (c) 2019 - Unosquare 5 | Unosquare 6 | Unosquare.Labs.LibFprint.Test 7 | 8.0 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unosquare.Labs.LibFprint", "Unosquare.Labs.LibFprint\Unosquare.Labs.LibFprint.csproj", "{88E552BF-2F88-4C04-A24C-45518EE574C5}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unosquare.Labs.LibFprint.Tests", "Unosquare.Labs.LibFprint.Tests\Unosquare.Labs.LibFprint.Tests.csproj", "{C1863959-C3E2-4593-B05B-074842C2AE10}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|Mixed Platforms = Debug|Mixed Platforms 12 | Debug|x86 = Debug|x86 13 | Release|Any CPU = Release|Any CPU 14 | Release|Mixed Platforms = Release|Mixed Platforms 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 21 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 22 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 26 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Release|Mixed Platforms.Build.0 = Release|Any CPU 27 | {88E552BF-2F88-4C04-A24C-45518EE574C5}.Release|x86.ActiveCfg = Release|Any CPU 28 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 31 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 32 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|x86.ActiveCfg = Debug|Any CPU 33 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Debug|x86.Build.0 = Debug|Any CPU 34 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 37 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|Mixed Platforms.Build.0 = Release|Any CPU 38 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|x86.ActiveCfg = Release|Any CPU 39 | {C1863959-C3E2-4593-B05B-074842C2AE10}.Release|x86.Build.0 = Release|Any CPU 40 | EndGlobalSection 41 | GlobalSection(MonoDevelopProperties) = preSolution 42 | StartupItem = Unosquare.Labs.LibFprint.Tests\Unosquare.Labs.LibFprint.Tests.csproj 43 | Policies = $0 44 | $0.DotNetNamingPolicy = $1 45 | $1.DirectoryNamespaceAssociation = None 46 | $1.ResourceNamePolicy = FileFormatDefault 47 | $0.StandardHeader = $2 48 | $2.Text = 49 | $2.IncludeInNewFiles = True 50 | $0.NameConventionPolicy = $3 51 | $3.Rules = $4 52 | $4.NamingRule = $5 53 | $5.Name = Namespaces 54 | $5.AffectedEntity = Namespace 55 | $5.VisibilityMask = VisibilityMask 56 | $5.NamingStyle = PascalCase 57 | $5.IncludeInstanceMembers = True 58 | $5.IncludeStaticEntities = True 59 | $4.NamingRule = $6 60 | $6.Name = Types 61 | $6.AffectedEntity = Class, Struct, Enum, Delegate 62 | $6.VisibilityMask = Public 63 | $6.NamingStyle = PascalCase 64 | $6.IncludeInstanceMembers = True 65 | $6.IncludeStaticEntities = True 66 | $4.NamingRule = $7 67 | $7.Name = Interfaces 68 | $7.RequiredPrefixes = $8 69 | $8.String = I 70 | $7.AffectedEntity = Interface 71 | $7.VisibilityMask = Public 72 | $7.NamingStyle = PascalCase 73 | $7.IncludeInstanceMembers = True 74 | $7.IncludeStaticEntities = True 75 | $4.NamingRule = $9 76 | $9.Name = Attributes 77 | $9.RequiredSuffixes = $10 78 | $10.String = Attribute 79 | $9.AffectedEntity = CustomAttributes 80 | $9.VisibilityMask = Public 81 | $9.NamingStyle = PascalCase 82 | $9.IncludeInstanceMembers = True 83 | $9.IncludeStaticEntities = True 84 | $4.NamingRule = $11 85 | $11.Name = Event Arguments 86 | $11.RequiredSuffixes = $12 87 | $12.String = EventArgs 88 | $11.AffectedEntity = CustomEventArgs 89 | $11.VisibilityMask = Public 90 | $11.NamingStyle = PascalCase 91 | $11.IncludeInstanceMembers = True 92 | $11.IncludeStaticEntities = True 93 | $4.NamingRule = $13 94 | $13.Name = Exceptions 95 | $13.RequiredSuffixes = $14 96 | $14.String = Exception 97 | $13.AffectedEntity = CustomExceptions 98 | $13.VisibilityMask = VisibilityMask 99 | $13.NamingStyle = PascalCase 100 | $13.IncludeInstanceMembers = True 101 | $13.IncludeStaticEntities = True 102 | $4.NamingRule = $15 103 | $15.Name = Methods 104 | $15.AffectedEntity = Methods 105 | $15.VisibilityMask = Protected, Public 106 | $15.NamingStyle = PascalCase 107 | $15.IncludeInstanceMembers = True 108 | $15.IncludeStaticEntities = True 109 | $4.NamingRule = $16 110 | $16.Name = Static Readonly Fields 111 | $16.AffectedEntity = ReadonlyField 112 | $16.VisibilityMask = Protected, Public 113 | $16.NamingStyle = PascalCase 114 | $16.IncludeInstanceMembers = False 115 | $16.IncludeStaticEntities = True 116 | $4.NamingRule = $17 117 | $17.Name = Fields 118 | $17.AffectedEntity = Field 119 | $17.VisibilityMask = Protected, Public 120 | $17.NamingStyle = PascalCase 121 | $17.IncludeInstanceMembers = True 122 | $17.IncludeStaticEntities = True 123 | $4.NamingRule = $18 124 | $18.Name = ReadOnly Fields 125 | $18.AffectedEntity = ReadonlyField 126 | $18.VisibilityMask = Protected, Public 127 | $18.NamingStyle = PascalCase 128 | $18.IncludeInstanceMembers = True 129 | $18.IncludeStaticEntities = False 130 | $4.NamingRule = $19 131 | $19.Name = Constant Fields 132 | $19.AffectedEntity = ConstantField 133 | $19.VisibilityMask = Protected, Public 134 | $19.NamingStyle = PascalCase 135 | $19.IncludeInstanceMembers = True 136 | $19.IncludeStaticEntities = True 137 | $4.NamingRule = $20 138 | $20.Name = Properties 139 | $20.AffectedEntity = Property 140 | $20.VisibilityMask = Protected, Public 141 | $20.NamingStyle = PascalCase 142 | $20.IncludeInstanceMembers = True 143 | $20.IncludeStaticEntities = True 144 | $4.NamingRule = $21 145 | $21.Name = Events 146 | $21.AffectedEntity = Event 147 | $21.VisibilityMask = Protected, Public 148 | $21.NamingStyle = PascalCase 149 | $21.IncludeInstanceMembers = True 150 | $21.IncludeStaticEntities = True 151 | $4.NamingRule = $22 152 | $22.Name = Enum Members 153 | $22.AffectedEntity = EnumMember 154 | $22.VisibilityMask = VisibilityMask 155 | $22.NamingStyle = PascalCase 156 | $22.IncludeInstanceMembers = True 157 | $22.IncludeStaticEntities = True 158 | $4.NamingRule = $23 159 | $23.Name = Parameters 160 | $23.AffectedEntity = Parameter 161 | $23.VisibilityMask = VisibilityMask 162 | $23.NamingStyle = CamelCase 163 | $23.IncludeInstanceMembers = True 164 | $23.IncludeStaticEntities = True 165 | $4.NamingRule = $24 166 | $24.Name = Type Parameters 167 | $24.RequiredPrefixes = $25 168 | $25.String = T 169 | $24.AffectedEntity = TypeParameter 170 | $24.VisibilityMask = VisibilityMask 171 | $24.NamingStyle = PascalCase 172 | $24.IncludeInstanceMembers = True 173 | $24.IncludeStaticEntities = True 174 | $0.TextStylePolicy = $26 175 | $26.FileWidth = 120 176 | $26.EolMarker = Windows 177 | $26.inheritsSet = VisualStudio 178 | $26.inheritsScope = text/plain 179 | $26.scope = text/plain 180 | $0.TextStylePolicy = $27 181 | $27.inheritsSet = null 182 | $27.scope = text/x-chdr 183 | EndGlobalSection 184 | GlobalSection(SolutionProperties) = preSolution 185 | HideSolutionNode = FALSE 186 | EndGlobalSection 187 | EndGlobal 188 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/EnrollResult.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | /// 4 | /// An enumeration that represents enrollment results. 5 | /// 6 | public enum EnrollResult 7 | { 8 | /// 9 | /// The unspecified 10 | /// 11 | Unspecified = 0, 12 | 13 | /// 14 | /// The enroll complete 15 | /// 16 | EnrollComplete = 1, 17 | 18 | /// 19 | /// The enroll failed 20 | /// 21 | EnrollFailed = 2, 22 | 23 | /// 24 | /// The enroll stage passed 25 | /// 26 | EnrollStagePassed = 3, 27 | 28 | /// 29 | /// The retry 30 | /// 31 | Retry = 100, 32 | 33 | /// 34 | /// The retry scan too short 35 | /// 36 | RetryScanTooShort = 101, 37 | 38 | /// 39 | /// The retry finger not centered 40 | /// 41 | RetryFingerNotCentered = 102, 42 | 43 | /// 44 | /// The retry remove finger 45 | /// 46 | RetryRemoveFinger = 103, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/EnrollStageResult.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | /// 4 | /// Represents the state of a Fingerprint Enrollment operation. 5 | /// 6 | public class EnrollStageResult 7 | { 8 | /// 9 | /// Initializes a new instance of the class. 10 | /// 11 | /// The enroll code. 12 | /// The fingerprint data. 13 | public EnrollStageResult(int enrollCode, byte[] fingerprintData) 14 | { 15 | ResultCode = enrollCode; 16 | 17 | Result = ResultCode < 0 ? EnrollResult.Unspecified : (EnrollResult)enrollCode; 18 | 19 | FingerprintData = fingerprintData; 20 | } 21 | 22 | /// 23 | /// Gets or sets the raw result code. 24 | /// 25 | /// 26 | /// The result code. 27 | /// 28 | public int ResultCode { get; protected set; } 29 | 30 | /// 31 | /// Gets or sets the friendly result code. 32 | /// 33 | /// 34 | /// The result. 35 | /// 36 | public EnrollResult Result { get; protected set; } 37 | 38 | /// 39 | /// Gets the buffer data holding the fingerprint scan. 40 | /// This is what needs to be saved in a database that will later be loased on to a 41 | /// FingerprintGallery object. 42 | /// 43 | /// 44 | /// The fingerprint data. 45 | /// 46 | public byte[] FingerprintData { get; protected set; } 47 | 48 | /// 49 | /// Gets a value indicating whether the enrollment requires retry. 50 | /// 51 | /// 52 | /// true if [requires retry]; otherwise, false. 53 | /// 54 | public bool RequiresRetry 55 | { 56 | get 57 | { 58 | if (IsFatalError) return false; 59 | 60 | return 61 | Result == EnrollResult.Retry || 62 | Result == EnrollResult.RetryFingerNotCentered || 63 | Result == EnrollResult.RetryRemoveFinger || 64 | Result == EnrollResult.RetryScanTooShort; 65 | } 66 | } 67 | 68 | /// 69 | /// Gets a value indicating whether the result contains a fatal error. 70 | /// 71 | /// 72 | /// true if this instance is fatal error; otherwise, false. 73 | /// 74 | public bool IsFatalError => ResultCode < 0; 75 | 76 | /// 77 | /// Gets a value indicating whether the result was a successful scan. 78 | /// 79 | /// 80 | /// true if this instance is success; otherwise, false. 81 | /// 82 | public bool IsSuccess => IsFatalError == false && (Result == EnrollResult.EnrollComplete || Result == EnrollResult.EnrollStagePassed); 83 | 84 | /// 85 | /// Gets a value indicating whether this instance represents an enrollment failure. 86 | /// 87 | /// 88 | /// true if this instance is enroll failure; otherwise, false. 89 | /// 90 | public bool IsEnrollFailure => IsFatalError == false && Result == EnrollResult.EnrollFailed; 91 | 92 | /// 93 | /// Gets a value indicating whether this instance represents an enrollment completion. 94 | /// 95 | /// 96 | /// true if this instance is enroll complete; otherwise, false. 97 | /// 98 | public bool IsEnrollComplete => IsFatalError == false && Result == EnrollResult.EnrollComplete; 99 | 100 | /// 101 | /// Gets a value indicating whether a new call to the Enroll Fingerprint method is required to advance or to retry. 102 | /// 103 | /// 104 | /// true if [requires new call]; otherwise, false. 105 | /// 106 | public bool RequiresNewCall => RequiresRetry || Result == EnrollResult.EnrollStagePassed; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/Extensions.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | using System; 4 | 5 | /// 6 | /// Helper methods for pointer management. 7 | /// 8 | internal static class Extensions 9 | { 10 | /// 11 | /// Dereferences the PTR into the given type. 12 | /// 13 | /// 14 | /// The PTR. 15 | /// 16 | public static T DereferencePtr(this IntPtr ptr) => (T)System.Runtime.InteropServices.Marshal.PtrToStructure(ptr, typeof(T)); 17 | 18 | /// 19 | /// Turns the given base address to an array of pointers. 20 | /// 21 | /// The base address. 22 | /// 23 | public static IntPtr[] ToPointerArray(this IntPtr baseAddress) 24 | { 25 | var ptrList = new System.Collections.Generic.List(); 26 | 27 | if (baseAddress == IntPtr.Zero) return ptrList.ToArray(); 28 | 29 | while (true) 30 | { 31 | var itemPtr = baseAddress.DereferencePtr(); 32 | if (itemPtr == IntPtr.Zero) 33 | break; 34 | 35 | ptrList.Add(itemPtr); 36 | baseAddress = IntPtr.Add(baseAddress, IntPtr.Size); 37 | } 38 | 39 | return ptrList.ToArray(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/FingerprintDevice.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | using System; 4 | using System.Runtime.InteropServices; 5 | 6 | /// 7 | /// Provides properties and methods to control and access fingerprint device finctionality. 8 | /// Use the FingerPrintDeviceManager class to discover and open instances of this class. 9 | /// Please note this class makes use of unmanaged resources. Dispose accordingly. 10 | /// 11 | public class FingerprintDevice : IDisposable 12 | { 13 | #region Properties 14 | 15 | internal Interop.fp_dscv_dev? DiscoveredDevice { get; set; } 16 | internal IntPtr DiscoveredDevicePtr { get; set; } 17 | internal Interop.fp_driver? Driver { get; set; } 18 | internal IntPtr RealDevicePtr { get; set; } 19 | internal Interop.fp_dev? RealDevice { get; set; } 20 | 21 | /// 22 | /// Gets a value indicating whether this device is open and ready for operation. 23 | /// 24 | /// 25 | /// true if this instance is open; otherwise, false. 26 | /// 27 | public bool IsOpen => RealDevice.HasValue; 28 | 29 | /// 30 | /// Gets or sets a value indicating whether this device supports imaging. 31 | /// 32 | /// 33 | /// true if [supports imaging]; otherwise, false. 34 | /// 35 | public bool SupportsImaging { get; protected set; } 36 | 37 | /// 38 | /// Gets or sets a value indicating whether this device supports identification. 39 | /// 40 | /// 41 | /// true if [supports identification]; otherwise, false. 42 | /// 43 | public bool SupportsIdentification { get; protected set; } 44 | 45 | /// 46 | /// Gets or sets the height of the image. 47 | /// 48 | /// 49 | /// The height of the image. 50 | /// 51 | public int ImageHeight { get; protected set; } 52 | 53 | /// 54 | /// Gets or sets the width of the image. 55 | /// 56 | /// 57 | /// The width of the image. 58 | /// 59 | public int ImageWidth { get; protected set; } 60 | 61 | /// 62 | /// Gets or sets a value indicating whether this device supports variable imaging dimensions. 63 | /// 64 | /// 65 | /// true if [supports variable imaging dimensions]; otherwise, false. 66 | /// 67 | public bool SupportsVariableImagingDimensions { get; protected set; } 68 | 69 | /// 70 | /// Gets the enroll stages count for this device. 71 | /// 72 | /// 73 | /// The enroll stages count. 74 | /// 75 | public int EnrollStagesCount { get; protected set; } 76 | 77 | /// 78 | /// Gets the name of the driver. 79 | /// 80 | /// 81 | /// The name of the driver. 82 | /// 83 | public string DriverName => Driver?.name; 84 | 85 | /// 86 | /// Gets the full name of the driver. 87 | /// 88 | /// 89 | /// The full name of the driver. 90 | /// 91 | public string DriverFullName => Driver?.full_name; 92 | 93 | #endregion 94 | 95 | #region Basic functions 96 | 97 | /// 98 | /// Prevents ourside instantiation of the class. 99 | /// 100 | internal FingerprintDevice() 101 | { 102 | // We want to prevent standalone instances of this class. 103 | // Only instances created via FingerprintDeviceManager are valid. 104 | } 105 | 106 | /// 107 | /// Helper method to save and free scanned images. 108 | /// 109 | /// The print image PTR. 110 | /// The PGM file path. 111 | /// if set to true [free image]. 112 | private static void SaveImageToDisk(IntPtr printImagePtr, string pgmFilePath, bool freeImage) 113 | { 114 | // Save the PGM file if required by the user 115 | if (string.IsNullOrWhiteSpace(pgmFilePath) == false && printImagePtr != IntPtr.Zero) 116 | { 117 | Interop.fp_img_save_to_file(printImagePtr, pgmFilePath); 118 | } 119 | 120 | // Free the image pointer immediately 121 | if (freeImage && printImagePtr != IntPtr.Zero) 122 | { 123 | Interop.fp_img_free(printImagePtr); 124 | } 125 | } 126 | 127 | /// 128 | /// Opens this fingerprint scanning device. 129 | /// This method has to be called before operating the device. 130 | /// 131 | /// Could not open device. 132 | public void Open() 133 | { 134 | RealDevicePtr = Interop.fp_dev_open(DiscoveredDevicePtr); 135 | if (RealDevicePtr == IntPtr.Zero) 136 | throw new InvalidOperationException("Could not open device."); 137 | 138 | RealDevice = RealDevicePtr.DereferencePtr(); 139 | 140 | // Populate device info upon opening 141 | var realDevice = RealDevice.Value; 142 | SupportsImaging = Interop.fp_dev_supports_imaging(ref realDevice) != 0; 143 | SupportsIdentification = Interop.fp_dev_supports_identification(ref realDevice) != 0; 144 | ImageHeight = Interop.fp_dev_get_img_height(ref realDevice); 145 | ImageWidth = Interop.fp_dev_get_img_width(ref realDevice); 146 | SupportsVariableImagingDimensions = ImageWidth <= 0 || ImageHeight <= 0; 147 | EnrollStagesCount = Interop.fp_dev_get_nr_enroll_stages(ref realDevice); 148 | } 149 | 150 | /// 151 | /// Resets the device by closing and re-opening it. 152 | /// 153 | public void Reset() 154 | { 155 | if (IsOpen == false) return; 156 | Interop.fp_dev_close(RealDevicePtr); 157 | Open(); 158 | } 159 | 160 | #endregion 161 | 162 | #region Enrollment 163 | 164 | /// 165 | /// Enrolls the fingerprint. 166 | /// 167 | /// The PGM file path. 168 | /// 169 | public EnrollStageResult EnrollFingerprint(string pgmFilePath) 170 | { 171 | // Make sure the device is open 172 | if (IsOpen == false) 173 | Open(); 174 | 175 | byte[] fingerprintData = null; 176 | 177 | var enrollResultCode = 178 | Interop.fp_enroll_finger_img(RealDevicePtr, out var printDataPtr, out var printImagePtr); 179 | 180 | // Save the PGM file if required by the user 181 | SaveImageToDisk(printImagePtr, pgmFilePath, true); 182 | 183 | // Create the fingerprint data buffer if the enroll fp data is available 184 | if (enrollResultCode == (int)EnrollResult.EnrollStagePassed || 185 | enrollResultCode == (int)EnrollResult.EnrollComplete) 186 | { 187 | if (printDataPtr != IntPtr.Zero) 188 | { 189 | var bufferLength = Convert.ToInt32(Interop.fp_print_data_get_data(printDataPtr, out var bufferPtr)); 190 | fingerprintData = new byte[bufferLength]; 191 | Marshal.Copy(bufferPtr, fingerprintData, 0, fingerprintData.Length); 192 | Interop.fp_print_data_free(printDataPtr); 193 | // TODO: free(bufferPtr) // Maybe Marshal.FreeHGlobal as done in the following line? 194 | Marshal.FreeHGlobal(bufferPtr); 195 | } 196 | } 197 | 198 | return new EnrollStageResult(enrollResultCode, fingerprintData); 199 | } 200 | 201 | /// 202 | /// Enrolls the fingerprint. 203 | /// 204 | /// 205 | public EnrollStageResult EnrollFingerprint() => EnrollFingerprint(null); 206 | 207 | #endregion 208 | 209 | #region Verification 210 | 211 | /// 212 | /// Verifies the fingerprint. 213 | /// 214 | /// The gallery key. 215 | /// The gallery. 216 | /// The PGM file path. 217 | /// 218 | public bool VerifyFingerprint(string galleryKey, FingerprintGallery gallery, string pgmFilePath) 219 | { 220 | // Make sure the device is open 221 | if (IsOpen == false) 222 | Open(); 223 | 224 | // Acquire the pointer to the stored fingerprint 225 | var fingerprintPtr = gallery.GetFingerprintPointer(galleryKey); 226 | if (fingerprintPtr == IntPtr.Zero) return false; 227 | 228 | // Perform verification 229 | var resultCode = Interop.fp_verify_finger_img(RealDevicePtr, fingerprintPtr, out var printImagePtr); 230 | 231 | // Save the PGM file if required by the user 232 | SaveImageToDisk(printImagePtr, pgmFilePath, true); 233 | 234 | return resultCode == (int)Interop.fp_verify_result.FP_VERIFY_MATCH; 235 | } 236 | 237 | /// 238 | /// Verifies the fingerprint. 239 | /// 240 | /// The gallery key. 241 | /// The gallery. 242 | /// 243 | public bool VerifyFingerprint(string galleryKey, FingerprintGallery gallery) => 244 | VerifyFingerprint(galleryKey, gallery, null); 245 | 246 | /// 247 | /// Verifies the fingerprint. 248 | /// 249 | /// The enroll result. 250 | /// The PGM file path. 251 | /// 252 | public bool VerifyFingerprint(EnrollStageResult enrollResult, string pgmFilePath) 253 | { 254 | const string galleryKey = "dummy"; 255 | using var gallery = new FingerprintGallery(); 256 | gallery.Add(galleryKey, enrollResult); 257 | return VerifyFingerprint(galleryKey, gallery, pgmFilePath); 258 | } 259 | 260 | /// 261 | /// Verifies the fingerprint. 262 | /// 263 | /// The enroll result. 264 | /// 265 | public bool VerifyFingerprint(EnrollStageResult enrollResult) => VerifyFingerprint(enrollResult, null); 266 | 267 | #endregion 268 | 269 | #region Identification 270 | 271 | /// 272 | /// Identifies the fingerprint. 273 | /// 274 | /// The gallery. 275 | /// The PGM file path. 276 | /// 277 | public string IdentifyFingerprint(FingerprintGallery gallery, string pgmFilePath) 278 | { 279 | // Make sure the device is open 280 | if (IsOpen == false) 281 | Open(); 282 | 283 | var matchResult = Interop.fp_identify_finger_img(RealDevicePtr, gallery.PointerArray, out var matchOffset, 284 | out var printImagePtr); 285 | 286 | // Save the PGM file if required by the user 287 | SaveImageToDisk(printImagePtr, pgmFilePath, true); 288 | 289 | // Return the key string based on the offset 290 | return matchResult == 1 ? gallery[Convert.ToInt32(matchOffset)] : null; 291 | } 292 | 293 | /// 294 | /// Identifies the fingerprint. 295 | /// 296 | /// The gallery. 297 | /// 298 | public string IdentifyFingerprint(FingerprintGallery gallery) => IdentifyFingerprint(gallery, null); 299 | 300 | #endregion 301 | 302 | #region IDisposable Implementation 303 | 304 | /// 305 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 306 | /// 307 | public void Dispose() 308 | { 309 | Dispose(true); 310 | GC.SuppressFinalize(this); 311 | } 312 | 313 | /// 314 | /// Finalizes an instance of the class. 315 | /// 316 | ~FingerprintDevice() 317 | { 318 | // Finalizer calls Dispose(false) 319 | Dispose(false); 320 | } 321 | 322 | /// 323 | /// Releases unmanaged and - optionally - managed resources. 324 | /// 325 | /// true to release both managed and unmanaged resources; false to release only unmanaged resources. 326 | protected virtual void Dispose(bool releaseOnlyManaged) 327 | { 328 | if (releaseOnlyManaged) 329 | { 330 | return; 331 | } 332 | 333 | // free native resources if there are any. 334 | if (IsOpen) 335 | { 336 | Interop.fp_dev_close(RealDevicePtr); 337 | RealDevice = null; 338 | RealDevicePtr = IntPtr.Zero; 339 | } 340 | } 341 | 342 | #endregion 343 | } 344 | } -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/FingerprintDeviceManager.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | /// 7 | /// Singleton class to Initialize the fprint library and perform fingerprint reader device discovery. 8 | /// Access properties and methods via the Instance Property. 9 | /// 10 | public sealed class FingerprintDeviceManager : IDisposable 11 | { 12 | #region Singleton Implementation 13 | 14 | /// 15 | /// The static, singleton instance reference. 16 | /// 17 | private static FingerprintDeviceManager m_Instance; 18 | 19 | /// 20 | /// Prevents a default instance of the class from being created. 21 | /// 22 | private FingerprintDeviceManager() 23 | { 24 | // placeholder 25 | } 26 | 27 | /// 28 | /// Gets the single instance of the Fingerprint Device Manager. 29 | /// 30 | /// 31 | /// The instance. 32 | /// 33 | public static FingerprintDeviceManager Instance => m_Instance ??= new FingerprintDeviceManager(); 34 | 35 | #endregion 36 | 37 | #region Properties 38 | 39 | /// 40 | /// Gets or sets a value indicating whether the library is initialized. 41 | /// 42 | /// 43 | /// true if this instance is initialized; otherwise, false. 44 | /// 45 | public bool IsInitialized { get; private set; } 46 | 47 | 48 | /// 49 | /// Holds a pointer to the base address of the array containing 50 | /// Discovered device references. 51 | /// 52 | /// 53 | /// The device discovery results PTR. 54 | /// 55 | private IntPtr DeviceDicoveryResultsPtr { get; set; } 56 | 57 | #endregion 58 | 59 | #region Methods 60 | 61 | /// 62 | /// Initializes the fprint library with the given debug level. 63 | /// The dibug level is not documented but 3 seems to have some level of verbosity. 64 | /// 65 | /// The debug level. 66 | /// 67 | public void Initialize(int debugLevel = 0) 68 | { 69 | if (IsInitialized) return; 70 | 71 | var result = Interop.fp_init(); 72 | if (result < 0) 73 | throw new InvalidOperationException($"Failed to initialize fprint library. Result code: {result}"); 74 | 75 | Interop.fp_set_debug(debugLevel); 76 | 77 | IsInitialized = true; 78 | } 79 | 80 | /// 81 | /// Performs a discovery of currently connected Fingerprint Scanner devices 82 | /// Use the resulting array of FingerPrintDevice to start operating the devices. 83 | /// 84 | /// 85 | public FingerprintDevice[] DiscoverDevices() 86 | { 87 | if (!IsInitialized) Initialize(); 88 | 89 | var result = new List(); 90 | 91 | ReleaseDeviceDiscoveryResults(); 92 | var dicoveredDevicePtrs = Interop.fp_discover_devs_pointers(out var deviceDiscoveryResultsPtr); // This returns the array of pointrs 93 | DeviceDicoveryResultsPtr = deviceDiscoveryResultsPtr; 94 | 95 | foreach (var devicePtr in dicoveredDevicePtrs) 96 | { 97 | var deviceStruct = devicePtr.DereferencePtr(); 98 | var driverStruct = Interop.fp_dscv_dev_get_driver_struct(ref deviceStruct); 99 | 100 | var managedDevice = new FingerprintDevice 101 | { 102 | DiscoveredDevice = deviceStruct, 103 | DiscoveredDevicePtr = devicePtr, 104 | Driver = driverStruct, 105 | }; 106 | 107 | result.Add(managedDevice); 108 | } 109 | 110 | return result.ToArray(); 111 | 112 | } 113 | 114 | #endregion 115 | 116 | #region IDisposable Implementation and cleanup 117 | 118 | /// 119 | /// Releases the device discovery results. 120 | /// This is only for internal purposes. 121 | /// 122 | private void ReleaseDeviceDiscoveryResults() 123 | { 124 | if (DeviceDicoveryResultsPtr != IntPtr.Zero) 125 | { 126 | // Destroy the memory allocation that resulted from device discovery 127 | Interop.fp_dscv_devs_free(DeviceDicoveryResultsPtr); 128 | DeviceDicoveryResultsPtr = IntPtr.Zero; 129 | } 130 | } 131 | 132 | /// 133 | public void Dispose() 134 | { 135 | Dispose(true); 136 | GC.SuppressFinalize(this); 137 | } 138 | 139 | /// 140 | /// Finalizes an instance of the class. 141 | /// 142 | ~FingerprintDeviceManager() 143 | { 144 | // Finalizer calls Dispose(false) 145 | Dispose(false); 146 | } 147 | 148 | /// 149 | /// Releases unmanaged and - optionally - managed resources. 150 | /// 151 | /// true to release both managed and unmanaged resources; false to release only unmanaged resources. 152 | private void Dispose(bool releaseOnlyManaged) 153 | { 154 | if (releaseOnlyManaged) 155 | { 156 | return; 157 | } 158 | 159 | // free native resources if there are any. 160 | if (IsInitialized) 161 | { 162 | ReleaseDeviceDiscoveryResults(); 163 | Interop.fp_exit(); 164 | IsInitialized = false; 165 | } 166 | 167 | // remove the reference to the singleton so it can be recreated. 168 | m_Instance = null; 169 | } 170 | 171 | #endregion 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/FingerprintGallery.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | /// 8 | /// Provides means to keeping a fingerprint database. 9 | /// A fingerprint gallery is needed for fingerprint identification. 10 | /// Fingerprints can be loaded from byte arrays or enrollment results. 11 | /// 12 | public class FingerprintGallery : IDisposable 13 | { 14 | #region Support Classes 15 | 16 | /// 17 | /// Tuple holding Identifier-Pointer pairs. 18 | /// Keys are strings, while values are pointers to fingerprint data. 19 | /// 20 | private class Fingerprint 21 | { 22 | public IntPtr Reference { get; set; } 23 | public string Identifier { get; set; } 24 | } 25 | 26 | #endregion 27 | 28 | #region Properties 29 | 30 | /// 31 | /// This is an ordered list of Fingerprint tuples (key-pointer pairs) 32 | /// This is basically an in-memory database. 33 | /// 34 | private readonly List InternalList = new List(); 35 | 36 | /// 37 | /// An ordered array of pointers to match an index when identification is required. 38 | /// Whenever the internal list changes, this array gets rebuilt. 39 | /// 40 | /// 41 | /// The pointer array. 42 | /// 43 | internal IntPtr[] PointerArray { get; private set; } 44 | 45 | #endregion 46 | 47 | #region Methods 48 | 49 | /// 50 | /// Initializes a new instance of the class. 51 | /// 52 | public FingerprintGallery() 53 | { 54 | if (FingerprintDeviceManager.Instance.IsInitialized == false) 55 | FingerprintDeviceManager.Instance.Initialize(); 56 | 57 | RebuildPointerArray(); 58 | } 59 | 60 | /// 61 | /// Rebuilds the pointer array. 62 | /// This method needs to be called whenever the Internal List gets modified in any way. 63 | /// 64 | private void RebuildPointerArray() 65 | { 66 | PointerArray = new IntPtr[InternalList.Count+1]; 67 | for (var i = 0; i < InternalList.Count; i++) 68 | PointerArray[i] = InternalList[i].Reference; 69 | PointerArray[InternalList.Count] = IntPtr.Zero; 70 | } 71 | 72 | /// 73 | /// Registers the supplied fingerprint data, associating it with the given key. 74 | /// 75 | /// The key. 76 | /// The fingerprint data. 77 | /// 78 | /// fingerprintData is invalid 79 | /// or 80 | /// key needs to contain a valid string. 81 | /// 82 | /// The fingerprint data buffer is invalid. 83 | private void RegisterFingerprintData(string key, byte[] fingerprintData) 84 | { 85 | if (fingerprintData == null || fingerprintData.Length <= 0) 86 | throw new ArgumentException("fingerprintData is invalid"); 87 | 88 | if (string.IsNullOrWhiteSpace(key)) 89 | throw new ArgumentException("key needs to contain a valid string"); 90 | 91 | var bufferLength = Convert.ToUInt32(fingerprintData.Length); 92 | var printDataFromBufferPtr = Interop.fp_print_data_from_data(fingerprintData, bufferLength); 93 | if (printDataFromBufferPtr == IntPtr.Zero) 94 | throw new FormatException("The fingerprint data buffer is invalid."); 95 | 96 | if (HasKey(key)) 97 | Remove(key, false); 98 | 99 | InternalList.Add(new Fingerprint() { Identifier = key, Reference = printDataFromBufferPtr }); 100 | } 101 | 102 | /// 103 | /// Adds the specified fingerprint data and associates it with the specified key. 104 | /// 105 | /// The key. 106 | /// The fingerprint data. 107 | public void Add(string key, byte[] fingerprintData) 108 | { 109 | RegisterFingerprintData(key, fingerprintData); 110 | RebuildPointerArray(); 111 | } 112 | 113 | /// 114 | /// Adds the specified fingerprint data and associates it with the specified key. 115 | /// 116 | /// The key. 117 | /// The enroll result. 118 | public void Add(string key, EnrollStageResult enrollResult) 119 | { 120 | Add(key, enrollResult.FingerprintData); 121 | } 122 | 123 | /// 124 | /// Adds the specified fingerprint key-value pairs to the gallery. 125 | /// This is the preferred method for bulk loading as it does not rebuild the database 126 | /// for every fingerprint. 127 | /// 128 | /// The fingerprints. 129 | public void AddRange(IEnumerable> fingerprints) 130 | { 131 | foreach (var (key, data) in fingerprints) 132 | { 133 | RegisterFingerprintData(key, data); 134 | } 135 | 136 | RebuildPointerArray(); 137 | } 138 | 139 | /// 140 | /// Gets the key with the specified offset. 141 | /// 142 | /// 143 | /// The . 144 | /// 145 | /// The offset. 146 | /// 147 | public string this[int offset] => InternalList[offset].Identifier; 148 | 149 | /// 150 | /// Determines whether the gallery contains the specified keys. 151 | /// 152 | /// The key. 153 | /// 154 | public bool HasKey(string key) => AllKeys().Contains(key); 155 | 156 | /// 157 | /// Gets all the keys registered in this gallery. 158 | /// 159 | /// 160 | public string[] AllKeys() => InternalList.Select(s => s.Identifier).ToArray(); 161 | 162 | /// 163 | /// Removes a fingerprint from the gallery given its key. 164 | /// 165 | /// The key. 166 | public void Remove(string key) => Remove(key, true); 167 | 168 | /// 169 | /// Removes a fingerprint from the gallery given its key. 170 | /// 171 | /// The key. 172 | /// if set to true rebuilds the pointer array. 173 | /// The key identifier was not found. 174 | private void Remove(string key, bool rebuild) 175 | { 176 | var items = InternalList.Where(f => f.Identifier.Equals(key)).ToArray(); 177 | if (items.Length == 0) 178 | throw new KeyNotFoundException("The key identifier was not found."); 179 | 180 | InternalList.Remove(items[0]); 181 | Interop.fp_print_data_free(items[0].Reference); 182 | 183 | if (rebuild) 184 | RebuildPointerArray(); 185 | } 186 | 187 | /// 188 | /// Gets the fingerprint pointer. 189 | /// 190 | /// The key. 191 | /// 192 | internal IntPtr GetFingerprintPointer(string key) => HasKey(key) ? InternalList.FirstOrDefault(f => f.Identifier.Equals(key)).Reference : IntPtr.Zero; 193 | 194 | #endregion 195 | 196 | #region IDisposable Implementation 197 | 198 | /// 199 | public void Dispose() 200 | { 201 | Dispose(true); 202 | GC.SuppressFinalize(this); 203 | } 204 | 205 | ~FingerprintGallery() 206 | { 207 | // Finalizer calls Dispose(false) 208 | Dispose(false); 209 | } 210 | 211 | /// 212 | /// Releases unmanaged and - optionally - managed resources. 213 | /// 214 | /// true to release both managed and unmanaged resources; false to release only unmanaged resources. 215 | protected virtual void Dispose(bool releaseOnlyManaged) 216 | { 217 | if (releaseOnlyManaged) 218 | { 219 | return; 220 | } 221 | 222 | // free native resources if there are any. 223 | foreach (var fingerprintPtr in PointerArray) 224 | { 225 | if (fingerprintPtr != IntPtr.Zero) 226 | Interop.fp_print_data_free(fingerprintPtr); 227 | } 228 | } 229 | 230 | #endregion 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/Interop.Types.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Unosquare.Labs.LibFprint 4 | { 5 | partial class Interop 6 | { 7 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 8 | public struct GSList 9 | { 10 | 11 | /// gpointer->void* 12 | public IntPtr data; 13 | 14 | /// GSList* 15 | public IntPtr next; 16 | } 17 | 18 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 19 | public struct libusb_device_handle 20 | { 21 | } 22 | 23 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 24 | public struct libusb_device_descriptor 25 | { 26 | 27 | /// uint8_t->unsigned char 28 | public byte bLength; 29 | 30 | /// uint8_t->unsigned char 31 | public byte bDescriptorType; 32 | 33 | /// uint16_t->unsigned short 34 | public ushort bcdUSB; 35 | 36 | /// uint8_t->unsigned char 37 | public byte bDeviceClass; 38 | 39 | /// uint8_t->unsigned char 40 | public byte bDeviceSubClass; 41 | 42 | /// uint8_t->unsigned char 43 | public byte bDeviceProtocol; 44 | 45 | /// uint8_t->unsigned char 46 | public byte bMaxPacketSize0; 47 | 48 | /// uint16_t->unsigned short 49 | public ushort idVendor; 50 | 51 | /// uint16_t->unsigned short 52 | public ushort idProduct; 53 | 54 | /// uint16_t->unsigned short 55 | public ushort bcdDevice; 56 | 57 | /// uint8_t->unsigned char 58 | public byte iManufacturer; 59 | 60 | /// uint8_t->unsigned char 61 | public byte iProduct; 62 | 63 | /// uint8_t->unsigned char 64 | public byte iSerialNumber; 65 | 66 | /// uint8_t->unsigned char 67 | public byte bNumConfigurations; 68 | } 69 | 70 | public enum fp_dev_state 71 | { 72 | 73 | /// DEV_STATE_INITIAL -> 0 74 | DEV_STATE_INITIAL = 0, 75 | 76 | DEV_STATE_ERROR, 77 | 78 | DEV_STATE_INITIALIZING, 79 | 80 | DEV_STATE_INITIALIZED, 81 | 82 | DEV_STATE_DEINITIALIZING, 83 | 84 | DEV_STATE_DEINITIALIZED, 85 | 86 | DEV_STATE_ENROLL_STARTING, 87 | 88 | DEV_STATE_ENROLLING, 89 | 90 | DEV_STATE_ENROLL_STOPPING, 91 | 92 | DEV_STATE_VERIFY_STARTING, 93 | 94 | DEV_STATE_VERIFYING, 95 | 96 | DEV_STATE_VERIFY_DONE, 97 | 98 | DEV_STATE_VERIFY_STOPPING, 99 | 100 | DEV_STATE_IDENTIFY_STARTING, 101 | 102 | DEV_STATE_IDENTIFYING, 103 | 104 | DEV_STATE_IDENTIFY_DONE, 105 | 106 | DEV_STATE_IDENTIFY_STOPPING, 107 | 108 | DEV_STATE_CAPTURE_STARTING, 109 | 110 | DEV_STATE_CAPTURING, 111 | 112 | DEV_STATE_CAPTURE_DONE, 113 | 114 | DEV_STATE_CAPTURE_STOPPING, 115 | } 116 | 117 | public enum fp_driver_type 118 | { 119 | 120 | /// DRIVER_PRIMITIVE -> 0 121 | DRIVER_PRIMITIVE = 0, 122 | 123 | /// DRIVER_IMAGING -> 1 124 | DRIVER_IMAGING = 1, 125 | } 126 | 127 | public enum fp_print_data_type 128 | { 129 | 130 | /// PRINT_DATA_RAW -> 0 131 | PRINT_DATA_RAW = 0, 132 | 133 | PRINT_DATA_NBIS_MINUTIAE, 134 | } 135 | 136 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 137 | public struct fp_dscv_dev 138 | { 139 | 140 | /// libusb_device* 141 | public IntPtr udev; 142 | 143 | /// fp_driver* 144 | public IntPtr drv; 145 | 146 | /// unsigned int 147 | public uint driver_data; 148 | 149 | /// uint32_t->unsigned int 150 | public uint devtype; 151 | } 152 | 153 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 154 | public struct fp_dscv_print 155 | { 156 | 157 | /// uint16_t->unsigned short 158 | public ushort driver_id; 159 | 160 | /// uint32_t->unsigned int 161 | public uint devtype; 162 | 163 | /// fp_finger 164 | public fp_finger finger; 165 | 166 | /// char* 167 | [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] 168 | public string path; 169 | } 170 | 171 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 172 | public struct fp_dev 173 | { 174 | 175 | /// fp_driver* 176 | public IntPtr drv; 177 | 178 | /// libusb_device_handle* 179 | public IntPtr udev; 180 | 181 | /// uint32_t->unsigned int 182 | public uint devtype; 183 | 184 | /// void* 185 | public IntPtr priv; 186 | 187 | /// int 188 | public int nr_enroll_stages; 189 | 190 | /// fp_print_data* 191 | public IntPtr verify_data; 192 | 193 | /// fp_dev_state 194 | public fp_dev_state state; 195 | 196 | /// int 197 | public int @__enroll_stage; 198 | 199 | /// int 200 | public int unconditional_capture; 201 | 202 | /// fp_dev_open_cb 203 | public fp_dev_open_cb open_cb; 204 | 205 | /// void* 206 | public IntPtr open_cb_data; 207 | 208 | /// fp_dev_close_cb 209 | public fp_dev_close_cb close_cb; 210 | 211 | /// void* 212 | public IntPtr close_cb_data; 213 | 214 | /// fp_enroll_stage_cb 215 | public fp_enroll_stage_cb enroll_stage_cb; 216 | 217 | /// void* 218 | public IntPtr enroll_stage_cb_data; 219 | 220 | /// fp_enroll_stop_cb 221 | public fp_enroll_stop_cb enroll_stop_cb; 222 | 223 | /// void* 224 | public IntPtr enroll_stop_cb_data; 225 | 226 | /// fp_verify_cb 227 | public fp_verify_cb verify_cb; 228 | 229 | /// void* 230 | public IntPtr verify_cb_data; 231 | 232 | /// fp_verify_stop_cb 233 | public fp_verify_stop_cb verify_stop_cb; 234 | 235 | /// void* 236 | public IntPtr verify_stop_cb_data; 237 | 238 | /// fp_identify_cb 239 | public fp_identify_cb identify_cb; 240 | 241 | /// void* 242 | public IntPtr identify_cb_data; 243 | 244 | /// fp_identify_stop_cb 245 | public fp_identify_stop_cb identify_stop_cb; 246 | 247 | /// void* 248 | public IntPtr identify_stop_cb_data; 249 | 250 | /// fp_capture_cb 251 | public fp_capture_cb capture_cb; 252 | 253 | /// void* 254 | public IntPtr capture_cb_data; 255 | 256 | /// fp_capture_stop_cb 257 | public fp_capture_stop_cb capture_stop_cb; 258 | 259 | /// void* 260 | public IntPtr capture_stop_cb_data; 261 | 262 | /// fp_print_data** 263 | public IntPtr identify_gallery; 264 | } 265 | 266 | /// Return Type: int 267 | ///dsc: libusb_device_descriptor* 268 | ///devtype: uint32_t* 269 | public delegate int fp_driver_discover(ref libusb_device_descriptor dsc, ref uint devtype); 270 | 271 | /// Return Type: int 272 | ///dev: fp_dev* 273 | ///driver_data: unsigned int 274 | public delegate int fp_driver_open(ref fp_dev dev, uint driver_data); 275 | 276 | /// Return Type: void 277 | ///dev: fp_dev* 278 | public delegate void fp_driver_close(ref fp_dev dev); 279 | 280 | /// Return Type: int 281 | ///dev: fp_dev* 282 | public delegate int fp_driver_enroll_start(ref fp_dev dev); 283 | 284 | /// Return Type: int 285 | ///dev: fp_dev* 286 | public delegate int fp_driver_enroll_stop(ref fp_dev dev); 287 | 288 | /// Return Type: int 289 | ///dev: fp_dev* 290 | public delegate int fp_driver_verify_start(ref fp_dev dev); 291 | 292 | /// Return Type: int 293 | ///dev: fp_dev* 294 | ///iterating: gboolean->gint->int 295 | public delegate int fp_driver_verify_stop(ref fp_dev dev, int iterating); 296 | 297 | /// Return Type: int 298 | ///dev: fp_dev* 299 | public delegate int fp_driver_identify_start(ref fp_dev dev); 300 | 301 | /// Return Type: int 302 | ///dev: fp_dev* 303 | ///iterating: gboolean->gint->int 304 | public delegate int fp_driver_identify_stop(ref fp_dev dev, int iterating); 305 | 306 | /// Return Type: int 307 | ///dev: fp_dev* 308 | public delegate int fp_driver_capture_start(ref fp_dev dev); 309 | 310 | /// Return Type: int 311 | ///dev: fp_dev* 312 | public delegate int fp_driver_capture_stop(ref fp_dev dev); 313 | 314 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 315 | public struct fp_driver 316 | { 317 | 318 | /// uint16_t->unsigned short 319 | public ushort id; 320 | 321 | /// char* 322 | [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] 323 | public string name; 324 | 325 | /// char* 326 | [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)] 327 | public string full_name; 328 | 329 | /// usb_id* 330 | public IntPtr id_table; 331 | 332 | /// fp_driver_type 333 | public fp_driver_type type; 334 | 335 | /// fp_scan_type 336 | public fp_scan_type scan_type; 337 | 338 | /// void* 339 | public IntPtr priv; 340 | 341 | /// fp_driver_discover 342 | public fp_driver_discover AnonymousMember1; 343 | 344 | /// fp_driver_open 345 | public fp_driver_open AnonymousMember2; 346 | 347 | /// fp_driver_close 348 | public fp_driver_close AnonymousMember3; 349 | 350 | /// fp_driver_enroll_start 351 | public fp_driver_enroll_start AnonymousMember4; 352 | 353 | /// fp_driver_enroll_stop 354 | public fp_driver_enroll_stop AnonymousMember5; 355 | 356 | /// fp_driver_verify_start 357 | public fp_driver_verify_start AnonymousMember6; 358 | 359 | /// fp_driver_verify_stop 360 | public fp_driver_verify_stop AnonymousMember7; 361 | 362 | /// fp_driver_identify_start 363 | public fp_driver_identify_start AnonymousMember8; 364 | 365 | /// fp_driver_identify_stop 366 | public fp_driver_identify_stop AnonymousMember9; 367 | 368 | /// fp_driver_capture_start 369 | public fp_driver_capture_start AnonymousMember10; 370 | 371 | /// fp_driver_capture_stop 372 | public fp_driver_capture_stop AnonymousMember11; 373 | } 374 | 375 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 376 | public struct fp_print_data 377 | { 378 | 379 | /// uint16_t->unsigned short 380 | public ushort driver_id; 381 | 382 | /// uint32_t->unsigned int 383 | public uint devtype; 384 | 385 | /// fp_print_data_type 386 | public fp_print_data_type type; 387 | 388 | /// GSList* 389 | public IntPtr prints; 390 | } 391 | 392 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)] 393 | public struct fp_img 394 | { 395 | 396 | /// int 397 | public int width; 398 | 399 | /// int 400 | public int height; 401 | 402 | /// size_t->unsigned int 403 | public uint length; 404 | 405 | /// uint16_t->unsigned short 406 | public ushort flags; 407 | 408 | /// fp_minutiae* 409 | public IntPtr minutiae; 410 | 411 | /// unsigned char* 412 | public IntPtr binarized; 413 | 414 | /// unsigned char[0] 415 | public IntPtr data; 416 | } 417 | 418 | public enum fp_finger 419 | { 420 | 421 | /// LEFT_THUMB -> 1 422 | LEFT_THUMB = 1, 423 | 424 | LEFT_INDEX, 425 | 426 | LEFT_MIDDLE, 427 | 428 | LEFT_RING, 429 | 430 | LEFT_LITTLE, 431 | 432 | RIGHT_THUMB, 433 | 434 | RIGHT_INDEX, 435 | 436 | RIGHT_MIDDLE, 437 | 438 | RIGHT_RING, 439 | 440 | RIGHT_LITTLE, 441 | } 442 | 443 | public enum fp_scan_type 444 | { 445 | 446 | /// FP_SCAN_TYPE_PRESS -> 0 447 | FP_SCAN_TYPE_PRESS = 0, 448 | 449 | FP_SCAN_TYPE_SWIPE, 450 | } 451 | 452 | public enum fp_capture_result 453 | { 454 | 455 | /// FP_CAPTURE_COMPLETE -> 0 456 | FP_CAPTURE_COMPLETE = 0, 457 | 458 | FP_CAPTURE_FAIL, 459 | } 460 | 461 | public enum fp_enroll_result 462 | { 463 | 464 | /// FP_ENROLL_COMPLETE -> 1 465 | FP_ENROLL_COMPLETE = 1, 466 | 467 | FP_ENROLL_FAIL, 468 | 469 | FP_ENROLL_PASS, 470 | 471 | /// FP_ENROLL_RETRY -> 100 472 | FP_ENROLL_RETRY = 100, 473 | 474 | FP_ENROLL_RETRY_TOO_SHORT, 475 | 476 | FP_ENROLL_RETRY_CENTER_FINGER, 477 | 478 | FP_ENROLL_RETRY_REMOVE_FINGER, 479 | } 480 | 481 | public enum fp_verify_result 482 | { 483 | 484 | /// FP_VERIFY_NO_MATCH -> 0 485 | FP_VERIFY_NO_MATCH = 0, 486 | 487 | /// FP_VERIFY_MATCH -> 1 488 | FP_VERIFY_MATCH = 1, 489 | 490 | /// FP_VERIFY_RETRY -> FP_ENROLL_RETRY 491 | FP_VERIFY_RETRY = fp_enroll_result.FP_ENROLL_RETRY, 492 | 493 | /// FP_VERIFY_RETRY_TOO_SHORT -> FP_ENROLL_RETRY_TOO_SHORT 494 | FP_VERIFY_RETRY_TOO_SHORT = fp_enroll_result.FP_ENROLL_RETRY_TOO_SHORT, 495 | 496 | /// FP_VERIFY_RETRY_CENTER_FINGER -> FP_ENROLL_RETRY_CENTER_FINGER 497 | FP_VERIFY_RETRY_CENTER_FINGER = fp_enroll_result.FP_ENROLL_RETRY_CENTER_FINGER, 498 | 499 | /// FP_VERIFY_RETRY_REMOVE_FINGER -> FP_ENROLL_RETRY_REMOVE_FINGER 500 | FP_VERIFY_RETRY_REMOVE_FINGER = fp_enroll_result.FP_ENROLL_RETRY_REMOVE_FINGER, 501 | } 502 | 503 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 504 | public struct fp_minutia 505 | { 506 | 507 | /// int 508 | public int x; 509 | 510 | /// int 511 | public int y; 512 | 513 | /// int 514 | public int ex; 515 | 516 | /// int 517 | public int ey; 518 | 519 | /// int 520 | public int direction; 521 | 522 | /// double 523 | public double reliability; 524 | 525 | /// int 526 | public int type; 527 | 528 | /// int 529 | public int appearing; 530 | 531 | /// int 532 | public int feature_id; 533 | 534 | /// int* 535 | public IntPtr nbrs; 536 | 537 | /// int* 538 | public IntPtr ridge_counts; 539 | 540 | /// int 541 | public int num_nbrs; 542 | } 543 | 544 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 545 | public struct fp_pollfd 546 | { 547 | 548 | /// int 549 | public int fd; 550 | 551 | /// short 552 | public short events; 553 | } 554 | 555 | /// Return Type: void 556 | ///fd: int 557 | ///events: short 558 | public delegate void fp_pollfd_added_cb(int fd, short events); 559 | 560 | /// Return Type: void 561 | ///fd: int 562 | public delegate void fp_pollfd_removed_cb(int fd); 563 | 564 | /// Return Type: void 565 | ///dev: fp_dev* 566 | ///status: int 567 | ///user_data: void* 568 | public delegate void fp_dev_open_cb(ref fp_dev dev, int status, IntPtr user_data); 569 | 570 | /// Return Type: void 571 | ///dev: fp_dev* 572 | ///user_data: void* 573 | public delegate void fp_dev_close_cb(ref fp_dev dev, IntPtr user_data); 574 | 575 | /// Return Type: void 576 | ///dev: fp_dev* 577 | ///result: int 578 | ///print: fp_print_data* 579 | ///img: fp_img* 580 | ///user_data: void* 581 | public delegate void fp_enroll_stage_cb(ref fp_dev dev, int result, ref fp_print_data print, ref fp_img img, IntPtr user_data); 582 | 583 | /// Return Type: void 584 | ///dev: fp_dev* 585 | ///user_data: void* 586 | public delegate void fp_enroll_stop_cb(ref fp_dev dev, IntPtr user_data); 587 | 588 | /// Return Type: void 589 | ///dev: fp_dev* 590 | ///result: int 591 | ///img: fp_img* 592 | ///user_data: void* 593 | public delegate void fp_verify_cb(ref fp_dev dev, int result, ref fp_img img, IntPtr user_data); 594 | 595 | /// Return Type: void 596 | ///dev: fp_dev* 597 | ///user_data: void* 598 | public delegate void fp_verify_stop_cb(ref fp_dev dev, IntPtr user_data); 599 | 600 | /// Return Type: void 601 | ///dev: fp_dev* 602 | ///result: int 603 | ///match_offset: size_t->unsigned int 604 | ///img: fp_img* 605 | ///user_data: void* 606 | public delegate void fp_identify_cb(ref fp_dev dev, int result, IntPtr match_offset, ref fp_img img, IntPtr user_data); 607 | 608 | /// Return Type: void 609 | ///dev: fp_dev* 610 | ///user_data: void* 611 | public delegate void fp_identify_stop_cb(ref fp_dev dev, IntPtr user_data); 612 | 613 | /// Return Type: void 614 | ///dev: fp_dev* 615 | ///result: int 616 | ///img: fp_img* 617 | ///user_data: void* 618 | public delegate void fp_capture_cb(ref fp_dev dev, int result, ref fp_img img, IntPtr user_data); 619 | 620 | /// Return Type: void 621 | ///dev: fp_dev* 622 | ///user_data: void* 623 | public delegate void fp_capture_stop_cb(ref fp_dev dev, IntPtr user_data); 624 | 625 | [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 626 | public struct timeval 627 | { 628 | 629 | /// int 630 | public int tv_sec; 631 | 632 | /// int 633 | public int tv_usec; 634 | } 635 | } 636 | } 637 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/Interop.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Unosquare.Labs.LibFprint 5 | { 6 | /// 7 | /// This file was generated automatically. -- Only very few manual modifications were made. 8 | /// 9 | internal partial class Interop 10 | { 11 | private const string FingerprintLibrary = "libfprint.so"; 12 | 13 | /// Return Type: char* 14 | ///drv: fp_driver* 15 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_driver_get_name")] 16 | public static extern IntPtr fp_driver_get_name(ref fp_driver drv); 17 | 18 | 19 | /// Return Type: char* 20 | ///drv: fp_driver* 21 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_driver_get_full_name")] 22 | public static extern IntPtr fp_driver_get_full_name(ref fp_driver drv); 23 | 24 | 25 | /// Return Type: uint16_t->unsigned short 26 | ///drv: fp_driver* 27 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_driver_get_driver_id")] 28 | public static extern ushort fp_driver_get_driver_id(ref fp_driver drv); 29 | 30 | 31 | /// Return Type: fp_scan_type 32 | ///drv: fp_driver* 33 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_driver_get_scan_type")] 34 | public static extern fp_scan_type fp_driver_get_scan_type(ref fp_driver drv); 35 | 36 | 37 | /// Return Type: fp_dscv_dev** 38 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_discover_devs")] 39 | public static extern IntPtr fp_discover_devs(); 40 | 41 | public static IntPtr[] fp_discover_devs_pointers(out IntPtr arrayPtr) 42 | { 43 | 44 | var baseAddress = fp_discover_devs(); 45 | arrayPtr = baseAddress; 46 | 47 | return baseAddress.ToPointerArray(); 48 | } 49 | 50 | public static fp_dscv_dev[] fp_discover_devs_structus(out IntPtr arrayPtr) 51 | { 52 | var devices = new List(); 53 | var devicePtrs = fp_discover_devs_pointers(out arrayPtr); 54 | 55 | foreach (var devicePtr in devicePtrs) 56 | { 57 | var device = devicePtr.DereferencePtr(); 58 | devices.Add(device); 59 | } 60 | 61 | return devices.ToArray(); 62 | } 63 | 64 | /// Return Type: void 65 | ///devs: fp_dscv_dev** 66 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_devs_free")] 67 | public static extern void fp_dscv_devs_free(IntPtr devs); 68 | 69 | 70 | /// Return Type: fp_driver* 71 | ///dev: fp_dscv_dev* 72 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_get_driver")] 73 | public static extern IntPtr fp_dscv_dev_get_driver(ref fp_dscv_dev dev); 74 | 75 | public static fp_driver fp_dscv_dev_get_driver_struct(ref fp_dscv_dev dev) 76 | { 77 | var ptr = fp_dscv_dev_get_driver(ref dev); 78 | return ptr.DereferencePtr(); 79 | } 80 | 81 | /// Return Type: uint32_t->unsigned int 82 | ///dev: fp_dscv_dev* 83 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_get_devtype")] 84 | public static extern uint fp_dscv_dev_get_devtype(ref fp_dscv_dev dev); 85 | 86 | 87 | /// Return Type: int 88 | ///dev: fp_dscv_dev* 89 | ///print: fp_print_data* 90 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_supports_print_data")] 91 | public static extern int fp_dscv_dev_supports_print_data(ref fp_dscv_dev dev, ref fp_print_data print); 92 | 93 | 94 | /// Return Type: int 95 | ///dev: fp_dscv_dev* 96 | ///print: fp_dscv_print* 97 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_supports_dscv_print")] 98 | public static extern int fp_dscv_dev_supports_dscv_print(ref fp_dscv_dev dev, ref fp_dscv_print print); 99 | 100 | 101 | /// Return Type: fp_dscv_dev* 102 | ///devs: fp_dscv_dev** 103 | ///print: fp_print_data* 104 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_for_print_data")] 105 | public static extern IntPtr fp_dscv_dev_for_print_data(ref IntPtr devs, ref fp_print_data print); 106 | 107 | 108 | /// Return Type: fp_dscv_dev* 109 | ///devs: fp_dscv_dev** 110 | ///print: fp_dscv_print* 111 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_for_dscv_print")] 112 | public static extern IntPtr fp_dscv_dev_for_dscv_print(ref IntPtr devs, ref fp_dscv_print print); 113 | 114 | 115 | /// Return Type: uint16_t->unsigned short 116 | ///dev: fp_dscv_dev* 117 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_dev_get_driver_id")] 118 | public static extern ushort fp_dscv_dev_get_driver_id(ref fp_dscv_dev dev); 119 | 120 | 121 | /// Return Type: fp_dscv_print** 122 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_discover_prints")] 123 | public static extern IntPtr fp_discover_prints(); 124 | 125 | 126 | /// Return Type: void 127 | ///prints: fp_dscv_print** 128 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_prints_free")] 129 | public static extern void fp_dscv_prints_free(ref IntPtr prints); 130 | 131 | 132 | /// Return Type: uint16_t->unsigned short 133 | ///print: fp_dscv_print* 134 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_print_get_driver_id")] 135 | public static extern ushort fp_dscv_print_get_driver_id(ref fp_dscv_print print); 136 | 137 | 138 | /// Return Type: uint32_t->unsigned int 139 | ///print: fp_dscv_print* 140 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_print_get_devtype")] 141 | public static extern uint fp_dscv_print_get_devtype(ref fp_dscv_print print); 142 | 143 | 144 | /// Return Type: fp_finger 145 | ///print: fp_dscv_print* 146 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_print_get_finger")] 147 | public static extern fp_finger fp_dscv_print_get_finger(ref fp_dscv_print print); 148 | 149 | 150 | /// Return Type: int 151 | ///print: fp_dscv_print* 152 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dscv_print_delete")] 153 | public static extern int fp_dscv_print_delete(ref fp_dscv_print print); 154 | 155 | 156 | /// Return Type: fp_dev* 157 | ///ddev: fp_dscv_dev* 158 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_open")] 159 | public static extern IntPtr fp_dev_open(IntPtr ddev); 160 | 161 | public static fp_dev fp_dev_open_struct(IntPtr ddev, out IntPtr devicePtr) 162 | { 163 | devicePtr = fp_dev_open(ddev); 164 | return devicePtr.DereferencePtr(); 165 | } 166 | 167 | /// Return Type: void 168 | ///dev: fp_dev* 169 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_close")] 170 | public static extern void fp_dev_close(IntPtr dev); 171 | 172 | 173 | /// Return Type: fp_driver* 174 | ///dev: fp_dev* 175 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_get_driver")] 176 | public static extern IntPtr fp_dev_get_driver(ref fp_dev dev); 177 | 178 | 179 | /// Return Type: int 180 | ///dev: fp_dev* 181 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_get_nr_enroll_stages")] 182 | public static extern int fp_dev_get_nr_enroll_stages(ref fp_dev dev); 183 | 184 | 185 | /// Return Type: uint32_t->unsigned int 186 | ///dev: fp_dev* 187 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_get_devtype")] 188 | public static extern uint fp_dev_get_devtype(ref fp_dev dev); 189 | 190 | 191 | /// Return Type: int 192 | ///dev: fp_dev* 193 | ///data: fp_print_data* 194 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_supports_print_data")] 195 | public static extern int fp_dev_supports_print_data(ref fp_dev dev, ref fp_print_data data); 196 | 197 | 198 | /// Return Type: int 199 | ///dev: fp_dev* 200 | ///print: fp_dscv_print* 201 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_supports_dscv_print")] 202 | public static extern int fp_dev_supports_dscv_print(ref fp_dev dev, ref fp_dscv_print print); 203 | 204 | 205 | /// Return Type: int 206 | ///dev: fp_dev* 207 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_supports_imaging")] 208 | public static extern int fp_dev_supports_imaging(ref fp_dev dev); 209 | 210 | 211 | /// Return Type: int 212 | ///dev: fp_dev* 213 | ///unconditional: int 214 | ///image: fp_img** 215 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_img_capture")] 216 | public static extern int fp_dev_img_capture(IntPtr dev, int unconditional, IntPtr image); 217 | 218 | 219 | /// Return Type: int 220 | ///dev: fp_dev* 221 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_get_img_width")] 222 | public static extern int fp_dev_get_img_width(ref fp_dev dev); 223 | 224 | 225 | /// Return Type: int 226 | ///dev: fp_dev* 227 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_get_img_height")] 228 | public static extern int fp_dev_get_img_height(ref fp_dev dev); 229 | 230 | 231 | /// Return Type: int 232 | ///dev: fp_dev* 233 | ///print_data: fp_print_data** 234 | ///img: fp_img** 235 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_enroll_finger_img")] 236 | public static extern int fp_enroll_finger_img(IntPtr dev, out IntPtr print_data, out IntPtr img); 237 | 238 | 239 | /// Return Type: int 240 | ///dev: fp_dev* 241 | ///print_data: fp_print_data** 242 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_enroll_finger")] 243 | public static extern int fp_enroll_finger(ref fp_dev dev, ref IntPtr print_data); 244 | 245 | 246 | /// Return Type: int 247 | ///dev: fp_dev* 248 | ///enrolled_print: fp_print_data* 249 | ///img: fp_img** 250 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_verify_finger_img")] 251 | public static extern int fp_verify_finger_img(IntPtr dev, IntPtr enrolled_print, out IntPtr img); 252 | 253 | 254 | /// Return Type: int 255 | ///dev: fp_dev* 256 | ///enrolled_print: fp_print_data* 257 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_verify_finger")] 258 | public static extern int fp_verify_finger(ref fp_dev dev, ref fp_print_data enrolled_print); 259 | 260 | 261 | /// Return Type: int 262 | ///dev: fp_dev* 263 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_dev_supports_identification")] 264 | public static extern int fp_dev_supports_identification(ref fp_dev dev); 265 | 266 | 267 | /// Return Type: int 268 | ///dev: fp_dev* 269 | ///print_gallery: fp_print_data** 270 | ///match_offset: size_t* 271 | ///img: fp_img** 272 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_identify_finger_img")] 273 | public static extern int fp_identify_finger_img(IntPtr dev, IntPtr[] print_gallery, out uint match_offset, out IntPtr img); 274 | 275 | 276 | /// Return Type: int 277 | ///dev: fp_dev* 278 | ///print_gallery: fp_print_data** 279 | ///match_offset: size_t* 280 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_identify_finger")] 281 | public static extern int fp_identify_finger(IntPtr dev, ref fp_print_data[] print_gallery, ref uint match_offset); 282 | 283 | 284 | /// Return Type: int 285 | ///dev: fp_dev* 286 | ///finger: fp_finger 287 | ///data: fp_print_data** 288 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_load")] 289 | public static extern int fp_print_data_load(ref fp_dev dev, fp_finger finger, ref IntPtr data); 290 | 291 | 292 | /// Return Type: int 293 | ///print: fp_dscv_print* 294 | ///data: fp_print_data** 295 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_from_dscv_print")] 296 | public static extern int fp_print_data_from_dscv_print(ref fp_dscv_print print, ref IntPtr data); 297 | 298 | 299 | /// Return Type: int 300 | ///data: fp_print_data* 301 | ///finger: fp_finger 302 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_save")] 303 | public static extern int fp_print_data_save(ref fp_print_data data, fp_finger finger); 304 | 305 | 306 | /// Return Type: int 307 | ///dev: fp_dev* 308 | ///finger: fp_finger 309 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_delete")] 310 | public static extern int fp_print_data_delete(ref fp_dev dev, fp_finger finger); 311 | 312 | 313 | /// Return Type: void 314 | ///data: fp_print_data* 315 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_free")] 316 | public static extern void fp_print_data_free(IntPtr data); 317 | 318 | 319 | /// Return Type: size_t->unsigned int 320 | ///data: fp_print_data* 321 | ///ret: unsigned char** 322 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_get_data")] 323 | [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysUInt)] 324 | public static extern uint fp_print_data_get_data(IntPtr data, out IntPtr ret); 325 | 326 | 327 | /// Return Type: fp_print_data* 328 | ///buf: unsigned char* 329 | ///buflen: size_t->unsigned int 330 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_from_data")] 331 | public static extern IntPtr fp_print_data_from_data( 332 | byte[] buf 333 | ,[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysUInt)] uint buflen); 334 | 335 | 336 | /// Return Type: uint16_t->unsigned short 337 | ///data: fp_print_data* 338 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_get_driver_id")] 339 | public static extern ushort fp_print_data_get_driver_id(ref fp_print_data data); 340 | 341 | 342 | /// Return Type: uint32_t->unsigned int 343 | ///data: fp_print_data* 344 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_print_data_get_devtype")] 345 | public static extern uint fp_print_data_get_devtype(ref fp_print_data data); 346 | 347 | 348 | /// Return Type: int 349 | ///img: fp_img* 350 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_get_height")] 351 | public static extern int fp_img_get_height(ref fp_img img); 352 | 353 | 354 | /// Return Type: int 355 | ///img: fp_img* 356 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_get_width")] 357 | public static extern int fp_img_get_width(ref fp_img img); 358 | 359 | 360 | /// Return Type: unsigned char* 361 | ///img: fp_img* 362 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_get_data")] 363 | public static extern IntPtr fp_img_get_data(ref fp_img img); 364 | 365 | 366 | /// Return Type: int 367 | ///img: fp_img* 368 | ///path: char* 369 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_save_to_file")] 370 | public static extern int fp_img_save_to_file(IntPtr img, string path); 371 | 372 | 373 | /// Return Type: void 374 | ///img: fp_img* 375 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_standardize")] 376 | public static extern void fp_img_standardize(ref fp_img img); 377 | 378 | 379 | /// Return Type: fp_img* 380 | ///img: fp_img* 381 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_binarize")] 382 | public static extern IntPtr fp_img_binarize(ref fp_img img); 383 | 384 | 385 | /// Return Type: fp_minutia** 386 | ///img: fp_img* 387 | ///nr_minutiae: int* 388 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_get_minutiae")] 389 | public static extern IntPtr fp_img_get_minutiae(ref fp_img img, ref int nr_minutiae); 390 | 391 | 392 | /// Return Type: void 393 | ///img: fp_img* 394 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_img_free")] 395 | public static extern void fp_img_free(IntPtr img); 396 | 397 | 398 | /// Return Type: int 399 | ///timeout: timeval* 400 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_handle_events_timeout")] 401 | public static extern int fp_handle_events_timeout(ref timeval timeout); 402 | 403 | 404 | /// Return Type: int 405 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_handle_events")] 406 | public static extern int fp_handle_events(); 407 | 408 | 409 | /// Return Type: size_t->unsigned int 410 | ///pollfds: fp_pollfd** 411 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_get_pollfds")] 412 | [return: System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.SysUInt)] 413 | public static extern uint fp_get_pollfds(ref IntPtr pollfds); 414 | 415 | 416 | /// Return Type: int 417 | ///tv: timeval* 418 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_get_next_timeout")] 419 | public static extern int fp_get_next_timeout(ref timeval tv); 420 | 421 | 422 | /// Return Type: void 423 | ///added_cb: fp_pollfd_added_cb 424 | ///removed_cb: fp_pollfd_removed_cb 425 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_set_pollfd_notifiers")] 426 | public static extern void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb, fp_pollfd_removed_cb removed_cb); 427 | 428 | 429 | /// Return Type: int 430 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_init")] 431 | public static extern int fp_init(); 432 | 433 | 434 | /// Return Type: void 435 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_exit")] 436 | public static extern void fp_exit(); 437 | 438 | 439 | /// Return Type: void 440 | ///level: int 441 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_set_debug")] 442 | public static extern void fp_set_debug(int level); 443 | 444 | 445 | /// Return Type: int 446 | ///ddev: fp_dscv_dev* 447 | ///callback: fp_dev_open_cb 448 | ///user_data: void* 449 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_dev_open")] 450 | public static extern int fp_async_dev_open(ref fp_dscv_dev ddev, fp_dev_open_cb callback, IntPtr user_data); 451 | 452 | 453 | /// Return Type: void 454 | ///dev: fp_dev* 455 | ///callback: fp_dev_close_cb 456 | ///user_data: void* 457 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_dev_close")] 458 | public static extern void fp_async_dev_close(ref fp_dev dev, fp_dev_close_cb callback, IntPtr user_data); 459 | 460 | 461 | /// Return Type: int 462 | ///dev: fp_dev* 463 | ///callback: fp_enroll_stage_cb 464 | ///user_data: void* 465 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_enroll_start")] 466 | public static extern int fp_async_enroll_start(ref fp_dev dev, fp_enroll_stage_cb callback, IntPtr user_data); 467 | 468 | 469 | /// Return Type: int 470 | ///dev: fp_dev* 471 | ///callback: fp_enroll_stop_cb 472 | ///user_data: void* 473 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_enroll_stop")] 474 | public static extern int fp_async_enroll_stop(ref fp_dev dev, fp_enroll_stop_cb callback, IntPtr user_data); 475 | 476 | 477 | /// Return Type: int 478 | ///dev: fp_dev* 479 | ///data: fp_print_data* 480 | ///callback: fp_verify_cb 481 | ///user_data: void* 482 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_verify_start")] 483 | public static extern int fp_async_verify_start(ref fp_dev dev, ref fp_print_data data, fp_verify_cb callback, IntPtr user_data); 484 | 485 | 486 | /// Return Type: int 487 | ///dev: fp_dev* 488 | ///callback: fp_verify_stop_cb 489 | ///user_data: void* 490 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_verify_stop")] 491 | public static extern int fp_async_verify_stop(ref fp_dev dev, fp_verify_stop_cb callback, IntPtr user_data); 492 | 493 | 494 | /// Return Type: int 495 | ///dev: fp_dev* 496 | ///gallery: fp_print_data** 497 | ///callback: fp_identify_cb 498 | ///user_data: void* 499 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_identify_start")] 500 | public static extern int fp_async_identify_start(ref fp_dev dev, ref IntPtr gallery, fp_identify_cb callback, IntPtr user_data); 501 | 502 | 503 | /// Return Type: int 504 | ///dev: fp_dev* 505 | ///callback: fp_identify_stop_cb 506 | ///user_data: void* 507 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_identify_stop")] 508 | public static extern int fp_async_identify_stop(ref fp_dev dev, fp_identify_stop_cb callback, IntPtr user_data); 509 | 510 | 511 | /// Return Type: int 512 | ///dev: fp_dev* 513 | ///unconditional: int 514 | ///callback: fp_capture_cb 515 | ///user_data: void* 516 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_capture_start")] 517 | public static extern int fp_async_capture_start(ref fp_dev dev, int unconditional, fp_capture_cb callback, IntPtr user_data); 518 | 519 | 520 | /// Return Type: int 521 | ///dev: fp_dev* 522 | ///callback: fp_capture_stop_cb 523 | ///user_data: void* 524 | [System.Runtime.InteropServices.DllImportAttribute(FingerprintLibrary, EntryPoint = "fp_async_capture_stop")] 525 | public static extern int fp_async_capture_stop(ref fp_dev dev, fp_capture_stop_cb callback, IntPtr user_data); 526 | 527 | } 528 | } 529 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/PgmFormatReader.cs: -------------------------------------------------------------------------------- 1 | namespace Unosquare.Labs.LibFprint 2 | { 3 | using System; 4 | using System.Drawing; 5 | using System.Drawing.Imaging; 6 | using System.IO; 7 | using System.Text; 8 | 9 | /// 10 | /// Provides utility methods to read PGM files into Bitmap objects. 11 | /// 12 | public static class PgmFormatReader 13 | { 14 | /// 15 | /// The standard grayscale palette that is loaded in the static constructor. 16 | /// 17 | private static readonly ColorPalette GrayscalePalette; 18 | 19 | /// 20 | /// Initializes the static class. 21 | /// 22 | static PgmFormatReader() 23 | { 24 | // We initialize the palette to 256 colors (grayscale) 25 | // PGM files are always grayscale and we will always represent them in 26 | // 256 shades of gray. 27 | using var dummyBitmap = new Bitmap(1, 1, PixelFormat.Format8bppIndexed); 28 | GrayscalePalette = dummyBitmap.Palette; 29 | for (var i = 0; i < 256; i++) 30 | { 31 | GrayscalePalette.Entries[i] = Color.FromArgb(i, i, i); 32 | } 33 | } 34 | 35 | /// 36 | /// Reads the specified PGM stream and returns a Bitmap. 37 | /// 38 | /// The stream. 39 | /// 40 | /// PGM Magic Number not found. 41 | public static Bitmap Read(Stream stream) 42 | { 43 | using var reader = new BinaryReader(stream, Encoding.ASCII); 44 | if ((reader.ReadChar() == 'P' && reader.ReadChar() == '5') == false) 45 | throw new BadImageFormatException("PGM Magic Number not found."); 46 | 47 | // Read onew whitespace character 48 | reader.ReadChar(); 49 | 50 | // Get basic PGM format properties 51 | var parseBuffer = new StringBuilder(); 52 | var pgmWidth = ReadInteger(reader, parseBuffer); 53 | var pgmHeight = ReadInteger(reader, parseBuffer); 54 | var grayscaleLevels = ReadInteger(reader, parseBuffer); 55 | var isTwoByteLevel = (grayscaleLevels > 255); 56 | 57 | // Create the bitmap and assign the 8bpp Indexed palette 58 | var bmp = new Bitmap(pgmWidth, pgmHeight, PixelFormat.Format8bppIndexed) {Palette = GrayscalePalette}; 59 | 60 | // Create the target lockbits 61 | var bitmapData = bmp.LockBits(new Rectangle(0, 0, pgmWidth, pgmHeight), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); 62 | var rowLengthOffset = bitmapData.Stride - bitmapData.Width; 63 | var dataLength = bitmapData.Stride * bitmapData.Height; 64 | var pixelData = new byte[dataLength]; 65 | 66 | var pixelDataIndex = 0; 67 | 68 | for (var rowIndex = 0; rowIndex < pgmHeight; rowIndex++) 69 | { 70 | for (var columnIndex = 0; columnIndex < pgmWidth; columnIndex++) 71 | { 72 | var currentPixelValue = reader.ReadByte(); 73 | if (isTwoByteLevel) 74 | currentPixelValue = (byte)(((double)((currentPixelValue << 8) + reader.ReadByte()) / grayscaleLevels) * 255.0); 75 | 76 | pixelData[pixelDataIndex] = currentPixelValue; 77 | pixelDataIndex++; 78 | } 79 | 80 | pixelDataIndex += rowLengthOffset; 81 | } 82 | 83 | // Use a fast copy mechanism to write the data to the bitmap 84 | System.Runtime.InteropServices.Marshal.Copy(pixelData, 0, bitmapData.Scan0, dataLength); 85 | 86 | // Release the write lock on the bits. 87 | bmp.UnlockBits(bitmapData); 88 | 89 | return bmp; 90 | } 91 | 92 | /// 93 | /// Reads the specified PGM buffer and returns a Bitmap. 94 | /// 95 | /// The buffer. 96 | /// 97 | public static Bitmap Read(byte[] buffer) 98 | { 99 | using var ms = new MemoryStream(buffer) {Position = 0}; 100 | return Read(ms); 101 | } 102 | 103 | /// 104 | /// Reads the specified PGM file and returns a Bitmap. 105 | /// 106 | /// The path. 107 | /// 108 | public static Bitmap Read(string path) 109 | { 110 | using var fs = new FileStream(path, FileMode.Open, FileAccess.Read); 111 | return Read(fs); 112 | } 113 | 114 | /// 115 | /// Reads an integer by reading from a Binary Reader. 116 | /// It uses a StringBuilder to hold and parse numbers. 117 | /// 118 | /// The reader. 119 | /// The sb. 120 | /// 121 | private static int ReadInteger(BinaryReader reader, StringBuilder sb) 122 | { 123 | var c = '\0'; 124 | sb.Length = 0; 125 | while (char.IsDigit(c = reader.ReadChar())) 126 | { 127 | sb.Append(c); 128 | } 129 | 130 | return int.Parse(sb.ToString().Trim()); 131 | } 132 | } 133 | } -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/Unosquare.Labs.LibFprint.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | Copyright (c) 2019 - Unosquare 5 | Unosquare 6 | Unosquare.Labs.LibFprint 7 | 8.0 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Unosquare.Labs.LibFprint/fprint.h: -------------------------------------------------------------------------------- 1 | // We are keeping this file for reference only because we generated a bunch of code from this "slightly" modified version :) 2 | 3 | typedef unsigned short uint16_t; 4 | typedef unsigned long uint32_t; 5 | typedef unsigned char uint8_t; 6 | typedef int gint; 7 | typedef gint gboolean; 8 | 9 | typedef void* gpointer; 10 | 11 | struct GSList { 12 | gpointer data; 13 | GSList *next; 14 | }; 15 | 16 | typedef struct libusb_device_handle { } libusb_device_handle; 17 | 18 | struct libusb_device_descriptor { 19 | /** Size of this descriptor (in bytes) */ 20 | uint8_t bLength; 21 | 22 | /** Descriptor type. Will have value 23 | * \ref libusb_descriptor_type::LIBUSB_DT_DEVICE LIBUSB_DT_DEVICE in this 24 | * context. */ 25 | uint8_t bDescriptorType; 26 | 27 | /** USB specification release number in binary-coded decimal. A value of 28 | * 0x0200 indicates USB 2.0, 0x0110 indicates USB 1.1, etc. */ 29 | uint16_t bcdUSB; 30 | 31 | /** USB-IF class code for the device. See \ref libusb_class_code. */ 32 | uint8_t bDeviceClass; 33 | 34 | /** USB-IF subclass code for the device, qualified by the bDeviceClass 35 | * value */ 36 | uint8_t bDeviceSubClass; 37 | 38 | /** USB-IF protocol code for the device, qualified by the bDeviceClass and 39 | * bDeviceSubClass values */ 40 | uint8_t bDeviceProtocol; 41 | 42 | /** Maximum packet size for endpoint 0 */ 43 | uint8_t bMaxPacketSize0; 44 | 45 | /** USB-IF vendor ID */ 46 | uint16_t idVendor; 47 | 48 | /** USB-IF product ID */ 49 | uint16_t idProduct; 50 | 51 | /** Device release number in binary-coded decimal */ 52 | uint16_t bcdDevice; 53 | 54 | /** Index of string descriptor describing manufacturer */ 55 | uint8_t iManufacturer; 56 | 57 | /** Index of string descriptor describing product */ 58 | uint8_t iProduct; 59 | 60 | /** Index of string descriptor containing device serial number */ 61 | uint8_t iSerialNumber; 62 | 63 | /** Number of possible configurations */ 64 | uint8_t bNumConfigurations; 65 | }; 66 | 67 | /* structs that applications are not allowed to peek into */ 68 | enum fp_dev_state { 69 | DEV_STATE_INITIAL = 0, 70 | DEV_STATE_ERROR, 71 | DEV_STATE_INITIALIZING, 72 | DEV_STATE_INITIALIZED, 73 | DEV_STATE_DEINITIALIZING, 74 | DEV_STATE_DEINITIALIZED, 75 | DEV_STATE_ENROLL_STARTING, 76 | DEV_STATE_ENROLLING, 77 | DEV_STATE_ENROLL_STOPPING, 78 | DEV_STATE_VERIFY_STARTING, 79 | DEV_STATE_VERIFYING, 80 | DEV_STATE_VERIFY_DONE, 81 | DEV_STATE_VERIFY_STOPPING, 82 | DEV_STATE_IDENTIFY_STARTING, 83 | DEV_STATE_IDENTIFYING, 84 | DEV_STATE_IDENTIFY_DONE, 85 | DEV_STATE_IDENTIFY_STOPPING, 86 | DEV_STATE_CAPTURE_STARTING, 87 | DEV_STATE_CAPTURING, 88 | DEV_STATE_CAPTURE_DONE, 89 | DEV_STATE_CAPTURE_STOPPING, 90 | }; 91 | 92 | enum fp_driver_type { 93 | DRIVER_PRIMITIVE = 0, 94 | DRIVER_IMAGING = 1, 95 | }; 96 | 97 | enum fp_print_data_type { 98 | PRINT_DATA_RAW = 0, /* memset-imposed default */ 99 | PRINT_DATA_NBIS_MINUTIAE, 100 | }; 101 | 102 | 103 | struct fp_dscv_dev { 104 | struct libusb_device *udev; 105 | struct fp_driver *drv; 106 | unsigned long driver_data; 107 | uint32_t devtype; 108 | }; 109 | struct fp_dscv_print { 110 | uint16_t driver_id; 111 | uint32_t devtype; 112 | enum fp_finger finger; 113 | char *path; 114 | }; 115 | struct fp_dev { 116 | struct fp_driver *drv; 117 | libusb_device_handle *udev; 118 | uint32_t devtype; 119 | void *priv; 120 | 121 | int nr_enroll_stages; 122 | 123 | /* read-only to drivers */ 124 | struct fp_print_data *verify_data; 125 | 126 | /* drivers should not mess with any of the below */ 127 | enum fp_dev_state state; 128 | int __enroll_stage; 129 | int unconditional_capture; 130 | 131 | /* async I/O callbacks and data */ 132 | /* FIXME: convert this to generic state operational data mechanism? */ 133 | fp_dev_open_cb open_cb; 134 | void *open_cb_data; 135 | fp_dev_close_cb close_cb; 136 | void *close_cb_data; 137 | fp_enroll_stage_cb enroll_stage_cb; 138 | void *enroll_stage_cb_data; 139 | fp_enroll_stop_cb enroll_stop_cb; 140 | void *enroll_stop_cb_data; 141 | fp_verify_cb verify_cb; 142 | void *verify_cb_data; 143 | fp_verify_stop_cb verify_stop_cb; 144 | void *verify_stop_cb_data; 145 | fp_identify_cb identify_cb; 146 | void *identify_cb_data; 147 | fp_identify_stop_cb identify_stop_cb; 148 | void *identify_stop_cb_data; 149 | fp_capture_cb capture_cb; 150 | void *capture_cb_data; 151 | fp_capture_stop_cb capture_stop_cb; 152 | void *capture_stop_cb_data; 153 | 154 | /* FIXME: better place to put this? */ 155 | struct fp_print_data **identify_gallery; 156 | }; 157 | struct fp_driver { 158 | const uint16_t id; 159 | const char *name; 160 | const char *full_name; 161 | const struct usb_id * const id_table; 162 | enum fp_driver_type type; 163 | enum fp_scan_type scan_type; 164 | 165 | void *priv; 166 | 167 | /* Device operations */ 168 | int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype); 169 | int (*open)(struct fp_dev *dev, unsigned long driver_data); 170 | void (*close)(struct fp_dev *dev); 171 | int (*enroll_start)(struct fp_dev *dev); 172 | int (*enroll_stop)(struct fp_dev *dev); 173 | int (*verify_start)(struct fp_dev *dev); 174 | int (*verify_stop)(struct fp_dev *dev, gboolean iterating); 175 | int (*identify_start)(struct fp_dev *dev); 176 | int (*identify_stop)(struct fp_dev *dev, gboolean iterating); 177 | int (*capture_start)(struct fp_dev *dev); 178 | int (*capture_stop)(struct fp_dev *dev); 179 | }; 180 | struct fp_print_data { 181 | uint16_t driver_id; 182 | uint32_t devtype; 183 | enum fp_print_data_type type; 184 | GSList *prints; 185 | }; 186 | struct fp_img { 187 | int width; 188 | int height; 189 | size_t length; 190 | uint16_t flags; 191 | struct fp_minutiae *minutiae; 192 | unsigned char *binarized; 193 | unsigned char data[0]; 194 | }; 195 | 196 | /* misc/general stuff */ 197 | 198 | /** \ingroup print_data 199 | * Numeric codes used to refer to fingers (and thumbs) of a human. These are 200 | * purposely not available as strings, to avoid getting the library tangled up 201 | * in localization efforts. 202 | */ 203 | enum fp_finger { 204 | LEFT_THUMB = 1, /** thumb (left hand) */ 205 | LEFT_INDEX, /** index finger (left hand) */ 206 | LEFT_MIDDLE, /** middle finger (left hand) */ 207 | LEFT_RING, /** ring finger (left hand) */ 208 | LEFT_LITTLE, /** little finger (left hand) */ 209 | RIGHT_THUMB, /** thumb (right hand) */ 210 | RIGHT_INDEX, /** index finger (right hand) */ 211 | RIGHT_MIDDLE, /** middle finger (right hand) */ 212 | RIGHT_RING, /** ring finger (right hand) */ 213 | RIGHT_LITTLE, /** little finger (right hand) */ 214 | }; 215 | 216 | /** \ingroup dev 217 | * Numeric codes used to refer to the scan type of the device. Devices require 218 | * either swiping or pressing the finger on the device. This is useful for 219 | * front-ends. 220 | */ 221 | enum fp_scan_type { 222 | FP_SCAN_TYPE_PRESS = 0, /** press */ 223 | FP_SCAN_TYPE_SWIPE, /** swipe */ 224 | }; 225 | 226 | /* Drivers */ 227 | const char *fp_driver_get_name(struct fp_driver *drv); 228 | const char *fp_driver_get_full_name(struct fp_driver *drv); 229 | uint16_t fp_driver_get_driver_id(struct fp_driver *drv); 230 | enum fp_scan_type fp_driver_get_scan_type(struct fp_driver *drv); 231 | 232 | /* Device discovery */ 233 | struct fp_dscv_dev **fp_discover_devs(void); 234 | void fp_dscv_devs_free(struct fp_dscv_dev **devs); 235 | struct fp_driver *fp_dscv_dev_get_driver(struct fp_dscv_dev *dev); 236 | uint32_t fp_dscv_dev_get_devtype(struct fp_dscv_dev *dev); 237 | int fp_dscv_dev_supports_print_data(struct fp_dscv_dev *dev, 238 | struct fp_print_data *print); 239 | int fp_dscv_dev_supports_dscv_print(struct fp_dscv_dev *dev, 240 | struct fp_dscv_print *print); 241 | struct fp_dscv_dev *fp_dscv_dev_for_print_data(struct fp_dscv_dev **devs, 242 | struct fp_print_data *print); 243 | struct fp_dscv_dev *fp_dscv_dev_for_dscv_print(struct fp_dscv_dev **devs, 244 | struct fp_dscv_print *print); 245 | 246 | static inline uint16_t fp_dscv_dev_get_driver_id(struct fp_dscv_dev *dev); 247 | 248 | /* Print discovery */ 249 | struct fp_dscv_print **fp_discover_prints(void); 250 | void fp_dscv_prints_free(struct fp_dscv_print **prints); 251 | uint16_t fp_dscv_print_get_driver_id(struct fp_dscv_print *print); 252 | uint32_t fp_dscv_print_get_devtype(struct fp_dscv_print *print); 253 | enum fp_finger fp_dscv_print_get_finger(struct fp_dscv_print *print); 254 | int fp_dscv_print_delete(struct fp_dscv_print *print); 255 | 256 | /* Device handling */ 257 | struct fp_dev *fp_dev_open(struct fp_dscv_dev *ddev); 258 | void fp_dev_close(struct fp_dev *dev); 259 | struct fp_driver *fp_dev_get_driver(struct fp_dev *dev); 260 | int fp_dev_get_nr_enroll_stages(struct fp_dev *dev); 261 | uint32_t fp_dev_get_devtype(struct fp_dev *dev); 262 | int fp_dev_supports_print_data(struct fp_dev *dev, struct fp_print_data *data); 263 | int fp_dev_supports_dscv_print(struct fp_dev *dev, struct fp_dscv_print *print); 264 | 265 | /** \ingroup dev 266 | * Image capture result codes returned from fp_dev_img_capture(). 267 | */ 268 | enum fp_capture_result { 269 | /** Capture completed successfully, the capture data has been 270 | * returned to the caller. */ 271 | FP_CAPTURE_COMPLETE = 0, 272 | /** Capture failed for some reason */ 273 | FP_CAPTURE_FAIL, 274 | }; 275 | 276 | int fp_dev_supports_imaging(struct fp_dev *dev); 277 | int fp_dev_img_capture(struct fp_dev *dev, int unconditional, 278 | struct fp_img **image); 279 | int fp_dev_get_img_width(struct fp_dev *dev); 280 | int fp_dev_get_img_height(struct fp_dev *dev); 281 | 282 | /** \ingroup dev 283 | * Enrollment result codes returned from fp_enroll_finger(). 284 | * Result codes with RETRY in the name suggest that the scan failed due to 285 | * user error. Applications will generally want to inform the user of the 286 | * problem and then retry the enrollment stage. For more info on the semantics 287 | * of interpreting these result codes and tracking enrollment process, see 288 | * \ref enrolling. 289 | */ 290 | enum fp_enroll_result { 291 | /** Enrollment completed successfully, the enrollment data has been 292 | * returned to the caller. */ 293 | FP_ENROLL_COMPLETE = 1, 294 | /** Enrollment failed due to incomprehensible data; this may occur when 295 | * the user scans a different finger on each enroll stage. */ 296 | FP_ENROLL_FAIL, 297 | /** Enroll stage passed; more stages are need to complete the process. */ 298 | FP_ENROLL_PASS, 299 | /** The enrollment scan did not succeed due to poor scan quality or 300 | * other general user scanning problem. */ 301 | FP_ENROLL_RETRY = 100, 302 | /** The enrollment scan did not succeed because the finger swipe was 303 | * too short. */ 304 | FP_ENROLL_RETRY_TOO_SHORT, 305 | /** The enrollment scan did not succeed because the finger was not 306 | * centered on the scanner. */ 307 | FP_ENROLL_RETRY_CENTER_FINGER, 308 | /** The verification scan did not succeed due to quality or pressure 309 | * problems; the user should remove their finger from the scanner before 310 | * retrying. */ 311 | FP_ENROLL_RETRY_REMOVE_FINGER, 312 | }; 313 | 314 | int fp_enroll_finger_img(struct fp_dev *dev, struct fp_print_data **print_data, 315 | struct fp_img **img); 316 | 317 | /** \ingroup dev 318 | * Performs an enroll stage. See \ref enrolling for an explanation of enroll 319 | * stages. This function is just a shortcut to calling fp_enroll_finger_img() 320 | * with a NULL image parameter. Be sure to read the description of 321 | * fp_enroll_finger_img() in order to understand its behaviour. 322 | * 323 | * \param dev the device 324 | * \param print_data a location to return the resultant enrollment data from 325 | * the final stage. Must be freed with fp_print_data_free() after use. 326 | * \return negative code on error, otherwise a code from #fp_enroll_result 327 | */ 328 | static inline int fp_enroll_finger(struct fp_dev *dev, 329 | struct fp_print_data **print_data); 330 | 331 | /** \ingroup dev 332 | * Verification result codes returned from fp_verify_finger(). Return codes 333 | * are also shared with fp_identify_finger(). 334 | * Result codes with RETRY in the name suggest that the scan failed due to 335 | * user error. Applications will generally want to inform the user of the 336 | * problem and then retry the verify operation. 337 | */ 338 | enum fp_verify_result { 339 | /** The scan completed successfully, but the newly scanned fingerprint 340 | * does not match the fingerprint being verified against. 341 | * In the case of identification, this return code indicates that the 342 | * scanned finger could not be found in the print gallery. */ 343 | FP_VERIFY_NO_MATCH = 0, 344 | /** The scan completed successfully and the newly scanned fingerprint does 345 | * match the fingerprint being verified, or in the case of identification, 346 | * the scanned fingerprint was found in the print gallery. */ 347 | FP_VERIFY_MATCH = 1, 348 | /** The scan did not succeed due to poor scan quality or other general 349 | * user scanning problem. */ 350 | FP_VERIFY_RETRY = FP_ENROLL_RETRY, 351 | /** The scan did not succeed because the finger swipe was too short. */ 352 | FP_VERIFY_RETRY_TOO_SHORT = FP_ENROLL_RETRY_TOO_SHORT, 353 | /** The scan did not succeed because the finger was not centered on the 354 | * scanner. */ 355 | FP_VERIFY_RETRY_CENTER_FINGER = FP_ENROLL_RETRY_CENTER_FINGER, 356 | /** The scan did not succeed due to quality or pressure problems; the user 357 | * should remove their finger from the scanner before retrying. */ 358 | FP_VERIFY_RETRY_REMOVE_FINGER = FP_ENROLL_RETRY_REMOVE_FINGER, 359 | }; 360 | 361 | int fp_verify_finger_img(struct fp_dev *dev, 362 | struct fp_print_data *enrolled_print, struct fp_img **img); 363 | 364 | /** \ingroup dev 365 | * Performs a new scan and verify it against a previously enrolled print. This 366 | * function is just a shortcut to calling fp_verify_finger_img() with a NULL 367 | * image output parameter. 368 | * \param dev the device to perform the scan. 369 | * \param enrolled_print the print to verify against. Must have been previously 370 | * enrolled with a device compatible to the device selected to perform the scan. 371 | * \return negative code on error, otherwise a code from #fp_verify_result 372 | * \sa fp_verify_finger_img() 373 | */ 374 | static inline int fp_verify_finger(struct fp_dev *dev, 375 | struct fp_print_data *enrolled_print); 376 | 377 | int fp_dev_supports_identification(struct fp_dev *dev); 378 | int fp_identify_finger_img(struct fp_dev *dev, 379 | struct fp_print_data **print_gallery, size_t *match_offset, 380 | struct fp_img **img); 381 | 382 | /** \ingroup dev 383 | * Performs a new scan and attempts to identify the scanned finger against a 384 | * collection of previously enrolled fingerprints. This function is just a 385 | * shortcut to calling fp_identify_finger_img() with a NULL image output 386 | * parameter. 387 | * \param dev the device to perform the scan. 388 | * \param print_gallery NULL-terminated array of pointers to the prints to 389 | * identify against. Each one must have been previously enrolled with a device 390 | * compatible to the device selected to perform the scan. 391 | * \param match_offset output location to store the array index of the matched 392 | * gallery print (if any was found). Only valid if FP_VERIFY_MATCH was 393 | * returned. 394 | * \return negative code on error, otherwise a code from #fp_verify_result 395 | * \sa fp_identify_finger_img() 396 | */ 397 | static inline int fp_identify_finger(struct fp_dev *dev, 398 | struct fp_print_data **print_gallery, size_t *match_offset); 399 | 400 | /* Data handling */ 401 | int fp_print_data_load(struct fp_dev *dev, enum fp_finger finger, 402 | struct fp_print_data **data); 403 | int fp_print_data_from_dscv_print(struct fp_dscv_print *print, 404 | struct fp_print_data **data); 405 | int fp_print_data_save(struct fp_print_data *data, enum fp_finger finger); 406 | int fp_print_data_delete(struct fp_dev *dev, enum fp_finger finger); 407 | void fp_print_data_free(struct fp_print_data *data); 408 | size_t fp_print_data_get_data(struct fp_print_data *data, unsigned char **ret); 409 | struct fp_print_data *fp_print_data_from_data(unsigned char *buf, 410 | size_t buflen); 411 | uint16_t fp_print_data_get_driver_id(struct fp_print_data *data); 412 | uint32_t fp_print_data_get_devtype(struct fp_print_data *data); 413 | 414 | /* Image handling */ 415 | 416 | /** \ingroup img */ 417 | struct fp_minutia { 418 | int x; 419 | int y; 420 | int ex; 421 | int ey; 422 | int direction; 423 | double reliability; 424 | int type; 425 | int appearing; 426 | int feature_id; 427 | int *nbrs; 428 | int *ridge_counts; 429 | int num_nbrs; 430 | }; 431 | 432 | int fp_img_get_height(struct fp_img *img); 433 | int fp_img_get_width(struct fp_img *img); 434 | unsigned char *fp_img_get_data(struct fp_img *img); 435 | int fp_img_save_to_file(struct fp_img *img, char *path); 436 | void fp_img_standardize(struct fp_img *img); 437 | struct fp_img *fp_img_binarize(struct fp_img *img); 438 | struct fp_minutia **fp_img_get_minutiae(struct fp_img *img, int *nr_minutiae); 439 | void fp_img_free(struct fp_img *img); 440 | 441 | /* Polling and timing */ 442 | 443 | struct fp_pollfd { 444 | int fd; 445 | short events; 446 | }; 447 | 448 | int fp_handle_events_timeout(struct timeval *timeout); 449 | int fp_handle_events(void); 450 | size_t fp_get_pollfds(struct fp_pollfd **pollfds); 451 | int fp_get_next_timeout(struct timeval *tv); 452 | 453 | typedef void (*fp_pollfd_added_cb)(int fd, short events); 454 | typedef void (*fp_pollfd_removed_cb)(int fd); 455 | void fp_set_pollfd_notifiers(fp_pollfd_added_cb added_cb, 456 | fp_pollfd_removed_cb removed_cb); 457 | 458 | /* Library */ 459 | int fp_init(void); 460 | void fp_exit(void); 461 | void fp_set_debug(int level); 462 | 463 | /* Asynchronous I/O */ 464 | 465 | typedef void (*fp_dev_open_cb)(struct fp_dev *dev, int status, void *user_data); 466 | int fp_async_dev_open(struct fp_dscv_dev *ddev, fp_dev_open_cb callback, 467 | void *user_data); 468 | 469 | typedef void (*fp_dev_close_cb)(struct fp_dev *dev, void *user_data); 470 | void fp_async_dev_close(struct fp_dev *dev, fp_dev_close_cb callback, 471 | void *user_data); 472 | 473 | typedef void (*fp_enroll_stage_cb)(struct fp_dev *dev, int result, 474 | struct fp_print_data *print, struct fp_img *img, void *user_data); 475 | int fp_async_enroll_start(struct fp_dev *dev, fp_enroll_stage_cb callback, 476 | void *user_data); 477 | 478 | typedef void (*fp_enroll_stop_cb)(struct fp_dev *dev, void *user_data); 479 | int fp_async_enroll_stop(struct fp_dev *dev, fp_enroll_stop_cb callback, 480 | void *user_data); 481 | 482 | typedef void (*fp_verify_cb)(struct fp_dev *dev, int result, 483 | struct fp_img *img, void *user_data); 484 | int fp_async_verify_start(struct fp_dev *dev, struct fp_print_data *data, 485 | fp_verify_cb callback, void *user_data); 486 | 487 | typedef void (*fp_verify_stop_cb)(struct fp_dev *dev, void *user_data); 488 | int fp_async_verify_stop(struct fp_dev *dev, fp_verify_stop_cb callback, 489 | void *user_data); 490 | 491 | typedef void (*fp_identify_cb)(struct fp_dev *dev, int result, 492 | size_t match_offset, struct fp_img *img, void *user_data); 493 | int fp_async_identify_start(struct fp_dev *dev, struct fp_print_data **gallery, 494 | fp_identify_cb callback, void *user_data); 495 | 496 | typedef void (*fp_identify_stop_cb)(struct fp_dev *dev, void *user_data); 497 | int fp_async_identify_stop(struct fp_dev *dev, fp_identify_stop_cb callback, 498 | void *user_data); 499 | 500 | typedef void (*fp_capture_cb)(struct fp_dev *dev, int result, 501 | struct fp_img *img, void *user_data); 502 | int fp_async_capture_start(struct fp_dev *dev, int unconditional, fp_capture_cb callback, void *user_data); 503 | 504 | typedef void (*fp_capture_stop_cb)(struct fp_dev *dev, void *user_data); 505 | int fp_async_capture_stop(struct fp_dev *dev, fp_capture_stop_cb callback, void *user_data); 506 | 507 | #endif 508 | 509 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '1.0.{build}' 2 | image: Visual Studio 2019 3 | configuration:Release 4 | platform: Any CPU 5 | notifications: 6 | - provider: Slack 7 | auth_token: 8 | secure: Q+xg4/yU5OR9BVF14cw4yZ+3qlhMeYDsAhUQyOIszmF1mHvq44tIvQpWByBJCd/cgUIZk3SwBpk4hh1MrkQIk6rnaOZ2LNBTev4zrq36oXk= 9 | channel: '#builds' 10 | environment: 11 | op_build_user: "Geo Perez" 12 | op_build_user_email: "geovanni.perez@gmail.com" 13 | access_token: 14 | secure: HzWdswNyfQbQ0vLk9IQyO+Ei9mxoPYp9rvv6HPhtC9J/Fm7EHRzyV953pbPRXI9I 15 | before_build: 16 | - ps: | 17 | if(-Not $env:APPVEYOR_PULL_REQUEST_TITLE -And $isWindows) 18 | { 19 | git checkout $env:APPVEYOR_REPO_BRANCH -q 20 | cinst docfx -y 21 | } 22 | after_build: 23 | - ps: | 24 | if(-Not $env:APPVEYOR_PULL_REQUEST_TITLE -And $isWindows) 25 | { 26 | docfx docfx.json 27 | git config --global credential.helper store 28 | Add-Content "$env:USERPROFILE\.git-credentials" "https://$($env:access_token):x-oauth-basic@github.com`n" 29 | git config --global core.autocrlf false 30 | git config --global user.email $env:op_build_user_email 31 | git config --global user.name $env:op_build_user 32 | 33 | git clone https://github.com/unosquare/libfprint-cs.git -b gh-pages origin_site -q 34 | git clone -b documentation https://github.com/unosquare/best-practices.git -q 35 | docfx docfx.json --logLevel Error 36 | Copy-Item origin_site/.git _site -recurse 37 | CD _site 38 | Copy-Item README.html index.html -force 39 | git add -A 2>&1 40 | git commit -m "Documentation update" -q 41 | git push origin gh-pages -q 42 | CD .. 43 | } 44 | -------------------------------------------------------------------------------- /docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "files": [ "Unosquare.Labs.LibFprint/**/*.cs" ], 7 | "exclude": [ "**/bin/**", "**/obj/**" ] 8 | } 9 | ], 10 | "dest": "obj/api" 11 | } 12 | ], 13 | "build": { 14 | "template": [ 15 | "best-practices/templates/default" 16 | ], 17 | "content": [ 18 | { 19 | "files": [ "**/*.yml" ], 20 | "cwd": "obj/api", 21 | "dest": "api" 22 | }, 23 | { 24 | "files": [ "*.md", "toc.yml" ] 25 | } 26 | ], 27 | "resource": [ 28 | { 29 | "files": [ "best-practices/resources/**" ] 30 | } 31 | ], 32 | "globalMetadata": { 33 | "_appTitle": "libfprint-cs", 34 | "_enableSearch": true, 35 | "_appLogoPath": "best-practices/resources/images/logo.png", 36 | "_docLogo": "best-practices/resources/images/transparent.gif" 37 | }, 38 | "dest": "_site" 39 | } 40 | } -------------------------------------------------------------------------------- /toc.yml: -------------------------------------------------------------------------------- 1 | - name: API Documentation 2 | href: obj/api/ --------------------------------------------------------------------------------