Developing a Web MRZ and VIN Scanner with JavaScript and HTML5
In the digital era, extracting information from documents and vehicle IDs has become increasingly important for web-based applications. Machine Readable Zones (MRZ) and Vehicle Identification Numbers (VIN) can now be scanned directly in the browser using modern web technologies. In this tutorial, you'll learn how to build a web-based MRZ and VIN scanner using JavaScript, HTML5 and Dynamsoft Capture Vision SDK. Web MRZ/VIN Scanner Demo Video Prerequisites Free Trial License for Dynamsoft Capture Vision. Online Demo Try it here Installation The dynamsoft-capture-vision-bundle is the JavaScript version of Dynamsoft Capture Vision, available via npm or CDN. To use it, include the library in your index.html: Setting Up the HTML Structure The target HTML layout for the MRZ/VIN scanner consists of three main sections: A div element for license key setup, input source selection (File or Camera), and scanning mode toggle (MRZ or VIN). Get a License key from here Activate SDK File Camera MRZ VIN A div for displaying the uploaded image and its scanning result. A dev for showing the live camera stream along with real-time scanning results. Start Initializing MRZ and VIN Recognition Engines The recognition engines for MRZ and VIN are initialized in the activate() function, which is triggered when the user clicks the Activate SDK button. This function sets up the license key, loads the required models and code parsers, and registers result receivers for both MRZ and VIN. async function activate() { toggleLoading(true); let divElement = document.getElementById("license_key"); let licenseKey = divElement.value == "" ? divElement.placeholder : divElement.value; try { await Dynamsoft.License.LicenseManager.initLicense( licenseKey, true ); Dynamsoft.Core.CoreModule.loadWasm(["DLR"]); parser = await Dynamsoft.DCP.CodeParser.createInstance(); // Load VIN and MRZ models await Dynamsoft.DCP.CodeParserModule.loadSpec("VIN"); await Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("VIN"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD1_ID"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_FRENCH_ID"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_ID"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_VISA"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_PASSPORT"); await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_VISA"); await Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("MRZ"); mrzRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance(); await mrzRouter.initSettings("./mrz.json"); mrzRouter.addResultReceiver({ onCapturedResultReceived: (result) => { // TODO: Handle MRZ result }, }); vinRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance(); await vinRouter.initSettings("./vin.json"); vinRouter.addResultReceiver({ onCapturedResultReceived: (result) => { // TODO: Handle MRZ result }, }); isSDKReady = true; } catch (ex) { console.error(ex); } toggleLoading(false); } Accessing the Camera Dynamsoft Capture Vision SDK provides the CameraEnhancer and CameraView classes for managing camera access and display. CameraEnhancer wraps the getUserMedia() method, while CameraView class adds a live video view to the DOM. async function openCamera(cameraEnhancer, cameraInfo) { if (!Dynamsoft) return; try { await cameraEnhancer.selectCamera(cameraInfo); cameraEnhancer.on("played", function () { resolution = cameraEnhancer.getResolution(); }); await cameraEnhancer.open(); } catch (ex) { console.error(ex); } } async function closeCamera(cameraEnhancer) { if (!Dynamsoft) return; try { await cameraEnhancer.close(); } catch (ex) { console.error(ex); } } async function setResolution(cameraEnhancer, width, height) { if (!Dynamsoft) return; try { await cameraEnhancer.setResolution(width, heig

In the digital era, extracting information from documents and vehicle IDs has become increasingly important for web-based applications. Machine Readable Zones (MRZ) and Vehicle Identification Numbers (VIN) can now be scanned directly in the browser using modern web technologies. In this tutorial, you'll learn how to build a web-based MRZ and VIN scanner using JavaScript, HTML5 and Dynamsoft Capture Vision SDK.
Web MRZ/VIN Scanner Demo Video
Prerequisites
- Free Trial License for Dynamsoft Capture Vision.
Online Demo
Installation
The dynamsoft-capture-vision-bundle is the JavaScript version of Dynamsoft Capture Vision, available via npm or CDN. To use it, include the library in your index.html
:
Setting Up the HTML Structure
The target HTML layout for the MRZ/VIN scanner consists of three main sections:
-
A
div
element for license key setup, input source selection (File or Camera), and scanning mode toggle (MRZ or VIN).
class="container">class="row">Get a License key from href="https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform" target="_blank">here type="text" id="license_key" value="LICENSE-KEY" placeholder="LICENSE-KEY">class="row"> -
A
div
for displaying the uploaded image and its scanning result.
class="container" id="file_container">type="file" id="pick_file" accept="image/*" />class="row">class="imageview">id="image_file" src="default.png" />
class="row"> -
A
dev
for showing the live camera stream along with real-time scanning results.
class="container" id="camera_container">id="videoview">id="camera_view">class="row">
Initializing MRZ and VIN Recognition Engines
The recognition engines for MRZ and VIN are initialized in the activate()
function, which is triggered when the user clicks the Activate SDK button. This function sets up the license key, loads the required models and code parsers, and registers result receivers for both MRZ and VIN.
async function activate() {
toggleLoading(true);
let divElement = document.getElementById("license_key");
let licenseKey = divElement.value == "" ? divElement.placeholder : divElement.value;
try {
await Dynamsoft.License.LicenseManager.initLicense(
licenseKey,
true
);
Dynamsoft.Core.CoreModule.loadWasm(["DLR"]);
parser = await Dynamsoft.DCP.CodeParser.createInstance();
// Load VIN and MRZ models
await Dynamsoft.DCP.CodeParserModule.loadSpec("VIN");
await Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("VIN");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD1_ID");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_FRENCH_ID");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_ID");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_VISA");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_PASSPORT");
await Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_VISA");
await Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("MRZ");
mrzRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
await mrzRouter.initSettings("./mrz.json");
mrzRouter.addResultReceiver({
onCapturedResultReceived: (result) => {
// TODO: Handle MRZ result
},
});
vinRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
await vinRouter.initSettings("./vin.json");
vinRouter.addResultReceiver({
onCapturedResultReceived: (result) => {
// TODO: Handle MRZ result
},
});
isSDKReady = true;
}
catch (ex) {
console.error(ex);
}
toggleLoading(false);
}
Accessing the Camera
Dynamsoft Capture Vision SDK provides the CameraEnhancer
and CameraView
classes for managing camera access and display. CameraEnhancer
wraps the getUserMedia()
method, while CameraView
class adds a live video view to the DOM.
async function openCamera(cameraEnhancer, cameraInfo) {
if (!Dynamsoft) return;
try {
await cameraEnhancer.selectCamera(cameraInfo);
cameraEnhancer.on("played", function () {
resolution = cameraEnhancer.getResolution();
});
await cameraEnhancer.open();
}
catch (ex) {
console.error(ex);
}
}
async function closeCamera(cameraEnhancer) {
if (!Dynamsoft) return;
try {
await cameraEnhancer.close();
}
catch (ex) {
console.error(ex);
}
}
async function setResolution(cameraEnhancer, width, height) {
if (!Dynamsoft) return;
try {
await cameraEnhancer.setResolution(width, height);
}
catch (ex) {
console.error(ex);
}
}
async function initCamera() {
if (!Dynamsoft) return;
try {
cameraView = await Dynamsoft.DCE.CameraView.createInstance();
cameraEnhancer = await Dynamsoft.DCE.CameraEnhancer.createInstance(cameraView);
let scanRegion = {
x: 10,
y: 30,
width: 80,
height: 40,
isMeasuredInPercentage: true
};
cameraEnhancer.setScanRegion(scanRegion);
cameras = await cameraEnhancer.getAllCameras();
if (cameras != null && cameras.length > 0) {
for (let i = 0; i < cameras.length; i++) {
let option = document.createElement("option");
option.text = cameras[i].label;
cameraSource.add(option);
}
try {
let uiElement = document.getElementById("camera_view");
uiElement.append(cameraView.getUIElement());
cameraView.getUIElement().shadowRoot?.querySelector('.dce-sel-camera')?.setAttribute('style', 'display: none');
cameraView.getUIElement().shadowRoot?.querySelector('.dce-sel-resolution')?.setAttribute('style', 'display: none');
}
catch (ex) {
console.error(ex);
}
}
else {
alert("No camera found.");
}
}
catch (ex) {
console.error(ex);
}
}
async function cameraChanged() {
if (cameras != null && cameras.length > 0) {
let index = cameraSource.selectedIndex;
await openCamera(cameraEnhancer, cameras[index]);
}
}
Implementing the MRZ/VIN Scanner Logic
To recognize MRZ and VIN from images or camera streams, use the capture()
and startCapturing()
methods respectively. The capture()
method returns the recognition results directly, while the startCapturing()
method starts a continuous capturing process and returns the results through the onCapturedResultReceived
callback.
-
Recognizing MRZ/VIN from Image Files
function loadImage2Canvas(base64Image) { imageFile.src = base64Image; img.src = base64Image; img.onload = function () { let width = img.width; let height = img.height; overlayCanvas.width = width; overlayCanvas.height = height; if (!isSDKReady) { alert("Please activate the SDK first."); return; } toggleLoading(true); let selectedMode = document.querySelector('input[name="scanMode"]:checked').value; let context = overlayCanvas.getContext('2d'); context.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height); try { if (selectedMode == "mrz") { mrzRouter.capture(img.src, "ReadMRZ").then((result) => { showFileResult(selectedMode, context, result); }); } else if (selectedMode == "vin") { vinRouter.capture(img.src, "ReadVINText").then((result) => { showFileResult(selectedMode, context, result); }); } } catch (ex) { console.error(ex); } toggleLoading(false); }; }
-
Recognizing MRZ/VIN from Camera Stream
async function scan() { if (!isSDKReady) { alert("Please activate the SDK first."); return; } let selectedMode = document.querySelector('input[name="scanMode"]:checked').value; if (!isDetecting) { scanButton.innerHTML = "Stop"; isDetecting = true; if (selectedMode == "mrz") { mrzRouter.setInput(cameraEnhancer); mrzRouter.startCapturing("ReadMRZ"); } else if (selectedMode == "vin") { vinRouter.setInput(cameraEnhancer); vinRouter.startCapturing("ReadVINText"); } } else { scanButton.innerHTML = "Scan"; isDetecting = false; if (selectedMode == "mrz") { mrzRouter.stopCapturing(); } else if (selectedMode == "vin") { vinRouter.stopCapturing(); } cameraView.clearAllInnerDrawingItems(); } }
Drawing Overlays and Results
You can draw overlays on the image or video stream to highlight recognized areas and display the parsed results in a text area.
-
On Image Files
async function showFileResult(selectedMode, context, result) { let parseResults = ''; let detection_result = document.getElementById('detection_result'); detection_result.innerHTML = ""; let txts = []; let items = result.items; if (items.length > 0) { for (var i = 0; i < items.length; ++i) { if (items[i].type !== Dynamsoft.Core.EnumCapturedResultItemType.CRIT_TEXT_LINE) { continue; } let item = items[i]; parseResults = await parser.parse(item.text); txts.push(item.text); localization = item.location; context.strokeStyle = '#ff0000'; context.lineWidth = 2; let points = localization.points; context.beginPath(); context.moveTo(points[0].x, points[0].y); context.lineTo(points[1].x, points[1].y); context.lineTo(points[2].x, points[2].y); context.lineTo(points[3].x, points[3].y); context.closePath(); context.stroke(); } } if (txts.length > 0) { detection_result.innerHTML += txts.join('\n') + '\n\n'; if (selectedMode == "mrz") { detection_result.innerHTML += JSON.stringify(extractMrzInfo(parseResults)); } else if (selectedMode == "vin") { detection_result.innerHTML += JSON.stringify(extractVinInfo(parseResults)); } } else { detection_result.innerHTML += "Recognition Failed\n"; } }
-
On Camera Stream
async function showCameraResult(result) { let selectedMode = document.querySelector('input[name="scanMode"]:checked').value; let items = result.items; let scan_result = document.getElementById('scan_result'); if (items != null && items.length > 0) { let item = items[0]; let parseResults = await parser.parse(item.text); if (selectedMode == "mrz") { scan_result.innerHTML = JSON.stringify(extractMrzInfo(parseResults)); } else if (selectedMode == "vin") { scan_result.innerHTML = JSON.stringify(extractVinInfo(parseResults)); } } }
Running the Web MRZ/VIN Scanner
- Open your terminal and navigate to the project directory.
-
Start a local server using Python:
python -m http.server 8000
-
Open your web browser and navigate to
http://localhost:8000
.
Source Code
https://github.com/yushulx/javascript-barcode-qr-code-scanner/tree/main/examples/mrz-vin-scanner