@wasmedia/wenblend 0.1.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/LICENSE +367 -0
- package/LICENSE-GPL-3.0 +674 -0
- package/README.md +98 -0
- package/dist/cli.d.ts +27 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +167 -0
- package/dist/cli.js.map +1 -0
- package/dist/filesystem.d.ts +25 -0
- package/dist/filesystem.d.ts.map +1 -0
- package/dist/filesystem.js +75 -0
- package/dist/filesystem.js.map +1 -0
- package/dist/handler.d.ts +62 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +91 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +74 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +181 -0
- package/dist/loader.js.map +1 -0
- package/dist/operations.d.ts +45 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +94 -0
- package/dist/operations.js.map +1 -0
- package/dist/staging.d.ts +37 -0
- package/dist/staging.d.ts.map +1 -0
- package/dist/staging.js +157 -0
- package/dist/staging.js.map +1 -0
- package/dist/tiff-header.d.ts +16 -0
- package/dist/tiff-header.d.ts.map +1 -0
- package/dist/tiff-header.js +97 -0
- package/dist/tiff-header.js.map +1 -0
- package/dist/types.d.ts +128 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +47 -0
- package/dist/types.js.map +1 -0
- package/dist/wenblend.js +2 -0
- package/dist/wenblend.wasm +0 -0
- package/dist/wenfuse.js +2 -0
- package/dist/wenfuse.wasm +0 -0
- package/dist/wopfs.d.ts +37 -0
- package/dist/wopfs.d.ts.map +1 -0
- package/dist/wopfs.js +38 -0
- package/dist/wopfs.js.map +1 -0
- package/dist/worker.d.ts +16 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +29 -0
- package/dist/worker.js.map +1 -0
- package/package.json +67 -0
- package/src/cli.ts +201 -0
- package/src/filesystem.ts +85 -0
- package/src/handler.ts +112 -0
- package/src/index.ts +41 -0
- package/src/loader.ts +223 -0
- package/src/operations.ts +147 -0
- package/src/staging.ts +173 -0
- package/src/tiff-header.ts +94 -0
- package/src/types.ts +153 -0
- package/src/wopfs.ts +70 -0
- package/src/worker.ts +31 -0
- package/types/wasm.d.ts +12 -0
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool wasm module loading.
|
|
3
|
+
*
|
|
4
|
+
* Two facts drive this file:
|
|
5
|
+
*
|
|
6
|
+
* 1. Each tool is its own ~3 MB module. A page that only blends must
|
|
7
|
+
* not pay for the fuse module, so the import is per-tool and lazy.
|
|
8
|
+
* 2. Both tools keep state in C++ globals and neither resets it, so a
|
|
9
|
+
* module INSTANCE is never reused across invocations.
|
|
10
|
+
*
|
|
11
|
+
* So two things are cached per tool and one is not:
|
|
12
|
+
*
|
|
13
|
+
* - the JS glue's factory (the dynamic import), and
|
|
14
|
+
* - the COMPILED `WebAssembly.Module`, fetched and compiled once and
|
|
15
|
+
* handed to every later factory call through Emscripten's
|
|
16
|
+
* `instantiateWasm` hook, so a new instance costs an instantiate,
|
|
17
|
+
* not a re-download and re-compile of ~3 MB;
|
|
18
|
+
* - never the instance itself.
|
|
19
|
+
*
|
|
20
|
+
* Without the hook, each factory call runs the glue's own createWasm,
|
|
21
|
+
* which fetches and compiles the .wasm from scratch every time.
|
|
22
|
+
*/
|
|
23
|
+
import type { WasmModule, LoaderOptions } from "./types.js";
|
|
24
|
+
export type Tool = "enblend" | "enfuse";
|
|
25
|
+
/**
|
|
26
|
+
* Output hooks, bound at construction.
|
|
27
|
+
*
|
|
28
|
+
* Emscripten reads `Module["print"]`/`Module["printErr"]` exactly once,
|
|
29
|
+
* inside the factory body, and binds them into module-local variables
|
|
30
|
+
* before the factory's promise resolves. Assigning `module.print` after
|
|
31
|
+
* `await factory(...)` returns is inert. Callers that want to capture
|
|
32
|
+
* output must build their closures first and pass them into
|
|
33
|
+
* `createInstance`.
|
|
34
|
+
*/
|
|
35
|
+
export type InstanceHooks = Pick<WasmModule, "print" | "printErr">;
|
|
36
|
+
/** A tool's Emscripten module factory: the default export of its `.js` glue. */
|
|
37
|
+
export type ModuleFactory = (config?: Record<string, unknown>) => Promise<WasmModule>;
|
|
38
|
+
type FactoryLoader = (tool: Tool, options?: LoaderOptions) => Promise<ModuleFactory>;
|
|
39
|
+
/** Test seam: replace the dynamic import. */
|
|
40
|
+
export declare function __setFactoryLoader(fn: FactoryLoader): void;
|
|
41
|
+
/** Test seam: replace the wasm fetch-and-compile step. */
|
|
42
|
+
export declare function __setWasmCompiler(fn: (tool: Tool, options?: LoaderOptions) => Promise<WebAssembly.Module>): void;
|
|
43
|
+
/** Test seam: drop cached factories and compiled modules. */
|
|
44
|
+
export declare function resetFactoryCache(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Import a tool's JS glue and return its module factory. Cached per tool and resolved glue URL.
|
|
47
|
+
*
|
|
48
|
+
* Calling the returned factory directly compiles the .wasm afresh on every
|
|
49
|
+
* call; `createInstance` is what supplies the cached compiled module.
|
|
50
|
+
*
|
|
51
|
+
* `async` so that a `wasmPath` that is not a valid URL rejects rather than
|
|
52
|
+
* throwing synchronously. The cache lookup still happens before the first
|
|
53
|
+
* `await`, so concurrent first calls share one import.
|
|
54
|
+
*/
|
|
55
|
+
export declare function loadFactory(tool: Tool, options?: LoaderOptions): Promise<ModuleFactory>;
|
|
56
|
+
/**
|
|
57
|
+
* Build a fresh module instance.
|
|
58
|
+
*
|
|
59
|
+
* Never cache the result. See the file header.
|
|
60
|
+
*
|
|
61
|
+
* `hooks` is passed straight into the factory's config object, since that
|
|
62
|
+
* is the only point at which `print`/`printErr` can take effect (see
|
|
63
|
+
* `InstanceHooks`).
|
|
64
|
+
*
|
|
65
|
+
* The compiled module reaches the glue through `instantiateWasm`: the glue
|
|
66
|
+
* calls it with its import object in place of its own fetch-and-compile,
|
|
67
|
+
* and waits for `receiveInstance`. That wait has no rejection path — the
|
|
68
|
+
* glue wraps the hook in a promise whose `reject` it never calls — so a
|
|
69
|
+
* compile or instantiate failure is raced against the factory here, or
|
|
70
|
+
* the call would hang forever instead of rejecting.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createInstance(tool: Tool, options?: LoaderOptions, hooks?: Partial<InstanceHooks>): Promise<WasmModule>;
|
|
73
|
+
export {};
|
|
74
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,MAAM,IAAI,GAAG,SAAS,GAAG,QAAQ,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC,CAAC;AAEnE,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AACtF,KAAK,aAAa,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAoGrF,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAE1D;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,GACvE,IAAI,CAEN;AAED,6DAA6D;AAC7D,wBAAgB,iBAAiB,IAAI,IAAI,CAKxC;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAW7F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,EACV,OAAO,CAAC,EAAE,aAAa,EACvB,KAAK,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAC7B,OAAO,CAAC,UAAU,CAAC,CAkBrB"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-tool wasm module loading.
|
|
3
|
+
*
|
|
4
|
+
* Two facts drive this file:
|
|
5
|
+
*
|
|
6
|
+
* 1. Each tool is its own ~3 MB module. A page that only blends must
|
|
7
|
+
* not pay for the fuse module, so the import is per-tool and lazy.
|
|
8
|
+
* 2. Both tools keep state in C++ globals and neither resets it, so a
|
|
9
|
+
* module INSTANCE is never reused across invocations.
|
|
10
|
+
*
|
|
11
|
+
* So two things are cached per tool and one is not:
|
|
12
|
+
*
|
|
13
|
+
* - the JS glue's factory (the dynamic import), and
|
|
14
|
+
* - the COMPILED `WebAssembly.Module`, fetched and compiled once and
|
|
15
|
+
* handed to every later factory call through Emscripten's
|
|
16
|
+
* `instantiateWasm` hook, so a new instance costs an instantiate,
|
|
17
|
+
* not a re-download and re-compile of ~3 MB;
|
|
18
|
+
* - never the instance itself.
|
|
19
|
+
*
|
|
20
|
+
* Without the hook, each factory call runs the glue's own createWasm,
|
|
21
|
+
* which fetches and compiles the .wasm from scratch every time.
|
|
22
|
+
*/
|
|
23
|
+
const MODULE_FILE = {
|
|
24
|
+
enblend: "wenblend.js",
|
|
25
|
+
enfuse: "wenfuse.js",
|
|
26
|
+
};
|
|
27
|
+
const WASM_FILE = {
|
|
28
|
+
enblend: "wenblend.wasm",
|
|
29
|
+
enfuse: "wenfuse.wasm",
|
|
30
|
+
};
|
|
31
|
+
// Both caches are keyed on the tool AND the absolute glue URL, so a second
|
|
32
|
+
// call with a different `wasmPath` loads that module instead of silently
|
|
33
|
+
// reusing the first. Relative and absolute spellings of one location resolve
|
|
34
|
+
// to the same key.
|
|
35
|
+
const factories = new Map();
|
|
36
|
+
const compiled = new Map();
|
|
37
|
+
function glueUrl(tool, options) {
|
|
38
|
+
return options?.wasmPath
|
|
39
|
+
?? new URL(`../dist/${MODULE_FILE[tool]}`, import.meta.url).href;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The glue's absolute URL. `new URL` needs an absolute base, but `wasmPath`
|
|
43
|
+
* may be relative (what bundlers hand out, e.g. Vite's `?url`), so it is
|
|
44
|
+
* resolved against this module — the same base `import()` uses for the glue.
|
|
45
|
+
*/
|
|
46
|
+
function resolvedGlueUrl(tool, options) {
|
|
47
|
+
return new URL(glueUrl(tool, options), import.meta.url);
|
|
48
|
+
}
|
|
49
|
+
function cacheKey(tool, options) {
|
|
50
|
+
return `${tool} ${resolvedGlueUrl(tool, options).href}`;
|
|
51
|
+
}
|
|
52
|
+
async function importFactory(tool, options) {
|
|
53
|
+
const mod = await import(/* webpackIgnore: true */ glueUrl(tool, options));
|
|
54
|
+
return (mod.default ?? mod);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Fetch and compile a tool's .wasm.
|
|
58
|
+
*
|
|
59
|
+
* The URL is the one the glue itself would use: its `locateFile` default
|
|
60
|
+
* resolves the .wasm name against the glue's own directory. `file:` URLs
|
|
61
|
+
* (Node) are read from disk, because Node's fetch does not do `file:`;
|
|
62
|
+
* everything else is fetched, streaming-compiled where the server's MIME
|
|
63
|
+
* type allows and compiled from bytes where it does not — the same
|
|
64
|
+
* fallback the glue performs.
|
|
65
|
+
*/
|
|
66
|
+
async function compileWasm(tool, options) {
|
|
67
|
+
const url = new URL(WASM_FILE[tool], resolvedGlueUrl(tool, options));
|
|
68
|
+
if (url.protocol === "file:") {
|
|
69
|
+
// A variable specifier keeps bundlers from trying to resolve a Node
|
|
70
|
+
// builtin into browser code; this branch only runs under Node.
|
|
71
|
+
const fsSpec = "node:fs/promises";
|
|
72
|
+
const urlSpec = "node:url";
|
|
73
|
+
const { readFile } = await import(/* webpackIgnore: true */ /* @vite-ignore */ fsSpec);
|
|
74
|
+
const { fileURLToPath } = await import(/* webpackIgnore: true */ /* @vite-ignore */ urlSpec);
|
|
75
|
+
return WebAssembly.compile(await readFile(fileURLToPath(url)));
|
|
76
|
+
}
|
|
77
|
+
const response = fetch(url.href, { credentials: "same-origin" });
|
|
78
|
+
if (typeof WebAssembly.compileStreaming === "function") {
|
|
79
|
+
try {
|
|
80
|
+
return await WebAssembly.compileStreaming(response);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// Wrong MIME type, most often. Fall through to compiling bytes.
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const res = await response;
|
|
87
|
+
if (!res.ok)
|
|
88
|
+
throw new Error(`failed to fetch ${url.href}: HTTP ${res.status}`);
|
|
89
|
+
return WebAssembly.compile(await res.arrayBuffer());
|
|
90
|
+
}
|
|
91
|
+
let compileWasmImpl = compileWasm;
|
|
92
|
+
/**
|
|
93
|
+
* The compiled module for a tool, compiled at most once per resolved URL.
|
|
94
|
+
*
|
|
95
|
+
* A promise is cached, so concurrent first calls share one compile. A
|
|
96
|
+
* failed compile is evicted, so a transient network error is retried on
|
|
97
|
+
* the next call rather than poisoning the cache for the page's lifetime.
|
|
98
|
+
*/
|
|
99
|
+
async function loadCompiled(tool, options) {
|
|
100
|
+
const key = cacheKey(tool, options);
|
|
101
|
+
let existing = compiled.get(key);
|
|
102
|
+
if (!existing) {
|
|
103
|
+
existing = compileWasmImpl(tool, options).catch((err) => {
|
|
104
|
+
compiled.delete(key);
|
|
105
|
+
throw err;
|
|
106
|
+
});
|
|
107
|
+
compiled.set(key, existing);
|
|
108
|
+
}
|
|
109
|
+
return existing;
|
|
110
|
+
}
|
|
111
|
+
let loadFactoryImpl = importFactory;
|
|
112
|
+
/** Test seam: replace the dynamic import. */
|
|
113
|
+
export function __setFactoryLoader(fn) {
|
|
114
|
+
loadFactoryImpl = fn;
|
|
115
|
+
}
|
|
116
|
+
/** Test seam: replace the wasm fetch-and-compile step. */
|
|
117
|
+
export function __setWasmCompiler(fn) {
|
|
118
|
+
compileWasmImpl = fn;
|
|
119
|
+
}
|
|
120
|
+
/** Test seam: drop cached factories and compiled modules. */
|
|
121
|
+
export function resetFactoryCache() {
|
|
122
|
+
factories.clear();
|
|
123
|
+
compiled.clear();
|
|
124
|
+
loadFactoryImpl = importFactory;
|
|
125
|
+
compileWasmImpl = compileWasm;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Import a tool's JS glue and return its module factory. Cached per tool and resolved glue URL.
|
|
129
|
+
*
|
|
130
|
+
* Calling the returned factory directly compiles the .wasm afresh on every
|
|
131
|
+
* call; `createInstance` is what supplies the cached compiled module.
|
|
132
|
+
*
|
|
133
|
+
* `async` so that a `wasmPath` that is not a valid URL rejects rather than
|
|
134
|
+
* throwing synchronously. The cache lookup still happens before the first
|
|
135
|
+
* `await`, so concurrent first calls share one import.
|
|
136
|
+
*/
|
|
137
|
+
export async function loadFactory(tool, options) {
|
|
138
|
+
const key = cacheKey(tool, options);
|
|
139
|
+
let existing = factories.get(key);
|
|
140
|
+
if (!existing) {
|
|
141
|
+
existing = loadFactoryImpl(tool, options).catch((err) => {
|
|
142
|
+
factories.delete(key);
|
|
143
|
+
throw err;
|
|
144
|
+
});
|
|
145
|
+
factories.set(key, existing);
|
|
146
|
+
}
|
|
147
|
+
return existing;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Build a fresh module instance.
|
|
151
|
+
*
|
|
152
|
+
* Never cache the result. See the file header.
|
|
153
|
+
*
|
|
154
|
+
* `hooks` is passed straight into the factory's config object, since that
|
|
155
|
+
* is the only point at which `print`/`printErr` can take effect (see
|
|
156
|
+
* `InstanceHooks`).
|
|
157
|
+
*
|
|
158
|
+
* The compiled module reaches the glue through `instantiateWasm`: the glue
|
|
159
|
+
* calls it with its import object in place of its own fetch-and-compile,
|
|
160
|
+
* and waits for `receiveInstance`. That wait has no rejection path — the
|
|
161
|
+
* glue wraps the hook in a promise whose `reject` it never calls — so a
|
|
162
|
+
* compile or instantiate failure is raced against the factory here, or
|
|
163
|
+
* the call would hang forever instead of rejecting.
|
|
164
|
+
*/
|
|
165
|
+
export async function createInstance(tool, options, hooks) {
|
|
166
|
+
options?.onProgress?.("loading");
|
|
167
|
+
const factory = await loadFactory(tool, options);
|
|
168
|
+
options?.onProgress?.("initializing");
|
|
169
|
+
let fail;
|
|
170
|
+
const failed = new Promise((_, reject) => { fail = reject; });
|
|
171
|
+
const instantiateWasm = (imports, receiveInstance) => {
|
|
172
|
+
loadCompiled(tool, options)
|
|
173
|
+
.then(async (module) => receiveInstance(await WebAssembly.instantiate(module, imports), module))
|
|
174
|
+
.catch(fail);
|
|
175
|
+
return {};
|
|
176
|
+
};
|
|
177
|
+
const instance = await Promise.race([factory({ ...hooks, instantiateWasm }), failed]);
|
|
178
|
+
options?.onProgress?.("ready");
|
|
179
|
+
return instance;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level functional API.
|
|
3
|
+
*
|
|
4
|
+
* Enblend is invocation-oriented — N inputs plus flags produce one
|
|
5
|
+
* output — so this layer is a thin argv builder rather than the
|
|
6
|
+
* chainable object the single-image siblings expose.
|
|
7
|
+
*/
|
|
8
|
+
import type { InputImage, BlendOptions, FuseOptions, LoaderOptions, FileInput, OutputDir, WrittenFile } from "./types.js";
|
|
9
|
+
import type { Tool } from "./loader.js";
|
|
10
|
+
export type ImageInput = InputImage | Uint8Array | ArrayBuffer;
|
|
11
|
+
/**
|
|
12
|
+
* Give every input a name, auto-naming bare buffers positionally.
|
|
13
|
+
*
|
|
14
|
+
* Throws on a name collision rather than silently renaming: a caller who
|
|
15
|
+
* supplies an explicit name may reference it again in `options.args`
|
|
16
|
+
* (an `--exclude somefile.tif` flag, say), so renaming around a clash
|
|
17
|
+
* could silently break a working invocation in a new way. Two inputs
|
|
18
|
+
* sharing a name would otherwise stage to the same MEMFS path — the
|
|
19
|
+
* second overwriting the first — and the tool would run to completion
|
|
20
|
+
* on the wrong input set with no error, which is exactly the kind of
|
|
21
|
+
* silent corruption this port cannot afford another instance of.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeInputs(images: ImageInput[]): InputImage[];
|
|
24
|
+
export declare function normalizeInputs(images: FileInput[]): FileInput[];
|
|
25
|
+
export declare function runOperation(tool: Tool, images: ImageInput[] | FileInput[], options?: (BlendOptions | FuseOptions) & {
|
|
26
|
+
outputDir?: OutputDir;
|
|
27
|
+
}, loaderOptions?: LoaderOptions): Promise<Uint8Array | WrittenFile>;
|
|
28
|
+
/**
|
|
29
|
+
* Blend overlapping images into one.
|
|
30
|
+
*
|
|
31
|
+
* Enblend positions images by their TIFF XPosition/YPosition tags, not
|
|
32
|
+
* by any argument. Inputs without correct offsets — two unaligned
|
|
33
|
+
* JPEGs, say — produce a valid file containing a useless image. Use
|
|
34
|
+
* remapped output from a stitcher.
|
|
35
|
+
*/
|
|
36
|
+
export declare function blend(images: ImageInput[], options?: BlendOptions, loaderOptions?: LoaderOptions): Promise<Uint8Array>;
|
|
37
|
+
export declare function blend(images: FileInput[], options: BlendOptions & {
|
|
38
|
+
outputDir: OutputDir;
|
|
39
|
+
}, loaderOptions?: LoaderOptions): Promise<WrittenFile>;
|
|
40
|
+
/** Fuse a bracketed exposure series into one image. */
|
|
41
|
+
export declare function fuse(images: ImageInput[], options?: FuseOptions, loaderOptions?: LoaderOptions): Promise<Uint8Array>;
|
|
42
|
+
export declare function fuse(images: FileInput[], options: FuseOptions & {
|
|
43
|
+
outputDir: OutputDir;
|
|
44
|
+
}, loaderOptions?: LoaderOptions): Promise<WrittenFile>;
|
|
45
|
+
//# sourceMappingURL=operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.d.ts","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG1H,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGxC,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,CAAC;AAI/D;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAAC;AACpE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAAC;AAwDlE,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,UAAU,EAAE,GAAG,SAAS,EAAE,EAClC,OAAO,GAAE,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,SAAS,CAAA;CAAO,EACtE,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,UAAU,GAAG,WAAW,CAAC,CAiCnC;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACxH,wBAAgB,KAAK,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,YAAY,GAAG;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;AAKlJ,uDAAuD;AACvD,wBAAgB,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACtH,wBAAgB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,WAAW,GAAG;IAAE,SAAS,EAAE,SAAS,CAAA;CAAE,EAAE,aAAa,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* High-level functional API.
|
|
3
|
+
*
|
|
4
|
+
* Enblend is invocation-oriented — N inputs plus flags produce one
|
|
5
|
+
* output — so this layer is a thin argv builder rather than the
|
|
6
|
+
* chainable object the single-image siblings expose.
|
|
7
|
+
*/
|
|
8
|
+
import { EnblendError } from "./types.js";
|
|
9
|
+
import { enblend, enfuse } from "./cli.js";
|
|
10
|
+
import { isFileInput } from "./staging.js";
|
|
11
|
+
const DEFAULT_OUTPUT = "output.tif";
|
|
12
|
+
export function normalizeInputs(images) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
return images.map((image, i) => {
|
|
15
|
+
const input = image instanceof Uint8Array || image instanceof ArrayBuffer
|
|
16
|
+
? { name: `in${i}.tif`, data: image }
|
|
17
|
+
: image;
|
|
18
|
+
if (seen.has(input.name)) {
|
|
19
|
+
throw new Error(`normalizeInputs: duplicate input name "${input.name}"`);
|
|
20
|
+
}
|
|
21
|
+
seen.add(input.name);
|
|
22
|
+
return input;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// Short options that take an argument in enblend or enfuse ("v" and "w" take
|
|
26
|
+
// an optional one). getopt treats the rest of a cluster after any of these as
|
|
27
|
+
// that argument, so scanning a cluster for "o" stops at the first of them.
|
|
28
|
+
const SHORT_WITH_ARGUMENT = new Set(["b", "d", "f", "l", "m", "o", "v", "w"]);
|
|
29
|
+
/** Whether getopt_long would read `arg` as the output option, as enblend and enfuse define it. */
|
|
30
|
+
function isOutputOption(arg) {
|
|
31
|
+
if (arg.startsWith("--")) {
|
|
32
|
+
// Any unambiguous prefix of a long option is accepted, so "--out" is
|
|
33
|
+
// "--output". "--o" is ambiguous in enblend (it has --optimize too) but
|
|
34
|
+
// means --output in enfuse; rejecting it costs nothing either way.
|
|
35
|
+
const name = arg.slice(2).split("=", 1)[0];
|
|
36
|
+
return name.startsWith("o") && "output".startsWith(name);
|
|
37
|
+
}
|
|
38
|
+
if (!arg.startsWith("-"))
|
|
39
|
+
return false;
|
|
40
|
+
for (const c of arg.slice(1)) {
|
|
41
|
+
if (c === "o")
|
|
42
|
+
return true;
|
|
43
|
+
if (SHORT_WITH_ARGUMENT.has(c))
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reject output settings that could only end in a confusing "produced no
|
|
50
|
+
* output file" after a full run. The tool writes into its per-invocation
|
|
51
|
+
* work directory, and the output is collected from there by name, so it
|
|
52
|
+
* must be a plain file name that no input shares, and set only once.
|
|
53
|
+
*/
|
|
54
|
+
function validateOutput(output, args, inputs) {
|
|
55
|
+
if (output === "" || output === "." || output === ".." || /[/\\]/.test(output)) {
|
|
56
|
+
throw new Error(`options.output must be a plain file name, got "${output}"`);
|
|
57
|
+
}
|
|
58
|
+
const setsOutput = args.find(isOutputOption);
|
|
59
|
+
if (setsOutput !== undefined) {
|
|
60
|
+
throw new Error(`set the output file with options.output, not "${setsOutput}" in args`);
|
|
61
|
+
}
|
|
62
|
+
if (inputs.some((i) => i.name === output)) {
|
|
63
|
+
throw new Error(`input name "${output}" collides with the output file name`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export async function runOperation(tool, images, options = {}, loaderOptions) {
|
|
67
|
+
if (images.length === 0) {
|
|
68
|
+
throw new Error(`${tool} requires at least one input image`);
|
|
69
|
+
}
|
|
70
|
+
const files = images.every(isFileInput);
|
|
71
|
+
const inputs = normalizeInputs(images);
|
|
72
|
+
const output = options.output ?? DEFAULT_OUTPUT;
|
|
73
|
+
validateOutput(output, options.args ?? [], inputs);
|
|
74
|
+
const argv = ["-o", output, ...(options.args ?? []), ...inputs.map((i) => i.name)];
|
|
75
|
+
const invoke = tool === "enblend" ? enblend : enfuse;
|
|
76
|
+
const result = files
|
|
77
|
+
? await invoke(argv, inputs, { ...loaderOptions, outputDir: options.outputDir })
|
|
78
|
+
: await invoke(argv, inputs, loaderOptions);
|
|
79
|
+
if (result.exitCode !== 0) {
|
|
80
|
+
throw new EnblendError(`${tool} exited with code ${result.exitCode}${result.stderr ? `: ${result.stderr}` : ""}`, result.exitCode, result.stderr);
|
|
81
|
+
}
|
|
82
|
+
const produced = "written" in result ? result.written.get(output) : result.outputFiles.get(output);
|
|
83
|
+
if (!produced) {
|
|
84
|
+
throw new EnblendError(`${tool} exited cleanly but produced no output file "${output}"`, 0, result.stderr);
|
|
85
|
+
}
|
|
86
|
+
return produced;
|
|
87
|
+
}
|
|
88
|
+
export function blend(images, options, loaderOptions) {
|
|
89
|
+
return runOperation("enblend", images, options, loaderOptions);
|
|
90
|
+
}
|
|
91
|
+
export function fuse(images, options, loaderOptions) {
|
|
92
|
+
return runOperation("enfuse", images, options, loaderOptions);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.js","sourceRoot":"","sources":["../src/operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a run's files reach the tool and come back.
|
|
3
|
+
*
|
|
4
|
+
* runTool() has one flow: stage, callMain, collect, release. This interface
|
|
5
|
+
* is what varies. stageBuffers is the MEMFS path every caller used before file
|
|
6
|
+
* mode existed, and its behaviour is unchanged. stageFiles (file mode) mounts
|
|
7
|
+
* files through wopfs.
|
|
8
|
+
*/
|
|
9
|
+
import type { FileInput, InputImage, LoaderOptions, OutputDir, WasmModule, WrittenFile } from "./types.js";
|
|
10
|
+
export interface Staging {
|
|
11
|
+
/** The directory the tool runs in (its cwd). */
|
|
12
|
+
readonly workDir: string;
|
|
13
|
+
readonly inputNames: ReadonlySet<string>;
|
|
14
|
+
/** Everything the run created. Buffer mode: bytes. File mode: committed files. */
|
|
15
|
+
collect(): Promise<Map<string, Uint8Array | WrittenFile>>;
|
|
16
|
+
/** Total input pixels, for OutOfMemoryError. Callable after release(). */
|
|
17
|
+
pixelCount(): Promise<number | undefined>;
|
|
18
|
+
/** Idempotent. runTool calls it in a finally on every path. */
|
|
19
|
+
release(): Promise<void>;
|
|
20
|
+
}
|
|
21
|
+
export declare function stageBuffers(module: WasmModule, inputs: InputImage[]): Staging;
|
|
22
|
+
/** True for `{ name, file }`, the file-mode input shape. */
|
|
23
|
+
export declare function isFileInput(x: unknown): x is FileInput;
|
|
24
|
+
/**
|
|
25
|
+
* How many files a run can create, from its argv: the -o output, plus
|
|
26
|
+
* --visualize's image, plus a soft and a hard mask per input for
|
|
27
|
+
* --save-mask(s). enblend and enfuse create no temporary files (spec,
|
|
28
|
+
* finding 2). --load-mask(s) reads, so it adds nothing here.
|
|
29
|
+
*/
|
|
30
|
+
export declare function scratchFor(argv: readonly string[], inputCount: number): number;
|
|
31
|
+
/**
|
|
32
|
+
* Mount the run's files through wopfs. Everything is opened here, before
|
|
33
|
+
* callMain, because the tool cannot await. The pool is strict: spilling
|
|
34
|
+
* would put new files back in memory and defeat the point (spec, Decisions).
|
|
35
|
+
*/
|
|
36
|
+
export declare function stageFiles(module: WasmModule, inputs: FileInput[], outputDir: OutputDir, argv: readonly string[], options?: LoaderOptions): Promise<Staging>;
|
|
37
|
+
//# sourceMappingURL=staging.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../src/staging.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK3G,MAAM,WAAW,OAAO;IACtB,gDAAgD;IAChD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,kFAAkF;IAClF,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC;IAC1D,0EAA0E;IAC1E,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC1C,+DAA+D;IAC/D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,OAAO,CA6B9E;AAED,4DAA4D;AAC5D,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,SAAS,CAEtD;AASD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAK9E;AA6CD;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,SAAS,EAAE,EACnB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,OAAO,CAAC,CAoClB"}
|
package/dist/staging.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a run's files reach the tool and come back.
|
|
3
|
+
*
|
|
4
|
+
* runTool() has one flow: stage, callMain, collect, release. This interface
|
|
5
|
+
* is what varies. stageBuffers is the MEMFS path every caller used before file
|
|
6
|
+
* mode existed, and its behaviour is unchanged. stageFiles (file mode) mounts
|
|
7
|
+
* files through wopfs.
|
|
8
|
+
*/
|
|
9
|
+
import { createWorkDir, stageInputs, collectOutputs, cleanWorkDir, nextWorkDirName, toBytes } from "./filesystem.js";
|
|
10
|
+
import { tiffPixelCount, tiffPixelCountAt } from "./tiff-header.js";
|
|
11
|
+
import { loadWopfs } from "./wopfs.js";
|
|
12
|
+
export function stageBuffers(module, inputs) {
|
|
13
|
+
const workDir = createWorkDir(module);
|
|
14
|
+
const inputNames = stageInputs(module, workDir, inputs);
|
|
15
|
+
let released = false;
|
|
16
|
+
return {
|
|
17
|
+
workDir,
|
|
18
|
+
inputNames,
|
|
19
|
+
async collect() {
|
|
20
|
+
return collectOutputs(module, workDir, inputNames);
|
|
21
|
+
},
|
|
22
|
+
async pixelCount() {
|
|
23
|
+
// With no inputs no header states a count, so none is known; 0 would be a claim.
|
|
24
|
+
if (inputs.length === 0)
|
|
25
|
+
return undefined;
|
|
26
|
+
let total = 0;
|
|
27
|
+
for (const input of inputs) {
|
|
28
|
+
const n = tiffPixelCount(toBytes(input.data));
|
|
29
|
+
if (n === undefined)
|
|
30
|
+
return undefined;
|
|
31
|
+
total += n;
|
|
32
|
+
}
|
|
33
|
+
return total;
|
|
34
|
+
},
|
|
35
|
+
async release() {
|
|
36
|
+
if (released)
|
|
37
|
+
return;
|
|
38
|
+
released = true;
|
|
39
|
+
// The instance is discarded after this call (never reused, per
|
|
40
|
+
// createInstance's contract), so there is no previous cwd to restore.
|
|
41
|
+
cleanWorkDir(module, workDir);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** True for `{ name, file }`, the file-mode input shape. */
|
|
46
|
+
export function isFileInput(x) {
|
|
47
|
+
return typeof x === "object" && x !== null && "file" in x && "name" in x && !("data" in x);
|
|
48
|
+
}
|
|
49
|
+
// getopt_long accepts any unambiguous prefix of a long option. Over-counting
|
|
50
|
+
// costs an empty pre-opened file; under-counting fails the run, so a prefix
|
|
51
|
+
// match errs on the generous side.
|
|
52
|
+
const longName = (arg) => (arg.startsWith("--") ? arg.slice(2).split("=", 1)[0] : "");
|
|
53
|
+
const names = (argv, option) => argv.some((arg) => { const n = longName(arg); return n.length >= 2 && option.startsWith(n); });
|
|
54
|
+
/**
|
|
55
|
+
* How many files a run can create, from its argv: the -o output, plus
|
|
56
|
+
* --visualize's image, plus a soft and a hard mask per input for
|
|
57
|
+
* --save-mask(s). enblend and enfuse create no temporary files (spec,
|
|
58
|
+
* finding 2). --load-mask(s) reads, so it adds nothing here.
|
|
59
|
+
*/
|
|
60
|
+
export function scratchFor(argv, inputCount) {
|
|
61
|
+
let n = 1;
|
|
62
|
+
if (names(argv, "visualize"))
|
|
63
|
+
n += 1;
|
|
64
|
+
if (names(argv, "save-masks"))
|
|
65
|
+
n += 2 * inputCount;
|
|
66
|
+
return n;
|
|
67
|
+
}
|
|
68
|
+
/** A reader for the pixel count: a byte range of a file, without reading the rest. */
|
|
69
|
+
function readerFor(file) {
|
|
70
|
+
if (typeof file === "string") {
|
|
71
|
+
return async (offset, length) => {
|
|
72
|
+
// A variable specifier: the browser build never resolves node:fs.
|
|
73
|
+
const specifier = "node:fs/promises";
|
|
74
|
+
const { open } = await import(/* @vite-ignore */ specifier);
|
|
75
|
+
const handle = await open(file, "r");
|
|
76
|
+
try {
|
|
77
|
+
const buffer = new Uint8Array(length);
|
|
78
|
+
const { bytesRead } = await handle.read(buffer, 0, length, offset);
|
|
79
|
+
return buffer.subarray(0, bytesRead);
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
await handle.close();
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return async (offset, length) => new Uint8Array(await (await file.getFile()).slice(offset, offset + length).arrayBuffer());
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Turn what wopfs committed into a WrittenFile. On the main thread wopfs
|
|
90
|
+
* falls back to MEMFS, which returns bytes and ignores outputDir. Write those
|
|
91
|
+
* into outputDir here, so file mode hands back a file in every environment.
|
|
92
|
+
*/
|
|
93
|
+
async function toWrittenFile(c, outputDir) {
|
|
94
|
+
if (c.handle)
|
|
95
|
+
return { name: c.path, file: c.handle, size: c.size };
|
|
96
|
+
if (c.hostPath)
|
|
97
|
+
return { name: c.path, file: c.hostPath, size: c.size };
|
|
98
|
+
if (c.bytes && typeof outputDir !== "string") {
|
|
99
|
+
// Check before creating the file, so a failure leaves no empty file behind.
|
|
100
|
+
if (typeof FileSystemFileHandle === "undefined" || !("createWritable" in FileSystemFileHandle.prototype)) {
|
|
101
|
+
throw new Error("file mode on this thread needs FileSystemFileHandle.createWritable; run it in a dedicated worker instead");
|
|
102
|
+
}
|
|
103
|
+
const handle = await outputDir.getFileHandle(c.path, { create: true });
|
|
104
|
+
const writable = await handle.createWritable();
|
|
105
|
+
await writable.write(c.bytes);
|
|
106
|
+
await writable.close();
|
|
107
|
+
return { name: c.path, file: handle, size: c.bytes.length };
|
|
108
|
+
}
|
|
109
|
+
throw new Error(`wopfs committed "${c.path}" with neither a file nor bytes`);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Mount the run's files through wopfs. Everything is opened here, before
|
|
113
|
+
* callMain, because the tool cannot await. The pool is strict: spilling
|
|
114
|
+
* would put new files back in memory and defeat the point (spec, Decisions).
|
|
115
|
+
*/
|
|
116
|
+
export async function stageFiles(module, inputs, outputDir, argv, options) {
|
|
117
|
+
const wopfs = await loadWopfs(options);
|
|
118
|
+
const workDir = nextWorkDirName();
|
|
119
|
+
const mount = await wopfs.mountFiles(module, workDir, {
|
|
120
|
+
inputs: Object.fromEntries(inputs.map((i) => [i.name, i.file])),
|
|
121
|
+
outputDir,
|
|
122
|
+
scratch: scratchFor(argv, inputs.length),
|
|
123
|
+
onExhausted: "strict",
|
|
124
|
+
});
|
|
125
|
+
let released = false;
|
|
126
|
+
return {
|
|
127
|
+
workDir,
|
|
128
|
+
inputNames: new Set(inputs.map((i) => i.name)),
|
|
129
|
+
async collect() {
|
|
130
|
+
const out = new Map();
|
|
131
|
+
for (const c of await mount.commit())
|
|
132
|
+
out.set(c.path, await toWrittenFile(c, outputDir));
|
|
133
|
+
return out;
|
|
134
|
+
},
|
|
135
|
+
async pixelCount() {
|
|
136
|
+
if (inputs.length === 0)
|
|
137
|
+
return undefined;
|
|
138
|
+
let total = 0;
|
|
139
|
+
for (const input of inputs) {
|
|
140
|
+
const n = await tiffPixelCountAt(readerFor(input.file));
|
|
141
|
+
if (n === undefined)
|
|
142
|
+
return undefined;
|
|
143
|
+
total += n;
|
|
144
|
+
}
|
|
145
|
+
return total;
|
|
146
|
+
},
|
|
147
|
+
async release() {
|
|
148
|
+
if (released)
|
|
149
|
+
return;
|
|
150
|
+
released = true;
|
|
151
|
+
// runTool ran the tool inside the mount; wopfs >= 0.2.0 moves the cwd
|
|
152
|
+
// out before unmounting (https://gitlab.com/wasmedia/wopfs/-/work_items/2).
|
|
153
|
+
await mount.release();
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=staging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staging.js","sourceRoot":"","sources":["../src/staging.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pixel count of a TIFF, read from its header and image directories only.
|
|
3
|
+
*
|
|
4
|
+
* One walker serves both callers: buffer mode, which has the whole file's
|
|
5
|
+
* bytes, and file mode, where the file sits in OPFS or on disk and only the
|
|
6
|
+
* few hundred bytes the walk needs should be read. The walker is a generator
|
|
7
|
+
* that yields the byte ranges it needs; tiffPixelCount drives it from a byte
|
|
8
|
+
* array, and tiffPixelCountAt from an async reader.
|
|
9
|
+
*/
|
|
10
|
+
/** A random-access reader. A short or empty result means past the end. */
|
|
11
|
+
export type ReadAt = (offset: number, length: number) => Promise<Uint8Array>;
|
|
12
|
+
/** The pixel count of a TIFF held in memory. */
|
|
13
|
+
export declare function tiffPixelCount(bytes: Uint8Array): number | undefined;
|
|
14
|
+
/** The pixel count of a TIFF read through `readAt`, fetching only what the walk needs. */
|
|
15
|
+
export declare function tiffPixelCountAt(readAt: ReadAt): Promise<number | undefined>;
|
|
16
|
+
//# sourceMappingURL=tiff-header.d.ts.map
|