Last active
November 20, 2025 05:41
-
-
Save skylarmt/e817c0ac9bbc4cc4bd4f671348619142 to your computer and use it in GitHub Desktop.
Parse the barcode on the back of a North America AAMVA drivers license/ID card and extract basic info. Code originally from PostalPoint Retail Shipping Software, https://postalpoint.app
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * Copyright 2024-2025 PostalPortal LLC, Netsyms Technologies LLC. All rights reserved. | |
| * This code file is hereby optionally made available under the MIT license. | |
| */ | |
| export function parseLicenseBarcode(data) { | |
| var fields = getLicenseDataStructure(); | |
| if (!data.startsWith("@") || data.substring(4, 9) != "ANSI ") { | |
| throw new Error("Not a valid AAMVA license barcode."); | |
| } | |
| var dataElSep = data.charAt(1); | |
| var recordSep = data.charAt(2); | |
| var segmentTerminator = data.charAt(3); | |
| var issuerIIN = data.substring(9, 15); | |
| var aamvaVersionNumber = data.substring(15, 17); | |
| var numberOfEntries = data.substring(19, 21) * 1; | |
| var entryList = chunkString(data.substring(21, 21 + (numberOfEntries * 10)), 10); | |
| var type = ""; | |
| var subfileOffset = 0; | |
| var subfileLength = 0; | |
| for (let i = 0; i < entryList.length; i++) { | |
| if (entryList[i].startsWith("Z")) { | |
| continue; | |
| } | |
| if (["DL", "ID", "EN"].includes(entryList[i].substring(0, 2))) { | |
| type = entryList[i].substring(0, 2); | |
| subfileOffset = entryList[i].substring(2, 6) * 1; | |
| subfileLength = entryList[i].substring(6, 10) * 1; | |
| break; | |
| } | |
| } | |
| // +2 offset because the subfile starts with its two-character type code | |
| var datafieldstr = data.substring(subfileOffset + 2, subfileLength + subfileOffset); | |
| var datafieldstrings = datafieldstr.split(dataElSep); | |
| var datafields = {}; | |
| for (let i = 0; i < datafieldstrings.length; i++) { | |
| if (datafieldstrings[i].length > 3) { | |
| datafields[datafieldstrings[i].substring(0, 3)] = datafieldstrings[i].substring(3); | |
| } | |
| } | |
| var firstname = datafields["DAC"] ?? ""; | |
| var lastname = datafields["DCS"] ?? ""; | |
| var middlename = (datafields["DAD"] ?? "").replaceAll(",", " "); | |
| var namesuffix = datafields["DCU"] ?? ""; | |
| fields.name = [firstname, middlename, lastname, namesuffix].filter(Boolean).join(" "); | |
| var street1 = (datafields["DAG"] ?? "").trim(); | |
| var street2 = (datafields["DAH"] ?? "").trim(); | |
| fields.address = [street1, street2].filter(Boolean).join(", "); | |
| fields.city = datafields["DAI"] ?? ""; | |
| fields.state = datafields["DAJ"] ?? ""; | |
| fields.zip = datafields["DAK"] ?? ""; | |
| if (fields.zip.endsWith("0000")) { | |
| fields.zip = fields.zip.substring(0, 5); | |
| } | |
| fields.zip = fields.zip.trim(); | |
| fields.number = datafields["DAQ"] ?? ""; | |
| fields.country = (datafields["DCG"] ?? "").substring(0, 2); | |
| if ((datafields["DCG"] ?? "") == "USA") { | |
| // Expiration date in MMDDYYYY | |
| fields.exp = `${datafields["DBA"].substring(4, 8)}-${datafields["DBA"].substring(0, 2)}-${datafields["DBA"].substring(2, 4)}`; | |
| } else if ((datafields["DCG"] ?? "") == "CAN") { | |
| // Expiration date in YYYYMMDD | |
| fields.exp = `${datafields["DBA"].substring(0, 4)}-${datafields["DBA"].substring(4, 6)}-${datafields["DBA"].substring(6, 8)}`; | |
| } | |
| if (typeof IIN_LIST[issuerIIN] != "undefined") { | |
| fields.issuer = IIN_LIST[issuerIIN].name; | |
| } | |
| return fields; | |
| } | |
| /** | |
| * Get blank data fields in the format used internally by the PS Form 1583 code | |
| */ | |
| export function getLicenseDataStructure() { | |
| return { | |
| type: "DL/ID", | |
| name: "", | |
| number: "", | |
| issuer: "", | |
| exp: "", | |
| address: "", | |
| city: "", | |
| state: "", | |
| zip: "", | |
| country: "" | |
| }; | |
| } | |
| function chunkString(str, chunksize) { | |
| return [].concat.apply([], | |
| str.split('').map(function (x, i) { | |
| return i % chunksize ? [] : str.slice(i, i + chunksize) | |
| }, str) | |
| ); | |
| } | |
| const IIN_LIST = { | |
| "604426": {name: "Prince Edward Island", abbr: "PE", country: "Canada"}, | |
| "604427": {name: "American Samoa", abbr: "AS", country: "USA"}, | |
| "604428": {name: "Quebec", abbr: "QC", country: "Canada"}, | |
| "604429": {name: "Yukon", abbr: "YT", country: "Canada"}, | |
| "604430": {name: "Norther Marianna Islands", abbr: "MP", country: "USA"}, | |
| "604431": {name: "Puerto Rico", abbr: "PR", country: "USA"}, | |
| "604432": {name: "Alberta", abbr: "AB", country: "Canada"}, | |
| "604433": {name: "Nunavut", abbr: "NU", country: "Canada"}, | |
| "604434": {name: "Northwest Territories", abbr: "NT", country: "Canada"}, | |
| "636000": {name: "Virginia", abbr: "VA", country: "USA"}, | |
| "636001": {name: "New York", abbr: "NY", country: "USA"}, | |
| "636002": {name: "Massachusetts", abbr: "MA", country: "USA"}, | |
| "636003": {name: "Maryland", abbr: "MD", country: "USA"}, | |
| "636004": {name: "North Carolina", abbr: "NC", country: "USA"}, | |
| "636005": {name: "South Carolina", abbr: "SC", country: "USA"}, | |
| "636006": {name: "Connecticut", abbr: "CT", country: "USA"}, | |
| "636007": {name: "Louisiana", abbr: "LA", country: "USA"}, | |
| "636008": {name: "Montana", abbr: "MT", country: "USA"}, | |
| "636009": {name: "New Mexico", abbr: "NM", country: "USA"}, | |
| "636010": {name: "Florida", abbr: "FL", country: "USA"}, | |
| "636011": {name: "Delaware", abbr: "DE", country: "USA"}, | |
| "636012": {name: "Ontario", abbr: "ON", country: "Canada"}, | |
| "636013": {name: "Nova Scotia", abbr: "NS", country: "Canada"}, | |
| "636014": {name: "California", abbr: "CA", country: "USA"}, | |
| "636015": {name: "Texas", abbr: "TX", country: "USA"}, | |
| "636016": {name: "Newfoundland", abbr: "NF", country: "Canada"}, | |
| "636017": {name: "New Brunswick", abbr: "NB", country: "Canada"}, | |
| "636018": {name: "Iowa", abbr: "IA", country: "USA"}, | |
| "636019": {name: "Guam", abbr: "GU", country: "USA"}, | |
| "636020": {name: "Colorado", abbr: "GM", country: "USA"}, | |
| "636021": {name: "Arkansas", abbr: "AR", country: "USA"}, | |
| "636022": {name: "Kansas", abbr: "KS", country: "USA"}, | |
| "636023": {name: "Ohio", abbr: "OH", country: "USA"}, | |
| "636024": {name: "Vermont", abbr: "VT", country: "USA"}, | |
| "636025": {name: "Pennsylvania", abbr: "PA", country: "USA"}, | |
| "636026": {name: "Arizona", abbr: "AZ", country: "USA"}, | |
| "636027": {name: "USA State Dept.", abbr: "", country: "USA"}, | |
| "636028": {name: "British Columbia", abbr: "BC", country: "Canada"}, | |
| "636029": {name: "Oregon", abbr: "OR", country: "USA"}, | |
| "636030": {name: "Missouri", abbr: "MO", country: "USA"}, | |
| "636031": {name: "Wisconsin", abbr: "WI", country: "USA"}, | |
| "636032": {name: "Michigan", abbr: "MI", country: "USA"}, | |
| "636033": {name: "Alabama", abbr: "AL", country: "USA"}, | |
| "636034": {name: "North Dakota", abbr: "ND", country: "USA"}, | |
| "636035": {name: "Illinois", abbr: "IL", country: "USA"}, | |
| "636036": {name: "New Jersey", abbr: "NJ", country: "USA"}, | |
| "636037": {name: "Indiana", abbr: "IN", country: "USA"}, | |
| "636038": {name: "Minnesota", abbr: "MN", country: "USA"}, | |
| "636039": {name: "New Hampshire", abbr: "NH", country: "USA"}, | |
| "636040": {name: "Utah", abbr: "UT", country: "USA"}, | |
| "636041": {name: "Maine", abbr: "ME", country: "USA"}, | |
| "636042": {name: "South Dakota", abbr: "SD", country: "USA"}, | |
| "636043": {name: "District of Columbia", abbr: "DC", country: "USA"}, | |
| "636044": {name: "Saskatchewan", abbr: "SK", country: "Canada"}, | |
| "636045": {name: "Washington", abbr: "WA", country: "USA"}, | |
| "636046": {name: "Kentucky", abbr: "KY", country: "USA"}, | |
| "636047": {name: "Hawaii", abbr: "HI", country: "USA"}, | |
| "636048": {name: "Manitoba", abbr: "MB", country: "Canada"}, | |
| "636049": {name: "Nevada", abbr: "NV", country: "USA"}, | |
| "636050": {name: "Idaho", abbr: "ID", country: "USA"}, | |
| "636051": {name: "Mississippi", abbr: "MS", country: "USA"}, | |
| "636052": {name: "Rhode Island", abbr: "RI", country: "USA"}, | |
| "636053": {name: "Tennessee", abbr: "TN", country: "USA"}, | |
| "636054": {name: "Nebraska", abbr: "NE", country: "USA"}, | |
| "636055": {name: "Georgia", abbr: "GA", country: "USA"}, | |
| "636056": {name: "Coahuila", abbr: "CU", country: "Mexico"}, | |
| "636057": {name: "Hidalgo", abbr: "HL", country: "Mexico"}, | |
| "636058": {name: "Oklahoma", abbr: "OK", country: "USA"}, | |
| "636059": {name: "Alaska", abbr: "AK", country: "USA"}, | |
| "636060": {name: "Wyoming", abbr: "WY", country: "USA"}, | |
| "636061": {name: "West Virginia", abbr: "WV", country: "USA"}, | |
| "636062": {name: "Virgin Islands", abbr: "VI", country: "USA"} | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment