This tutorial shows how to create a Windows C/C++ API application that writes PDF417 AAMVA standard barcodes using the LEADTOOLS SDK.
Overview | |
---|---|
Summary | This tutorial covers how to use LEADTOOLS AAMVA Builder SDK technology in a Windows C DLL Application. |
Completion Time | 30 minutes |
Visual Studio Project | Download tutorial project (20 KB) |
Platform | Windows C DLL Application |
IDE | Visual Studio 2017, 2019 |
Development License | Download LEADTOOLS |
Try it in another language |
|
Before working on the Write AAMVA Driver's License Barcode - Windows C DLL tutorial, get familiar with the basic steps of creating a project and loading/displaying an image by reviewing the Add References and Set a License and Load, Display and Save Images tutorials.
Start with a copy of the 64-bit Windows API project created in the Load, Display and Save Images tutorial. If the project is not available, create it by following the steps in that tutorial.
To build AAMVA data and write barcodes using LEADTOOLS, add the required header and DLL files. Open the pre-compiled header file (either pch.h
or stdafx.h
, depending on the version of Visual Studio used) and add the following lines:
#include "C:\LEADTOOLS23\Include\Ltbar.h"
#pragma comment (lib, "C:\\LEADTOOLS23\\Lib\\CDLL\\x64\\Ltbar_x.lib") // barcode and AAMVA support
Note
For a full list of which DLLs are required for specific toolkit features or file formats, refer to Files to be Included With Your Application.
For details on needed Barcode DLLs, see the help topic Barcode Files to be Included With Your Application.
The License unlocks the features needed for the project. It must be set before any toolkit functionality is called. For details, including tutorials for different platforms, refer to Setting a Runtime License.
There are two types of runtime licenses:
Note
Adding LEADTOOLS references and setting a license are covered in more detail in the Add References and Set a License tutorial.
With the project created, the references added, the license set, and the load and display image code added, coding can begin.
The steps below are for Visual Studio 2019; they could be different for other versions of Visual Studio.
Go to the Solution Explorer and double-click the resources file (.rc).
Add a new &Barcode drop down menu next to the File menu. In the newly added &Barcode menu, add a &Write AAMVA Barcode menu item. The new item's ID should be ID_BARCODE_WRITEAAMVABARCODE
.
Go to the WndProc
function and under the switch (wmId)
statement that is below the WM_COMMAND
case, add a new case:
switch (wmId)
{
case ID_BARCODE_WRITEAAMVABARCODE:
{
// create empty bitmap and fill it with light color
BITMAPHANDLE BarcodeBmp = { 0 };
int w = 700, h = 450;
L_CreateBitmap(&BarcodeBmp, sizeof LEADBmp, TYPE_CONV, w, h, 24, ORDER_BGR, NULL, BOTTOM_LEFT, NULL, 0);
BarcodeBmp.XResolution = BarcodeBmp.YResolution = 200;
L_FillBitmap(&BarcodeBmp, RGB(255, 200, 150));
L_CHAR* data = NULL;
L_UINT dataLength = 0;
L_INT nRet = SetAAMVAIDInformation(&data, &dataLength);
if (nRet != SUCCESS)
{
MessageBox(hWnd, TEXT("Error setting AAMVA information"), TEXT("Barcode Demo"), MB_ICONERROR);
if (data)
L_BarCodeAAMVAMemoryFree(data);
break;
}
if (WritePdf417Barcode(hWnd, &BarcodeBmp, data, dataLength) == SUCCESS)
{
if (LEADBmp.Flags.Allocated)
L_FreeBitmap(&LEADBmp);
LEADBmp = BarcodeBmp; //this copies the structure without copying the image data
InvalidateRect(hWnd, NULL, TRUE);
}
if (data)
L_BarCodeAAMVAMemoryFree(data);
}
break;
// keep rest of the code as is
Add a new SetAAMVAIDInformation
function and add the following code to it. This function can be placed above the WndProc
function:
L_INT SetAAMVAIDInformation(L_CHAR** pData, L_UINT* pDataLength)
{
AAMVAIDBUILDER Builder = { 0 };
L_INT nRet = L_BarCodeAAMVAIDBuilderInit(&Builder);
if (nRet != SUCCESS) return nRet;
nRet = L_BarCodeAAMVAIDBuilderSetJurisdiction(&Builder, L_AAMVA_JURISDICTION_PENNSYLVANIA, NULL);
if (nRet != SUCCESS) return nRet;
nRet = L_BarCodeAAMVAIDBuilderSetJurisdictionVersion(&Builder, "00");
if (nRet != SUCCESS) return nRet;
nRet = L_BarCodeAAMVAIDBuilderSetVersion(&Builder, L_AAMVA_VERSION_2016);
if (nRet != SUCCESS) return nRet;
nRet = L_BarCodeAAMVAIDBuilderSetNumberOfEntries(&Builder, 1);
if (nRet != SUCCESS) return nRet;
nRet = L_BarCodeAAMVAIDBuilderSetSubfileType(&Builder, 0, L_AAMVA_SUBFILE_TYPE_DL, NULL);
if (nRet != SUCCESS) return nRet;
//Add all required data elements per AAMVA CDS
//Could use L_BarCodeAAMVAIDLookup* functions for data element values of enumerated D20 types
// Macro to declare a date string variable and fill it with date
// Date value equal to today's data offset forward or backward a number of years
#define DeclareDate(szVar, nYearOffset) \
char szVar[9]; \
strcpy_s(szVar, 9, GetCurrentDate(nYearOffset))
// Example below uses date values for 17 year old person
DeclareDate(szNow, 0); // Today's date
DeclareDate(szExpiry, 6); // Expires in 6 years
DeclareDate(szBirthday, -17); // Born 17 years ago
DeclareDate(szBirthPlus21, 4); // Will be 21 in 4 year
DeclareDate(szBirthPlus19, 2); // Will be 19 in 2 years
DeclareDate(szBirthPlus18, 1); // Will be 18 in 1 year
const char* driversLicenseData[][2] = {
{"DDF", "N"}, // First name truncation (N = not truncated)
{"DDE", "N"}, // Last name truncation (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", szBirthday}, // Date of Birth
{"DBD", szNow}, // Document Issue Date
{"DAD", "NONE"}, // Middle Name
{"DAC", "John"}, // First name
{"DCS", "Doe"}, // Last name
{"DBA", szExpiry}, // Expiration date
{"DCD", "M"}, // Jurisdiction-specific endorsement codes
{"DCB", "NONE"}, // Jurisdiction-specific restriction codes
{"DCA", "C"}, // Jurisdiction-specific vehicle class
{"DDJ", szBirthPlus21}, // Under 21 until
{"DDI", szBirthPlus19}, // Under 19 until
{"DDH", szBirthPlus18}, // Under 18 until
{"DAZ", "BRO"} // Hair color
};
int elementCount = sizeof driversLicenseData / sizeof driversLicenseData[0];
for (int i = 0; i < elementCount; ++i)
{
L_UINT valueLen = (L_UINT)strlen(driversLicenseData[i][1]);
nRet = L_BarCodeAAMVAIDBuilderAddDataElementToSubfile(&Builder, 0, driversLicenseData[i][0], driversLicenseData[i][1], valueLen);
if (nRet != SUCCESS) return nRet;
}
nRet = L_BarCodeAAMVAIDBuilderBuild(&Builder);
if (nRet != SUCCESS) return nRet;
//Valid AAMVAID is now in pBuilder->OutputID
nRet = L_BarCodeWriteAAMVAData(Builder.OutputID, pData, pDataLength);
L_BarCodeFreeAAMVAID(Builder.OutputID);
return nRet;
}
Add a new helper function named GetDatePlusYears
that returns the current date with the specified number of offset years. Any function that returns the date in yyyymmdd format can be used instead of it.
#include <time.h>
L_CHAR* GetDatePlusYears(int nYears)
{
static char currentDate[9];
time_t t = time(NULL);
struct tm local_t = { 0 };
localtime_s(&local_t, &t);
wsprintfA(currentDate, "%4.4d%2.2d%2.2d", local_t.tm_year + 1900 + nYears, local_t.tm_mon + 1, local_t.tm_mday);
return currentDate;
}
Add a new WritePdf417Barcode
function that writes the barcode on the image after the AAMVA data has been built successfully and add the following code to it:
L_INT WritePdf417Barcode(HWND hwnd, pBITMAPHANDLE pBarcodeBmp, L_CHAR* pData, L_INT nDataLen)
{
L_INT nRet = L_BarCodeInit(BARCODES_PDF_WRITE);
if (nRet != SUCCESS)
return nRet;
BARCODEDATA BarCodeData = { 0 };
BARCODECOLOR BarColor = { 0 };
BARCODEWRITEPDF BarCodePDF = { 0 };
BarColor.uStructSize = sizeof BARCODECOLOR;
BarColor.dwColorBar = RGB(0, 0, 0);
BarColor.dwColorSpace = RGB(255, 255, 255);
BarCodeData.uStructSize = sizeof BarCodeData;
BarCodeData.rcBarLocation.left = 50;
BarCodeData.rcBarLocation.top = 50;
BarCodeData.rcBarLocation.right = 650;
BarCodeData.rcBarLocation.bottom = 400;
BarCodeData.nUnits = BARCODE_SCANLINES_PER_PIXELS;
BarCodeData.ulType = BARCODE_PDF417;
BarCodeData.pszBarCodeData = pData;
BarCodeData.nSizeofBarCodeData = nDataLen;
BarCodePDF.uStructSize = sizeof BarCodePDF;
BarCodePDF.wModule = 15;
BarCodePDF.wModAspectRatio = 3;
BarCodePDF.wEccLevel = BARCODE_PDF417_ECCLEVEL_5;
BarCodePDF.wAspectWidth = 4;
//Write the barcode
nRet = L_BarCodeWrite(pBarcodeBmp, &BarCodeData, &BarColor, BARCODE_USECOLORS, NULL, &BarCodePDF, NULL, NULL, NULL, NULL, NULL, NULL);
if (SUCCESS != nRet)
MessageBox(hwnd, TEXT("Could Not Write PDF417 Barcode"), TEXT("Barcode Demo"), MB_ICONERROR);
L_BarCodeExit();
return nRet;
}
Run the project by pressing F5, or by selecting Debug -> Start Debugging.
If the steps are followed correctly, the application will run and enable the user to select Barcode -> Write AAMVA Barcode to create an empty bitmap and write the AAMVA data on it.
The resulting image looks like this:
This tutorial showed how to use the AAMVAIDBUILDER
structure and related builder and barcode writer functions.