Developing a Web MRZ and VIN Scanner with JavaScript and HTML5
Xiao Ling

Xiao Ling @yushulx

Joined:
Mar 10, 2021

Developing a Web MRZ and VIN Scanner with JavaScript and HTML5

Publish Date: Apr 15
0 0

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

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:

<script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-bundle@2.6.1000/dist/dcv.bundle.min.js"></script>
Enter fullscreen mode Exit fullscreen mode

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).

    <div class="container">
        <div class="row">
            <div>
                <label>
                    Get a License key from <a
                        href="https://www.dynamsoft.com/customer/license/trialLicense/?product=dcv&package=cross-platform"
                        target="_blank">here</a>
                </label>
                <input type="text" id="license_key"
                    value="LICENSE-KEY"
                    placeholder="LICENSE-KEY">
                <button onclick="activate()">Activate SDK</button>
            </div>
        </div>
    
        <div class="row">
            <div>
                <select onchange="selectChanged()" id="dropdown">
                    <option value="file">File</option>
                    <option value="camera">Camera</option>
                </select>
                <form id="modeSelector">
                    <label>
                        <input type="radio" name="scanMode" value="mrz" checked>
                        MRZ
                    </label>
                    <label>
                        <input type="radio" name="scanMode" value="vin">
                        VIN
                    </label>
                </form>
            </div>
        </div>
    </div>
    
  • A div for displaying the uploaded image and its scanning result.

    <div class="container" id="file_container">
        <div>
            <input type="file" id="pick_file" accept="image/*" />
        </div>
    
        <div class="row">
            <div class="imageview">
                <img id="image_file" src="default.png" />
                <canvas id="overlay_canvas" class="overlay"></canvas>
            </div>
        </div>
    
        <div class="row">
            <div>
                <textarea id="detection_result"></textarea>
            </div>
        </div>
    
    </div>
    
  • A dev for showing the live camera stream along with real-time scanning results.

    <div class="container" id="camera_container">
        <div>
            <select onchange="cameraChanged()" id="camera_source">
            </select>
            <button onclick="scan()" id="scan_button">Start</button>
            <div id="videoview">
                <div id="camera_view"></div>
            </div>
    
            <div class="row">
                <div>
                    <textarea id="scan_result"></textarea>
                </div>
            </div>
    
        </div>
    </div>
    

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);
}
Enter fullscreen mode Exit fullscreen mode

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]);
    }
}
Enter fullscreen mode Exit fullscreen mode

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

  1. Open your terminal and navigate to the project directory.
  2. Start a local server using Python:

    python -m http.server 8000
    
  3. Open your web browser and navigate to http://localhost:8000.

    Web MRZ VIN scanner

Source Code

https://github.com/yushulx/javascript-barcode-qr-code-scanner/tree/main/examples/mrz-vin-scanner

Comments 0 total

    Add comment