Reading Driver's License Information from PDF417 in JavaScript

A few weeks ago, I wrote an article sharing how to read driver’s license information from PDF417 on Android. Comparing to building an Android native camera app, building a web camera app is much easier. In this article, let’s take a glimpse at a JavaScript sample, which is implemented with a few lines of code by invoking Dynamsoft web barcode SDK.

Dynamsoft Web Barcode SDK

The JavaScript barcode library is available for download on npmjs.org.

You can either download the package via

npm install dynamsoft-javascript-barcode --save

or include the online JS file directly in your HTML file:

<script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode@9.0.0/dist/dbr.js"></script>

You need to apply for a 30-day trial license to activate the SDK:

Dynamsoft.DBR.BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==";

Building a Web Barcode Reader in less than 30 Seconds

Dynamsoft JavaScript barcode SDK is based on WebAssembly, which brings the high performance of barcode scanning functionality to web developers. Besides, it provides built-in camera module APIs. With the deeply encapsulated JavaScript SDK, you will find making an HTML5 barcode scanner with cameras can never be such convenient.

To quickly build a web barcode scanner app, copy the following code to your HTML file:

<!DOCTYPE html>
<html>

<body>
  <script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode@9.0.0/dist/dbr.js"></script>
  <script>
    // initializes and uses the library
    Dynamsoft.DBR.BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==";
    var scanner = null;
    (async () => {
      scanner = await Dynamsoft.DBR.BarcodeScanner.createInstance();
      scanner.onFrameRead = results => {
        if (results.length > 0) console.log(results);
      };
      scanner.onUnduplicatedRead = (txt, result) => {
        alert(txt);
      };
      await scanner.show();
    })();
  </script>
</body>

</html>

Parsing Driver’s License Information Based on AAMVA Standard

For better balance the accuracy and performance of decoding PDF417 symbology, you’d better make some parameter configurations according to the online documentation:

 let runtimeSettings = await scanner.getRuntimeSettings();
 runtimeSettings.barcodeFormatIds = Dynamsoft.DBR.EnumBarcodeFormat.BF_PDF417;
 runtimeSettings.LocalizationModes = [2,8,0,0,0,0,0,0];
 runtimeSettings.deblurLevel = 7;
 await scanner.updateRuntimeSettings(runtimeSettings);

As PDF417 is decoded by the barcode library, you need to create a parser for extracting driver’s license information based on the AAMVA standard:

const DLAbbrDesMap = {
    'DCA': 'Jurisdiction-specific vehicle class',
    'DBA': 'Expiry Date',
    'DCS': 'Last Name',
    'DAC': 'First Name',
    'DBD': 'Issue Date',
    'DBB': 'Birth Date',
    'DBC': 'Gender',
    'DAY': 'Eye Color',
    'DAU': 'Height',
    'DAG': 'Street',
    'DAI': 'City',
    'DAJ': 'State',
    'DAK': 'Zip',
    'DAQ': 'License Number',
    'DCF': 'Document Discriminator',
    'DCG': 'Issue Country',
    'DAH': 'Street 2',
    'DAZ': 'Hair Color',
    'DCI': 'Place of birth',
    'DCJ': 'Audit information',
    'DCK': 'Inventory Control Number',
    'DBN': 'Alias / AKA Family Name',
    'DBG': 'Alias / AKA Given Name',
    'DBS': 'Alias / AKA Suffix Name',
    'DCU': 'Name Suffix',
    'DCE': 'Physical Description Weight Range',
    'DCL': 'Race / Ethnicity',
    'DCM': 'Standard vehicle classification',
    'DCN': 'Standard endorsement code',
    'DCO': 'Standard restriction code',
    'DCP': 'Jurisdiction-specific vehicle classification description',
    'DCQ': 'Jurisdiction-specific endorsement code description',
    'DCR': 'Jurisdiction-specific restriction code description',
    'DDA': 'Compliance Type',
    'DDB': 'Card Revision Date',
    'DDC': 'HazMat Endorsement Expiration Date',
    'DDD': 'Limited Duration Document Indicator',
    'DAW': 'Weight(pounds)',
    'DAX': 'Weight(kilograms)',
    'DDH': 'Under 18 Until',
    'DDI': 'Under 19 Until',
    'DDJ': 'Under 21 Until',
    'DDK': 'Organ Donor Indicator',
    'DDL': 'Veteran Indicator',
    // old standard
    'DAA': 'Customer Full Name',
    'DAB': 'Customer Last Name',
    'DAE': 'Name Suffix',
    'DAF': 'Name Prefix',
    'DAL': 'Residence Street Address1',
    'DAM': 'Residence Street Address2',
    'DAN': 'Residence City',
    'DAO': 'Residence Jurisdiction Code',
    'DAR': 'License Classification Code',
    'DAS': 'License Restriction Code',
    'DAT': 'License Endorsements Code',
    'DAV': 'Height in CM',
    'DBE': 'Issue Timestamp',
    'DBF': 'Number of Duplicates',
    'DBH': 'Organ Donor',
    'DBI': 'Non-Resident Indicator',
    'DBJ': 'Unique Customer Identifier',
    'DBK': 'Social Security Number',
    'DBM': 'Social Security Number',
    'DCH': 'Federal Commercial Vehicle Codes',
    'DBR': 'Name Suffix',
    'PAA': 'Permit Classification Code',
    'PAB': 'Permit Expiration Date',
    'PAC': 'Permit Identifier',
    'PAD': 'Permit IssueDate',
    'PAE': 'Permit Restriction Code',
    'PAF': 'Permit Endorsement Code',
    'ZVA': 'Court Restriction Code',
    'DAD': 'Middle Name'
};

var parseDriverLicense = txt => {
    console.log(txt);
    let lines = txt.split(']n');
    let abbrs = Object.keys(DLAbbrDesMap);
    let map = {};
    lines.forEach((line, i) => {
        let abbr;
        let content;
        if(i === 1){
            abbr = 'DAQ';
            content = line.substring(line.indexOf(abbr) + 3);
        }else{
            abbr = line.substring(0, 3);
            content = line.substring(3).trim();
        } 
        if(abbrs.includes(abbr)){
            map[abbr] = {
                description: DLAbbrDesMap[abbr],
                content: content
            };
        }
    });
    return map;
};

Finally, concatenate the information and display it on the web page:

scanner.onFrameRead = results => {
    let txts = [];
    try {
        if (results.length > 0) {
            for (var i = 0; i < results.length; ++i) {
                txts.push(results[i].barcodeText);
                // Get infos
                let licenseInfo = parseDriverLicense(results[i].barcodeText);
                if (licenseInfo) {
                    let div = document.getElementById("div-licenseInfo");
                    div.innerHTML = '';
                    let p = document.createElement('p');
                    p.innerText = 'Document Type: DL';
                    div.appendChild(p);
                    for (let key in licenseInfo) {
                        let info = licenseInfo[key];
                        let p = document.createElement('p');
                        p.innerText = info.description + ': ' + info.content;
                        div.appendChild(p);
                    }
                }
                else {
                    document.getElementById("div-licenseInfo").innerHTML = '<p>No license info found.</p>';
                }
            }
        }
        else {
            document.getElementById("div-licenseInfo").innerHTML = '<p>No license info found.</p>';
        }

    } catch (e) {
        console.log(e);
    }
};

JavaScript driver's license

Source Code

https://github.com/yushulx/javascript-driver-license