Provides information encoded in an AAMVA CDS related to ID card or driver's license, of the cardholder.
public class AAMVAID : IDisposable
The class will be filled by calling BarcodeData.ParseAAMVAData(byte[], bool) when reading PDF417 barcodes from North American ID cards and driver's licenses.
using Leadtools;
using Leadtools.Barcode;
using Leadtools.Codecs;
/* This example defines an instance of AAMVAID, sets and reads the data, and finally saves a PDF17 barcode.
* The code is outlined in sections as follows:
*
* 1. Set the members to simulate reading AAMVAID and extract it at a later point
* 2. Build the AAMVAID instance
* 3. Define a hash set and parse to a specific element
* 4. Process AAMAValidCharacters
* 5. Extract AAMVAID properties
* 6. Extract data and write as PDF417 barcode
*/
public void AAMVA_Example()
{
//1. Set the members to simulate reading AAMVAID and extract it at a later point
const string JURISDICTION_VERSION = "00";
const string SUBFILE_TYPE_CODE = "DL";
const int SUBFILES_COUNT = 1;
const int BITS_PER_PIXEL = 24;
const int IMAGE_DPI = 300;
AAMVAID driversLicenseID = null;
AAMVANameResult nameResult = null;
DateTime birthday = new DateTime(DateTime.Now.Year - 16, DateTime.Now.Month, DateTime.Now.Day);
string[,] driversLicenseData = new string[,] {{"DDF", "N"}, // First name truction (N = not truncated)
{"DDE", "N"}, // Last name truction (N = not truncated)
{"DCG", "USA"}, // Country identification
{"DCF", "NONE"}, // Document discriminator
{"DAQ", "1234567890"}, // ID Number
{"DAK", "123456 "}, // Postal code
{"DAJ", "PA"}, // Address Jurisdiction Code
{"DAI", "Any Town"}, // Address City
{"DAG", "123 Main Street"}, // Address Street 1
{"DAU", "072 in"}, // Height (inches or centimeters)
{"DAY", "BRO"}, // Eye color
{"DBC", "1"}, // Sex (Male = 1, Female = 2, 9 = Not specified)
{"DBB", birthday.ToString("MMddyyyy")}, // Date of Birth
{"DBD", DateTime.Now.ToString("MMddyyyy")}, // Document Issue Date
{"DAD", "NONE"}, // Middle Name
{"DAC", "John"}, // First name
{"DCS", "Doe"}, // Last name
{"DBA", DateTime.Now.AddYears(6).ToString("MMddyyyy")},// Expiration date
{"DCD", "M"}, // Jurisdiction-specific endorsement codes
{"DCB", "NONE"}, // Jurisdiction-specific restriction codes
{"DCA", "C"}, // Jurisdiction-specific vehicle class
{"DDJ", birthday.AddYears(21).ToString("MMddyyyy")}, // Under 21 until
{"DDI", birthday.AddYears(19).ToString("MMddyyyy")}, // Under 19 until
{"DDH", birthday.AddYears(18).ToString("MMddyyyy")}, // Under 18 until
{"DAZ", "BRO"}}; // Hair color
// 2. Build the AAMVAID instance
using (AAMVAIDBuilder builder = new AAMVAIDBuilder())
{
builder.SetJurisdiction(AAMVAJurisdiction.Pennsylvania, AAMVAID.LookupIssuerIdentificationNumber(AAMVAJurisdiction.Pennsylvania))
.SetVersion(AAMVAVersion.Version2016)
.SetJurisdictionVersion(JURISDICTION_VERSION)
.SetNumberOfEntries(SUBFILES_COUNT);
builder.SetSubfileType(SUBFILES_COUNT - 1, AAMVASubfileType.DL, SUBFILE_TYPE_CODE);
for (int i = 0; i < driversLicenseData.GetLength(0); i++)
builder.AddDataElementToSubfile(0, driversLicenseData[i, 0], driversLicenseData[i, 1]);
Console.WriteLine($"Is AAMVAIDBuilder disposed: {builder.IsDisposed} \n");
Console.WriteLine("===================================================================");
Console.WriteLine("\n");
driversLicenseID = builder.Build();
builder.Reset();
}
foreach (KeyValuePair<string, AAMVADataElement> element in driversLicenseID.Subfiles[0].DataElements)
{
Console.WriteLine($"ElementID: {element.Value.ElementID} Element value:{element.Value.Value}");
}
// 3. Define a hash set and parse to a specific element
IDictionary<string, AAMVADataElementInfo> _dataElementInfo;
_dataElementInfo = AAMVADataElementInfo.RetrieveAll(AAMVAVersion.Version2016);
HashSet<string> DataElements = new HashSet<string>()
{
"DCA", "DCB", "DCD", "DBA", "DCS", "DAC", "DAD", "DBD", "DBB", "DBC", "DAY", "DAZ", "DCL",
"DAU", "DAG", "DAI", "DAJ", "DAH", "DAK", "DAQ", "DCF", "DCG", "DDE", "DDF", "DDG", "DCU"
};
foreach (string elementID in DataElements)
{
AAMVADataElementInfo info = _dataElementInfo[elementID];
info.LengthType = AAMVALengthType.Fixed;
Console.WriteLine($"ElementID: {info.ElementID}");
switch (elementID)
{
case "DAY": // Eye color
AAMVAEyeColor eyeColor = driversLicenseID.EyeColor;
Console.WriteLine($"Eye Color: {eyeColor}");
break;
case "DAZ": // Hair color
AAMVAHairColor hairColor = driversLicenseID.HairColor;
Console.WriteLine($"Eye Color: {hairColor}");
break;
case "DAI": // City
Console.WriteLine($"City Name: {driversLicenseID.AddressCity}");
break;
case "DAK": // Jurisdiction
AAMVARegion rgn = AAMVAID.LookupRegion(driversLicenseID.Jurisdiction);
Console.WriteLine($"Postal Code: {driversLicenseID.AddressPostalCode} {rgn}");
break;
case "DCG": // Address region (country)
Console.WriteLine($"Address Region: {driversLicenseID.AddressRegion}");
break;
case "DAJ": // State abbreviation
AAMVAJurisdiction[] jurisdictions = (AAMVAJurisdiction[])Enum.GetValues(typeof(AAMVAJurisdiction));
for (int i = 0; i < jurisdictions.Length; i++)
{
string abbr = AAMVAID.LookupStateAbbreviation(jurisdictions[i]);
Console.WriteLine($"State abbreviations: {abbr}");
}
Console.WriteLine($"Address State Abbreviation: {driversLicenseID.AddressStateAbbreviation}");
break;
case "DBC": // Sex
AAMVASex[] sex = (AAMVASex[])Enum.GetValues(typeof(AAMVASex));
for (int i = 0; i < sex.Length; i++)
{
Console.WriteLine($"Sex codes: {sex[i]}");
}
break;
case "DAG": // Street address 1
Console.WriteLine($"Street Address1: {driversLicenseID.AddressStreet1}");
break;
case "DAH": // Street address 2
Console.WriteLine($"Street Address2: {driversLicenseID.AddressStreet2}" +
$"- Can be null if address street line 2 is not encoded in the barcode data");
break;
case "DBB": // Date of Birth
Console.WriteLine($"Date of Birth: {driversLicenseID.DateOfBirth}");
break;
case "DBA": // Expiration date
Console.WriteLine($"Expiration Available: {driversLicenseID.ExpirationAvailable} | Is Expired: {driversLicenseID.Expired} | Expiration Date: {driversLicenseID.ExpirationDate}");
break;
case "DBD": // Issue date
Console.WriteLine($"Issue Date: {driversLicenseID.IssueDate}");
break;
case "DCS": // Last name
Console.WriteLine($"Last Name: {driversLicenseID.LastName.Value}");
break;
case "DAD": // Middle name
Console.WriteLine($"Middle Name: {driversLicenseID.MiddleName.Value}");
break;
case "DAC": // First name
Console.WriteLine($"Middle Name: {driversLicenseID.FirstName.Value}");
break;
case "DCU": // Suffix
AAMVANameSuffix[] enums = (AAMVANameSuffix[])Enum.GetValues(typeof(AAMVANameSuffix));
for (int i = 2; i < enums.Length; i++)
{
AAMVANameSuffix enumValue = enums[i];
string codeArabic = AAMVAID.LookupNameSuffixCodeArabic(enumValue);
Console.WriteLine("Arabic suffix: " + enumValue.ToString() + " - \"" + codeArabic + "\"");
string codeRoman = AAMVAID.LookupNameSuffixCodeRoman(enumValue);
Console.WriteLine("Roman suffix: " + enumValue.ToString() + " - \"" + codeRoman + "\"");
}
break;
case "DCL": // Suffix
AAMVARaceEthnicity[] races = (AAMVARaceEthnicity[])Enum.GetValues(typeof(AAMVARaceEthnicity));
for (int i = 0; i < races.Length; i++)
{
AAMVARaceEthnicity race = races[i];
string code = AAMVAID.LookupRaceEthnicityCode(race);
Console.WriteLine("Race: " + race + " - \"" + code + "\"");
}
break;
}
Console.WriteLine($"Definition: {info.Definition}");
Console.WriteLine($"Friendly Name: {info.FriendlyName}");
Console.WriteLine($"Length Type: {info.LengthType}");
Console.WriteLine($"Valid Characters: {info.ValidCharacters}");
Console.WriteLine($"Valid Subfile Types: {info.ValidSubfileTypes}");
Console.WriteLine($"Value Max Length: {info.ValueMaxLength}");
Console.WriteLine("\n");
Console.WriteLine("===================================================================");
Console.WriteLine("\n");
}
// 4. Process AAMAValidCharacters
AAMVAValidCharacters[] characters = (AAMVAValidCharacters[])Enum.GetValues(typeof(AAMVAValidCharacters));
for (int i = 0; i < characters.Length; i++)
{
Console.WriteLine($"Valid characters: {characters[i]}");
}
// 5. Extract AAMVAID properties
Console.WriteLine($"Is over 18: {driversLicenseID.Over18}"); //Is over 18
Console.WriteLine($"Is over 18: {driversLicenseID.Over18Available}"); //Over 18 available
Console.WriteLine($"Is over 19: {driversLicenseID.Over19}"); //Is over 19
Console.WriteLine($"Is over 19: {driversLicenseID.Over19Available}"); //Over 19 available
Console.WriteLine($"Is over 21: {driversLicenseID.Over21}"); //Is over 21
Console.WriteLine($"Is over 21: {driversLicenseID.Over21Available}"); //Over 21 available
Console.WriteLine($"Version: {driversLicenseID.Version}"); //Version
Console.WriteLine($"Number of entries: {driversLicenseID.NumberOfEntries}"); //Number of entries
Console.WriteLine($"Is AMMVAID Disposed: {driversLicenseID.IsDisposed}"); //Is Disposed
Console.WriteLine($"Issuer Identification Number: {driversLicenseID.IssuerIdentificationNumber}"); //Issuer Identification Number
Console.WriteLine($"Jurisdiction Version Number: {driversLicenseID.JurisdictionVersion}"); // Jurisdiction Version Number
var jurisdiction = AAMVAID.LookupJurisdiction(driversLicenseID.IssuerIdentificationNumber); // Returns state
var suffix = AAMVAID.LookupNameSuffix("JR"); // Returns name suffix
var raceEthnicity = AAMVAID.LookupRaceEthnicity("BK"); // Returns race/ethnicity
Console.WriteLine($"{jurisdiction} \n {suffix} \n {raceEthnicity}");
nameResult = driversLicenseID.FirstName;
nameResult.InferredFromFullName = true;
Console.WriteLine($"Name result: {nameResult.Value}");
var subfilesList = driversLicenseID.Subfiles;
foreach (AAMVASubfile subfile in subfilesList)
{
Console.WriteLine($"{subfile.Offset} \n {subfile.SubfileType} \n {subfile.SubfileTypeCode}");
}
// 6. Extract data and write as PDF417 barcode
PDF417BarcodeData data = new PDF417BarcodeData();
data.Symbology = BarcodeSymbology.PDF417;
data.SetData(driversLicenseID.GetBytes());
Console.WriteLine($"=======================================");
AAMVAID parsedAAMVAData = BarcodeData.ParseAAMVAData(driversLicenseID.GetBytes(), true);
Console.WriteLine($"Parsed AAMVAData First Name: {parsedAAMVAData.FirstName.Value}");
Console.WriteLine($"Parsed AAMVAData Last Name: {parsedAAMVAData.LastName.Value}");
Console.WriteLine($"Parsed AAMVAData Issue Date: {parsedAAMVAData.IssueDate}");
BarcodeEngine barcodeEngine = new BarcodeEngine();
PDF417BarcodeWriteOptions pdf417WriteOptions = (PDF417BarcodeWriteOptions)barcodeEngine.Writer.GetDefaultOptions(BarcodeSymbology.PDF417);
//Refer to AAMVA CDS 2016 Section D.3 thru D.11.2
//Must range from 0.0066 to 0.015 inches
pdf417WriteOptions.XModule = 15; //0.015
//Must >= 3
pdf417WriteOptions.XModuleAspectRatio = 3;
//Error level must be at least 3, 5 is recommended
pdf417WriteOptions.ECCLevel = PDF417BarcodeECCLevel.Level5;
//Default WidthAspectRatio is 2:1. 4:1 looks similar to ID barcodes in the wild
pdf417WriteOptions.SymbolWidthAspectRatio = 4;
//Default quiet zone for PDF417 is 2 * XModule
RasterCodecs codecs = new RasterCodecs();
barcodeEngine.Writer.CalculateBarcodeDataBounds(LeadRect.Empty, IMAGE_DPI, IMAGE_DPI, data, pdf417WriteOptions);
using (RasterImage image = RasterImage.Create(data.Bounds.Width, data.Bounds.Height, BITS_PER_PIXEL, IMAGE_DPI, new RasterColor(255, 255, 255)))
{
barcodeEngine.Writer.WriteBarcode(image, data, pdf417WriteOptions); // Write the barcode
codecs.Save(image, Path.Combine(LEAD_VARS.ImagesDir, "MyDriversLicense.png"), RasterImageFormat.Png, 1); // write the output to file
}
codecs.Dispose();
}
static class LEAD_VARS
{
public const string ImagesDir = @"C:\LEADTOOLS23\Resources\Images";
}