DEV Community

Cover image for How to Build a Document Scanning Component with LitElement
xulihang
xulihang

Posted on • Originally published at dynamsoft.com

How to Build a Document Scanning Component with LitElement

Lit is a simple library for building fast, lightweight web components. At Lit's core is a boilerplate-killing component base class that provides reactive state, scoped styles, and a declarative template system that's tiny, fast and expressive.

In this article, we are going to build a web component with LitElement to scan documents in an HTML website based on Dynamic Web TWAIN.

New Project

Although Lit can be used without a build system, in this article, we are going to use webpack with the following template (clone with git):

git clone https://github.com/wbkd/webpack-starter
Enter fullscreen mode Exit fullscreen mode

Install Dependencies

  1. Install Lit.
   npm install lit
Enter fullscreen mode Exit fullscreen mode
  1. Install Dynamic Web TWAIN.
   npm install dwt
Enter fullscreen mode Exit fullscreen mode

In addition, we need to copy the resources of Dynamic Web TWAIN to the public folder.

  1. Install ncp.

      npm install --save-dev ncp
    
  2. Modify package.json to copy the resources for the build and start commands.

       "scripts": {
         "lint": "npm run lint:styles; npm run lint:scripts",
         "lint:styles": "stylelint src",
         "lint:scripts": "eslint src",
         "build": "cross-env NODE_ENV=production webpack --config webpack/webpack.config.prod.js",
         "start": "webpack serve --config webpack/webpack.config.dev.js"
      +  "build": "ncp node_modules/dwt/dist public/dwt-resources && cross-env NODE_ENV=production webpack --config webpack/webpack.config.prod.js",
      +  "start": "ncp node_modules/dwt/dist public/dwt-resources && webpack serve --config webpack/webpack.config.dev.js"
       },
    
  3. Modify webpack.common.js to copy the files in the public folder to the output folder instead of the public folder inside the output folder.

       new CopyWebpackPlugin({
      -  patterns: [{ from: Path.resolve(__dirname, '../public'), to: 'public' }],
      +  patterns: [{ from: Path.resolve(__dirname, '../public'), to: '' }],
       }),
    

Write a Document Scanner Component

  1. Create a new documentscanner.js file under src\scripts with the following template.
   import {LitElement, html, css} from 'lit';

   export class DocumentScanner extends LitElement {
     static properties = {
     };
     DWObject;
     static styles = css`
       :host {
         display: block;
       }
       `;
     constructor() {
       super();
     }

     render() {
       return html``;
     }
   }
   customElements.define('document-scanner', DocumentScanner);
Enter fullscreen mode Exit fullscreen mode
  1. Add a div element as the container for the controls of Dynamic Web TWAIN (mainly to view documents).
   render() {
     return html`<div id="dwtcontrolContainer"></div>`;
   }
Enter fullscreen mode Exit fullscreen mode
  1. Configure Dynamic Web TWAIN in the constructor. You need a license to use Dynamic Web TWAIN. You can apply for a license here.
   constructor() {
     super();
     Dynamsoft.DWT.AutoLoad = false;
     Dynamsoft.DWT.ResourcesPath = "/dwt/dist";
     Dynamsoft.DWT.ProductKey = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ=="; //one-day trial
   }
Enter fullscreen mode Exit fullscreen mode
  1. Initialize Dynamic Web TWAIN in the firstUpdated lifecycle after the dom is first updated and bind it to the container in the previous step. In addition, dispatch a custom event with the object of Dynamic Web TWAIN so that we can control it in a parent node.
   DWObject;
   firstUpdated() {
     let pThis = this;
     let dwtContainer = this.renderRoot.getElementById("dwtcontrolContainer");
     Dynamsoft.DWT.CreateDWTObjectEx(
       {
         WebTwainId: 'dwtcontrol'
       },
       function(obj) {
         pThis.DWObject = obj;
         pThis.DWObject.Viewer.bind(dwtContainer);
         pThis.DWObject.Viewer.show();
         pThis.DWObject.Viewer.width = "100%";
         pThis.DWObject.Viewer.height = "100%";
         const event = new CustomEvent('initialized', {
           detail: {
             DWObject: pThis.DWObject
           }
         });
         pThis.dispatchEvent(event);
       },
       function(err) {
         console.log(err);
       }
     );
   } 
Enter fullscreen mode Exit fullscreen mode
  1. Add one button to scan documents and one button to save the document images as a PDF file.
   render() {
     return html`
     <div class="buttons">
       <button @click=${this.scan}>Scan</button>
       <button @click=${this.save}>Save</button>
     </div>
     <div id="dwtcontrolContainer"></div>`;
   }
   scan(){
     let pThis = this;
     if (pThis.DWObject) {
       pThis.DWObject.SelectSource(function () {
         pThis.DWObject.OpenSource();
         pThis.DWObject.AcquireImage();
       },
         function () {
           console.log("SelectSource failed!");
         }
       );
     }
   }

   save(){
     if (this.DWObject) {
       this.DWObject.SaveAllAsPDF("Scanned.pdf");
     }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Add a reactive property named total to reflect how many documents are scanned. We can update its value in the OnBufferChanged event of Web TWAIN.
   export class DocumentScanner extends LitElement {
     static properties = {
       total: {},
     };
     constructor() {
       super();
       this.total = 0;
       //...
     }
     render() {
       return html`
       <div class="buttons">
         <button @click=${this.scan}>Scan</button>
         <button @click=${this.save}>Save</button>
       </div>
       <div id="dwtcontrolContainer"></div>
       <div class="status">Total: ${this.total}</div>`;
     }

     firstUpdated() {
       //...
       Dynamsoft.DWT.CreateDWTObjectEx(
         {
           WebTwainId: 'dwtcontrol'
         },
         function(obj) {
           //...
           pThis.DWObject.RegisterEvent('OnBufferChanged',function () {
             pThis.total = pThis.DWObject.HowManyImagesInBuffer;
           });
           //...
         },
         function(err) {
           console.log(err);
         }
       );
     } 
   }
Enter fullscreen mode Exit fullscreen mode
  1. Set the styles for the component.
   static styles = css`
     :host {
       display: block;
     }
     .buttons {
       height: 25px;
     }
     #dwtcontrolContainer {
       width: 100%;
       height: calc(100% - 50px);
     }
     .status {
       height: 25px;
     }
     `;
Enter fullscreen mode Exit fullscreen mode

Use the Document Scanner Component

  1. Import the component in the index.js file.
   import { DocumentScanner } from './documentscanner'; // eslint-disable-line
Enter fullscreen mode Exit fullscreen mode
  1. Add the component in the index.html.
   <document-scanner 
     style="width:320px;height:480px;"
   ></document-scanner>
Enter fullscreen mode Exit fullscreen mode

All right, we can now scan documents from the browser.

Lit document scanner

Online demo

Source Code

Get the source code of the demo to have a try:

https://github.com/tony-xlh/document-scanner-lit-element

Top comments (0)