Skip to content

update to internal commit 39066676 #899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
270 changes: 270 additions & 0 deletions _articles/indepth/development/mrz.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
---
layout: default-layout
needAutoGenerateSidebar: true
title: Dynamic Web TWAIN SDK Development - MRZ Scanner Integration
keywords: Dynamic Web TWAIN, Documentation, Development, MRZ, MRZ Scanner, Integration
breadcrumbText: MRZ Scanner Integration
description: Dynamic Web TWAIN SDK Documentation MRZ Scanner Integration Page
---

# Integrating the MRZ Scanner into a Dynamic Web TWAIN Application

One of the solutions that Dynamsoft offers is the [MRZ Scanner](https://www.dynamsoft.com/use-cases/mrz-scanner/), which is built on the foundational products [Dynamsoft Label Recognizer]({{ site.dcv }}core/introduction/?ver=latest&ver=latest#dynamsoft-label-recognizer) and the [Dynamsoft Code Parser]({{ site.dcv }}core/introduction/?ver=latest&ver=latest#dynamsoft-code-parser). This solution allows the user to scan MRZs in a web or native mobile application, either via a camera or static images from the local photo library.

In this article, we will address how you can integrate the foundational products of the MRZ Scanner JavaScript Edition (Dynamsoft Label Recognizer, Dynamsoft Code Parser) with Dynamic Web TWAIN to implement the ability to read from static images without the need for a camera input.

> You can download the [full sample code](https://github.com/Dynamsoft/mrz-scanner-javascript/tree/main/samples/dwt-mrz) from the Github repository of the MRZ Scanner Samples. Please use this sample as reference when building your own application.

## Initialization

Dynamic Web TWAIN (DWT for short) allows users to acquire images from scanners in a web application, as well as load or download existing documents. One of the advantages of using Dynamic Web TWAIN is that it allows the user to load in PDFs as well as images. So whether you are loading in a local image or acquiring an image from a physical scanner, Dynamic Web TWAIN keeps things simple and implements these features with a few simple API.

### Setting up the Resources

The first thing to do when creating a web application that utilizes DWT is to include the Resources folder of DWT. In this folder, the template for the MRZ Reader needs to also be included since it will be referenced by the MRZ Reader. To get a copy of the DWT Resources, please download the [30-day free trial](https://www.dynamsoft.com/web-twain/downloads) of Dynamic Web TWAIN.

To get started with setting up the DWT resources and license key, please refer to the [General Usage]({{ site.general-usage }}index.html) page of the DWT docs. For the implementation that this guide will address, we will keep it to the basic functionalities of DWT, which is to [acquire images from a scanner]({{ site.general-usage }}scanner-image-acquisition.html) and [loading documents from local files]({{ site.extended-usage }}file-import.html).

### Initializing the Input Source and Capture Vision Instance

The following is the full code needed to implement the basic functionalities of Dynamic Web TWAIN as well as the initialization of the MRZ reader using the [foundational API]({{ site.dcv }}web/programming/javascript/api-reference/index.html) of Dynamsoft Capture Vision.

```html
<!DOCTYPE html>
<html>

<head>
<title>Hello World</title>
<script type="text/javascript" src="Resources/dynamsoft.webtwain.initiate.js"></script>
<script type="text/javascript" src="Resources/dynamsoft.webtwain.config.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-bundle@2.6.1000/dist/dcv.bundle.js"></script>
</head>

<body>
<input type="button" value="Scan" onclick="AcquireImage();" />
<input type="button" value="Load" onclick="LoadImage();" />
<input type="button" value="Read MRZ" onclick="readMRZ();" />
<div id="dwtcontrolContainer" style="width: 350px; height: 380px;"></div>

<p>MRZ Result:</p>
<div
id="divNoteMessage"
style="width: 500px; height: 450px; border: 1px solid #ccc; overflow: auto; white-space: pre-line"
></div>

<script type="text/javascript">
var DWTObject;
var cvRouter;

Dynamsoft.DWT.RegisterEvent("OnWebTwainReady", function () {
initializeMRZ();
DWTObject = Dynamsoft.DWT.GetWebTwain('dwtcontrolContainer'); // Get the Dynamic Web TWAIN object that is embedded in the div with id 'dwtcontrolContainer'
});

/* The objective of this function is to initialize the Capture Vision instance and apply the necessary settings for reading MRZ */
async function initializeMRZ() {
// Inialize License Key
Dynamsoft.License.LicenseManager.initLicense("MRZ_LICENSE_KEY_HERE");

// Load MRZ Resources
Dynamsoft.Core.CoreModule.loadWasm(["DLR", "DCP"]);
Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_PASSPORT");
Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD1_ID");
Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_ID");
Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("MRZ");

// Create Capture Vision Router Instance with MRZ templates
cvRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
await cvRouter.initSettings("./Resources/mrz-template.json");

console.log("MRZ Initialized Successfully");
}

/* This function is used to acquire an image from a physical scanner using the DWT API */
function AcquireImage() {
if (DWTObject) {
DWTObject.SelectSourceAsync().then(function(){
return DWTObject.AcquireImageAsync({
IfCloseSourceAfterAcquire: true // Scanner source will be closed automatically after the scan.
});
}).catch(function (exp) {
alert(exp.message);
});
}
}

//Callback functions for async APIs
function OnSuccess() {
console.log('successful');
}

function OnFailure(errorCode, errorString) {
if(errorCode != -2326)
alert(errorString);
}

/* The fucntion that is triggered when the user clicks the "Load" button */
function LoadImage() {
if (DWTObject) {
DWTObject.IfShowFileDialog = true; // Open the system's file dialog to load image
DWTObject.LoadImageEx("", Dynamsoft.DWT.EnumDWT_ImageType.IT_ALL, OnSuccess, OnFailure); // Load images in all supported formats (.bmp, .jpg, .tif, .png, .pdf). OnSuccess or OnFailure will be called after the operation
}
}

/* A function to check if there are any images in the DWT buffer */
function checkIfImagesInBuffer() {
if (DWTObject.HowManyImagesInBuffer == 0) {
console.log("There is no image in the buffer.")
return false;
}
else return true;
}
</script>
</body>

</html>
```

## Implementing the MRZ Reader

Now that we introduced the code to initialize DWT and the MRZ Reader, as well as defined the functions that implement the scanning and loading capabilities of Web TWAIN, it's time now to implement the MRZ reading portion of the code. Continuing the **script** from the previous section:

```js
// Used by the Button on page, to trigger a MRZ read with the current select page
async function readMRZ() {
if (!checkIfImagesInBuffer()) {
return;
}
if (!cvRouter) {
console.log("cvRouter is not initialized.");
return;
}
let imgURL = DWTObject.GetImageURL(DWTObject.CurrentImageIndexInBuffer);
let capturedResults = await cvRouter.capture(imgURL, "ReadPassportAndId");
const recognizedResults = capturedResults.textLineResultItems;
const parsedResults = capturedResults.parsedResultItems;
if (!parsedResults || !parsedResults.length) {
console.log("No Result");
return;
}

let extractedResults = JSON.stringify(extractDocumentFields(parsedResults[0]));
extractedResults = extractedResults.split(",").join("\n");
extractedResults = extractedResults.replace(/{"text":|[{"}]/g, "");
document.getElementById("divNoteMessage").innerHTML = extractedResults; // print the result to the result div
}

/**
* Extracts and returns document fields from the parsed MRZ result
*
* @param {Object} result - The parsed result object containing document fields.
* @returns {Object} An object with key-value pairs of the extracted fields.
*/
function extractDocumentFields(result) {
if (!result || result.exception) {
return {};
}

const fieldWithStatus = (fieldName, raw=false) => ({
text: raw ? result.getFieldRawValue(fieldName) : result.getFieldValue(fieldName),
});

const parseDate = (yearField, monthField, dayField) => {
const year = result.getFieldValue(yearField);
const currentYear = new Date().getFullYear() % 100;
const baseYear =
yearField === "expiryYear" ? (parseInt(year) >= 60 ? "19" : "20") : parseInt(year) > currentYear ? "19" : "20";

return {
text: `${baseYear}${year}-${result.getFieldValue(monthField)}-${result.getFieldValue(dayField)}`,
};
};

// Add special case for Spanish IDs
const getDocumentNumber = (codeType) => {
const documentType = mapDocumentType(codeType);
const documentNumberField =
documentType === "passport" && codeType === "MRTD_TD3_PASSPORT"
? "passportNumber"
: result.getFieldRawValue("nationality") === "ESP" ?
"optionalData1" : "documentNumber";

const primaryNumber = fieldWithStatus(documentNumberField);
const longNumber = fieldWithStatus("longDocumentNumber");

return primaryNumber?.text ? primaryNumber : longNumber;
};

// Document Type and Name
const codeType = result.codeType;

return {
Surname: fieldWithStatus("primaryIdentifier"),
"Given Name": fieldWithStatus("secondaryIdentifier"),
Nationality: fieldWithStatus("nationality", true),
"Document Number": getDocumentNumber(codeType),
"Document Type": documentTypeLabel(codeType),
"Issuing State": fieldWithStatus("issuingState", true),
Sex: fieldWithStatus("sex", true),
"Date of Birth (YYYY-MM-DD)": parseDate("birthYear", "birthMonth", "birthDay"),
"Date of Expiry (YYYY-MM-DD)": parseDate("expiryYear", "expiryMonth", "expiryDay"),
"Document Type": JSON.parse(result.jsonString).CodeType,
};
}

function mapDocumentType(codeType) {
switch (codeType) {
case "MRTD_TD1_ID":
return "td1";

case "MRTD_TD2_ID":
case "MRTD_TD2_VISA":
case "MRTD_TD2_FRENCH_ID":
return "td2";

case "MRTD_TD3_PASSPORT":
case "MRTD_TD3_VISA":
return "passport";

default:
throw new Error(`Unknown document type: ${codeType}`);
}
}

function documentTypeLabel(codeType) {
switch (codeType) {
case "MRTD_TD1_ID":
return "ID (TD1)";

case "MRTD_TD2_ID":
return "ID (TD2)";
case "MRTD_TD2_VISA":
return "ID (VISA)";
case "MRTD_TD2_FRENCH_ID":
return "French ID (TD2)";

case "MRTD_TD3_PASSPORT":
return "Passport (TD3)";
case "MRTD_TD3_VISA":
return "Visa (TD3)";

default:
throw new Error(`Unknown document type: ${codeType}`);
}
}
```

By completing the script with the code above, you can now go ahead and test the app that you just created. Please note that in order to properly function, the sample will need to be hosted on a server.

If you are using VS Code, a quick and easy way to serve the project is using the [Five Server VSCode extension](https://marketplace.visualstudio.com/items?itemName=yandeu.five-server). Simply install the extension, open the `hello-world.html` file in the editor, and click "Go Live" in the bottom right corner of the editor. This will serve the application at `http://127.0.0.1:5500/hello-world.html`. Alternatively, you can also use IIS or Github Pages to quickly serve your application.

## Final Comments

This sample was built based on the Hello World sample code of Web TWAIN as well as the Hello World code of the previous version of the MRZ Scanner that was dependent fully on the foundational API of Dynamsoft Capture Vision. Here are some references to check out:

- [Dynamic Web TWAIN User Guide]({{ site.general-usage }}index.html)
- [MRZ Scanner User Guide using Foundational DCV API](https://www.dynamsoft.com/mrz-scanner/docs/web/guides/mrz-scanner-v1.1.html?ver=1.1&matchVer=true&cVer=true)
- [Dynamic Web TWAIN API Reference]({{ site.api }})
- [DCV Foundational API Reference]({{ site.dcv }}web/programming/javascript/api-reference/index.html)

If there are any questions regarding this sample or your own implementation, please feel free to contact the [Dynamsoft Support Team](https://www.dynamsoft.com/company/contact/).
2 changes: 2 additions & 0 deletions _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ general-usage: /web-twain/docs/general-usage/
extended-usage: /web-twain/docs/extended-usage/
api: /web-twain/docs/info/api/

dcv: /capture-vision/docs/

dynamsoft_logo: /web-twain/docs/assets/img-icon/dynamsoft-logo.png
dbr_logo: /web-twain/docs/assets/img-icon/dbr-logo.png
edit_icon: /web-twain/docs/assets/img-icon/edit-icon.png
Expand Down
2 changes: 2 additions & 0 deletions _data/full_tree.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ tree_list:
path: /indepth/development/react.html
- name: Use Web TWAIN in Vue
path: /indepth/development/vue.html
- name: Use Web TWAIN with the MRZ Scanner
path: /indepth/development/mrz.html
# - name: Use Web TWAIN in Vue 3
# path: /indepth/development/vue3.html
# - name: Using Web TWAIN with REST API
Expand Down
1 change: 1 addition & 0 deletions index.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ permalink: /index.html
- [Use Web TWAIN in Angular]({{site.indepth}}development/angular.html)
- [Use Web TWAIN in React]({{site.indepth}}development/react.html)
- [Use Web TWAIN in Vue]({{site.indepth}}development/vue.html)
- [Use Web TWAIN with the MRZ Scanner]({{site.indepth}}development/mrz.html)
- [Code Gallery](https://www.dynamsoft.com/web-twain/resources/code-gallery/)

### [API Reference]({{site.api}}index.html)
Expand Down