Skip to content

Commit a31aea6

Browse files
committed
feat: release v1.0.0
0 parents  commit a31aea6

26 files changed

+5584
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
dist
2+
node_modules

LICENSE

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
License Notice
2+
3+
The source code of Dynamsoft Document Scanner (DDS) provided here is released under the Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0.
4+
Dynamsoft Document Normalizer (DDN) and Dynamsoft Camera Enhancer (DCE) SDKs, which are dependencies of Dynamsoft Document Scanner (DDS), are licensed under a commercial license: https://www.dynamsoft.com/company/license-agreement/.
5+
6+
This file is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
7+
8+
Copyright © 2003–2025 Dynamsoft. All Rights Reserved.

README.md

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Dynamsoft Document Scanner for the Web
2+
3+
**Dynamsoft Document Scanner (DDS)** is designed to handle the following use case:
4+
5+
* Capturing a clear image of a physical document, such as a single-page patient intake form or the front side of a driver’s license.
6+
7+
> DDS not only captures the document but also enhances its quality to meet professional standards.
8+
9+
## Key Features
10+
11+
1. Capture single documents using mobile devices or webcams.
12+
2. Import a single local image of a document.
13+
3. Automatically detect document borders during image capture.
14+
4. Automatically capture and correct images to align with detected document boundaries.
15+
5. Export a single-page document as an image.
16+
17+
> To deliver these features, DDS leverages the following Dynamsoft products:
18+
>
19+
> 1. **Dynamsoft Camera Enhancer (DCE)**: Focuses on image capture and video feed enhancement.
20+
> 2. **Dynamsoft Document Normalizer (DDN)**: Processes the captured document image, restoring its quality with cropping and perspective transformations.
21+
22+
## How to Use the SDK to Build a Web Page for Document Scanning
23+
24+
### Step 1: Get a License
25+
26+
DDS requires a license key to function. You can request a [30-day free trial license](https://www.dynamsoft.com/customer/license/trialLicense?product=mwc&source=readme) via our customer portal.
27+
28+
### Step 2: Create a "Hello World" Page
29+
30+
#### Option 1: Work with the GitHub Repository
31+
32+
If you're **working with the [GitHub Repository](https://github.com/Dynamsoft/document-scanner-javascript)**, the "hello-world.html" page is available under the [`/samples`](https://github.com/Dynamsoft/document-scanner-javascript/tree/main/samples) directory.
33+
34+
Find the following code snippet and replace `YOUR_LICENSE_KEY_HERE` with the license key you obtained in [Step 1](https://github.com/Dynamsoft/document-scanner-javascript/tree/main?tab=readme-ov-file#step-1-get-a-license).
35+
36+
```js
37+
const documentScanner = new Dynamsoft.DocumentScanner({
38+
license: "YOUR_LICENSE_KEY_HERE",
39+
});
40+
```
41+
42+
#### Option 2: Create Your Own Page
43+
44+
Alternatively, you can create an empty file named `hello-world.html`, paste the following code into it, and replace `YOUR_LICENSE_KEY_HERE` with the license key you obtained in [Step 1](https://github.com/Dynamsoft/document-scanner-javascript/tree/main?tab=readme-ov-file#step-1-get-a-license):
45+
46+
```html
47+
<!DOCTYPE html>
48+
<html lang="en">
49+
<head>
50+
<meta charset="utf-8" />
51+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
52+
<title>Dynamsoft Document Scanner - Hello World</title>
53+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/dbr.bundle.js"></script>
54+
<style>
55+
html,
56+
body {
57+
margin: 0;
58+
padding: 0;
59+
box-sizing: border-box;
60+
font-family: Arial, sans-serif;
61+
background-color: #f9f9f9;
62+
}
63+
</style>
64+
</head>
65+
66+
<body>
67+
<h1 style="font-size: large">Dynamsoft Document Scanner</h1>
68+
<div id="results"></div>
69+
70+
<script>
71+
const resultContainer = document.querySelector("#results");
72+
73+
// Initialize the Dynamsoft Document Scanner
74+
const documentScanner = new Dynamsoft.DocumentScanner({
75+
license: "YOUR_LICENSE_KEY_HERE",
76+
});
77+
(async () => {
78+
// Launch the scanner and wait for the result
79+
const result = await documentScanner.launch();
80+
console.log(result);
81+
82+
// Clear the result container and display the scanned result as a canvas
83+
if (result?.correctedImageResult) {
84+
resultContainer.innerHTML = ""; // Clear placeholder content
85+
const canvas = result.correctedImageResult.toCanvas();
86+
resultContainer.appendChild(canvas);
87+
} else {
88+
resultContainer.innerHTML = "<p>No image scanned. Please try again.</p>";
89+
}
90+
})();
91+
</script>
92+
</body>
93+
</html>
94+
```
95+
96+
### Step 3: Run the "Hello World" Page
97+
98+
#### Option 1: Work with the GitHub Repository
99+
100+
If you're **working with the [GitHub Repository](https://github.com/Dynamsoft/document-scanner-javascript)**, follow these steps:
101+
102+
1. Install project dependencies:
103+
104+
```bash
105+
npm install
106+
```
107+
108+
2. Build the project:
109+
110+
```bash
111+
npm run build
112+
```
113+
114+
3. Serve the project locally:
115+
116+
```bash
117+
npm run serve
118+
```
119+
120+
4. Open the application:
121+
122+
After running `npm run serve`, the terminal will display the local address. Open the address in your browser to access the application.
123+
124+
> Notes on the Test Server (Development Only)
125+
>
126+
> This sample uses the web server provided by Express (https://expressjs.com/). It is intended solely for local development and testing purposes, and it lacks production-grade features like advanced security, scalability, and detailed logging.
127+
>
128+
> - The server is configured to run on **"localhost"** using port `3000` and on your computer's **local IP address** using port `3001` with SSL enabled via self-signed certificates.
129+
> - To access the application from a mobile device or another computer on your network, use your computer's **local IP address** and ensure the device is connected to the same Local Area Network (LAN).
130+
> - If there are multiple **local IP addresses**, choose one that works.
131+
> - You will get an security alert in the browser for "self-signed certificates", click "Advanced" to continue
132+
133+
#### Option 2: Run the Page You Created
134+
135+
If you created your own `hello-world.html` file (as described in [Step 2, Option 2](https://github.com/Dynamsoft/document-scanner-javascript/tree/main?tab=readme-ov-file#option-2-create-your-own-page)), follow these steps to run it:
136+
137+
1. Deploy to a web server:
138+
139+
- You can use a production server like IIS or Apache.
140+
- Alternatively, for local testing, use a simple server such as the [Five Server](https://marketplace.visualstudio.com/items?itemName=yandeu.five-server) extension for Visual Studio Code.
141+
142+
1. Access the file in your browser:
143+
144+
Once the server is running, open the URL where the file is served (e.g., http://localhost/hello-world.html).
145+
146+
## Contact us
147+
148+
If you encounter any issues, need assistance, or have suggestions, please don’t hesitate to reach out to us. You can:
149+
150+
- **Submit an issue** directly in this repository.
151+
- **Contact us through various channels** listed on our official [Contact Us](https://www.dynamsoft.com/contact/) page.
152+
153+
We’re here to help!

dev-server/index.js

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import express from "express";
2+
import fs from "fs";
3+
import http from "http";
4+
import https from "https";
5+
import cors from "cors";
6+
import path from "path";
7+
import os from "os";
8+
import { fileURLToPath } from "url";
9+
10+
const __filename = fileURLToPath(import.meta.url);
11+
const __dirname = path.dirname(__filename);
12+
13+
// Check if dist folder exists
14+
const distPath = path.join(__dirname, "../dist");
15+
if (!fs.existsSync(distPath)) {
16+
console.error("\x1b[31m%s\x1b[0m", "Error: 'dist' folder not found!");
17+
console.log("\nPlease build the project first by running:");
18+
console.log("\x1b[33m%s\x1b[0m", "npm run build");
19+
console.log("\nThen try running the server again.\n");
20+
process.exit(1);
21+
}
22+
23+
const app = express();
24+
25+
app.use(
26+
cors({
27+
origin: (origin, callback) => {
28+
return callback(null, true);
29+
},
30+
})
31+
);
32+
33+
// Serve static files
34+
app.use("/dist", express.static(distPath));
35+
36+
// Routes
37+
app.get("/", (req, res) => {
38+
res.sendFile(path.join(__dirname, "../samples/hello-world.html"));
39+
});
40+
41+
app.get("/hello-world", (req, res) => {
42+
res.sendFile(path.join(__dirname, "../samples/hello-world.html"));
43+
});
44+
45+
let httpPort = 3000;
46+
let httpsPort = 3001;
47+
48+
// redirect handling
49+
app.use((req, res, next) => {
50+
const host = req.get("Host"); // Get the host name from the request
51+
52+
// Skip redirection if it's localhost with the correct HTTP port
53+
if (!req.secure && host !== `localhost:${httpPort}`) {
54+
// Replace the HTTP port with HTTPS port in the host
55+
const httpsHost = host.replace(`:${httpPort}`, `:${httpsPort}`);
56+
return res.redirect(["https://", httpsHost, req.url].join(""));
57+
}
58+
59+
next(); // Proceed to the next middleware or route
60+
});
61+
62+
// HTTPS server configuration
63+
const httpsOptions = {
64+
key: fs.readFileSync(path.join(__dirname, "pem/key.pem")),
65+
cert: fs.readFileSync(path.join(__dirname, "pem/cert.pem")),
66+
};
67+
68+
// Create HTTPS server
69+
const httpsServer = https.createServer(httpsOptions, app);
70+
71+
// Create HTTP server
72+
const httpServer = http.createServer(app);
73+
74+
// Add error handlers before starting servers
75+
httpServer.on("error", (error) => {
76+
if (error.code === "EADDRINUSE") {
77+
console.error(`\x1b[31mError: Port ${httpPort} is already in use\x1b[0m`);
78+
console.log("\nTo fix this, you can:");
79+
console.log(`1. Update the port manually by changing \x1b[33mhttpPort\x1b[0m in the code`);
80+
console.log(`2. Close any other applications using port ${httpPort}`);
81+
console.log(`3. Wait a few moments and try again - the port might be in a cleanup state\n`);
82+
} else {
83+
console.error("\x1b[31mHTTP Server error:\x1b[0m", error);
84+
}
85+
process.exit(1);
86+
});
87+
88+
httpsServer.on("error", (error) => {
89+
if (error.code === "EADDRINUSE") {
90+
console.error(`\x1b[31mError: Port ${httpsPort} is already in use\x1b[0m`);
91+
console.log("\nTo fix this, you can:");
92+
console.log(`1. Update the port manually by changing \x1b[33mhttpsPort\x1b[0m in the code`);
93+
console.log(`2. Close any other applications using port ${httpsPort}`);
94+
console.log(`3. Wait a few moments and try again - the port might be in a cleanup state\n`);
95+
} else {
96+
console.error("\x1b[31mHTTP Server error:\x1b[0m", error);
97+
}
98+
process.exit(1);
99+
});
100+
101+
// Start the servers
102+
httpServer.listen(httpPort, () => {
103+
console.log("\n\x1b[1m Dynamsoft Document Scanner Sample\x1b[0m\n");
104+
console.log("\x1b[36m Access URLs:\x1b[0m");
105+
console.log("\x1b[90m-------------------\x1b[0m");
106+
console.log("\x1b[32m Local:\x1b[0m http://localhost:" + httpPort + "/");
107+
});
108+
109+
httpsServer.listen(httpsPort, "0.0.0.0", () => {
110+
const networkInterfaces = os.networkInterfaces();
111+
const ipv4Addresses = [];
112+
Object.keys(networkInterfaces).forEach((interfaceName) => {
113+
networkInterfaces[interfaceName].forEach((iface) => {
114+
if (iface.family === "IPv4" && !iface.internal) {
115+
ipv4Addresses.push(iface.address);
116+
}
117+
});
118+
});
119+
120+
ipv4Addresses.forEach((localIP) => {
121+
console.log("\x1b[32m Network:\x1b[0m https://" + localIP + ":" + httpsPort + "/");
122+
});
123+
console.log("\x1b[36m Available Pages:\x1b[0m");
124+
console.log("\x1b[90m-------------------\x1b[0m");
125+
console.log("\x1b[33m Hello World:\x1b[0m /hello-world\n");
126+
127+
console.log("\x1b[90mPress Ctrl+C to stop the server\x1b[0m\n");
128+
});

dev-server/pem/cert.pem

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICDDCCAXUCFGlprxUW7YsQSmqXwS3fjySQwexCMA0GCSqGSIb3DQEBCwUAMEUx
3+
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
4+
cm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMjAwMTE3MDE0OTM0WhcNMjAwMjE2MDE0
5+
OTM0WjBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UE
6+
CgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GN
7+
ADCBiQKBgQCt3L/syEyB8B9O8Xhf3/SJOfTsoSs+3+/ELvFd07QEP0mySRjh9hUL
8+
BjB1bWJXBshn9JBzlfGUjRtNkc54VF1JfjFgi7UzqqyAlAwfEMBbp8jUX1Hh9iU7
9+
ctTAHxcAicTWTkRmToXJBUhbgTH+eF/GfQTdnByrncprQfuqdPg2KwIDAQABMA0G
10+
CSqGSIb3DQEBCwUAA4GBAKRRbXBhTS95IimKoIZq3RtVrjXpcsBn5ncyvFULc6Y5
11+
OkOxum5TO++XHVOJyalqyWpAQuz6i348hxTW6wqt5Js0UPGLGIb4Kq965QKKT+yJ
12+
WnHOnzZzJxiTs/1uGFjPAKgdvuDhcx36YsvSQ/UnJvF0rttjLKOGI5SkFMgz1Ufz
13+
-----END CERTIFICATE-----

dev-server/pem/csr.pem

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
-----BEGIN CERTIFICATE REQUEST-----
2+
MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
3+
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
4+
AQUAA4GNADCBiQKBgQCt3L/syEyB8B9O8Xhf3/SJOfTsoSs+3+/ELvFd07QEP0my
5+
SRjh9hULBjB1bWJXBshn9JBzlfGUjRtNkc54VF1JfjFgi7UzqqyAlAwfEMBbp8jU
6+
X1Hh9iU7ctTAHxcAicTWTkRmToXJBUhbgTH+eF/GfQTdnByrncprQfuqdPg2KwID
7+
AQABoAAwDQYJKoZIhvcNAQELBQADgYEAgwEY90gQQzxIonWEgDxGRBHxSk0h3UE4
8+
rTP3JggV6h0vXMndOrDXC2qrh20fJaWIHqbBtmfOF4NmPhQTSZOZ2fIjPBeHZqLq
9+
8+K9iZPeyjnVIRyWkXfCPacoddTw2FcykRobgL6Wi/RoldutOnIDlTawo5Y/eXvm
10+
JI0428mqYU4=
11+
-----END CERTIFICATE REQUEST-----

dev-server/pem/key.pem

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIICXAIBAAKBgQCt3L/syEyB8B9O8Xhf3/SJOfTsoSs+3+/ELvFd07QEP0mySRjh
3+
9hULBjB1bWJXBshn9JBzlfGUjRtNkc54VF1JfjFgi7UzqqyAlAwfEMBbp8jUX1Hh
4+
9iU7ctTAHxcAicTWTkRmToXJBUhbgTH+eF/GfQTdnByrncprQfuqdPg2KwIDAQAB
5+
AoGAO6O6zm2TGQuWoczhPvoi9yPDaZyLqiDFLaXws//YA5D2Jcs/VtvEMijoXI+u
6+
KS4xdr+FAbFQ0mVpFT3L9qjx6p/lSVKzJ1tlVlp7klJzK0VOWmMojLrhsstp44ah
7+
jZQdxcnlEDgeBwXj5m09fr7YFfIiyHef+r9ORqn00F7K+xkCQQDhy5k00dsfL5MY
8+
oy70Ikb70n90qktnFXrgsgEeojG0j0OmJUdNLV6gXbkD4lEeh6iK5XdAEuso+Qw1
9+
5Ksa3d11AkEAxR6yMXPIbl+4y24TbIGAZwb44Lyn9DAnLm5qgFvMgJARz+kqlYyr
10+
tpZ6cD1JY3fuF+umDlNPYzxGxy3kz/sxHwJBAJNiLDzYBmmSyjc4vPtKLH9PZTan
11+
udQtpylnx2dRg5RSN1wJ1ULBLJUM2Cl63mxJLHCNW4uNTcZO2fOLsUw2KckCQBFp
12+
dboSjSjawbsOfR6/jbUME53ebEOQoVVjoXq3IShWEYy4/u743w4g2q3hbAMiS+DH
13+
CwMG7uNIJsRfVG/es2cCQD7R6ebztt858vYZzfLMLMsJTF2YQs1YG91x76lZLhNp
14+
tcTTENHD4g9v/Q5MV+fhN0UuJ2ikrXULAgDmJMvAVyk=
15+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)