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 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 web.
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
- Currently, it only supports USB scanners and is only tested on a browser environment (WebUSB).
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. Exposes all scanning options to the user for full control.
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
- If you are interested in seeing the compiled output of sane-wasm, check:
15
+ ## Usage
16
16
 
17
- * [webscan.goncalomb.com/sane-wasm/](https://webscan.goncalomb.com/sane-wasm/): all files
18
- * [webscan.goncalomb.com/sane-wasm/libsane.html](https://webscan.goncalomb.com/sane-wasm/libsane.html): test page
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
- ### build.sh
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
- ## Using
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
- This will be improved in the future.
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 [libsane.d.ts](libsane.d.ts) for the API declaration.
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
@@ -80,6 +80,7 @@ Module["ready"] = new Promise(function(resolve, reject) {
80
80
  obj.__proto__ = this.prototype;
81
81
  obj[this.reverseObject] = {};
82
82
  Object.keys(obj).forEach(k => {
83
+ obj[obj[k]] = k;
83
84
  obj[this.reverseObject][obj[k]] = k;
84
85
  });
85
86
  }
Binary file
@@ -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
@@ -0,0 +1,7 @@
1
+ if (globalThis.window && globalThis.window.document) {
2
+ // browser environment (e.g. webpack)
3
+ module.exports = require('./loader.js');
4
+ } else {
5
+ // local environment (e.g. node)
6
+ module.exports = eval('require')('../build/libsane.js');
7
+ }
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.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "A project to bring the SANE API to the web.",
5
- "main": "build/libsane.js",
6
- "types": "libsane.d.ts",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
7
  "scripts": {
8
- "clean": "./build.sh --with-docker --no-build --clean",
9
- "build": "./build.sh --with-docker --clean",
10
- "build-debug": "./build.sh --with-docker --debug --emrun"
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
- "dependencies": {
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>