Reading and Writing AAMVA Barcodes on Driver’s Licenses

If you’ve renewed your driver’s license any time in the last few years, you have likely noticed an increase in its visual complexity. Many governing bodies have made significant strides towards making forgery more difficult. The unfortunate side-effect from that positive change is that traditional recognition algorithms are more difficult with the many colors, backgrounds, holograms, and layouts.

Thankfully, new driver’s licenses also have PDF417 barcodes on them, and in North America, follow specifications laid out by the American Association of Motor Vehicle Administrators (AAMVA). These barcodes are small, error resistant, and can encode a lot of information.

This tutorial will introduce you to the classes and methods for both reading and writing AAMVA-compliant barcodes from Driver’s Licenses.

Reading AAMVA Barcodes

Since Driver’s Licenses are so broadly accepted as forms of identification, there are a wealth of opportunities for reading the information from them. We covered those concepts in an earlier white paper on Capturing Customer Information from Driver’s Licenses, so we won’t repeat them here. That paper also discussed using the PDF417 barcodes before they were regulated by AAMVA. Since then, LEADTOOLS has added a new AAMVAID class which does all the field parsing for you.

What’s the big deal? Take a look at the raw data for an AAMVA barcode:

@∖n∖u001e∖rANSI 636004080002DL00410266ZN03070017DLDAQ123456789123∖nDCSDOE∖nDDEN∖nDACJANE∖nDDFN∖nDAD∖nDDGN∖nDCAC∖nDCBNONE∖nDCDNONE∖nDBD08152015∖nDBB08151987∖nDBA08152020∖nDBC2∖nDAU070 in∖nDAYBRO∖nDAG1100 NEW BERN AVENUE∖nDAIRALEIGH∖nDAJNC∖nDAK276970001∖nDCF0123456789∖nDCGUSA∖nDAZBRO∖nDCLU  ∖nDCK000012345678NCSVTL01∖nDDB10242014∖nDDK1∖nDDL1∖nZNZNADUP∖nZNB∖nZNC0∖n

Where’s the name? Or the birthdate? Do you need to calculate if this person is over 21 and legally allowed to make a purchase? With LEADTOOLS, you can get that kind of information in beautiful, strongly typed properties:

using (AAMVAID id = BarcodeData.ParseAAMVAData(data.GetData(), false))
   Console.WriteLine("Issuer Identification Number: " + id.IssuerIdentificationNumber);
   Console.WriteLine("First Name: " + id.FirstName.Value);
   Console.WriteLine("Last Name: " + id.LastName.Value);
   Console.WriteLine("Over 21?: " + id.Over21);
   // etc.

Writing AAMVA Barcodes

There may be fewer reasons for generating AAMVA barcodes, but every motor vehicle agency in every state or province in the United States, Canada, and Mexico needs the ability to print them on the licenses they issue. Naturally, you can’t just print any old barcode onto licenses and IDs. As with most specifications, they are hard to follow and can cause a significant development roadblock due to the R&D requirements. LEADTOOLS simplifies this in two ways: generating the AAMVA string and creating the PDF417 barcode.

First, you need to convert your customer data into a valid AAMVA string value. To aid in this process, LEADTOOLS provides the AAMVAIDBuilder class. The builder will help organize the data and output it conforming to the 2016 AAMVA CDS. Here we initialize the AAMVAIDBuilder, add some information and then use the Build function to generate the AAMVAID object:

AAMVAIDBuilder builder = new AAMVAIDBuilder();
builder.SetJurisdiction(AAMVAJurisdiction.NorthCarolina, AAMVAID.LookupIssuerIdentificationNumber(AAMVAJurisdiction.NorthCarolina));

// Set primary data

// Build the subfile entry as a driver's license (vs. an ID)
builder.SetSubfileType(0, AAMVASubfileType.DL, "DL");
builder.AddDataElementToSubfile(0, "DAC", "John");
builder.AddDataElementToSubfile(0, "DCS", "Doe");
// etc.

// Get the AAMVA string data
byte[] data;
using (AAMVAID id = builder.Build())
   data = id.GetBytes();

Now that our customer’s information is correctly encoded for AAMVA, we will create the PDF417 barcode. Thanks to LEAD’s nearly three decades of experience in with raster and document imaging technologies, this process is even simpler than writing the AAMVA string despite the barcode’s greater complexity. Here we generate the BarcodeEngine, set a few options to help the proportions make AAMVA happy, and LEADTOOLS takes care of the rest. In this simple case, we simply created a blank image using the calculated bounds of the barcode:

BarcodeEngine engine = new BarcodeEngine();

PDF417BarcodeWriteOptions writeOptions = (PDF417BarcodeWriteOptions)engine.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
writeOptions.XModule = 15; //0.015
                           //Must >= 3
writeOptions.XModuleAspectRatio = 3;
//Error level must be at least 3, 5 is recommended
writeOptions.ECCLevel = PDF417BarcodeECCLevel.Level5;
//Default WidthAspectRatio is 2:1. 4:1 looks similar to ID barcodes in the wild
writeOptions.SymbolWidthAspectRatio = 4;
//Default quiet zone for PDF417 is 2 * XModule

PDF417BarcodeData barcodeData = (PDF417BarcodeData)BarcodeData.CreateDefaultBarcodeData(BarcodeSymbology.PDF417);
const int resolution = 96; // screen resolution

using (RasterImage image = RasterImage.Create(barcodeData.Bounds.Width, barcodeData.Bounds.Height, 24, resolution,
   engine.Writer.WriteBarcode(image, barcodeData, writeOptions);

   using (RasterCodecs codecs = new RasterCodecs())
      codecs.Save(image, imageFilePath, RasterImageFormat.Png, image.BitsPerPixel);

As a check, we’ll load the image back into the Main Barcode demo like before and read the data.

Change the World! (or at least your DMV...)

Reading is actually the easy part. Most of you on this blog are pretty keen and might've picked up on how the raw data in that string worked and thought, "I could parse that!" As mentioned previously, the biggest catch out there is adoption. It's one thing to figure out how to parse some values from a long text string, but writing them out correctly and following the AAMVA spec is what's really holding states and countries back. LEADTOOLS makes it incredibly easy to make sure your data follows the specifications, AND can write the barcode. So get out there and code something that's so easy, even a sloth can do it!


LEADTOOLS has a history of staying on the forefront of document imaging and recognition technologies like OCR, Forms, Barcode, and PDF. Driver’s licenses and IDs have become far more complex, yet better regulated with the adoption of AAMVA barcodes. LEADTOOLS will stay a viable option for developers wanting to quickly and easily create software to read and write identification data stored in AAMVA barcodes.

Download the Full AAMVA Barcode Example

You can download the fully functional demo which includes the features discussed above. To run this example you will need the following:

  • LEADTOOLS free evaluation
  • Visual Studio 2010 or later
  • Browse to the LEADTOOLS Examples folder (e.g. C:∖LEADTOOLS 20∖Examples∖) where you can find example projects for this and many more technologies in LEADTOOLS.

Need help getting this sample up and going? Contact our support team for free technical support! For pricing or licensing questions, you can contact our sales team ( or call us at 704-332-5532.

This entry was posted in Barcode and tagged , , , , , , . Bookmark the permalink.

12 Responses to Reading and Writing AAMVA Barcodes on Driver’s Licenses

  1. Junfeng Chen says:

    I wanna to use demo Writing AAMVA Barcodes Builder . Can i try demo ? And if i wanna to buy , how much for it ?

  2. Hi, Junfeng Chen.

    Once you have downloaded and installed the LEADTOOLS Evaluation SDK, you can find .NET demo source code to generate an AAMVA compliant PDF417 barcodes in “C:\LEADTOOLS 20\Examples\DotNet\CS\AAMVAWriteDemo”

    If you need source in another programming language, let us know, and we can direct you to another demo that can generate barcodes.

    You can download the evaluation SDK from this link:

    If you have any questions, please do not hesitate to contact They are experts and respond very quickly. Thanks!

    Gabriel Smith

  3. anita says:

    what program do i use to generate the barcode?

  4. bob says:

    so this will create and exact DL or ID pdf417 aamva barcode?

  5. Richard Schneider says:

    Can you give me php source code?

  6. Feeny says:

    Is there a way to add the “valid” field for for barcodes that return unexpired dates?

    • Hi Feeny,

      Thank you for your question.

      It looks like you’re looking for this property in the AAVAID class:

      Expired: Determines whether the AAMVAID is expired, based on the encoded data elements.

      Here are a few other properties of the AAVAID class that relate to the expiration date:

      ExpirationAvailable: Determines whether it is possible to determine the expiration date of the AAMVAID, based on the encoded data elements.

      ExpirationDate: Gets the expiration date.

      You can find a list of all properties in the AAMVAID class here:

      If you’d like to discuss more about AAMVAID recognition, feel free to email us directly at or come into our live chat M-F 8:30am-6:00pm ET:

  7. Anthony says:

    Hello, how can I change the height from inches or centimeters to feet? The program only gives me the option to enter height as “073 in” and not “6′-0”.

    • Anthony,

      According to the AAMVA standard, the Physical Description – Height will be
      entered only as inches or centimeters. It’s up to the application that is
      parsing the barcode to do the calculations to display the inches total as
      ft’in”. Here is a helper function that you can use to achieve this:

      static string GetHeightString(AAMVAID id)
         var subFile = id.Subfiles.FirstOrDefault();
         if (subFile != null)
            var height = subFile.DataElements["DAU"].Value;
            var i = height.IndexOf("in");
            if (i > 0) //is in inches
               var totalInches = int.Parse(height.Substring(0, i));
               var feet = totalInches / 12;
               var inches = totalInches % 12;
               return $"{feet}'{inches}\"";
               return height;
         return default;

      Here is an example of how you would call that:

      static void ExtractPDF417Data(RasterImage image)
         BarcodeEngine engine = new BarcodeEngine();
         BarcodeData data = engine.Reader.ReadBarcode(image, LeadRect.Empty, BarcodeSymbology.PDF417);
         if (data.Value != null && data.Symbology == BarcodeSymbology.PDF417)
            AAMVAID id = BarcodeData.ParseAAMVAData(data.GetData(), false);
            if (id != null)
               Console.WriteLine($"Issuer Identification Number: {id.IssuerIdentificationNumber}\n" +
                     $"First Name: {id.FirstName.Value}\n" +
                     $"Last Name: {id.LastName.Value}\n" +
                     $"Over 21? {id.Over21}\n" +
                     $"Height: {GetHeightString(id)}");

      And this is how it would display:

      Issuer Identification Number: 636004

      First Name: John

      Last Name: Doe

      Over 21? False

      Height: 6’1″

Leave a Reply

Your email address will not be published. Required fields are marked *