c0shea / idparser Goto Github PK
View Code? Open in Web Editor NEWParses PDF417 AAMVA-compliant driver's licenses and ID cards
License: MIT License
Parses PDF417 AAMVA-compliant driver's licenses and ID cards
License: MIT License
Might help to keep the top-level object a little less cluttered with properties
using the TEST Application to scan a South Carolina Drivers License using a Keyboard Emulation barcode scanner...
OUTPUT OF THE SCAN LOOKS LIKE
@Ansi 636053060002ID00410228ZT02690036IDDAQ115775955DCSLASTNAMEDACFIRSTNAMDADSHANEDBD02062018DBC1DAYHAZDAU069 inDAGADDRESSDAICITYDAJSTATEDAKPOSTALCODE DAQSEFISEFUOI1029293092938288472991939384882HJDKSDHFKJSHDFK DCM****DDAFDDB03929382883991SASD
After hitting Parse.. I get this
System.NullReferenceException: 'Object reference not set to an instance of an object.'
IdParser.Address.PostalCode.get returned null.
The "01" version of the Maryland driver license is not compliant with the AMVAA standard. According to the published standard, the 5th field in the PDF417 data should always be the characters "ANSI ". I have a Maryland DL for which the 5th field is "AMVAA". This is the error on which IdParser complains and stops parsing.
System.ArgumentException: The file type is invalid. Expected "ANSI "
Parameter name: input
at IdParser.IdParser.ValidateFormat(String input)
There are also several other compliance issues in this barcode.
- The header appears to be missing field 8 (number of entries), or field 7 (jurisdiction version number), or the fields are one byte instead of two, impossible to tell which as they could both be "01", "0" or "1".
- There is an extra "DL" prepended to the subfile data.
- The full customer name is merged into an undefined comma separated "DAA" field rather than split into "DCS", "DAC", "DAD" fields.
- There are a few other undefined fields present, specifically "DAR", "DAS", "DAT" and "DBH".
- And just for fun, the dates are in the canadian format "YYYYMMDD" rather than the US format "MMDDYYYY".
The following sample barcode data has been sanitized -
@<LF><RS><CR>AAMVA9999990101DL00290175DLDAQT-520-098-009-843<LF>DAADOE,SUE,,<LF>DAG9999 FAKE DR<LF>DAIANYTOWN<LF>DAJMD<LF>DAK11111 <LF>DARC <LF>DAS <LF>DAT <LF>DAU999<LF>DAW999<LF>DBA20211102<LF>DBB19720211<LF>DBC9<LF>DBD20131024<LF>DBHY<CR>
~~
Some licenses start with @A and should be fixed so parsing can continue.
With NH licenses version 2013, the revision date has an M
at the end of the date, which causes the date parsing to throw an exception.
All of the fixes in the Fixes.cs class operate on a string. Now that there are more fixes, it might be more efficient to operate on a StringBuilder
instead of allocating so many strings to parse one barcode.
Some licenses are scanned with whitespace before the start of the header @ and fail to parse.
It would be neat and might help maintainability to do something similar to NLog with their transformers. Individual parser classes could be decorated with a ParserAttribute
that would define the 3-character record it handles (e.g. DCS). These could then be dynamically found and invoked per record to avoid a massive switch statement.
Rather than have each test duplicate dozens of asserts on the various properties such as
Assert.AreEqual("JOEY", idCard.FirstName);
Assert.AreEqual("TESTER", idCard.LastName);
the test should construct the expected object like
var expectedId = new DriversLicense
{
FirstName = "JOEY",
LastName = "TESTER"
}
and pass the actual and expected objects to a method that will assert each property.
The JSON object is empty
Hi there,
Please bear with me - I am still a newbie and am learning how to program. I added IdParser to my Visual Studio project via. NuGet package. I'd like to modify the JSON output to include the issuer abbreviation (e.g. State/Province) and issuer country.
For example:
"IssuerIdentificationNumber": 636025,
"IssuerIdentificationAbbreviation": PA,
"IssuerIdentificationCountryAbbreviation": US,
"AamvaVersionNumber": 9,
"JurisdictionVersionNumber": 0,
If I go through the object browser, I can see the location where I could probably make this change, however it's locked (presumably because I'm using a package?? If you can point me in the right direction on how I can change this, I would really appreciate it.
Thank you
West Virginia uses "BN" for brown eye color.
Your code would not parse the name element on a PA license correctly. I have attached a sample PA license and the code I used to parse the name.
case "DAA":
var names = data.Split(',', '$');
if (names.Length == 1)
{
var namesSpaces = data.Split(' ');
FirstName = namesSpaces[0].Trim().ReplaceEmptyWithNull();
if (namesSpaces.Length == 2)
{
LastName = namesSpaces[1].Trim().ReplaceEmptyWithNull();
MiddleName = null;
}
else
{
LastName = namesSpaces[namesSpaces.Length-1].Trim().ReplaceEmptyWithNull();
MiddleName = String.Join(" ", namesSpaces.Skip(1).Take(namesSpaces.Length - 2)).ReplaceEmptyWithNull();
}
}
else
{
LastName = names.Length > 0 ? names[0].Trim().ReplaceEmptyWithNull() : null;
FirstName = names.Length > 1 ? names[1].Trim().ReplaceEmptyWithNull() : null;
MiddleName = names.Length > 2 ? names[2].Trim().ReplaceEmptyWithNull() : null;
}
break;
Fix typo
Apparently WV had some trouble understanding the AMVAA spec. The birthdate is written as YYYYMMDD (should be MMDDYYYY, but IdParser 3.0.4+ can handle this). But more egregiously, the "Under 18/21 Until" (DDH and DDJ) are written as MMDYYYY with no leading 0's on the day. So for a person born on November 3, 1972 the "Under 18/21 Until" fields are "DDH1131990" and "DDJ1131993". I am not sure if the month would also have a missing leading 0 as the only example I have is for someone born in November.
Unfortunately setting the validation to none does not allow the rest of the data to be parsed.
Hi,
I was testing a specific CO state license and was getting a parsing error due to empty string in subfileRecord. Can you please modify the below method with the new validation check to continue when length is less than 3. If you want that specific DL details, let me know and I can remove the basic data and share it across.
/// <summary>
/// Parses the country based on the DCG subfile record.
/// Gets the country from the IIN if no matching subfile record was found.
/// </summary>
private static Country ParseCountry(IssuerIdentificationNumber iin, Version version, List<string> subfileRecords)
{
// Country is not a subfile record in the AAMVA 2000 standard
if (version == Version.Aamva2000)
{
return Country.Usa;
}
foreach (var subfileRecord in subfileRecords)
{
if (subfileRecord.Length < 3)
{
continue;
}
var elementId = subfileRecord.Substring(0, 3);
var data = subfileRecord.Substring(3).Trim();
if (elementId == "DCG")
{
if (data == "USA")
{
return Country.Usa;
}
if (data == "CAN" || data == "CDN")
{
return Country.Canada;
}
}
}
return iin.GetCountry();
}
Thanks!
Bala
Semantically the value is undefined and -1 seems odd
Hi, I installed the package via Nuget. When I build my project, the build folder now include a lot of the system DLLs. Is there anyway to avoid this?
Hello there,
When I used the test IDs, all worked.
But when I use my ID (a Missouri ID), I get all null values!
Looking closer at the scanned Text (from a 2D scanner), it looks different than all other test IDs.
I also tested a new Missouri version ID (my friend's ID), and all I got is his name!
so do you think Missouri's IDs should be handled a little different?
Thanks.
When parsing an Illinois barcode that uses the 2003 AAMVA spec, I get an ArgumentOutOfRangeException thrown by the GetSubfileRecords.
Running through it manually, it attempts to parse the offset as Substring(23, 4) which results in "2901", this is incorrect, it seems it needs to be shifted left 2 characters to return "0029", with this offset it parses correctly.
Line 202 in 1002a17
I replaced the above with the following
var offsetStart = (idCard.IssuerIdentificationNumber == IssuerIdentificationNumber.Illinois) ? 21 : 23;
offset = Convert.ToInt32(input.Substring(offsetStart, 4));
And it seems to parse correctly now.
NameParser.cs has a logic flaw on surname for users with more than one middle names.
Suggested code fix:
IdCard.Name.Last = names.LastOrDefault().Trim().ReplaceEmptyWithNull();
I would also recommend the line above to become:
IdCard.Name.Middle = string.Join(" ", names.Skip(1).Take(names.Length - 2)).Trim().ReplaceEmptyWithNull();
This will take any middle names and merge them back together as a string separated by spaces. Retaining existing code for .Middle would work, and you could create a new IdCard field for FullMiddle or something, but the .Last one fix is needed for sure to avoid surname issues.
IssueDate, DateOfBirth, and ExpirationDate all fail to parse with "Cannot provide the value: host value not found". However, it works fine in C#. Not wanting to re-do the entire application to fix this issue. Any ideas? I did do some tracing and it when it's setting the date in DateOfBirthPaser.cs, ExpirationdateParser.cs they all properly populate the idCard object, but it just will not return the final output.
If the 4-digit extension is unknown, trailing zeros are added (e.g. 123450000). These should be removed so client applications do not trust these as being the truth.
Prior to the individual parser classes introduced in #8, the 12 drivers license tests typically completed in 0.072 seconds. Since the parsers are now dynamically invoked, they are now completing in about 2.9 seconds.
Having individual parser classes is good for maintainability and encapsulation but not so good for performance. Hopefully caching the types that GetParser
is always scanning (maybe with a dictionary with the key as the element ID and the value as the type) will make the change negligible.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.