How to Scan Documents to a WebDAV Server

WebDAV stands for Web Distributed Authoring and Versioning. It is an HTTP extension that makes it easy to create, read, and edit files hosted on remote Web servers. Many HTTP servers or file sync and share applications support this protocol like Apache, Lighttpd, Seafile and Nextcloud.

In this article, we are going to create a web app to scan documents with Dynamic Web TWAIN and save them to a WebDAV server.

Create a Web Page to Scan Documents

Let’s first create a web page to scan documents in the browser.

  1. Create a new HTML file with the following template.

    <!DOCTYPE html>
    <html>
    <head>
      <title>Scan to WebDAV</title>
      <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
      <style></style>
    </head>
    <body>
      <div>
      </div>
      <script type="text/javascript">
      </script>
    </body>
    </html>
    
  2. Add the following in the head to include Dynamic Web TWAIN via CDN.

    <script src="https://unpkg.com/dwt@18.0.0/dist/dynamsoft.webtwain.min.js"></script>
    
  3. Add a container for the document viewer of Web TWAIN.

    <div style="width: 360px; height: 480px;" id="dwtcontrolContainer"></div>
    
  4. Initialize an instance of Web TWAIN and bind it with the viewer. A license is needed. You can apply for one here.

    let DWObject;
    Dynamsoft.DWT.AutoLoad = false;
    Dynamsoft.DWT.ResourcesPath = "https://unpkg.com/dwt@18.0.0/dist";
    Dynamsoft.DWT.ProductKey = "<your license>";
       
    init();
    
    function init(){
      Dynamsoft.DWT.Containers = [{ ContainerId: "dwtcontrolContainer" }];
      Dynamsoft.DWT.RegisterEvent("OnWebTwainReady", function () {
        console.log("ready");
        DWObject = Dynamsoft.DWT.GetWebTwain("dwtcontrolContainer");
        DWObject.Viewer.width = "100%";
        DWObject.Viewer.height = "100%";
        DWObject.SetViewMode(2,2);
      });
      Dynamsoft.DWT.Load();
    }
    
  5. Add a button to scan documents.

    HTML:

    <input class="scanButton" type="button" value="Scan" onclick="AcquireImage();" />
    

    JavaScript:

    async function AcquireImage() {
      if (DWObject) {
        if (Dynamsoft.Lib.env.bMobile) {
          DWObject.Addon.Camera.scanDocument(); //use camera on mobile devices
        }else{
          const index = await DWObject.SelectSourceAsync(); //use document scanners on desktop devices
          DWObject.AcquireImageAsync({SelectSourceByIndex:index});
        }
      }
    }
    

The web page is finished. We can now scan documents in the browser.

Basic scanner

Start a Nextcloud Server

Here, we are going to start a local Nextcloud server to save documents. For convenience, we can use docker to start one with the following command:

docker run -d -p 8080:80 nextcloud

By default, it can only be accessed in the local network. We can modify the /var/www/html/config/config.php to add extra domains.

'trusted_domains' => 
array (
  0 => '127.0.0.1:8080',
  1 => '192.168.8.65:8080',
),

Write a Python Backend to Upload a File to the WebDAV Server

Directly accessing a WebDAV server in the browser will encounter CORS errors. We need to create a backend server to receive the documents from the web page and upload them to a WebDAV server. Here, we use Python + Flask to do this.

from webdav4.client import Client
from io import BytesIO
import base64
import os
import json

app = Flask(__name__, static_url_path='/', static_folder='./')

@app.route('/uploadfile', methods=['POST'])
def upload_file():
    if request.method == 'POST':
        data = request.get_json()
        URL = data["URL"]
        username = data["username"]
        password = data["password"]
        client = Client(URL, auth=(username, password))
        
        path = data["filepath"]
        if client.exists(path) == False:
            base64str = data["base64"]
            bytes_decoded = base64.b64decode(base64str)
            
            client.upload_fileobj(BytesIO(bytes_decoded), path, overwrite = True)
            return json.dumps({"status":"success"})
        else:
            return json.dumps({"status":"file exists"})

if __name__ == '__main__':
   app.run(host = "0.0.0.0", port = 8888)

Send Scanned Documents to the WebDAV Server

On the web page, add several input controls to set the info about the WebDAV server: URL, username, password, along with the file path to save into.

<div>
  <div>
    <label>
      Server URL:
      <input type="text" id="URL" value="http://127.0.0.1:8080/remote.php/dav/files/admin/"/>
    </label>
  </div>
  <div>
    <label>
      Username:
      <input type="text" id="username"/>
    </label>
  </div>
  <div>
    <label>
      Password:
      <input type="password" id="password"/>
    </label>
  </div>
  <div>
    <label>
      Path:
      <input type="text" id="filepath" value="scanned.pdf"/>
    </label>
  </div>
</div>

Convert the scanned documents as a base64-encoded PDF file and send it to the Python server.

function convertAndUpload(){
  if (DWObject) {
    DWObject.ConvertToBase64(
      getIndices(),
      Dynamsoft.DWT.EnumDWT_ImageType.IT_PDF,
      function (result, indices, type) {
        var base64 = result.getData(0, result.getLength());
        upload(base64);
      },
      function (errorCode, errorString) {
        console.log(errorString);
      }
    );
  }
}

function getIndices(){
  var indices = [];
  for (let index = 0; index < DWObject.HowManyImagesInBuffer; index++) {
    indices.push(index);
  }
  return indices;
}

function upload(base64){
  document.getElementById("status").innerText = "Uploading...";
  let xhr = new XMLHttpRequest();
  let pay_load = {};
  pay_load["URL"] = document.getElementById("URL").value;
  pay_load["username"] = document.getElementById("username").value;
  pay_load["password"] = document.getElementById("password").value;
  pay_load["filepath"] = document.getElementById("filepath").value;
  pay_load["base64"] = base64;
  console.log(pay_load);
  xhr.open("POST", "/uploadfile");
  xhr.setRequestHeader("content-type", "application/json"); 

  xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
      if (xhr.status === 200) {
        document.getElementById("status").innerText = "";
        var status = JSON.parse(xhr.responseText)["status"];
        alert(status);
      }else{
        onerror();
      }
    }
  }

  xhr.onerror = onerror;

  xhr.send(JSON.stringify(pay_load));
}

function onerror(){
  document.getElementById("status").innerText = "";
  alert("Failed");
}

Source Code

Check out the source code of the demo to have a try.

https://github.com/tony-xlh/Scan-to-WebDAV

Getting Started With Dynamic Web TWAIN