whitebox-wasm 0.3.0 → 0.4.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
@@ -9,6 +9,7 @@ in the browser, Node, Deno, or any Wasm host:
9
9
  - **Vector** - read GeoJSON, TopoJSON, GML, GPX, KML, FlatGeobuf, GeoPackage, KMZ -> GeoJSON, with reprojection
10
10
  - **LiDAR** - read LAS / LAZ / PLY point clouds (xyz, classification, intensity)
11
11
  - **Analysis** - convex hull, Moran's I spatial autocorrelation
12
+ - **Tools** - the full WhiteboxTools suite (733 tools) via `whitebox-wasm/tools`
12
13
 
13
14
  This wraps `wbgeotiff`, the shared GeoTIFF engine from the original
14
15
  [**whitebox_next_gen**](https://github.com/jblindsay/whitebox_next_gen) project
@@ -172,6 +173,40 @@ const xyz = lidar_read_xyz(las, "laz"); // Float64Array [x0,y0,z0, x1,y
172
173
  - `convex_hull(points_xy)` -> hull ring `Float64Array` (input `[x0,y0,x1,y1,...]`)
173
174
  - `morans_i(points_xy, values, distance_threshold)` -> JSON global spatial autocorrelation `{morans_i, expected, variance, z_score, p_value, n}`
174
175
 
176
+ ## Tools (the full WhiteboxTools suite)
177
+
178
+ The `whitebox-wasm/tools` subpath runs the complete **WhiteboxTools** algorithm
179
+ suite (**733 tools** - slope, filters, hydrology, geomorphometry, vector ops,
180
+ ...). The tools are path-based, so they run through an in-memory WASI filesystem
181
+ (bundled `whitebox-cli.wasm`); raster outputs are Cloud Optimized GeoTIFFs.
182
+
183
+ ```js
184
+ import { runTool, listTools } from "whitebox-wasm/tools";
185
+
186
+ console.log((await listTools()).length); // 733
187
+
188
+ // raster: slope -> a COG
189
+ const { files } = await runTool("slope", {
190
+ args: ["--input=/work/dem.tif", "--output=/work/slope.tif", "--units=degrees"],
191
+ input: { "dem.tif": demBytes }, // Uint8Array, placed under /work
192
+ });
193
+ const slopeCog = files["slope.tif"]; // Uint8Array (tiled, Deflate, overviews)
194
+
195
+ // vector: convex hull -> GeoJSON
196
+ const hull = await runTool("minimum_convex_hull", {
197
+ args: ["--input=/work/in.geojson", "--output=/work/hull.geojson"],
198
+ input: { "in.geojson": geojsonBytes },
199
+ });
200
+ ```
201
+
202
+ - `listTools()` -> `string[]` of tool ids
203
+ - `runTool(id, { args, input })` -> `{ exitCode, stdout, files }` (`files` = outputs the tool wrote)
204
+ - `initTools(source?)` -> compile the runner; in Node pass the wasm bytes (browsers/bundlers omit it)
205
+
206
+ Needs the `@bjorn3/browser_wasi_shim` peer (declared as a dependency). The
207
+ `whitebox-cli.wasm` (~5 MB gzipped) is only fetched the first time you call a
208
+ tool, so the rest of the library stays lightweight.
209
+
175
210
  ## Limits
176
211
 
177
212
  WebAssembly is 32-bit, so linear memory is capped at ~4 GiB. `geotiff_info` is
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "whitebox-wasm",
3
3
  "type": "module",
4
4
  "description": "Pure-Rust geospatial toolkit (raster, vector, LiDAR, projections) compiled to WebAssembly",
5
- "version": "0.3.0",
5
+ "version": "0.4.0",
6
6
  "license": "MIT OR Apache-2.0",
7
7
  "repository": {
8
8
  "type": "git",
@@ -11,7 +11,10 @@
11
11
  "files": [
12
12
  "whitebox_wasm_bg.wasm",
13
13
  "whitebox_wasm.js",
14
- "whitebox_wasm.d.ts"
14
+ "whitebox_wasm.d.ts",
15
+ "whitebox-cli.wasm",
16
+ "tools.mjs",
17
+ "tools.d.ts"
15
18
  ],
16
19
  "main": "whitebox_wasm.js",
17
20
  "homepage": "https://github.com/opengeos/whitebox-wasm",
@@ -25,5 +28,18 @@
25
28
  "gis",
26
29
  "geotiff",
27
30
  "lidar"
28
- ]
31
+ ],
32
+ "dependencies": {
33
+ "@bjorn3/browser_wasi_shim": "^0.4.2"
34
+ },
35
+ "exports": {
36
+ ".": {
37
+ "types": "./whitebox_wasm.d.ts",
38
+ "default": "./whitebox_wasm.js"
39
+ },
40
+ "./tools": {
41
+ "types": "./tools.d.ts",
42
+ "default": "./tools.mjs"
43
+ }
44
+ }
29
45
  }
package/tools.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /** Result of running a tool. */
2
+ export interface ToolResult {
3
+ /** Process exit code (0 = success). */
4
+ exitCode: number;
5
+ /** Captured stdout/stderr lines. */
6
+ stdout: string[];
7
+ /** New files the tool wrote, keyed by filename (e.g. the --output path's basename). */
8
+ files: Record<string, Uint8Array>;
9
+ }
10
+
11
+ export interface RunToolOptions {
12
+ /** CLI args, e.g. ["--input=/work/dem.tif", "--output=/work/out.tif", "--units=degrees"]. */
13
+ args?: string[];
14
+ /** Input files placed under /work, keyed by filename. */
15
+ input?: Record<string, Uint8Array>;
16
+ }
17
+
18
+ /** Compile the WASI tool runner once. Omit `source` in browsers/bundlers; pass
19
+ * the wasm bytes or a URL/Response in Node. */
20
+ export function initTools(source?: URL | Response | BufferSource | string): Promise<WebAssembly.Module>;
21
+
22
+ /** List every available tool id. */
23
+ export function listTools(): Promise<string[]>;
24
+
25
+ /** Run one tool over an in-memory filesystem. */
26
+ export function runTool(tool: string, opts?: RunToolOptions): Promise<ToolResult>;
package/tools.mjs ADDED
@@ -0,0 +1,83 @@
1
+ // whitebox-wasm/tools - run the WhiteboxTools (wbtools_oss) algorithm suite from
2
+ // JavaScript. The tools are the WASI binary `whitebox-cli.wasm` (733 path-based
3
+ // tools); this module executes them through a WASI shim with an in-memory
4
+ // filesystem, so they run in browsers, Node, Deno, and bundlers without a real
5
+ // disk. Raster outputs are Cloud Optimized GeoTIFFs.
6
+ //
7
+ // import { runTool, listTools } from "whitebox-wasm/tools";
8
+ // const { files } = await runTool("slope", {
9
+ // args: ["--input=/work/dem.tif", "--output=/work/slope.tif", "--units=degrees"],
10
+ // input: { "dem.tif": demBytes }, // Uint8Array, placed under /work
11
+ // });
12
+ // const slopeCog = files["slope.tif"]; // Uint8Array
13
+ import { WASI, File, OpenFile, ConsoleStdout, PreopenDirectory } from "@bjorn3/browser_wasi_shim";
14
+
15
+ let _module = null;
16
+
17
+ /**
18
+ * Compile the WASI tool runner once. In browsers/bundlers it loads the bundled
19
+ * `whitebox-cli.wasm` relative to this module. In Node (no fetch of file URLs),
20
+ * pass the wasm bytes or a URL/Response explicitly.
21
+ * @param {URL|Response|BufferSource|string} [source]
22
+ * @returns {Promise<WebAssembly.Module>}
23
+ */
24
+ export async function initTools(source) {
25
+ if (_module) return _module;
26
+ if (!source) source = new URL("./whitebox-cli.wasm", import.meta.url);
27
+ if (source instanceof Uint8Array || source instanceof ArrayBuffer) {
28
+ _module = await WebAssembly.compile(source);
29
+ } else if (source instanceof Response) {
30
+ _module = await WebAssembly.compileStreaming(source);
31
+ } else {
32
+ _module = await WebAssembly.compileStreaming(fetch(source));
33
+ }
34
+ return _module;
35
+ }
36
+
37
+ async function exec(argv, inputFiles) {
38
+ const mod = await initTools();
39
+ const inNames = new Set(Object.keys(inputFiles));
40
+ const contents = new Map(
41
+ Object.entries(inputFiles).map(([k, v]) => [k, new File(new Uint8Array(v))]));
42
+ const work = new PreopenDirectory("/work", contents);
43
+ const stdout = [];
44
+ const fds = [
45
+ new OpenFile(new File(new Uint8Array())),
46
+ ConsoleStdout.lineBuffered((s) => stdout.push(s)),
47
+ ConsoleStdout.lineBuffered((s) => stdout.push(s)),
48
+ work,
49
+ ];
50
+ const wasi = new WASI(["whitebox", ...argv], [], fds, { debug: false });
51
+ const inst = await WebAssembly.instantiate(mod, { wasi_snapshot_preview1: wasi.wasiImport });
52
+ let exitCode = 0;
53
+ try { exitCode = wasi.start(inst); }
54
+ catch (e) { if (e && e.constructor && e.constructor.name === "WASIProcExit") exitCode = e.code; else throw e; }
55
+ const files = {};
56
+ for (const [name, entry] of work.dir.contents) {
57
+ if (entry.data && !inNames.has(name)) files[name] = entry.data;
58
+ }
59
+ return { exitCode, stdout, files };
60
+ }
61
+
62
+ /**
63
+ * List every available tool id (733 of them).
64
+ * @returns {Promise<string[]>}
65
+ */
66
+ export async function listTools() {
67
+ const { stdout } = await exec(["list"], {});
68
+ return stdout.map((s) => s.trim()).filter((s) => s && !/tools:$/.test(s));
69
+ }
70
+
71
+ /**
72
+ * Run one tool over an in-memory filesystem.
73
+ * @param {string} tool tool id, e.g. "slope" (see {@link listTools})
74
+ * @param {object} [opts]
75
+ * @param {string[]} [opts.args] CLI args, e.g. ["--input=/work/dem.tif","--output=/work/out.tif","--units=degrees"]
76
+ * @param {Object<string, Uint8Array>} [opts.input] files placed under /work (key = filename)
77
+ * @returns {Promise<{exitCode:number, stdout:string[], files:Object<string,Uint8Array>}>}
78
+ * `files` contains any new files the tool wrote (e.g. the --output path).
79
+ */
80
+ export async function runTool(tool, opts = {}) {
81
+ const { args = [], input = {} } = opts;
82
+ return exec([tool, ...args], input);
83
+ }
Binary file
@@ -282,10 +282,10 @@ export function geotiff_stats(data: Uint8Array): string;
282
282
  export function lidar_formats(): string;
283
283
 
284
284
  /**
285
- * Read a LiDAR file's metadata as JSON without loading all points where
286
- * possible (LAS/LAZ report count and bounds from the header):
285
+ * Read a LiDAR file's metadata as JSON. For LAS/LAZ this is header-only (count,
286
+ * bounds, CRS, point format, COPC flag) and never decodes points:
287
287
  * `{"ok":true,"format","points","epsg"|null,"point_format"|null,
288
- * "bounds":[min_x,min_y,min_z,max_x,max_y,max_z]|null}`.
288
+ * "bounds":[min_x,min_y,min_z,max_x,max_y,max_z]|null,"copc":bool}`.
289
289
  */
290
290
  export function lidar_info(data: Uint8Array, format: string): string;
291
291
 
package/whitebox_wasm.js CHANGED
@@ -1120,10 +1120,10 @@ export function lidar_formats() {
1120
1120
  }
1121
1121
 
1122
1122
  /**
1123
- * Read a LiDAR file's metadata as JSON without loading all points where
1124
- * possible (LAS/LAZ report count and bounds from the header):
1123
+ * Read a LiDAR file's metadata as JSON. For LAS/LAZ this is header-only (count,
1124
+ * bounds, CRS, point format, COPC flag) and never decodes points:
1125
1125
  * `{"ok":true,"format","points","epsg"|null,"point_format"|null,
1126
- * "bounds":[min_x,min_y,min_z,max_x,max_y,max_z]|null}`.
1126
+ * "bounds":[min_x,min_y,min_z,max_x,max_y,max_z]|null,"copc":bool}`.
1127
1127
  * @param {Uint8Array} data
1128
1128
  * @param {string} format
1129
1129
  * @returns {string}
Binary file