{"id":18696300,"url":"https://github.com/dynamsoft/document-normalizer-javascript","last_synced_at":"2026-02-17T09:40:32.486Z","repository":{"id":62808782,"uuid":"561593961","full_name":"Dynamsoft/document-normalizer-javascript","owner":"Dynamsoft","description":null,"archived":false,"fork":false,"pushed_at":"2024-04-08T09:18:08.000Z","size":985,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-08-09T15:57:20.152Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dynamsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-11-04T03:02:39.000Z","updated_at":"2022-11-04T03:02:39.000Z","dependencies_parsed_at":"2025-01-02T00:30:31.351Z","dependency_job_id":null,"html_url":"https://github.com/Dynamsoft/document-normalizer-javascript","commit_stats":{"total_commits":6,"total_committers":2,"mean_commits":3.0,"dds":"0.16666666666666663","last_synced_commit":"12cdc53472de43ae728ceb36531dd922935922d8"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/Dynamsoft/document-normalizer-javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynamsoft%2Fdocument-normalizer-javascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynamsoft%2Fdocument-normalizer-javascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynamsoft%2Fdocument-normalizer-javascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynamsoft%2Fdocument-normalizer-javascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dynamsoft","download_url":"https://codeload.github.com/Dynamsoft/document-normalizer-javascript/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dynamsoft%2Fdocument-normalizer-javascript/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279249740,"owners_count":26134039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-16T02:00:06.019Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-07T11:18:00.399Z","updated_at":"2025-10-16T22:39:15.819Z","avatar_url":"https://github.com/Dynamsoft.png","language":null,"readme":"# Document Normalizer for Your Website - User Guide\n\nWith Dynamsoft Document Normalizer JavaScript edition, you can add to your website the ability to take pictures of documents with your camera and normalize them to obtain high-quality images for further processing or archiving purposes.\n\n\u003e Dynamsoft Document Normalizer v2.0.11 and above is based on Dynamsoft Capture Vision Architecture. To learn more, read [Introduction to Dynamsoft Capture Vision](https://www.dynamsoft.com/capture-vision/docs/core/introduction/).\n\nIn this guide, you'll learn step-by-step how to build such a simple solution in a web page.\n\n\u003cspan style=\"font-size:20px\"\u003eTable of Contents\u003c/span\u003e\n\n- [Document Normalizer for Your Website - User Guide](#document-normalizer-for-your-website---user-guide)\n  - [Hello World - Simplest Implementation](#hello-world---simplest-implementation)\n    - [Understand the code](#understand-the-code)\n      - [About the code](#about-the-code)\n    - [Run the example](#run-the-example)\n  - [Building your own page](#building-your-own-page)\n    - [Include the SDK](#include-the-sdk)\n      - [Use a CDN](#use-a-cdn)\n      - [Host the SDK yourself](#host-the-sdk-yourself)\n      - [Specify the location of the \"engine\" files (optional)](#specify-the-location-of-the-engine-files-optional)\n    - [Define necessary HTML elements](#define-necessary-html-elements)\n    - [Prepare the SDK for the task](#prepare-the-sdk-for-the-task)\n    - [Start the detection](#start-the-detection)\n    - [Review and adjust the boundary](#review-and-adjust-the-boundary)\n    - [Normalize the document](#normalize-the-document)\n    - [Output the document as a file](#output-the-document-as-a-file)\n    - [Restart task](#restart-task)\n  - [System requirements](#system-requirements)\n  - [Release notes](#release-notes)\n  - [Next steps](#next-steps)\n\n## Hello World - Simplest Implementation\n\nThe solution consists of two steps\n\n1. Detect the document boundaries\n2. Normalize the document based on the detected boundaries\n\n### Understand the code\n\nThe following sample code sets up the SDK and implements boundary detection on a web page, which is just the first step in capturing a normalized image of your document. We'll cover the second step later in [Building Your Own Page](#building-your-own-page).\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\n\u003chead\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.10/dist/core.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.10/dist/license.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-utility@1.2.10/dist/utility.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-document-normalizer@2.2.10/dist/ddn.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.10/dist/cvr.js\"\u003e\u003c/script\u003e\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.2/dist/dce.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n\n\u003cbody\u003e\n    \u003ch1\u003eDetect the Boundary of the Document\u003c/h1\u003e\n    \u003cbutton onclick=\"startDetection()\"\u003eStart Detection\u003c/button\u003e\n    \u003cdiv id=\"cameraViewContainer\" style=\"width: 50vw; height: 45vh; margin-top: 10px; display: none\"\u003e\u003c/div\u003e\n\n    \u003cscript\u003e\n        const cameraViewContainer = document.querySelector(\n            \"#cameraViewContainer\"\n        );\n        let router;\n        let cameraEnhancer;\n        Dynamsoft.License.LicenseManager.initLicense(\n                \"DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9\"\n        );\n        Dynamsoft.Core.CoreModule.loadWasm([\"DDN\"]);\n\n        (async function() {\n            router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();\n            let view = await Dynamsoft.DCE.CameraView.createInstance();\n            cameraEnhancer = await Dynamsoft.DCE.CameraEnhancer.createInstance(\n                view\n            );\n            cameraViewContainer.append(view.getUIElement());\n            router.setInput(cameraEnhancer);\n        })();\n        async function startDetection() {\n            cameraViewContainer.style.display = \"block\";\n            await cameraEnhancer.open();\n            await router.startCapturing(\"DetectDocumentBoundaries_Default\");\n        };\n    \u003c/script\u003e\n\u003c/body\u003e\n\n\u003c/html\u003e\n```\n\n-----\n\n#### About the code\n\n- `Dynamsoft.License.LicenseManager.initLicense()`: initializes the license using a license key string.\n\n- `Dynamsoft.Core.CoreModule.loadWasm([\"DDN\"])`: preloads the `DocumentNormalizer` module, saving time in preparing for document border detection and image normalization.\n\n- `Dynamsoft.CVR.CaptureVisionRouter.createInstance()`: initializes the `router` variable by creating an instance of the `CaptureVisionRouter` class. An instance of `CaptureVisionRouter` is the core of any solution based on Dynamsoft Capture Vision architecture.\n\n  \u003e Read more on [what is CaptureVisionRouter](https://www.dynamsoft.com/capture-vision/docs/core/architecture/#capture-vision-router)\n\n- `Dynamsoft.DCE.CameraEnhancer.createInstance(view)`: initializes the `cameraEnhancer` variable by creating an instance of the `CameraEnhancer` class.\n\n- `setInput()`: `router` connects to the image source through the [Image Source Adapter](https://www.dynamsoft.com/capture-vision/docs/web//programming/javascript/api-reference/core/image-source-adapter.html) interface with the method `setInput()`.\n\n  \u003e The image source in our case is a CameraEnhancer object created with `Dynamsoft.DCE.CameraEnhancer.createInstance(view)`\n\n  \u003e In some cases, a different camera might be required instead of the default one. Also, a different resolution might work better. To change the camera or the resolution, use the `CameraEnhancer` instance `cameraEnhancer`. Learn more [here](https://www.dynamsoft.com/camera-enhancer/docs/web/programming/javascript/api-reference/camera-control.html).\n\n- `startCapturing(\"DetectDocumentBoundaries_Default\")` : starts to run images through a pre-defined process which, in the case of \"DetectDocumentBoundaries_Default\", tries to find the boundary of a document present in the image(s).\n\n### Run the example\n\nCreate a text file called \"Detect-A-Document-Boundary.html\", fill it with the code above and save it. After that, open the example page in your browser, allow the page to access your camera, and the video will be displayed on the page. Afterwards, you will see the detected boundaries displayed on the video in real time.\n\n\u003e NOTE:\n\u003e \n\u003e The sample code requires the following to run:\n\u003e \n\u003e 1. Internet connection\n\u003e 2. [A supported browser](#system-requirements)\n\u003e 3. An accessible Camera\n\nPlease note:\n\n- Although the page should work properly when opened directly as a file (\"file:///\"), it's recommended that you deploy it to a web server and access it via HTTPS.\n- On first use, you need to wait a few seconds for the SDK to initialize.\n- The license \"DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9\" used in this sample is an online license good for 24 hours and requires network connection to work. To test the SDK further, you can request a 30-day trial license via the [customer portal](https://www.dynamsoft.com/customer/license/trialLicense?utm_source=github\u0026architecture=dcv\u0026product=ddn\u0026package=js).\n\nIf the test doesn't go as expected, you can [contact us](https://www.dynamsoft.com/company/customer-service/#contact).\n\n## Building your own page\n\nIn this section, we'll break down and show all the steps needed to build the solution in a web page.\n\nWe'll build on this skeleton page:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n    \u003ch1\u003eDetect the Boundary of the Document and Normalize it\u003c/h1\u003e\n    \u003cscript\u003e\n      // Write your code here.\n    \u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### Include the SDK\n\nTo utilize the SDK, the initial step involves including the corresponding resource files:\n\n* `core.js`: Required, encompasses common classes, interfaces, and enumerations that are shared across all Dynamsoft SDKs under Dynamsoft Capture Vision Architecture.\n* `license.js`: Required, introduces the `LicenseManager` class, which manages the licensing for all Dynamsoft SDKs under Dynamsoft Capture Vision Architecture.\n* `utility.js`Optional, encompasses auxiliary classes that are shared among all Dynamsoft SDKs under Dynamsoft Capture Vision Architecture.\n* `ddn.js`: Required, defines interfaces and enumerations specifically tailored to the document normalizer module.\n* `cvr.js`: Required, introduces the `CaptureVisionRouter` class, which governs the entire image processing workflow.\n* `dce.js`: Recommended, comprises classes that offer camera support and basic user interface functionalities.\n\n#### Use a CDN\n\nThe simplest way to include the SDK is to use either the [jsDelivr](https://jsdelivr.com/) or [UNPKG](https://unpkg.com/) CDN.\n\n- jsDelivr\n\n  ```html\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.10/dist/core.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.10/dist/license.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-utility@1.2.10/dist/utility.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-document-normalizer@2.2.10/dist/ddn.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.10/dist/cvr.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.2/dist/dce.js\"\u003e\u003c/script\u003e\n  ```\n\n- UNPKG\n\n  ```html\n  \u003cscript src=\"https://unpkg.com/dynamsoft-core@3.2.10/dist/core.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/dynamsoft-license@3.2.10/dist/license.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/dynamsoft-utility@1.2.10/dist/utility.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/dynamsoft-document-normalizer@2.2.10/dist/ddn.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/dynamsoft-capture-vision-router@2.2.10/dist/cvr.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"https://unpkg.com/dynamsoft-camera-enhancer@4.0.2/dist/dce.js\"\u003e\u003c/script\u003e\n  ```\n\n#### Host the SDK yourself\n\nBesides using the CDN, you can also download the SDK and host its files on your own website / server before including it in your application. When using a CDN, resources related to `dynamsoft-image-processing` and `dynamsoft-capture-vision-std` are automatically loaded over the network; When using them locally, these two packages need to be configured manually.\n\nOptions to download the SDK:\n\n- From the website\n\n  [Download the JavaScript ZIP package](https://www.dynamsoft.com/document-normalizer/downloads/?ver=2.2.10\u0026utm_source=github)\n\n- yarn\n\n  ```cmd\n  yarn add dynamsoft-core@3.2.10 --save\n  yarn add dynamsoft-license@3.2.10 --save\n  yarn add dynamsoft-utility@1.2.10 --save\n  yarn add dynamsoft-document-normalizer@2.2.10 --save\n  yarn add dynamsoft-capture-vision-router@2.2.10 --save\n  yarn add dynamsoft-camera-enhancer@4.0.2 --save\n  yarn add dynamsoft-capture-vision-std@1.2.0 --save\n  yarn add dynamsoft-image-processing@2.2.10 --save\n  ```\n\n- npm\n\n  ```cmd\n  npm install dynamsoft-core@3.2.10 --save\n  npm install dynamsoft-license@3.2.10 --save\n  npm install dynamsoft-utility@1.2.10 --save\n  npm install dynamsoft-document-normalizer@2.2.10 --save\n  npm install dynamsoft-capture-vision-router@2.2.10 --save\n  npm install dynamsoft-camera-enhancer@4.0.2 --save\n  npm install dynamsoft-capture-vision-std@1.2.0 --save\n  npm install dynamsoft-image-processing@2.2.10 --save\n  ```\n\nDepending on how you downloaded the SDK and where you put it, you can typically include it like this:\n\n  ```html\n  \u003c!-- Upon extracting the zip package into your project, you can generally include it in the following manner --\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-core@3.2.10/dist/core.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-license@3.2.10/dist/license.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-utility@1.2.10/dist/utility.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-document-normalizer@2.2.10/dist/ddn.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-capture-vision-router@2.2.10/dist/cvr.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./dynamsoft/distributables/dynamsoft-camera-enhancer@4.0.2/dist/dce.js\"\u003e\u003c/script\u003e\n  ```\n\nor\n\n  ```html\n  \u003cscript src=\"./node_modules/dynamsoft-core/dist/core.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./node_modules/dynamsoft-license/dist/license.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./node_modules/dynamsoft-utility/dist/utility.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./node_modules/dynamsoft-document-normalizer/dist/ddn.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./node_modules/dynamsoft-capture-vision-router/dist/cvr.js\"\u003e\u003c/script\u003e\n  \u003cscript src=\"./node_modules/dynamsoft-camera-enhancer/dist/dce.js\"\u003e\u003c/script\u003e\n  ```\n\n#### Specify the location of the \"engine\" files (optional)\n\nThis is usually only required with frameworks like Angular or React, etc. where the referenced JavaScript files such as `cvr.js`, `ddn.js` are compiled into another file, or using the SDKs completely offline.\n\nThe purpose is to tell the SDK where to find the engine files (\\*.worker.js, \\*.wasm.js and \\*.wasm, etc.). The API is called `Dynamsoft.Core.CoreModule.engineResourcePaths`:\n\n```javascript\n//The following code uses the jsDelivr CDN, feel free to change it to your own location of these files\nObject.assign(Dynamsoft.Core.CoreModule.engineResourcePaths, {\n  core: \"https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.10/dist/\",\n  license: \"https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.10/dist/\",\n  ddn: \"https://cdn.jsdelivr.net/npm/dynamsoft-document-normalizer@2.2.10/dist/\",\n  cvr: \"https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.10/dist/\",\n  dce: \"https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.2/dist/\",\n  std: \"https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-std@1.2.0/dist/\",\n  dip: \"https://cdn.jsdelivr.net/npm/dynamsoft-image-processing@2.2.10/dist/\",\n});\n```\n\n### Define necessary HTML elements\n\nFor this solution, we define three buttons and three `\u003cdiv\u003e` elements.\n\n```html\n\u003cbutton id=\"start-detecting\" onclick=\"startDetecting()\"\u003eStart Detecting\u003c/button\u003e\n\u003cbutton id=\"restart-detecting\" onclick=\"restartDetecting()\" style=\"display: none\"\u003eRestart Detecting\u003c/button\u003e\n\u003cbutton id=\"normalize-with-confirmed-quad\" disabled\u003eNormalize\u003c/button\u003e\u003cbr /\u003e\n\u003cdiv id=\"div-ui-container\" style=\"margin-top: 10px; height: 450px\"\u003e\u003c/div\u003e\n\u003cdiv id=\"div-image-container\" style=\"display: none; width: 100%; height: 70vh\"\u003e\u003c/div\u003e\n\u003cdiv id=\"normalized-result\"\u003e\u003c/div\u003e\n```\n\n```js\nconst btnStart = document.querySelector(\"#start-detecting\");\nconst btnRestart = document.querySelector(\"#restart-detecting\");\nconst btnNormalize = document.querySelector(\"#normalize-with-confirmed-quad\");\nconst cameraViewContainer = document.querySelector(\"#div-ui-container\");\nconst imageEditorViewContainer = document.querySelector(\"#div-image-container\");\nconst normalizedImageContainer = document.querySelector(\"#normalized-result\");\n```\n\n### Prepare the SDK for the task\n\nThe following function executes as soon as the page loads to get the SDK prepared:\n\n```js\nlet cameraEnhancer = null;\nlet router = null;\nlet items;\nlet layer;\nlet originalImage;\nlet imageEditorView;\nlet promiseCVRReady;\nlet frameCount = 0\n\nDynamsoft.License.LicenseManager.initLicense(\"DLS2eyJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSJ9\");\n/* Preloads the `DocumentNormalizer` module, saving time in preparing for document border detection and image normalization.*/\nDynamsoft.Core.CoreModule.loadWasm([\"DDN\"])\n\nasync function initDCE() {\n  const view = await Dynamsoft.DCE.CameraView.createInstance();\n  cameraEnhancer = await Dynamsoft.DCE.CameraEnhancer.createInstance(view);\n  imageEditorView = await Dynamsoft.DCE.ImageEditorView.createInstance(imageEditorViewContainer);\n  /* Creates an image editing layer for drawing found document boundaries. */\n  layer = imageEditorView.createDrawingLayer();\n  cameraViewContainer.append(view.getUIElement());\n}\n\nlet cvrReady = (async function initCVR() {\n  await initDCE();\n  router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();\n  router.setInput(cameraEnhancer);\n})();\n```\n\nThe code was explained earlier. Please refer to [About the Code](#about-the-code).\n\n### Start the detection\n\nOnce the image processing is complete, the results are sent to all the registered `CapturedResultReceiver` objects. Each `CapturedResultReceiver` object may encompass one or multiple callback functions associated with various result types. In our task, we need to detect the document border and normalize it, so we use callback function `onCapturedResultReceived` to get both detected borders and the original image for later normalization.\n\n\u003e Read more on [`CapturedResultReceiver`](https://www.dynamsoft.com/capture-vision/docs/web/programming/javascript/api-reference/capture-vision-router/interfaces/captured-result-receiver.html)\n\n```js\nlet cvrReady = (async function initCVR() {\n  /**\n   * Creates a CaptureVisionRouter instance and configure the task to detect document boundaries.\n   * Also, make sure the original image is returned after it has been processed.\n   */\n  await initDCE();\n  router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();\n  router.setInput(cameraEnhancer);\n  /**\n   * Sets the result types to be returned.\n   * Because we need to normalize a document from the original image later, here we set the return result type to\n   * include both the quadrilateral and original image data.\n   */  \n  let newSettings = await router.getSimplifiedSettings(\"DetectDocumentBoundaries_Default\");\n  newSettings.capturedResultItemTypes = Dynamsoft.Core.EnumCapturedResultItemType.CRIT_DETECTED_QUAD | Dynamsoft.Core.EnumCapturedResultItemType.CRIT_ORIGINAL_IMAGE;\n  await router.updateSettings(\"DetectDocumentBoundaries_Default\", newSettings)\n  /* Defines the result receiver for the task.*/\n  const resultReceiver = new Dynamsoft.CVR.CapturedResultReceiver();\n  resultReceiver.onCapturedResultReceived = handleCapturedResult;\n  router.addResultReceiver(resultReceiver);\n})();\n\nasync function handleCapturedResult(result) {\n  /* Update the result of the latest frame to the global variable items*/\n  items = result.items;\n  /* Do something with the result items*/\n}\n```\n\nAnd we define the function `startDetecting` like this:\n\n```js\nasync function startDetecting() {\n  try {\n    await (promiseCVRReady = promiseCVRReady || (async () =\u003e {\n      await cvrReady;\n      /* Starts streaming the video. */\n      await cameraEnhancer.open();\n      /* Uses the built-in template \"DetectDocumentBoundaries_Default\" to start a continuous boundary detection task. */\n      await router.startCapturing(\"DetectDocumentBoundaries_Default\");\n    })());\n  } catch (ex) {\n    let errMsg = ex.message || ex;\n    console.error(errMsg);\n    alert(errMsg);\n  }\n}\n```\n\nThe steps of the workflow is as follows\n\n1. `cameraEnhancer` streams the video, captures live video frames and stores them in a buffer.\n2. `router` gets the video frames from `Image Source Adapter` and passes them to be processed by an internal `DocumentNormalizer` instance. The `cameraEnhancer` used here is a special implementation of the `Image Source Adapter`.\n3. The internal `DocumentNormalizer` instance returns the found document boundaries, known as `quadsResultItems`, to `router`.\n4. The `router` can output all types of CapturedResults that need to be captured through the `onCapturedResultReceived` callback function. In this example code we use the callback function to output `quadsResultItems` and `originalImageResultItem`.\n\n\u003e Also note that the `quadsResultItems` are drawn over the video automatically to show the detection in action.\n\n*Note*:\n\n* `router` is engineered to consistently request images from the image source.\n* Three preset templates are at your disposal for document normalizing or border detection:\n\n| Template Name                          | Function                                          |\n| -------------------------------------- | ------------------------------------------------- |\n| **DetectDocumentBoundaries_Default**   | Detect document border on images.                 |\n| **NormalizeDocument_Default**          | Input an ROI and an image and normalize it.       |\n| **DetectAndNormalizeDocument_Default** | Detect document border on images and normalize it |\n\nRead more on the [preset CaptureVisionTemplates](./preset-templates.md).\n\n### Review and adjust the boundary\n\nFirst we update the callback function, use a specific condition to ensure that the camera has stabilized:\n\n```js\nasync function handleCapturedResult(result) {\n      /* Update the result of the latest frame to the global variable items*/\n      items = result.items;\n      /* Do something with the result */\n      /* Saves the image data of the current frame for subsequent image editing. */\n      const originalImage = result.items.filter((item) =\u003e item.type === 1);\n      originalImageData = originalImage.length \u0026\u0026 originalImage[0].imageData;\n      if (originalImageData) {\n        if (result.items.length \u003c= 1) {\n          frameCount = 0;\n          return;\n        }\n        frameCount++;\n        /**\n         * In our case, we define a good condition for \"ready for normalization\" as \n         * \"getting the document boundary detected for 30 consecutive frames\".\n         * \n         * NOTE that this condition is not valid if you add a CapturedResultFilter \n         * with ResultDeduplication enabled.\n         */\n        if (frameCount === 30) {\n          frameCount = 0;\n          /* Stops the detection task since we assume we have found a good boundary. */\n          router.stopCapturing();\n          /* Hides the cameraView and shows the imageEditorView. */\n          cameraViewContainer.style.display = \"none\";\n          imageEditorViewContainer.style.display = \"block\";\n          /* Draws the image on the imageEditorView first. */\n          imageEditorView.setOriginalImage(originalImageData);\n          quads = [];\n          /* Draws the document boundary (quad) over the image. */\n          for (let i = 0; i \u003c result.items.length; i++) {\n            if (result.items[i].type === Dynamsoft.Core.EnumCapturedResultItemType.CRIT_ORIGINAL_IMAGE) continue;\n            const points = result.items[i].location.points;\n            const quad = new Dynamsoft.DCE.QuadDrawingItem({ points });\n            quads.push(quad);\n            layer.addDrawingItems(quads);\n          }\n          btnStart.style.display = \"none\";\n          btnRestart.style.display = \"inline\";\n          btnNormalize.disabled = false;\n        }\n      }\n    }\n```\n\nThe SDK tries to find the boundary of the document in each and every image processed. This happens very fast and we don't always get the perfect boundary for normalization. Therefore, we can refine the boundary within the `ImageEditorView` to enhance its quality before proceeding with the normalization process.\nTo do this, we can record the manually edited border information by:\n\n```js\nbtnNormalize.addEventListener(\"click\", async () =\u003e {\n  /* Gets the selected quadrilateral. */\n  let seletedItems = imageEditorView.getSelectedDrawingItems();\n  let quad;\n  if (seletedItems.length) {\n    quad = seletedItems[0].getQuad();\n  } else {\n    quad = items[1].location;\n  }\n});\n```\n\nNow, the behavior will be\n\n1. The page constantly detect the boundary of the document in the video.\n2. When the border is successfully found for 30 consecutive frames, the page hides the video stream and draw both the image and the boundary in the \"imageEditorViewer\".\n3. The user can adjust the boundary to be more precise.\n\n### Normalize the document\n\nAfter the user has adjusted the boundary or determined that the found boundary is good enough, he can press the button \"Normalize\" to carry out the normalization as the last step of the solution.\nOne way to use the adjusted border is to set it as the new ROI in the template `NormalizeDocument_Default`. You can simply update the code like this:\n\n```js\nbtnNormalize.addEventListener(\"click\", async () =\u003e {\n  /* Gets the selected quadrilateral. */\n  let seletedItems = imageEditorView.getSelectedDrawingItems();\n  let quad;\n  if (seletedItems.length) {\n    quad = seletedItems[0].getQuad();\n  } else {\n    quad = items[1].location;\n  }\n  /* Hides the imageEditorView. */\n  imageEditorViewContainer.style.display = \"none\";\n  /* Removes the old normalized image if any. */\n  normalizedImageContainer.innerHTML = \"\";\n  /**\n   * Sets the coordinates of the ROI (region of interest)\n   * in the built-in template \"NormalizeDocument_Default\".\n   */\n  let newSettings = await router.getSimplifiedSettings(\"NormalizeDocument_Default\");\n  newSettings.roiMeasuredInPercentage = 0;\n  newSettings.roi.points = quad.points;\n  await router.updateSettings(\"NormalizeDocument_Default\", newSettings);\n  /* Executes the normalization and shows the result on the page. */\n  let normalizeResult = await router.capture(originalImageData, \"NormalizeDocument_Default\");\n  if (normalizeResult.items[0]) {\n    normalizedImageContainer.append(normalizeResult.items[0].toCanvas());\n  }\n  layer.clearDrawingItems();\n  btnNormalize.disabled = true;\n});\n```\n\nThe added behavior is:\n\n1. The user hits \"Normalize Image\"\n2. The image gets normalized with the adjusted boundary\n3. The normalized image shows up on the page\n\n### Output the document as a file\n\nWe can output the document as a file with the help of the class `Dynamsoft.Utility.ImageManager`. To do this, we change the following line in the function \"normalizeImage()\":\n\n```js\nnormalizedImageContainer.append(normalizeResult.items[0].toCanvas());\n```\n\nto \n\n```js\nconst imageManager = new Dynamsoft.Utility.ImageManager();\nimageManager.saveToFile(normalizeResult.items[0].imageData, \"result.jpg\", true);\n```\n\nThen once a document has been normalized, it is downloaded as JPEG file in the browser.\n\n### Restart task\n\nYou can also add a button to restart the entire task:\n\n```js\nasync function restartDetecting() {\n  /* Reset the UI elements and restart the detection task. */\n  imageEditorViewContainer.style.display = \"none\";\n  normalizedImageContainer.innerHTML = \"\";\n  cameraViewContainer.style.display = \"block\";\n  btnStart.style.display = \"inline\";\n  btnRestart.style.display = \"none\";\n  btnNormalize.disabled = true;\n  layer.clearDrawingItems()\n  await router.startCapturing(\"DetectDocumentBoundaries_Default\");\n}\n```\n\u003c!--TODO--\u003e\nYou can also test the code above at [https://jsfiddle.net/DynamsoftTeam/](https://jsfiddle.net/DynamsoftTeam/L4m7r1db/)\n\n\u003cp align=\"center\" style=\"text-align:center; white-space: normal; \"\u003e\n  \u003ca target=\"_blank\" href=\"https://github.com/Dynamsoft/document-normalizer-javascript-samples/blob/v2.2.10/hello-world/hello-world.html\" title=\"Code in Github\" style=\"text-decoration:none;\"\u003e\n    \u003cimg src=\"https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/github.svg\" alt=\"Code in Github\" width=\"20\" height=\"20\" style=\"width:20px;height:20px;\"\u003e\n  \u003c/a\u003e\n  \u0026nbsp;\n  \u003ca target=\"_blank\" href=\"https://jsfiddle.net/DynamsoftTeam/L4m7r1db/\" title=\"Run via JSFiddle\"\u003e\n    \u003cimg src=\"https://cdn.jsdelivr.net/npm/simple-icons@3.0.1/icons/jsfiddle.svg\" alt=\"Run via JSFiddle\" width=\"20\" height=\"20\" style=\"width:20px;height:20px;\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## System requirements\n\nThe SDK requires the following features to work:\n\n- Secure context (HTTPS deployment)\n\n  When deploying your application / website for production, make sure to serve it via a secure HTTPS connection. This is required for two reasons\n  \n  - Access to the camera video stream is only granted in a security context. Most browsers impose this restriction.\n  \u003e Some browsers like Chrome may grant the access for `http://127.0.0.1` and `http://localhost` or even for pages opened directly from the local disk (`file:///...`). This can be helpful for temporary development and test.\n  \n  - Dynamsoft License requires a secure context to work.\n\n- `WebAssembly`, `Blob`, `URL`/`createObjectURL`, `Web Workers`\n\n  The above four features are required for the SDK to work.\n\nThe following table is a list of supported browsers based on the above requirements:\n\n  | Browser Name | Version |\n  | :----------: | :-----: |\n  |    Chrome    |  v78+   |\n  |   Firefox    |  v62+   |\n  |    Safari    |  v14+   |\n  |     Edge     |  v79+   |\n\nApart from the browsers, the operating systems may impose some limitations of their own that could restrict the use of the SDK.\n\n## Release notes\n\nLearn what are included in each release at [https://www.dynamsoft.com/document-normalizer/docs/programming/javascript/release-notes/?ver=latest](https://www.dynamsoft.com/document-normalizer/docs/programming/javascript/release-notes/?ver=latest).\n\n## Next steps\n\nNow that you have got the SDK integrated, you can choose to move forward in the following directions\n\n1. Check out the [official samples](https://github.com/Dynamsoft/document-normalizer-javascript-samples).\n2. Learn about the available [APIs](https://www.dynamsoft.com/document-normalizer/docs/web/programming/javascript/api-reference/?ver=latest).","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynamsoft%2Fdocument-normalizer-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdynamsoft%2Fdocument-normalizer-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdynamsoft%2Fdocument-normalizer-javascript/lists"}