scanic 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 marquaye
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,334 @@
1
+ <p align="center">
2
+ <a href="#">
3
+ <img src="./public/scanic-logo-bg.png" alt="scanic logo" height="400">
4
+ </a>
5
+ </p>
6
+
7
+ # Scanic
8
+
9
+ **Modern Document Scanner for the Web**
10
+
11
+ Scanic is a blazing-fast, lightweight, and modern document scanner library written in JavaScript and rust (WASM). It enables developers to detect, scan, and process documents from images directly in the browser or Node.js, with no dependencies or external services.
12
+
13
+ ## Why Scanic?
14
+
15
+ I always wanted to use document scanning features within web environments for years. While OpenCV makes this easy, it comes at the cost of a 30+ MB download.
16
+
17
+ Scanic combines pure JavaScript algorithms with **Rust-compiled WebAssembly** for performance-critical operations like Gaussian blur, Canny edge detection, and gradient calculations. This hybrid approach delivers near-native performance while maintaining JavaScript's accessibility and a lightweight footprint.
18
+
19
+ Performance-wise, I'm working to match OpenCV solutions while maintaining the lightweight footprint - this is an ongoing area of improvement.
20
+
21
+ This library is heavily inspired by [jscanify](https://github.com/puffinsoft/jscanify)
22
+
23
+ ## Features
24
+
25
+ - 📄 **Document Detection**: Accurately finds and extracts document contours from images
26
+ - ⚡ **Pure JavaScript**: Works everywhere JavaScript runs
27
+ - 🦀 **Rust WebAssembly**: Performance-critical operations optimized with Rust-compiled WASM
28
+ - 🛠️ **Easy Integration**: Simple API for web apps, Electron, or Node.js applications
29
+ - 🏷️ **MIT Licensed**: Free for personal and commercial use
30
+ - 📦 **Lightweight**: Small bundle size compared to OpenCV-based solutions
31
+
32
+ ## Demo
33
+
34
+ Try the live demo: [Open Demo](https://marquaye.github.io/scanic/demo.html)
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install scanic
40
+ ```
41
+
42
+ Or use via CDN:
43
+
44
+ ```html
45
+ <script src="https://unpkg.com/scanic/dist/scanic.js"></script>
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ```js
51
+ import { scanDocument, LiveScanner, checkWebcamAvailability } from 'scanic';
52
+
53
+ // Simple usage - just detect document
54
+ const result = await scanDocument(imageElement);
55
+ if (result.success) {
56
+ console.log('Document found at corners:', result.corners);
57
+ }
58
+
59
+ // Extract the document (perspective correction)
60
+ const extracted = await scanDocument(imageElement, { mode: 'extract' });
61
+ if (extracted.success) {
62
+ document.body.appendChild(extracted.output); // Display extracted document
63
+ }
64
+ ```
65
+
66
+ ### Complete Example
67
+
68
+ ```js
69
+ import { scanDocument } from 'scanic';
70
+
71
+ async function processDocument() {
72
+ // Get image from file input or any source
73
+ const imageFile = document.getElementById('fileInput').files[0];
74
+ const img = new Image();
75
+
76
+ img.onload = async () => {
77
+ try {
78
+ // Extract and display the scanned document
79
+ const result = await scanDocument(img, {
80
+ mode: 'extract',
81
+ output: 'canvas'
82
+ });
83
+
84
+ if (result.success) {
85
+ // Add the extracted document to the page
86
+ document.getElementById('output').appendChild(result.output);
87
+
88
+ // Or get as data URL for download/display
89
+ const dataUrl = result.output.toDataURL('image/png');
90
+ console.log('Extracted document as data URL:', dataUrl);
91
+ }
92
+ } catch (error) {
93
+ console.error('Error processing document:', error);
94
+ }
95
+ };
96
+
97
+ img.src = URL.createObjectURL(imageFile);
98
+ }
99
+
100
+ // HTML setup
101
+ // <input type="file" id="fileInput" accept="image/*" onchange="processDocument()">
102
+ // <div id="output"></div>
103
+ ```
104
+
105
+ ## API Reference
106
+
107
+ ### Core Function
108
+
109
+ #### `scanDocument(image, options?)`
110
+ Main entry point for document scanning with flexible modes and output options.
111
+
112
+ **Parameters:**
113
+ - `image`: HTMLImageElement, HTMLCanvasElement, or ImageData
114
+ - `options`: Optional configuration object
115
+ - `mode`: String - 'detect' (default), 'highlight', or 'extract'
116
+ - `'detect'`: Only detect document, return corners/contour info (no image processing)
117
+ - `'highlight'`: Draw outline on original image
118
+ - `'extract'`: Extract/warp the document region
119
+ - `output`: String - 'canvas' (default), 'imagedata', or 'dataurl'
120
+ - `debug`: Boolean (default: false) - Enable debug information
121
+ - Detection options:
122
+ - `maxProcessingDimension`: Number (default: 800) - Maximum dimension for processing
123
+ - `lowThreshold`: Number (default: 75) - Lower threshold for Canny edge detection
124
+ - `highThreshold`: Number (default: 200) - Upper threshold for Canny edge detection
125
+ - `dilationKernelSize`: Number (default: 3) - Kernel size for dilation
126
+ - `dilationIterations`: Number (default: 1) - Number of dilation iterations
127
+ - `minArea`: Number (default: 1000) - Minimum contour area for document detection
128
+ - `epsilon`: Number - Epsilon for polygon approximation
129
+
130
+ **Returns:** `Promise<{ output, corners, contour, debug, success, message }>`
131
+
132
+ - `output`: Processed image (null for 'detect' mode)
133
+ - `corners`: Object with `{ topLeft, topRight, bottomRight, bottomLeft }` coordinates
134
+ - `contour`: Array of contour points
135
+ - `success`: Boolean indicating if document was detected
136
+ - `message`: Status message
137
+
138
+ ### Live Scanner
139
+
140
+ #### `LiveScanner`
141
+ Real-time document scanner for webcam integration.
142
+
143
+ **Constructor Options:**
144
+ - `targetFPS`: Number (default: 10) - Target frames per second
145
+ - `detectionInterval`: Number (default: 150) - Milliseconds between detections
146
+ - `confidenceThreshold`: Number (default: 0.7) - Confidence threshold for detections
147
+ - `stabilizationFrames`: Number (default: 3) - Frames needed for stable detection
148
+ - `maxProcessingDimension`: Number (default: 500) - Max dimension for live processing
149
+
150
+ **Methods:**
151
+ - `init(outputElement, constraints)` - Initialize webcam and start scanning
152
+ - `stop()` - Stop scanning and release resources
153
+ - `pause()` - Pause scanning
154
+ - `resume()` - Resume scanning
155
+ - `capture()` - Capture current frame
156
+
157
+ **Events:**
158
+ - `onDetection(result)` - Called when document is detected
159
+ - `onFPSUpdate(fps)` - Called with current FPS
160
+ - `onError(error)` - Called on errors
161
+
162
+ #### `checkWebcamAvailability()`
163
+ Checks if webcam is available and lists video devices.
164
+
165
+ **Returns:** `Promise<{ available: boolean, deviceCount?: number, devices?: Array, error?: string }>`
166
+
167
+ All functions work in both browser and Node.js environments. For Node.js, use a compatible canvas/image implementation like `canvas` or `node-canvas`.
168
+
169
+ ## Examples
170
+
171
+ ```js
172
+ const options = {
173
+ mode: 'extract',
174
+ maxProcessingDimension: 1000, // Higher quality, slower processing
175
+ lowThreshold: 50, // More sensitive edge detection
176
+ highThreshold: 150,
177
+ dilationKernelSize: 5, // Larger dilation kernel
178
+ minArea: 2000, // Larger minimum document area
179
+ debug: true // Enable debug information
180
+ };
181
+
182
+ const result = await scanDocument(imageElement, options);
183
+ ```
184
+
185
+ ### Different Modes and Output Formats
186
+
187
+ ```js
188
+ // Just detect (no image processing)
189
+ const detection = await scanDocument(imageElement, { mode: 'detect' });
190
+
191
+ // Extract as canvas
192
+ const extracted = await scanDocument(imageElement, {
193
+ mode: 'extract',
194
+ output: 'canvas'
195
+ });
196
+
197
+ // Highlight as data URL
198
+ const highlighted = await scanDocument(imageElement, {
199
+ mode: 'highlight',
200
+ output: 'dataurl'
201
+ });
202
+
203
+ // Extract as ImageData
204
+ const rawData = await scanDocument(imageElement, {
205
+ mode: 'extract',
206
+ output: 'imagedata'
207
+ });
208
+ ```
209
+
210
+ ### Live Scanner Usage
211
+
212
+ ```js
213
+ import { LiveScanner, checkWebcamAvailability } from 'scanic';
214
+
215
+ // Check if webcam is available
216
+ const webcamStatus = await checkWebcamAvailability();
217
+ if (!webcamStatus.available) {
218
+ console.error('No webcam available');
219
+ return;
220
+ }
221
+
222
+ // Create live scanner
223
+ const liveScanner = new LiveScanner({
224
+ targetFPS: 15,
225
+ detectionInterval: 100,
226
+ maxProcessingDimension: 600
227
+ });
228
+
229
+ // Set up event handlers
230
+ liveScanner.onDetection = (result) => {
231
+ if (result.success) {
232
+ console.log('Document detected:', result.corners);
233
+ }
234
+ };
235
+
236
+ liveScanner.onFPSUpdate = (fps) => {
237
+ console.log('Current FPS:', fps);
238
+ };
239
+
240
+ // Start scanning
241
+ const outputCanvas = document.getElementById('scanner-output');
242
+ await liveScanner.init(outputCanvas);
243
+
244
+ // Stop scanning when done
245
+ // liveScanner.stop();
246
+ ```
247
+
248
+ ## Development
249
+
250
+ Clone the repository and set up the development environment:
251
+
252
+ ```bash
253
+ git clone https://github.com/marquaye/scanic.git
254
+ cd scanic
255
+ npm install
256
+ ```
257
+
258
+ Start the development server:
259
+
260
+ ```bash
261
+ npm run dev
262
+ ```
263
+
264
+ Build for production:
265
+
266
+ ```bash
267
+ npm run build
268
+ ```
269
+
270
+ The built files will be available in the `dist/` directory.
271
+
272
+ ### Building the WebAssembly Module
273
+
274
+ The Rust WASM module is pre-compiled and included in the repository. If you need to rebuild it:
275
+
276
+ ```bash
277
+ npm run build:wasm
278
+ ```
279
+
280
+ This uses Docker to build the WASM module without requiring local Rust installation.
281
+
282
+
283
+ ### Performance Architecture
284
+
285
+ Scanic uses a **hybrid JavaScript + WebAssembly approach**:
286
+
287
+ - **JavaScript Layer**: High-level API, DOM manipulation, and workflow coordination
288
+ - **WebAssembly Layer**: CPU-intensive operations like:
289
+ - Gaussian blur with SIMD optimizations
290
+ - Canny edge detection with hysteresis thresholding
291
+ - Gradient calculations using Sobel operators
292
+ - Non-maximum suppression for edge thinning
293
+ - Morphological operations (dilation/erosion)
294
+
295
+ The WASM module is compiled from Rust using `wasm-bindgen` and includes fixed-point arithmetic optimizations for better performance on integer operations.
296
+
297
+ ## Contributing
298
+
299
+ Contributions are welcome! Here's how you can help:
300
+
301
+ 1. **Report Issues**: Found a bug? Open an issue with details and reproduction steps
302
+ 2. **Feature Requests**: Have an idea? Create an issue to discuss it
303
+ 3. **Pull Requests**: Ready to contribute code?
304
+ - Fork the repository
305
+ - Create a feature branch (`git checkout -b feature/amazing-feature`)
306
+ - Commit your changes (`git commit -m 'Add amazing feature'`)
307
+ - Push to the branch (`git push origin feature/amazing-feature`)
308
+ - Open a Pull Request
309
+
310
+ Please ensure your code follows the existing style and includes appropriate tests.
311
+
312
+ ## Sponsors
313
+
314
+ [zeugnisprofi](https://zeugnisprofi.com)
315
+
316
+ [zeugnisprofi.de] (https://zeugnisprofi.de)
317
+
318
+ [verlingo](https://www.verlingo.de)
319
+
320
+ ## Roadmap
321
+
322
+ - [ ] Performance optimizations to match OpenCV speed
323
+ - [ ] Enhanced WASM module with additional Rust-optimized algorithms
324
+ - [ ] SIMD vectorization for more image processing operations
325
+ - [ ] TypeScript definitions
326
+ - [ ] Additional image enhancement filters
327
+ - [ ] Mobile-optimized processing
328
+ - [ ] WebGPU acceleration for supported browsers
329
+
330
+ ## License
331
+
332
+ MIT License © [marquaye](https://github.com/marquaye)
333
+
334
+ See [LICENSE](LICENSE) for more details.
Binary file
@@ -0,0 +1,17 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+ <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8
+ <title><%= htmlWebpackPlugin.options.title %></title>
9
+ </head>
10
+ <body>
11
+ <noscript>
12
+ <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
13
+ </noscript>
14
+ <div id="app"></div>
15
+ <!-- built files will be auto injected -->
16
+ </body>
17
+ </html>
Binary file