How to Build Angular Document Scanner with Dynamsoft Web Capture SDK
Tags: angular, webdev, document, typescript
Published: 2022-06-22 06:52:21

[Dynamsoft Web Capture SDK](https://www.dynamsoft.com/web-twain/features/mobile-web-capture-sdk/) is a camera-based document scanning SDK implemented in WebAssembly and JavaScript. Comparing to [Dynamic Web TWAIN](https://www.dynamsoft.com/web-twain/overview/), the classic web scanner SDK, there is no local service installation required, which means the web capture SDK can work in any desktop browser, mobile browser, and WebView. This article guides you through how to build an Angular document scanner app using the web capture SDK from scratch.

## Angular Development Environment
- [Node.js](https://nodejs.org/en/download/)
- Angular CLI v13.3.7

    ```bash
    npm install -g @angular/cli
    
    ng --version

    Angular CLI: 13.3.7
    Node: 16.13.1
    Package Manager: npm 8.1.2
    OS: win32 x64
    
    Angular: 13.3.10
    ... animations, common, compiler, compiler-cli, core, forms
    ... platform-browser, platform-browser-dynamic, router
    
    Package                         Version
    ---------------------------------------------------------
    @angular-devkit/architect       0.1303.7
    @angular-devkit/build-angular   13.3.7
    @angular-devkit/core            13.3.7
    @angular-devkit/schematics      13.3.7
    @angular/cli                    13.3.7
    @schematics/angular             13.3.7
    ng-packagr                      13.3.1
    rxjs                            7.5.5
    typescript                      4.6.4
    ```
- [Dynamsoft Web Capture SDK v17.2.5](https://www.npmjs.com/package/mobile-web-capture)
    

## Creating Angular Document Scanner App Step by Step
We scaffold a new Angular project via `ng new` command  and install Dynamsoft Web Capture SDK in terminal:

```bash
ng new angular-document-scanner
cd angular-document-scanner
npm i mobile-web-capture
``` 

Then open the `angular.json` file to configure the assets.

```json

"build": 
{
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
    ...
    "assets": [
      "src/favicon.ico",
      "src/assets",
      {
        "glob": "**/*",
        "input": "./node_modules/mobile-web-capture/dist",
        "output": "assets/dynamic-web-twain"
      }
    ...
    ],
  },
  ...
},

``` 

When running `ng build`, all static resource files will be copied to the `assets/dynamic-web-twain` folder.

The next step is to create a document scanner component, which contains `document-scanner.component.css`, `document-scanner.component.html`, `document-scanner.component.spec.ts`, and `document-scanner.component.ts` files.

```bash
ng generate component document-scanner
```

The target UI layout includes following elements:
- An `HTMLSelectElement` for selecting the camera sources. For desktop browsers, all USB cameras are listed. For mobile browsers, all front-facing and back-facing cameras are listed.
- A button used to trigger document scanning and a button used to download the scanned document.
- An `HTMLDivElement` set as the container for storing the scanned and processed document images.

The UI implementation in `document-scanner.component.html` is as follows:

```html

<div class="document-scanner">
    <h1>Angular Document Scanner</h1>
    <div>
        <label for="videoSource">Video source: </label>
        <select id="videoSource"></select>
        <p></p>
        <button id="scanButton" (click)="scanDocument()">Scan Document</button> <button id="scanButton" (click)="downloadDocument()">Download Document</button>
    </div>
    
    <h3>Document Container</h3>
    <div id="dwtcontrolContainer"></div>

</div>
```

Now, we are going to add the corresponding TypeScript code in `document-scanner.component.ts`.
1. Import the SDK module from `mobile-web-capture` package.

    ```typescript
    import Dynamsoft from 'mobile-web-capture';
    import { WebTwain } from 'mobile-web-capture/dist/types/WebTwain';  
    ```
2. In `ngOnInit()`, initialize the SDK. 

    ```typescript
    dwtObject: WebTwain | undefined;
    videoSelect: HTMLSelectElement | undefined;
    sourceDict: any = {};

    ngOnInit(): void {
      this.videoSelect = document.querySelector('select#videoSource') as HTMLSelectElement;
      Dynamsoft.DWT.ProductKey = "LICENSE-KEY";
      Dynamsoft.DWT.ResourcesPath = 'assets/dynamic-web-twain';
      Dynamsoft.DWT.Containers = [{ ContainerId: 'dwtcontrolContainer' }];
      Dynamsoft.DWT.UseLocalService = false;
      Dynamsoft.DWT.Load();
      Dynamsoft.DWT.RegisterEvent('OnWebTwainReady', () => { this.onReady(); });
    }
    ```

    **Two things need to be noted here**: 
    - Apply for a [30-day trial license](https://www.dynamsoft.com/customer/license/trialLicense?product=dwt) and thereafter update the `LICENSE-KEY`.
    - Set the resource path `assets/dynamic-web-twain` as we configure above in `angular.json` file.
     

3. Once the `OnWebTwainReady` event is triggered, we get the SDK instance and update the camera source list.

    ```typescript
    onReady() {
      this.dwtObject = Dynamsoft.DWT.GetWebTwain('dwtcontrolContainer');
      this.updateCameraList();
    }

    updateCameraList() {
      if (this.videoSelect && this.dwtObject) {
        this.videoSelect.options.length = 0;
        this.dwtObject.Addon.Camera.getSourceList().then((list) => {
          for (var i = 0; i < list.length; i++) {
            var option = document.createElement('option');
            option.text = list[i].label || list[i].deviceId;
            if (list[i].label) {
              this.sourceDict[list[i].label] = list[i].deviceId;
            }
            else {
              this.sourceDict[list[i].deviceId] = list[i].deviceId;
            }
            if (this.videoSelect) this.videoSelect.options.add(option);
          }

        });
      }
    }
    ```

4. Select a camera source and start document scanning.

    ```typescript
    scanDocument() {
      if (this.videoSelect) {
        let index = this.videoSelect.selectedIndex;
        if (index < 0) return;

        var option = this.videoSelect.options[index];
        if (this.dwtObject) {
          this.dwtObject.Addon.Camera.selectSource(this.sourceDict[option.text]).then(camera => {
            if (this.videoSelect) this.createCameraScanner(this.sourceDict[option.text]);
          });
        }

      }

    }

    async createCameraScanner(deviceId: string): Promise<void> {
      if (this.dwtObject) {
        await this.dwtObject.Addon.Camera.closeVideo();
        this.dwtObject.Addon.Camera.scanDocument({
          scannerViewer: {
            deviceId: deviceId,
            fullScreen: true,
            autoDetect: {
              enableAutoDetect: true
            },
            continuousScan: {
              visibility: false,
              enableContinuousScan: false
            }
          }

        }).then(
          function () { console.log("OK"); },
          function (error: any) { console.log(error.message); });
      }

    }
    ```

5. After capturing and editing a document image, we can save it to local disk.

    ```typescript
    downloadDocument() {
      if (this.dwtObject) {
        this.dwtObject.SaveAsJPEG("document.jpg", this.dwtObject.CurrentImageIndexInBuffer);
      }
    }
    ```
6. Run the Angular document scanner in desktop and mobile browsers:

    ```bash
    ng serve --ssl
    ```

    **Desktop browser**

    ![Angular document scanner for desktop browser](https://www.dynamsoft.com/codepool/img/2022/06/angular-document-scanner-desktop-browser.png)


    **Mobile browser**

    ![Angular document scanner for mobile browser](https://www.dynamsoft.com/codepool/img/2022/06/angular-document-scanner-filter.jpg)



## GitHub Page Deployment
One more thing is to deploy the Angular document scanner project to GitHub pages.

Here are the steps:
1. Open `angular.json` file to increase the size [budgets](https://angular.io/guide/build#configure-size-budgets). The default budgets setting may cause the error: `WARNING in budgets, maximum exceeded for initial`.

    ```json
    "budgets": [
      {
        "type": "initial",
        "maximumWarning": "2.5mb",
        "maximumError": "5mb"
      },
    ]
    ```

2. Create a GitHub action workflow:

    ```yml
    name: Build and Deploy
    on:
      push:
        branches:
          - main
    jobs:
      build:

        runs-on: ubuntu-latest

        steps:
        - uses: actions/checkout@v2
        - name: All things angular
          uses: AhsanAyaz/angular-deploy-gh-pages-actions@v1.3.2
          with:
            github_access_token: ${{ secrets.GITHUB_TOKEN }} 
            build_configuration: production 
            base_href: /angular-document-scanner/   
            deploy_branch: gh-pages 
            angular_dist_build_folder: dist/angular-document-scanner

    ```
    You need to replace `angular-document-scanner` with your project name.

3. After the build is done, go to your GitHub `Settings > Pages` to launch the GtiHub page with the `gh-pages` branch. Don't forget to check the `Enforce HTTPS` option.

**Try the Demo Page**

[https://yushulx.me/angular-document-scanner/](https://yushulx.me/angular-document-scanner/)


## Source Code
[https://github.com/yushulx/angular-document-scanner](https://github.com/yushulx/angular-document-scanner)