|
| 1 | +--- |
| 2 | +layout: default-layout |
| 3 | +needAutoGenerateSidebar: true |
| 4 | +needGenerateH3Content: true |
| 5 | +noTitleIndex: false |
| 6 | +title: Dynamsoft MRZ Scanner JavaScript Edition - Reading from Local Images |
| 7 | +keywords: Documentation, MRZ Scanner, Dynamsoft MRZ Scanner JavaScript Edition, Local Images, Load |
| 8 | +description: Reading from Local Images with the Dynamsoft MRZ Scanner JavaScript Edition |
| 9 | +permalink: /codegallery/dwt-mrz/index.html |
| 10 | +--- |
| 11 | + |
| 12 | +# Reading MRZs from Local Images - JavaScript Edition |
| 13 | + |
| 14 | +So far, the [MRZ Scanner JS User Guide]({{ site.guides }}mrz-scanner.html) addressed how you can use the library to scan MRZs from a camera in an interactive live video scenario. The majority of use cases will involve using the camera of a phone or a laptop directly, but there could be cases where a camera is not needed at all. Although the **MRZ Scanner JavaScript Edition** has the ability to read from local static images via the Load Image feature of the MRZScannerView, that still requires connecting to a valid camera input. |
| 15 | + |
| 16 | +In this article, we will address how you can use the foundational products of the MRZ Scanner (Dynamsoft Label Recognizer, Dynamsoft Code Parser) to implement the ability to read from static images without the need for a camera input. |
| 17 | + |
| 18 | +## Initialization |
| 19 | + |
| 20 | +The first thing that needs to be determined is what the source of the images will be. There are several methods in which you can load images in JavaScript application, but in this article we will be using another Dynamsoft product, [Dynamic Web TWAIN]({{ site.dwt }}about/index.html). |
| 21 | + |
| 22 | +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. |
| 23 | + |
| 24 | +### Setting up the Resources |
| 25 | + |
| 26 | +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. |
| 27 | + |
| 28 | +Alternatively, 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. |
| 29 | + |
| 30 | +### Initializing the Input Source and Capture Vision Instance |
| 31 | + |
| 32 | +Let's now introduce 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.dcvb_js_api }}index.html) of Dynamsoft Capture Vision. |
| 33 | + |
| 34 | +```html |
| 35 | +<!DOCTYPE html> |
| 36 | +<html> |
| 37 | + |
| 38 | +<head> |
| 39 | + <title>Hello World</title> |
| 40 | + <script type="text/javascript" src="Resources/dynamsoft.webtwain.initiate.js"></script> |
| 41 | + <script type="text/javascript" src="Resources/dynamsoft.webtwain.config.js"></script> |
| 42 | + <script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-bundle@2.6.1000/dist/dcv.bundle.js"></script> |
| 43 | +</head> |
| 44 | + |
| 45 | +<body> |
| 46 | + <input type="button" value="Scan" onclick="AcquireImage();" /> |
| 47 | + <input type="button" value="Load" onclick="LoadImage();" /> |
| 48 | + <input type="button" value="Read MRZ" onclick="readMRZ();" /> |
| 49 | + <div id="dwtcontrolContainer" style="width: 350px; height: 380px;"></div> |
| 50 | + |
| 51 | + <script type="text/javascript"> |
| 52 | + var DWTObject; |
| 53 | + var cvRouter; |
| 54 | +
|
| 55 | + Dynamsoft.DWT.RegisterEvent("OnWebTwainReady", function () { |
| 56 | + initializeMRZ(); |
| 57 | + DWTObject = Dynamsoft.DWT.GetWebTwain('dwtcontrolContainer'); // Get the Dynamic Web TWAIN object that is embedded in the div with id 'dwtcontrolContainer' |
| 58 | + }); |
| 59 | +
|
| 60 | + /* The objective of this function is to initialize the Capture Vision instance and apply the necessary settings for reading MRZ */ |
| 61 | + async function initializeMRZ() { |
| 62 | + // Inialize License Key |
| 63 | + Dynamsoft.License.LicenseManager.initLicense("MRZ_LICENSE_KEY_HERE"); |
| 64 | + |
| 65 | + // Load MRZ Resources |
| 66 | + Dynamsoft.Core.CoreModule.loadWasm(["DLR", "DCP"]); |
| 67 | + Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD3_PASSPORT"); |
| 68 | + Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD1_ID"); |
| 69 | + Dynamsoft.DCP.CodeParserModule.loadSpec("MRTD_TD2_ID"); |
| 70 | + Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("MRZ"); |
| 71 | +
|
| 72 | + // Create Capture Vision Router Instance with MRZ templates |
| 73 | + cvRouter = await Dynamsoft.CVR.CaptureVisionRouter.createInstance(); |
| 74 | + await cvRouter.initSettings("./Resources/mrz-template.json"); |
| 75 | +
|
| 76 | + console.log("MRZ Initialized Successfully"); |
| 77 | + } |
| 78 | +
|
| 79 | + /* This function is used to acquire an image from a physical scanner using the DWT API */ |
| 80 | + function AcquireImage() { |
| 81 | + if (DWTObject) { |
| 82 | + DWTObject.SelectSourceAsync().then(function(){ |
| 83 | + return DWTObject.AcquireImageAsync({ |
| 84 | + IfCloseSourceAfterAcquire: true // Scanner source will be closed automatically after the scan. |
| 85 | + }); |
| 86 | + }).catch(function (exp) { |
| 87 | + alert(exp.message); |
| 88 | + }); |
| 89 | + } |
| 90 | + } |
| 91 | +
|
| 92 | + //Callback functions for async APIs |
| 93 | + function OnSuccess() { |
| 94 | + console.log('successful'); |
| 95 | + } |
| 96 | +
|
| 97 | + function OnFailure(errorCode, errorString) { |
| 98 | + if(errorCode != -2326) |
| 99 | + alert(errorString); |
| 100 | + } |
| 101 | +
|
| 102 | + /* The fucntion that is triggered when the user clicks the "Load" button */ |
| 103 | + function LoadImage() { |
| 104 | + if (DWTObject) { |
| 105 | + DWTObject.IfShowFileDialog = true; // Open the system's file dialog to load image |
| 106 | + 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 |
| 107 | + } |
| 108 | + } |
| 109 | +
|
| 110 | + /* A function to check if there are any images in the DWT buffer */ |
| 111 | + function checkIfImagesInBuffer() { |
| 112 | + if (DWTObject.HowManyImagesInBuffer == 0) { |
| 113 | + console.log("There is no image in the buffer.") |
| 114 | + return false; |
| 115 | + } |
| 116 | + else |
| 117 | + return true; |
| 118 | + } |
| 119 | + </script> |
| 120 | +</body> |
| 121 | + |
| 122 | +</html> |
| 123 | +``` |
| 124 | + |
| 125 | +## Implementing the MRZ Reader |
| 126 | + |
| 127 | +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: |
| 128 | + |
| 129 | +```js |
| 130 | +// Used by the Button on page, to trigger a MRZ read with the current select page |
| 131 | +async function readMRZ() { |
| 132 | + if (!checkIfImagesInBuffer()) { |
| 133 | + return; |
| 134 | + } |
| 135 | + if (!cvRouter) { |
| 136 | + console.log("cvRouter is not initialized."); |
| 137 | + return; |
| 138 | + } |
| 139 | + console.log("Reading MRZ on Index " + DWTObject.CurrentImageIndexInBuffer); |
| 140 | + let imgURL = DWTObject.GetImageURL(DWTObject.CurrentImageIndexInBuffer); |
| 141 | + let capturedResults = await cvRouter.capture(imgURL, "ReadPassportAndId"); |
| 142 | + const recognizedResults = capturedResults.textLineResultItems; |
| 143 | + const parsedResults = capturedResults.parsedResultItems; |
| 144 | + console.log(parsedResults); |
| 145 | + if (!parsedResults || !parsedResults.length) { |
| 146 | + console.log("No Result"); |
| 147 | + return; |
| 148 | + } |
| 149 | + |
| 150 | + extractedResults = extractDocumentFields(parsedResults[0]); |
| 151 | + console.log(recognizedResults); |
| 152 | + console.log(extractedResults); |
| 153 | + console.log("Please See Detailed MRZ Result in Console"); |
| 154 | +} |
| 155 | + |
| 156 | +/** |
| 157 | + * Extracts and returns document fields from the parsed MRZ result |
| 158 | + * |
| 159 | + * @param {Object} result - The parsed result object containing document fields. |
| 160 | + * @returns {Object} An object with key-value pairs of the extracted fields. |
| 161 | + */ |
| 162 | +function extractDocumentFields(result) { |
| 163 | + if (!result || result.exception) { |
| 164 | + return {}; |
| 165 | + } |
| 166 | + |
| 167 | + const fieldWithStatus = (fieldName, raw=false) => ({ |
| 168 | + text: raw ? result.getFieldRawValue(fieldName) : result.getFieldValue(fieldName), |
| 169 | + status: result.getFieldValidationStatus(fieldName), |
| 170 | + }); |
| 171 | + |
| 172 | + const parseDate = (yearField, monthField, dayField) => { |
| 173 | + const year = result.getFieldValue(yearField); |
| 174 | + const currentYear = new Date().getFullYear() % 100; |
| 175 | + const baseYear = |
| 176 | + yearField === "expiryYear" ? (parseInt(year) >= 60 ? "19" : "20") : parseInt(year) > currentYear ? "19" : "20"; |
| 177 | + |
| 178 | + return { |
| 179 | + text: `${baseYear}${year}-${result.getFieldValue(monthField)}-${result.getFieldValue(dayField)}`, |
| 180 | + status: [yearField, monthField, dayField].every( |
| 181 | + (field) => result.getFieldValidationStatus(field) === Dynamsoft.DCP.EnumValidationStatus.VS_SUCCEEDED |
| 182 | + ) |
| 183 | + ? Dynamsoft.DCP.EnumValidationStatus.VS_SUCCEEDED |
| 184 | + : Dynamsoft.DCP.EnumValidationStatus.VS_FAILED, |
| 185 | + }; |
| 186 | + }; |
| 187 | + |
| 188 | + // Add special case for Spanish IDs |
| 189 | + const getDocumentNumber = (codeType) => { |
| 190 | + const documentType = mapDocumentType(codeType); |
| 191 | + const documentNumberField = |
| 192 | + documentType === "passport" && codeType === "MRTD_TD3_PASSPORT" |
| 193 | + ? "passportNumber" |
| 194 | + : result.getFieldRawValue("nationality") === "ESP" ? |
| 195 | + "optionalData1" : "documentNumber"; |
| 196 | + |
| 197 | + const primaryNumber = fieldWithStatus(documentNumberField); |
| 198 | + const longNumber = fieldWithStatus("longDocumentNumber"); |
| 199 | + |
| 200 | + return primaryNumber?.text ? primaryNumber : longNumber; |
| 201 | + }; |
| 202 | + |
| 203 | + // Document Type and Name |
| 204 | + const codeType = result.codeType; |
| 205 | + |
| 206 | + return { |
| 207 | + Surname: fieldWithStatus("primaryIdentifier"), |
| 208 | + "Given Name": fieldWithStatus("secondaryIdentifier"), |
| 209 | + Nationality: fieldWithStatus("nationality", true), |
| 210 | + "Document Number": getDocumentNumber(codeType), |
| 211 | + "Document Type": documentTypeLabel(codeType), |
| 212 | + "Issuing State": fieldWithStatus("issuingState", true), |
| 213 | + Sex: fieldWithStatus("sex"), |
| 214 | + "Date of Birth (YYYY-MM-DD)": parseDate("birthYear", "birthMonth", "birthDay"), |
| 215 | + "Date of Expiry (YYYY-MM-DD)": parseDate("expiryYear", "expiryMonth", "expiryDay"), |
| 216 | + "Document Type": JSON.parse(result.jsonString).CodeType, |
| 217 | + }; |
| 218 | +} |
| 219 | + |
| 220 | +function mapDocumentType(codeType) { |
| 221 | + switch (codeType) { |
| 222 | + case "MRTD_TD1_ID": |
| 223 | + return "td1"; |
| 224 | + |
| 225 | + case "MRTD_TD2_ID": |
| 226 | + case "MRTD_TD2_VISA": |
| 227 | + case "MRTD_TD2_FRENCH_ID": |
| 228 | + return "td2"; |
| 229 | + |
| 230 | + case "MRTD_TD3_PASSPORT": |
| 231 | + case "MRTD_TD3_VISA": |
| 232 | + return "passport"; |
| 233 | + |
| 234 | + default: |
| 235 | + throw new Error(`Unknown document type: ${codeType}`); |
| 236 | + } |
| 237 | +} |
| 238 | + |
| 239 | +function documentTypeLabel(codeType) { |
| 240 | + switch (codeType) { |
| 241 | + case "MRTD_TD1_ID": |
| 242 | + return "ID (TD1)"; |
| 243 | + |
| 244 | + case "MRTD_TD2_ID": |
| 245 | + return "ID (TD2)"; |
| 246 | + case "MRTD_TD2_VISA": |
| 247 | + return "ID (VISA)"; |
| 248 | + case "MRTD_TD2_FRENCH_ID": |
| 249 | + return "French ID (TD2)"; |
| 250 | + |
| 251 | + case "MRTD_TD3_PASSPORT": |
| 252 | + return "Passport (TD3)"; |
| 253 | + case "MRTD_TD3_VISA": |
| 254 | + return "Visa (TD3)"; |
| 255 | + |
| 256 | + default: |
| 257 | + throw new Error(`Unknown document type: ${codeType}`); |
| 258 | + } |
| 259 | +} |
| 260 | +``` |
| 261 | +
|
| 262 | +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. |
| 263 | +
|
| 264 | +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. |
| 265 | + |
| 266 | +## Final Comments |
| 267 | + |
| 268 | +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: |
| 269 | + |
| 270 | +- [Dynamic Web TWAIN User Guide]({{ site.dwt }}general-usage/index.html) |
| 271 | +- [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) |
| 272 | +- [Dynamic Web TWAIN API Reference]({{ site.dwt }}info/api/) |
| 273 | +- [DCV Foundational API Reference]({{ site.dcvb_js_api }}index.html) |
| 274 | + |
| 275 | +If there are any questions regarding this sample or your own implementation, do not hesitate to get in touch with the [Dynamsoft Support Team](https://www.dynamsoft.com/company/contact/). |
0 commit comments