sane-wasm 0.1.1 → 0.2.0
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/README.md +62 -25
- package/build/libsane.js +1 -0
- package/build/libsane.wasm +0 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +61 -0
- package/lib/index.js +7 -0
- package/lib/loader.js +80 -0
- package/package.json +30 -7
- package/libsane.d.ts +0 -163
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# SANE WebAssembly (sane-wasm)
|
|
2
2
|
|
|
3
|
-
A project to bring the [SANE API](http://www.sane-project.org/intro.html) to the
|
|
3
|
+
A project to bring the [SANE API](http://www.sane-project.org/intro.html) to Node.js and the Web using WebAssembly.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It supports USB scanners on browser environments through the [WebUSB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API) and on Node.js using [node-usb](https://github.com/node-usb/node-usb).
|
|
6
6
|
|
|
7
7
|
This works by compiling all SANE backends (and required dependencies) to WebAssembly using Emscripten. The other key piece is @RReverser's [bridge from libusb to WebUSB](https://github.com/libusb/libusb/pull/1057) ([1](https://web.dev/porting-libusb-to-webusb/)/[2](https://web.dev/porting-gphoto2-to-the-web/)) with [some patching](https://github.com/goncalomb/sane-wasm/issues/1) to support multi-threading.
|
|
8
8
|
|
|
@@ -10,15 +10,67 @@ Right now, it includes [all backends](http://www.sane-project.org/lists/sane-bac
|
|
|
10
10
|
|
|
11
11
|
## WebScan
|
|
12
12
|
|
|
13
|
-
**Check [webscan.goncalomb.com](https://webscan.goncalomb.com/) for a demo of sane-wasm.** This is a React application that uses sane-wasm for document/image scanning directly in the browser.
|
|
13
|
+
**Check [webscan.goncalomb.com](https://webscan.goncalomb.com/) for a demo of sane-wasm.** This is a React application that uses sane-wasm for document/image scanning directly in the browser. It exposes all scanning options to the user for full control.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## Usage
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
The pre-compiled WebAssembly package for sane-wasm is published on NPM:
|
|
18
|
+
|
|
19
|
+
https://www.npmjs.com/package/sane-wasm?activeTab=code
|
|
20
|
+
|
|
21
|
+
### For Web Environments (e.g. Webpack)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
npm install -D sane-wasm
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The main .js will not be bundled with your application. A loader ([lib/loader.js](lib/loader.js)) is provided to automatically load the .js/.wasm files from a CDN ([jsdelivr.com](https://www.jsdelivr.com/)). You can configure the loader to serve the files from your server if you want.
|
|
28
|
+
|
|
29
|
+
See [examples/webpack/](examples/webpack/) for a working example.
|
|
30
|
+
|
|
31
|
+
### For Node.js
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
npm install sane-wasm usb
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The usb package ([node-usb](https://github.com/node-usb/node-usb)) is required to provide USB functionality.
|
|
38
|
+
|
|
39
|
+
See [examples/node/](examples/node/) for a working example.
|
|
40
|
+
|
|
41
|
+
### As Git Submodule (not recommended) / Custom Build
|
|
42
|
+
|
|
43
|
+
As an alternative, you can add sane-wasm as a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to your application and integrate `./build.sh` with your build process. This is not recommended as it relies on some magical/dubious code on `./build.sh` to make the build work.
|
|
44
|
+
|
|
45
|
+
You can also just build sane-wasm independently and use the build artifacts...
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
<script src="build/libsane.js"></script>
|
|
49
|
+
<script>
|
|
50
|
+
window.LibSANE().then(lib => {
|
|
51
|
+
// your code
|
|
52
|
+
console.log(lib.sane_init());
|
|
53
|
+
});
|
|
54
|
+
</script>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
const { libsane } = require('./sane-wasm');
|
|
59
|
+
libsane().then(lib => {
|
|
60
|
+
console.log(lib.sane_init());
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
import { libsane } from './sane-wasm';
|
|
66
|
+
const lib = await libsane();
|
|
67
|
+
console.log(lib.sane_init());
|
|
68
|
+
```
|
|
19
69
|
|
|
20
70
|
## Building
|
|
21
71
|
|
|
72
|
+
### SANE Only
|
|
73
|
+
|
|
22
74
|
Building requires [emscripten](https://github.com/emscripten-core/emscripten) and all the required tools to build the dependencies.
|
|
23
75
|
|
|
24
76
|
The preferred way is just to use the pre-configured Docker image:
|
|
@@ -33,7 +85,7 @@ Start the test server with:
|
|
|
33
85
|
|
|
34
86
|
Check the test page at: http://localhost:6931/libsane.html.
|
|
35
87
|
|
|
36
|
-
|
|
88
|
+
#### build.sh
|
|
37
89
|
|
|
38
90
|
The `./build.sh` script has other options for debugging:
|
|
39
91
|
|
|
@@ -47,24 +99,9 @@ usage: build.sh [options]
|
|
|
47
99
|
--shell run debug shell (depends on --with-docker)
|
|
48
100
|
```
|
|
49
101
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
For now, this project has only been used on a browser environment, usage with Node.js or other environments is untested/unsupported.
|
|
53
|
-
|
|
54
|
-
The recommended way to use this project is to add it as a [submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to your application. Integrate `./build.sh` with your build process. And include the main .js file:
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
<script src="build/libsane.js"></script>
|
|
58
|
-
<script>
|
|
59
|
-
window.LibSANE().then(LibSANE => {
|
|
60
|
-
window.LibSANE = LibSANE;
|
|
61
|
-
// your code
|
|
62
|
-
console.log(LibSANE.sane_init());
|
|
63
|
-
});
|
|
64
|
-
</script>
|
|
65
|
-
```
|
|
102
|
+
### Full Build (SANE + TypeScript)
|
|
66
103
|
|
|
67
|
-
|
|
104
|
+
To do a full build use `npm run build`.
|
|
68
105
|
|
|
69
106
|
## Exposed API
|
|
70
107
|
|
|
@@ -80,7 +117,7 @@ The most important difference with the underlying SANE API is that **device hand
|
|
|
80
117
|
|
|
81
118
|
### Documentation
|
|
82
119
|
|
|
83
|
-
For now, check the [
|
|
120
|
+
For now, check the [src/index.ts](src/index.ts) for the API declaration.
|
|
84
121
|
|
|
85
122
|
## License
|
|
86
123
|
|
package/build/libsane.js
CHANGED
package/build/libsane.wasm
CHANGED
|
Binary file
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
export declare enum SANEStatus {
|
|
2
|
+
GOOD = 0,
|
|
3
|
+
UNSUPPORTED = 1,
|
|
4
|
+
CANCELLED = 2,
|
|
5
|
+
DEVICE_BUSY = 3,
|
|
6
|
+
INVAL = 4,
|
|
7
|
+
EOF = 5,
|
|
8
|
+
JAMMED = 6,
|
|
9
|
+
NO_DOCS = 7,
|
|
10
|
+
COVER_OPEN = 8,
|
|
11
|
+
IO_ERROR = 9,
|
|
12
|
+
NO_MEM = 10,
|
|
13
|
+
ACCESS_DENIED = 11
|
|
14
|
+
}
|
|
15
|
+
export declare enum SANEValueType {
|
|
16
|
+
BOOL = 0,
|
|
17
|
+
INT = 1,
|
|
18
|
+
FIXED = 2,
|
|
19
|
+
STRING = 3,
|
|
20
|
+
BUTTON = 4,
|
|
21
|
+
GROUP = 5
|
|
22
|
+
}
|
|
23
|
+
export declare enum SANEUnit {
|
|
24
|
+
NONE = 0,
|
|
25
|
+
PIXEL = 1,
|
|
26
|
+
BIT = 2,
|
|
27
|
+
MM = 3,
|
|
28
|
+
DPI = 4,
|
|
29
|
+
PERCENT = 5,
|
|
30
|
+
MICROSECOND = 6
|
|
31
|
+
}
|
|
32
|
+
export declare enum SANEConstraintType {
|
|
33
|
+
NONE = 0,
|
|
34
|
+
RANGE = 1,
|
|
35
|
+
WORD_LIST = 2,
|
|
36
|
+
STRING_LIST = 3
|
|
37
|
+
}
|
|
38
|
+
export declare enum SANEFrame {
|
|
39
|
+
GRAY = 0,
|
|
40
|
+
RGB = 1,
|
|
41
|
+
RED = 2,
|
|
42
|
+
GREEN = 3,
|
|
43
|
+
BLUE = 4
|
|
44
|
+
}
|
|
45
|
+
export type SANEState = {
|
|
46
|
+
initialized: boolean;
|
|
47
|
+
version_code: number;
|
|
48
|
+
version: {
|
|
49
|
+
major: number;
|
|
50
|
+
minor: number;
|
|
51
|
+
build: number;
|
|
52
|
+
};
|
|
53
|
+
open: boolean;
|
|
54
|
+
};
|
|
55
|
+
export type SANEDevice = {
|
|
56
|
+
name: string;
|
|
57
|
+
vendor: string;
|
|
58
|
+
model: string;
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
export type SANEOptionDescriptor = {
|
|
62
|
+
name: string;
|
|
63
|
+
title: string;
|
|
64
|
+
desc: string;
|
|
65
|
+
type: SANEValueType;
|
|
66
|
+
unit: SANEUnit;
|
|
67
|
+
size: number;
|
|
68
|
+
cap: {
|
|
69
|
+
SOFT_SELECT: boolean;
|
|
70
|
+
HARD_SELECT: boolean;
|
|
71
|
+
SOFT_DETECT: boolean;
|
|
72
|
+
EMULATED: boolean;
|
|
73
|
+
AUTOMATIC: boolean;
|
|
74
|
+
INACTIVE: boolean;
|
|
75
|
+
ADVANCED: boolean;
|
|
76
|
+
};
|
|
77
|
+
} & ({
|
|
78
|
+
constraint_type: SANEConstraintType.NONE;
|
|
79
|
+
constraint: null;
|
|
80
|
+
} | {
|
|
81
|
+
constraint_type: SANEConstraintType.RANGE;
|
|
82
|
+
constraint: {
|
|
83
|
+
min: number;
|
|
84
|
+
max: number;
|
|
85
|
+
quant: number;
|
|
86
|
+
};
|
|
87
|
+
} | {
|
|
88
|
+
constraint_type: SANEConstraintType.WORD_LIST;
|
|
89
|
+
constraint: number[];
|
|
90
|
+
} | {
|
|
91
|
+
constraint_type: SANEConstraintType.STRING_LIST;
|
|
92
|
+
constraint: string[];
|
|
93
|
+
});
|
|
94
|
+
export type SANEInfo = {
|
|
95
|
+
INEXACT: boolean;
|
|
96
|
+
RELOAD_OPTIONS: boolean;
|
|
97
|
+
RELOAD_PARAMS: boolean;
|
|
98
|
+
};
|
|
99
|
+
export type SANEParameters = {
|
|
100
|
+
format: SANEFrame;
|
|
101
|
+
last_frame: boolean;
|
|
102
|
+
bytes_per_line: number;
|
|
103
|
+
pixels_per_line: number;
|
|
104
|
+
lines: number;
|
|
105
|
+
depth: number;
|
|
106
|
+
};
|
|
107
|
+
type SANEEnum<E, TE> = E & {
|
|
108
|
+
/**
|
|
109
|
+
* @deprecated Use reverse map already built into TS enums.
|
|
110
|
+
*/
|
|
111
|
+
asString: (value: TE) => string;
|
|
112
|
+
};
|
|
113
|
+
export interface LibSANE {
|
|
114
|
+
SANE_WASM_COMMIT: string;
|
|
115
|
+
SANE_WASM_VERSION: string;
|
|
116
|
+
SANE_WASM_BACKENDS: string;
|
|
117
|
+
SANE_CURRENT_MAJOR: number;
|
|
118
|
+
SANE_CURRENT_MINOR: number;
|
|
119
|
+
SANE_STATUS: SANEEnum<typeof SANEStatus, SANEStatus>;
|
|
120
|
+
SANE_TYPE: SANEEnum<typeof SANEValueType, SANEValueType>;
|
|
121
|
+
SANE_UNIT: SANEEnum<typeof SANEUnit, SANEUnit>;
|
|
122
|
+
SANE_CONSTRAINT: SANEEnum<typeof SANEConstraintType, SANEConstraintType>;
|
|
123
|
+
SANE_FRAME: SANEEnum<typeof SANEFrame, SANEFrame>;
|
|
124
|
+
sane_get_state: () => SANEState;
|
|
125
|
+
sane_init: () => {
|
|
126
|
+
status: SANEStatus;
|
|
127
|
+
version_code: number;
|
|
128
|
+
};
|
|
129
|
+
sane_exit: () => Promise<{
|
|
130
|
+
status: SANEStatus;
|
|
131
|
+
}>;
|
|
132
|
+
sane_get_devices: () => Promise<{
|
|
133
|
+
status: SANEStatus;
|
|
134
|
+
devices: SANEDevice[];
|
|
135
|
+
}>;
|
|
136
|
+
sane_open: (devicename: string) => Promise<{
|
|
137
|
+
status: SANEStatus;
|
|
138
|
+
}>;
|
|
139
|
+
sane_close: () => Promise<{
|
|
140
|
+
status: SANEStatus;
|
|
141
|
+
}>;
|
|
142
|
+
sane_get_option_descriptor: (option: number) => {
|
|
143
|
+
status: SANEStatus;
|
|
144
|
+
option_descriptor: SANEOptionDescriptor | null;
|
|
145
|
+
};
|
|
146
|
+
sane_control_option_get_value: (option: number) => Promise<{
|
|
147
|
+
status: SANEStatus;
|
|
148
|
+
value: any;
|
|
149
|
+
}>;
|
|
150
|
+
sane_control_option_set_value: (option: number, value: any) => Promise<{
|
|
151
|
+
status: SANEStatus;
|
|
152
|
+
info: SANEInfo;
|
|
153
|
+
}>;
|
|
154
|
+
sane_control_option_set_auto: (option: number) => Promise<{
|
|
155
|
+
status: SANEStatus;
|
|
156
|
+
info: SANEInfo;
|
|
157
|
+
}>;
|
|
158
|
+
sane_get_parameters: () => {
|
|
159
|
+
status: SANEStatus;
|
|
160
|
+
parameters: SANEParameters;
|
|
161
|
+
};
|
|
162
|
+
sane_start: () => {
|
|
163
|
+
status: SANEStatus;
|
|
164
|
+
};
|
|
165
|
+
sane_read: () => Promise<{
|
|
166
|
+
status: SANEStatus;
|
|
167
|
+
data: Uint8Array;
|
|
168
|
+
}>;
|
|
169
|
+
sane_cancel: () => Promise<{
|
|
170
|
+
status: SANEStatus;
|
|
171
|
+
}>;
|
|
172
|
+
sane_strstatus: (status: SANEStatus) => string;
|
|
173
|
+
}
|
|
174
|
+
export type LibSANEFactory = (option?: {
|
|
175
|
+
sane?: {
|
|
176
|
+
loaderURL: string;
|
|
177
|
+
loaderPrefetchToBlob: boolean;
|
|
178
|
+
loaderRemoveGlobal: boolean;
|
|
179
|
+
debugSANE?: boolean;
|
|
180
|
+
debugUSB?: boolean;
|
|
181
|
+
debugFunctionCalls?: boolean;
|
|
182
|
+
debugTestDevices?: number;
|
|
183
|
+
promisify?: boolean;
|
|
184
|
+
promisifyQueue?: boolean;
|
|
185
|
+
};
|
|
186
|
+
} & {
|
|
187
|
+
[k: string]: any;
|
|
188
|
+
}) => Promise<LibSANE>;
|
|
189
|
+
/**
|
|
190
|
+
* Main LibSANE factory.
|
|
191
|
+
*/
|
|
192
|
+
export declare const libsane: LibSANEFactory;
|
|
193
|
+
/**
|
|
194
|
+
* @deprecated The default export may be removed in the future.
|
|
195
|
+
* Use the 'libsane' named export.
|
|
196
|
+
*/
|
|
197
|
+
export default libsane;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.libsane = exports.SANEFrame = exports.SANEConstraintType = exports.SANEUnit = exports.SANEValueType = exports.SANEStatus = void 0;
|
|
4
|
+
var SANEStatus;
|
|
5
|
+
(function (SANEStatus) {
|
|
6
|
+
SANEStatus[SANEStatus["GOOD"] = 0] = "GOOD";
|
|
7
|
+
SANEStatus[SANEStatus["UNSUPPORTED"] = 1] = "UNSUPPORTED";
|
|
8
|
+
SANEStatus[SANEStatus["CANCELLED"] = 2] = "CANCELLED";
|
|
9
|
+
SANEStatus[SANEStatus["DEVICE_BUSY"] = 3] = "DEVICE_BUSY";
|
|
10
|
+
SANEStatus[SANEStatus["INVAL"] = 4] = "INVAL";
|
|
11
|
+
SANEStatus[SANEStatus["EOF"] = 5] = "EOF";
|
|
12
|
+
SANEStatus[SANEStatus["JAMMED"] = 6] = "JAMMED";
|
|
13
|
+
SANEStatus[SANEStatus["NO_DOCS"] = 7] = "NO_DOCS";
|
|
14
|
+
SANEStatus[SANEStatus["COVER_OPEN"] = 8] = "COVER_OPEN";
|
|
15
|
+
SANEStatus[SANEStatus["IO_ERROR"] = 9] = "IO_ERROR";
|
|
16
|
+
SANEStatus[SANEStatus["NO_MEM"] = 10] = "NO_MEM";
|
|
17
|
+
SANEStatus[SANEStatus["ACCESS_DENIED"] = 11] = "ACCESS_DENIED";
|
|
18
|
+
})(SANEStatus || (exports.SANEStatus = SANEStatus = {}));
|
|
19
|
+
var SANEValueType;
|
|
20
|
+
(function (SANEValueType) {
|
|
21
|
+
SANEValueType[SANEValueType["BOOL"] = 0] = "BOOL";
|
|
22
|
+
SANEValueType[SANEValueType["INT"] = 1] = "INT";
|
|
23
|
+
SANEValueType[SANEValueType["FIXED"] = 2] = "FIXED";
|
|
24
|
+
SANEValueType[SANEValueType["STRING"] = 3] = "STRING";
|
|
25
|
+
SANEValueType[SANEValueType["BUTTON"] = 4] = "BUTTON";
|
|
26
|
+
SANEValueType[SANEValueType["GROUP"] = 5] = "GROUP";
|
|
27
|
+
})(SANEValueType || (exports.SANEValueType = SANEValueType = {}));
|
|
28
|
+
var SANEUnit;
|
|
29
|
+
(function (SANEUnit) {
|
|
30
|
+
SANEUnit[SANEUnit["NONE"] = 0] = "NONE";
|
|
31
|
+
SANEUnit[SANEUnit["PIXEL"] = 1] = "PIXEL";
|
|
32
|
+
SANEUnit[SANEUnit["BIT"] = 2] = "BIT";
|
|
33
|
+
SANEUnit[SANEUnit["MM"] = 3] = "MM";
|
|
34
|
+
SANEUnit[SANEUnit["DPI"] = 4] = "DPI";
|
|
35
|
+
SANEUnit[SANEUnit["PERCENT"] = 5] = "PERCENT";
|
|
36
|
+
SANEUnit[SANEUnit["MICROSECOND"] = 6] = "MICROSECOND";
|
|
37
|
+
})(SANEUnit || (exports.SANEUnit = SANEUnit = {}));
|
|
38
|
+
var SANEConstraintType;
|
|
39
|
+
(function (SANEConstraintType) {
|
|
40
|
+
SANEConstraintType[SANEConstraintType["NONE"] = 0] = "NONE";
|
|
41
|
+
SANEConstraintType[SANEConstraintType["RANGE"] = 1] = "RANGE";
|
|
42
|
+
SANEConstraintType[SANEConstraintType["WORD_LIST"] = 2] = "WORD_LIST";
|
|
43
|
+
SANEConstraintType[SANEConstraintType["STRING_LIST"] = 3] = "STRING_LIST";
|
|
44
|
+
})(SANEConstraintType || (exports.SANEConstraintType = SANEConstraintType = {}));
|
|
45
|
+
var SANEFrame;
|
|
46
|
+
(function (SANEFrame) {
|
|
47
|
+
SANEFrame[SANEFrame["GRAY"] = 0] = "GRAY";
|
|
48
|
+
SANEFrame[SANEFrame["RGB"] = 1] = "RGB";
|
|
49
|
+
SANEFrame[SANEFrame["RED"] = 2] = "RED";
|
|
50
|
+
SANEFrame[SANEFrame["GREEN"] = 3] = "GREEN";
|
|
51
|
+
SANEFrame[SANEFrame["BLUE"] = 4] = "BLUE";
|
|
52
|
+
})(SANEFrame || (exports.SANEFrame = SANEFrame = {}));
|
|
53
|
+
/**
|
|
54
|
+
* Main LibSANE factory.
|
|
55
|
+
*/
|
|
56
|
+
exports.libsane = require('../lib');
|
|
57
|
+
/**
|
|
58
|
+
* @deprecated The default export may be removed in the future.
|
|
59
|
+
* Use the 'libsane' named export.
|
|
60
|
+
*/
|
|
61
|
+
exports.default = exports.libsane;
|
package/lib/index.js
ADDED
package/lib/loader.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const { version } = require('../package.json');
|
|
2
|
+
|
|
3
|
+
// we cannot use unpkg as a CDN because they don't set CORP
|
|
4
|
+
// Cross-Origin-Resource-Policy: cross-origin
|
|
5
|
+
// const cdnURL = `https://unpkg.com/sane-wasm@${version}/build`;
|
|
6
|
+
|
|
7
|
+
// use good old jsdelivr
|
|
8
|
+
const cdnURL = `https://cdn.jsdelivr.net/npm/sane-wasm@${version}/build`;
|
|
9
|
+
|
|
10
|
+
let libPromise = null;
|
|
11
|
+
|
|
12
|
+
function loadScript(src) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
document.head.append(Object.assign(
|
|
15
|
+
document.createElement('script'),
|
|
16
|
+
{ src, onload: resolve, onerror: reject }
|
|
17
|
+
));
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function fetchFileToBlobURL(src) {
|
|
22
|
+
return fetch(src).then(res => res.ok ? res.blob() : new Blob()).then(blob => URL.createObjectURL(blob));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function prepareLib(options) {
|
|
26
|
+
const jsURL = `${options.sane.loaderURL}/libsane.js`;
|
|
27
|
+
const jsWorkerURL = `${options.sane.loaderURL}/libsane.worker.js`;
|
|
28
|
+
const jsWasmURL = `${options.sane.loaderURL}/libsane.wasm`;
|
|
29
|
+
|
|
30
|
+
const filesToPrefetch = options.sane.loaderPrefetchToBlob ? [
|
|
31
|
+
// because of security restrictions around the Worker constructor
|
|
32
|
+
// we need to prefetch the worker js and serve it from a blob
|
|
33
|
+
// see: https://github.com/emscripten-core/emscripten/issues/8338
|
|
34
|
+
jsWorkerURL,
|
|
35
|
+
// since we are already doing all this work to fetch the files in
|
|
36
|
+
// parallel, might as well prefetch the wasm file
|
|
37
|
+
jsWasmURL,
|
|
38
|
+
] : [];
|
|
39
|
+
|
|
40
|
+
const [lib, prefetchResult] = await Promise.all([
|
|
41
|
+
loadScript(jsURL).then(() => {
|
|
42
|
+
const lib = window.LibSANE;
|
|
43
|
+
if (options.sane.loaderRemoveGlobal) {
|
|
44
|
+
window.LibSANE = undefined; // nuke global variable
|
|
45
|
+
}
|
|
46
|
+
return lib;
|
|
47
|
+
}),
|
|
48
|
+
Promise.all(filesToPrefetch.map(url => fetchFileToBlobURL(url).then(urlBlob => ({ url, urlBlob })))),
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
const preFetchedFiles = prefetchResult.reduce((obj, { url, urlBlob }) => {
|
|
52
|
+
obj[url] = urlBlob;
|
|
53
|
+
return obj;
|
|
54
|
+
}, {});
|
|
55
|
+
|
|
56
|
+
return { lib, preFetchedFiles };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = async (options) => {
|
|
60
|
+
options = options || {};
|
|
61
|
+
options.sane = {
|
|
62
|
+
loaderURL: cdnURL,
|
|
63
|
+
loaderPrefetchToBlob: true,
|
|
64
|
+
loaderRemoveGlobal: true,
|
|
65
|
+
...(options.sane || {}),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
if (!libPromise) {
|
|
69
|
+
libPromise = prepareLib(options);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const { lib, preFetchedFiles } = await libPromise;
|
|
73
|
+
return lib({
|
|
74
|
+
...(options || {}),
|
|
75
|
+
locateFile: (path, prefix) => {
|
|
76
|
+
const fullUrl = `${prefix}${path}`;
|
|
77
|
+
return preFetchedFiles[fullUrl] ? preFetchedFiles[fullUrl] : (options.locateFile ? options.locateFile(path, prefix) : fullUrl);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
};
|
package/package.json
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sane-wasm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A project to bring the SANE API to the web.",
|
|
5
|
-
"main": "
|
|
6
|
-
"types": "
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
8
|
+
"test": "jest",
|
|
9
|
+
"clean": "npm run clean:tsc && npm run clean:sane",
|
|
10
|
+
"clean:tsc": "rm -rf dist/",
|
|
11
|
+
"clean:sane": "./build.sh --no-build --clean",
|
|
12
|
+
"prebuild": "rm -rf dist/ build/",
|
|
13
|
+
"build": "npm run build:tsc && npm run build:sane",
|
|
14
|
+
"build:tsc": "tsc",
|
|
15
|
+
"build:sane": "./build.sh --with-docker --clean",
|
|
16
|
+
"debug:sane": "./build.sh --with-docker --debug --emrun"
|
|
11
17
|
},
|
|
12
18
|
"files": [
|
|
19
|
+
"dist/",
|
|
20
|
+
"lib/",
|
|
13
21
|
"build/",
|
|
14
22
|
"libsane.d.ts",
|
|
15
23
|
"LICENSE-LGPL.txt",
|
|
@@ -25,7 +33,22 @@
|
|
|
25
33
|
"url": "https://github.com/goncalomb/sane-wasm/issues"
|
|
26
34
|
},
|
|
27
35
|
"homepage": "https://github.com/goncalomb/sane-wasm#readme",
|
|
28
|
-
"
|
|
36
|
+
"jest": {
|
|
37
|
+
"setupFilesAfterEnv": [
|
|
38
|
+
"jest-extended/all"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
29
42
|
"usb": "^2.10.0"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"usb": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"jest": "^29.6.4",
|
|
51
|
+
"jest-extended": "^4.0.1",
|
|
52
|
+
"typescript": "^5.2.2"
|
|
30
53
|
}
|
|
31
54
|
}
|
package/libsane.d.ts
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
export enum SANEStatus {
|
|
2
|
-
GOOD = 0,
|
|
3
|
-
UNSUPPORTED,
|
|
4
|
-
CANCELLED,
|
|
5
|
-
DEVICE_BUSY,
|
|
6
|
-
INVAL,
|
|
7
|
-
EOF,
|
|
8
|
-
JAMMED,
|
|
9
|
-
NO_DOCS,
|
|
10
|
-
COVER_OPEN,
|
|
11
|
-
IO_ERROR,
|
|
12
|
-
NO_MEM,
|
|
13
|
-
ACCESS_DENIED,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export enum SANEValueType {
|
|
17
|
-
BOOL = 0,
|
|
18
|
-
INT,
|
|
19
|
-
FIXED,
|
|
20
|
-
STRING,
|
|
21
|
-
BUTTON,
|
|
22
|
-
GROUP,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export enum SANEUnit {
|
|
26
|
-
NONE = 0,
|
|
27
|
-
PIXEL,
|
|
28
|
-
BIT,
|
|
29
|
-
MM,
|
|
30
|
-
DPI,
|
|
31
|
-
PERCENT,
|
|
32
|
-
MICROSECOND,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export enum SANEConstraintType {
|
|
36
|
-
NONE = 0,
|
|
37
|
-
RANGE,
|
|
38
|
-
WORD_LIST,
|
|
39
|
-
STRING_LIST,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export enum SANEFrame {
|
|
43
|
-
GRAY = 0,
|
|
44
|
-
RGB,
|
|
45
|
-
RED,
|
|
46
|
-
GREEN,
|
|
47
|
-
BLUE,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export type SANEState = {
|
|
51
|
-
initialized: boolean;
|
|
52
|
-
version_code: number;
|
|
53
|
-
version: {
|
|
54
|
-
major: number;
|
|
55
|
-
minor: number;
|
|
56
|
-
build: number;
|
|
57
|
-
},
|
|
58
|
-
open: boolean;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export type SANEDevice = {
|
|
62
|
-
name: string;
|
|
63
|
-
vendor: string;
|
|
64
|
-
model: string;
|
|
65
|
-
type: string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export type SANEOptionDescriptor = {
|
|
69
|
-
name: string;
|
|
70
|
-
title: string;
|
|
71
|
-
desc: string;
|
|
72
|
-
type: SANEValueType;
|
|
73
|
-
unit: SANEUnit;
|
|
74
|
-
size: number;
|
|
75
|
-
cap: {
|
|
76
|
-
SOFT_SELECT: boolean;
|
|
77
|
-
HARD_SELECT: boolean;
|
|
78
|
-
SOFT_DETECT: boolean;
|
|
79
|
-
EMULATED: boolean;
|
|
80
|
-
AUTOMATIC: boolean;
|
|
81
|
-
INACTIVE: boolean;
|
|
82
|
-
ADVANCED: boolean;
|
|
83
|
-
};
|
|
84
|
-
} & ({
|
|
85
|
-
constraint_type: SANEConstraintType.NONE
|
|
86
|
-
constraint: null
|
|
87
|
-
} | {
|
|
88
|
-
constraint_type: SANEConstraintType.RANGE
|
|
89
|
-
constraint: {
|
|
90
|
-
min: number;
|
|
91
|
-
max: number;
|
|
92
|
-
quant: number;
|
|
93
|
-
}
|
|
94
|
-
} | {
|
|
95
|
-
constraint_type: SANEConstraintType.WORD_LIST
|
|
96
|
-
constraint: number[]
|
|
97
|
-
} | {
|
|
98
|
-
constraint_type: SANEConstraintType.STRING_LIST
|
|
99
|
-
constraint: string[]
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
export type SANEInfo = {
|
|
103
|
-
INEXACT: boolean;
|
|
104
|
-
RELOAD_OPTIONS: boolean;
|
|
105
|
-
RELOAD_PARAMS: boolean;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
export type SANEParameters = {
|
|
109
|
-
format: SANEFrame;
|
|
110
|
-
last_frame: boolean;
|
|
111
|
-
bytes_per_line: number;
|
|
112
|
-
pixels_per_line: number;
|
|
113
|
-
lines: number;
|
|
114
|
-
depth: number;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
type SANEEnum<E, TE> = E & {
|
|
118
|
-
asString: (value: TE) => string;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export interface LibSANE {
|
|
122
|
-
SANE_WASM_COMMIT: string;
|
|
123
|
-
SANE_WASM_VERSION: string;
|
|
124
|
-
SANE_WASM_BACKENDS: string;
|
|
125
|
-
|
|
126
|
-
SANE_CURRENT_MAJOR: number;
|
|
127
|
-
SANE_CURRENT_MINOR: number;
|
|
128
|
-
|
|
129
|
-
SANE_STATUS: SANEEnum<typeof SANEStatus, SANEStatus>;
|
|
130
|
-
SANE_TYPE: SANEEnum<typeof SANEValueType, SANEValueType>;
|
|
131
|
-
SANE_UNIT: SANEEnum<typeof SANEUnit, SANEUnit>;
|
|
132
|
-
SANE_CONSTRAINT: SANEEnum<typeof SANEConstraintType, SANEConstraintType>;
|
|
133
|
-
SANE_FRAME: SANEEnum<typeof SANEFrame, SANEFrame>;
|
|
134
|
-
|
|
135
|
-
sane_get_state: () => SANEState;
|
|
136
|
-
sane_init: () => { status: SANEStatus; version_code: number };
|
|
137
|
-
sane_exit: () => Promise<{ status: SANEStatus; }>;
|
|
138
|
-
sane_get_devices: () => Promise<{ status: SANEStatus; devices: SANEDevice[] }>;
|
|
139
|
-
sane_open: (devicename: string) => Promise<{ status: SANEStatus; }>;
|
|
140
|
-
sane_close: () => Promise<{ status: SANEStatus; }>;
|
|
141
|
-
sane_get_option_descriptor: (option: number) => { status: SANEStatus; option_descriptor: SANEOptionDescriptor | null };
|
|
142
|
-
sane_control_option_get_value: (option: number) => Promise<{ status: SANEStatus; value: any }>;
|
|
143
|
-
sane_control_option_set_value: (option: number, value: any) => Promise<{ status: SANEStatus; info: SANEInfo }>;
|
|
144
|
-
sane_control_option_set_auto: (option: number) => Promise<{ status: SANEStatus; info: SANEInfo }>;
|
|
145
|
-
sane_get_parameters: () => { status: SANEStatus; parameters: SANEParameters };
|
|
146
|
-
sane_start: () => { status: SANEStatus; };
|
|
147
|
-
sane_read: () => Promise<{ status: SANEStatus; data: Uint8Array }>;
|
|
148
|
-
sane_cancel: () => Promise<{ status: SANEStatus; }>;
|
|
149
|
-
sane_strstatus: (status: SANEStatus) => string;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export type LibSANEFactory = (option?: {
|
|
153
|
-
sane?: {
|
|
154
|
-
debugSANE?: boolean;
|
|
155
|
-
debugUSB?: boolean;
|
|
156
|
-
debugFunctionCalls?: boolean;
|
|
157
|
-
debugTestDevices?: number;
|
|
158
|
-
promisify?: boolean;
|
|
159
|
-
promisifyQueue?: boolean;
|
|
160
|
-
}
|
|
161
|
-
} & {
|
|
162
|
-
[k: string]: any
|
|
163
|
-
}) => Promise<LibSANE>
|