cog-tiler-wasm 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/cog-tiler.d.ts +73 -0
- package/cog-tiler.js +358 -0
- package/cog_tiler_wasm.d.ts +101 -0
- package/cog_tiler_wasm.js +470 -0
- package/cog_tiler_wasm_bg.wasm +0 -0
- package/package.json +56 -0
package/cog-tiler.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cog-tiler-wasm - reusable client-side COG tiling for MapLibre/Leaflet.
|
|
3
|
+
* High-level wrapper over the wasm `CogTiler` + whitebox-wasm `CogStream`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface RenderOptions {
|
|
7
|
+
/** Low end of the rescale range (continuous bands). Default 0. */
|
|
8
|
+
min?: number;
|
|
9
|
+
/** High end of the rescale range (continuous bands). Default 1. */
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Colormap name: "viridis" | "magma" | "terrain" | "gray". Default "viridis". */
|
|
12
|
+
colormap?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A level descriptor from `CogStream.levels_json()`. */
|
|
16
|
+
export interface LevelInfo {
|
|
17
|
+
level: number;
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
tile_width: number;
|
|
21
|
+
tile_height: number;
|
|
22
|
+
tiles_x: number;
|
|
23
|
+
tiles_y: number;
|
|
24
|
+
bands: number;
|
|
25
|
+
bits_per_sample: number;
|
|
26
|
+
sample_format: string;
|
|
27
|
+
compression: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** An opened COG; renders XYZ tiles in either the 3857 or warp path. */
|
|
31
|
+
export declare class CogSource {
|
|
32
|
+
/** "3857" (fast affine path) or "warp" (reprojected on the fly). */
|
|
33
|
+
readonly mode: "3857" | "warp";
|
|
34
|
+
/** Human-readable CRS label, e.g. "EPSG:3857" or "warped from +proj=aea". */
|
|
35
|
+
readonly crsLabel: string;
|
|
36
|
+
/** Overview levels, finest first. */
|
|
37
|
+
readonly levels: LevelInfo[];
|
|
38
|
+
/** WGS84 bounds [minLon, minLat, maxLon, maxLat] for fitBounds. */
|
|
39
|
+
readonly boundsLonLat: number[];
|
|
40
|
+
/** True when the band is paletted (categorical) and rendered via its table. */
|
|
41
|
+
readonly hasPalette: boolean;
|
|
42
|
+
/** Render an XYZ tile to a 256x256 RGBA buffer, or null if empty. */
|
|
43
|
+
renderTileRGBA(z: number, x: number, y: number, opts?: RenderOptions): Promise<Uint8ClampedArray | null>;
|
|
44
|
+
/** Render an XYZ tile to PNG bytes (empty Uint8Array for a blank tile). */
|
|
45
|
+
renderTilePNG(z: number, x: number, y: number, opts?: RenderOptions): Promise<Uint8Array>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Initialize the wasm modules (idempotent). Resolve before `openCog`. */
|
|
49
|
+
export declare function init(): Promise<unknown>;
|
|
50
|
+
|
|
51
|
+
/** Open a COG and return a {@link CogSource} ready to render XYZ tiles. */
|
|
52
|
+
export declare function openCog(url: string): Promise<CogSource>;
|
|
53
|
+
|
|
54
|
+
/** Encode a 256x256 RGBA buffer to PNG bytes (browser; uses OffscreenCanvas). */
|
|
55
|
+
export declare function rgbaToPng(rgba: Uint8Array | Uint8ClampedArray): Promise<Uint8Array>;
|
|
56
|
+
|
|
57
|
+
/** Minimal shape of the maplibre-gl module needed to register a protocol. */
|
|
58
|
+
export interface MapLibreLike {
|
|
59
|
+
addProtocol(
|
|
60
|
+
name: string,
|
|
61
|
+
handler: (params: { url: string }) => Promise<{ data: Uint8Array }>,
|
|
62
|
+
): void;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Register a MapLibre custom protocol (e.g. `cog://{z}/{x}/{y}`). `resolve()` is
|
|
67
|
+
* called per tile and returns the active source + render settings.
|
|
68
|
+
*/
|
|
69
|
+
export declare function registerCogProtocol(
|
|
70
|
+
maplibregl: MapLibreLike,
|
|
71
|
+
name: string,
|
|
72
|
+
resolve: () => { source: CogSource | null; render?: RenderOptions } | null,
|
|
73
|
+
): void;
|
package/cog-tiler.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cog-tiler-wasm - reusable, client-side COG tiling for MapLibre/Leaflet.
|
|
3
|
+
*
|
|
4
|
+
* Wraps whitebox-wasm (`CogStream`: pure-Rust COG decode + HTTP range reads) and
|
|
5
|
+
* this repo's `CogTiler` (Web Mercator math + rescale/colormap render) into a
|
|
6
|
+
* tiler that:
|
|
7
|
+
* - serves EPSG:3857 COGs directly (fast affine path), and
|
|
8
|
+
* - warps any other projected / EPSG:4326 COG to Web Mercator on the fly,
|
|
9
|
+
* rendering paletted (categorical) bands through their color table.
|
|
10
|
+
*
|
|
11
|
+
* Dependencies are bare module specifiers - provide them through your bundler
|
|
12
|
+
* (as peer dependencies) or an import map:
|
|
13
|
+
* whitebox-wasm, proj4, geotiff, geotiff-geokeys-to-proj4
|
|
14
|
+
* The wasm package (`cog_tiler_wasm.js` + `_bg.wasm`) must sit next to this file.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* import { init, openCog, registerCogProtocol } from "./cog-tiler.js";
|
|
18
|
+
* await init();
|
|
19
|
+
* const src = await openCog(url);
|
|
20
|
+
* registerCogProtocol(maplibregl, "cog", () => ({ source: src, render: { min, max, colormap } }));
|
|
21
|
+
* map.addSource("cog", { type: "raster", tiles: ["cog://{z}/{x}/{y}"], tileSize: 256 });
|
|
22
|
+
*/
|
|
23
|
+
import initWhitebox, { CogStream } from "whitebox-wasm";
|
|
24
|
+
import initTiler, { CogTiler } from "./cog_tiler_wasm.js";
|
|
25
|
+
import proj4 from "proj4";
|
|
26
|
+
import * as GeoTIFF from "geotiff";
|
|
27
|
+
import geokeysToProj4 from "geotiff-geokeys-to-proj4";
|
|
28
|
+
|
|
29
|
+
const OS = 20037508.342789244; // Web Mercator half-extent (m)
|
|
30
|
+
const TILE = 256; // output tile size (px)
|
|
31
|
+
const NG = 16; // warp grid cells per axis
|
|
32
|
+
const MAX_CACHED_TILES = 256; // ~0.5 MB each at 256x256 f64
|
|
33
|
+
|
|
34
|
+
proj4.defs(
|
|
35
|
+
"EPSG:3857",
|
|
36
|
+
"+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs",
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
let _ready = null;
|
|
40
|
+
/** Initialize the wasm modules (idempotent). Resolve this before `openCog`. */
|
|
41
|
+
export function init() {
|
|
42
|
+
if (!_ready) _ready = Promise.all([initWhitebox(), initTiler()]);
|
|
43
|
+
return _ready;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** EPSG:3857 bounds [minx,miny,maxx,maxy] of an XYZ tile. */
|
|
47
|
+
function tileBounds3857(z, x, y) {
|
|
48
|
+
const span = (2 * OS) / 2 ** z;
|
|
49
|
+
return [-OS + x * span, OS - (y + 1) * span, -OS + (x + 1) * span, OS - y * span];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const rangeFetcher = (url) => (a, b) =>
|
|
53
|
+
fetch(url, { headers: { Range: `bytes=${a}-${b}` } })
|
|
54
|
+
.then((r) => r.arrayBuffer())
|
|
55
|
+
.then((b) => new Uint8Array(b));
|
|
56
|
+
|
|
57
|
+
/** Build a 256-entry RGBA palette from a TIFF ColorMap (16-bit R,G,B blocks). */
|
|
58
|
+
function buildPalette(colorMap) {
|
|
59
|
+
if (!colorMap) return null;
|
|
60
|
+
const n = colorMap.length / 3;
|
|
61
|
+
const pal = new Uint8ClampedArray(256 * 4);
|
|
62
|
+
for (let i = 0; i < 256 && i < n; i++) {
|
|
63
|
+
pal[i * 4] = colorMap[i] >> 8;
|
|
64
|
+
pal[i * 4 + 1] = colorMap[n + i] >> 8;
|
|
65
|
+
pal[i * 4 + 2] = colorMap[2 * n + i] >> 8;
|
|
66
|
+
pal[i * 4 + 3] = 255;
|
|
67
|
+
}
|
|
68
|
+
return pal;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function bilin(v00, v10, v01, v11, tx, ty) {
|
|
72
|
+
if (!isFinite(v00) || !isFinite(v10) || !isFinite(v01) || !isFinite(v11)) {
|
|
73
|
+
return isFinite(v00) ? v00 : NaN; // near projection edges
|
|
74
|
+
}
|
|
75
|
+
const top = v00 + (v10 - v00) * tx, bot = v01 + (v11 - v01) * tx;
|
|
76
|
+
return top + (bot - top) * ty;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Open a COG and return a {@link CogSource} ready to render XYZ tiles.
|
|
81
|
+
* Detects EPSG:3857 (fast path) vs. any other CRS (warp path), and reads the
|
|
82
|
+
* source projection + color table from the GeoTIFF header (whitebox-wasm 0.4.0
|
|
83
|
+
* does not expose them).
|
|
84
|
+
*/
|
|
85
|
+
export async function openCog(url) {
|
|
86
|
+
await init();
|
|
87
|
+
const range = rangeFetcher(url);
|
|
88
|
+
// Parse the COG header; grow the prefix and retry for large COGs whose IFDs
|
|
89
|
+
// exceed 64 KB (many overviews / huge tile-offset arrays).
|
|
90
|
+
let stream;
|
|
91
|
+
for (let len = 65536; ; len *= 8) {
|
|
92
|
+
try {
|
|
93
|
+
stream = new CogStream(await range(0, len - 1));
|
|
94
|
+
break;
|
|
95
|
+
} catch (e) {
|
|
96
|
+
if (len >= 1 << 25) throw e; // give up past ~32 MB
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const gt = stream.geo_transform(); // [x0, px_w, rot, y0, rot, px_h]
|
|
100
|
+
const levels = JSON.parse(stream.levels_json());
|
|
101
|
+
if (!Array.isArray(levels) || levels.length === 0) {
|
|
102
|
+
throw new Error("levels_json() returned no levels");
|
|
103
|
+
}
|
|
104
|
+
// CogTiler renders an assembled f64 window -> RGBA (rescale + colormap +
|
|
105
|
+
// nodata). render() ignores the CRS, so we build one in both modes.
|
|
106
|
+
const tiler = new CogTiler(
|
|
107
|
+
Float64Array.from(gt),
|
|
108
|
+
levels[0].width,
|
|
109
|
+
levels[0].height,
|
|
110
|
+
3857,
|
|
111
|
+
stream.nodata,
|
|
112
|
+
JSON.stringify(levels),
|
|
113
|
+
);
|
|
114
|
+
const base = { url, range, stream, tiler, levels, gt, nodata: stream.nodata };
|
|
115
|
+
|
|
116
|
+
if (stream.epsg === 3857) {
|
|
117
|
+
return new CogSource({
|
|
118
|
+
...base,
|
|
119
|
+
mode: "3857",
|
|
120
|
+
crsLabel: "EPSG:3857",
|
|
121
|
+
palette: null,
|
|
122
|
+
boundsLonLat: Array.from(stream.bounds_lonlat()),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Warp path: read the real source CRS + optional palette from the header.
|
|
127
|
+
const tiff = await GeoTIFF.fromUrl(url);
|
|
128
|
+
const img = await tiff.getImage();
|
|
129
|
+
const srcDef = geokeysToProj4.toProj4(img.getGeoKeys()).proj4;
|
|
130
|
+
if (!srcDef) throw new Error("could not derive source CRS from GeoTIFF geokeys");
|
|
131
|
+
const toSource = proj4("EPSG:3857", srcDef); // forward: mercator -> source
|
|
132
|
+
const toLonLat = proj4(srcDef, "EPSG:4326"); // forward: source -> lon/lat
|
|
133
|
+
const palette = buildPalette(img.fileDirectory.ColorMap);
|
|
134
|
+
|
|
135
|
+
// fitBounds bounds: transform the source corners to lon/lat.
|
|
136
|
+
const fw = levels[0].width, fh = levels[0].height;
|
|
137
|
+
const corners = [
|
|
138
|
+
[gt[0], gt[3]],
|
|
139
|
+
[gt[0] + fw * gt[1], gt[3]],
|
|
140
|
+
[gt[0], gt[3] + fh * gt[5]],
|
|
141
|
+
[gt[0] + fw * gt[1], gt[3] + fh * gt[5]],
|
|
142
|
+
].map((c) => toLonLat.forward(c));
|
|
143
|
+
const lons = corners.map((c) => c[0]), lats = corners.map((c) => c[1]);
|
|
144
|
+
|
|
145
|
+
return new CogSource({
|
|
146
|
+
...base,
|
|
147
|
+
mode: "warp",
|
|
148
|
+
toSource,
|
|
149
|
+
palette,
|
|
150
|
+
boundsLonLat: [Math.min(...lons), Math.min(...lats), Math.max(...lons), Math.max(...lats)],
|
|
151
|
+
crsLabel: "warped from " + (srcDef.match(/\+proj=\w+/) || ["custom CRS"])[0],
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** A single opened COG. Renders XYZ tiles via {@link CogSource#renderTileRGBA}. */
|
|
156
|
+
export class CogSource {
|
|
157
|
+
constructor(fields) {
|
|
158
|
+
Object.assign(this, fields);
|
|
159
|
+
// Decoded source tiles keyed by "level/col/row"; caching the decode lets
|
|
160
|
+
// panning/zooming reuse overlapping tiles instead of re-fetching/decoding.
|
|
161
|
+
this.tileCache = new Map();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** True when the band is paletted (categorical) and rendered via its table. */
|
|
165
|
+
get hasPalette() {
|
|
166
|
+
return !!this.palette;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Render an XYZ tile to a 256x256 RGBA `Uint8ClampedArray`, or null if empty. */
|
|
170
|
+
async renderTileRGBA(z, x, y, opts = {}) {
|
|
171
|
+
return this.mode === "warp"
|
|
172
|
+
? this._warp(z, x, y, opts)
|
|
173
|
+
: this._render3857(z, x, y, opts);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Render an XYZ tile to PNG bytes (empty `Uint8Array` for a blank tile). */
|
|
177
|
+
async renderTilePNG(z, x, y, opts = {}) {
|
|
178
|
+
const rgba = await this.renderTileRGBA(z, x, y, opts);
|
|
179
|
+
return rgba ? rgbaToPng(rgba) : new Uint8Array();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// --- internals ------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
_getTile(level, t) {
|
|
185
|
+
const key = level + "/" + t.col + "/" + t.row;
|
|
186
|
+
let p = this.tileCache.get(key);
|
|
187
|
+
if (!p) {
|
|
188
|
+
p = this.range(t.offset, t.offset + t.length - 1)
|
|
189
|
+
.then((bytes) => this.stream.decode_tile_f64(level, bytes))
|
|
190
|
+
.catch((err) => {
|
|
191
|
+
this.tileCache.delete(key); // don't cache failures; allow retry
|
|
192
|
+
throw err;
|
|
193
|
+
});
|
|
194
|
+
this.tileCache.set(key, p);
|
|
195
|
+
if (this.tileCache.size > MAX_CACHED_TILES) {
|
|
196
|
+
this.tileCache.delete(this.tileCache.keys().next().value); // evict oldest
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return p;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Fetch (parallel, cached) + decode the source tiles covering a level pixel
|
|
203
|
+
// window and assemble them into a row-major f64 buffer (NaN = no data).
|
|
204
|
+
async _assembleWindow(level, x, y, w, h) {
|
|
205
|
+
const lv = this.levels[level];
|
|
206
|
+
const tiles = JSON.parse(this.stream.tiles_for_window(level, x, y, w, h));
|
|
207
|
+
const decoded = await Promise.all(tiles.map((t) => this._getTile(level, t)));
|
|
208
|
+
const buf = new Float64Array(w * h).fill(NaN);
|
|
209
|
+
const tw = lv.tile_width, th = lv.tile_height, bands = lv.bands;
|
|
210
|
+
tiles.forEach((t, i) => {
|
|
211
|
+
const px = decoded[i];
|
|
212
|
+
const tx0 = t.col * tw, ty0 = t.row * th;
|
|
213
|
+
for (let ry = 0; ry < th; ry++) {
|
|
214
|
+
const oy = ty0 + ry - y;
|
|
215
|
+
if (oy < 0 || oy >= h) continue;
|
|
216
|
+
for (let rx = 0; rx < tw; rx++) {
|
|
217
|
+
const ox = tx0 + rx - x;
|
|
218
|
+
if (ox < 0 || ox >= w) continue;
|
|
219
|
+
buf[oy * w + ox] = px[(ry * tw + rx) * bands]; // band 0
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return buf;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Choose the overview whose source resolution is the coarsest still finer than
|
|
227
|
+
// `srcRes` (m/px), avoiding upsampling; finest level otherwise.
|
|
228
|
+
_chooseLevel(srcRes) {
|
|
229
|
+
const baseRes = Math.abs(this.gt[1]), fw = this.levels[0].width;
|
|
230
|
+
let best = -1, bestRes = 0, finest = 0, finestRes = Infinity;
|
|
231
|
+
this.levels.forEach((lv, i) => {
|
|
232
|
+
const res = baseRes * (fw / lv.width);
|
|
233
|
+
if (res < finestRes) { finestRes = res; finest = i; }
|
|
234
|
+
if (res <= srcRes && res > bestRes) { best = i; bestRes = res; }
|
|
235
|
+
});
|
|
236
|
+
return best >= 0 ? best : finest;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
_levelPixelSize(level) {
|
|
240
|
+
const lv = this.levels[level], L0 = this.levels[0];
|
|
241
|
+
return [
|
|
242
|
+
Math.abs(this.gt[1]) * (L0.width / lv.width),
|
|
243
|
+
Math.abs(this.gt[5]) * (L0.height / lv.height),
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Fast path: source already EPSG:3857, so a tile maps affinely to a window.
|
|
248
|
+
async _render3857(z, x, y, { min = 0, max = 1, colormap = "viridis" } = {}) {
|
|
249
|
+
const win = this.tiler.pixel_window_for_tile(z, x, y);
|
|
250
|
+
if (win.empty) return null;
|
|
251
|
+
const buf = await this._assembleWindow(win.level, win.x, win.y, win.w, win.h);
|
|
252
|
+
return this.tiler.render(buf, win.w, win.h, min, max, colormap, true);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Warp path: reproject a Web Mercator tile from the source CRS on the fly.
|
|
256
|
+
// A coarse grid of mercator->source samples (proj4) is bilinearly interpolated
|
|
257
|
+
// per output pixel, then nearest-sampled from the source window (correct for
|
|
258
|
+
// categorical data). Paletted sources use the color table; others reuse the
|
|
259
|
+
// Rust colormap (render resamples 256->256, ~identity).
|
|
260
|
+
async _warp(z, x, y, { min = 0, max = 1, colormap = "viridis" } = {}) {
|
|
261
|
+
const tb = tileBounds3857(z, x, y);
|
|
262
|
+
const nx = new Float64Array((NG + 1) * (NG + 1));
|
|
263
|
+
const ny = new Float64Array((NG + 1) * (NG + 1));
|
|
264
|
+
let sminx = Infinity, sminy = Infinity, smaxx = -Infinity, smaxy = -Infinity, any = false;
|
|
265
|
+
for (let gy = 0; gy <= NG; gy++) {
|
|
266
|
+
const my = tb[3] - (gy / NG) * (tb[3] - tb[1]);
|
|
267
|
+
for (let gx = 0; gx <= NG; gx++) {
|
|
268
|
+
const mx = tb[0] + (gx / NG) * (tb[2] - tb[0]);
|
|
269
|
+
let s;
|
|
270
|
+
try { s = this.toSource.forward([mx, my]); } catch { s = [NaN, NaN]; }
|
|
271
|
+
const i = gy * (NG + 1) + gx;
|
|
272
|
+
nx[i] = s[0]; ny[i] = s[1];
|
|
273
|
+
if (isFinite(s[0]) && isFinite(s[1])) {
|
|
274
|
+
any = true;
|
|
275
|
+
if (s[0] < sminx) sminx = s[0];
|
|
276
|
+
if (s[0] > smaxx) smaxx = s[0];
|
|
277
|
+
if (s[1] < sminy) sminy = s[1];
|
|
278
|
+
if (s[1] > smaxy) smaxy = s[1];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (!any) return null;
|
|
283
|
+
|
|
284
|
+
const level = this._chooseLevel((smaxx - sminx) / TILE);
|
|
285
|
+
const lv = this.levels[level];
|
|
286
|
+
const [lpw, lph] = this._levelPixelSize(level);
|
|
287
|
+
const ox = this.gt[0], oy = this.gt[3];
|
|
288
|
+
let c0 = Math.floor((sminx - ox) / lpw), c1 = Math.ceil((smaxx - ox) / lpw);
|
|
289
|
+
let r0 = Math.floor((oy - smaxy) / lph), r1 = Math.ceil((oy - sminy) / lph);
|
|
290
|
+
c0 = Math.max(0, Math.min(c0, lv.width)); c1 = Math.max(0, Math.min(c1, lv.width));
|
|
291
|
+
r0 = Math.max(0, Math.min(r0, lv.height)); r1 = Math.max(0, Math.min(r1, lv.height));
|
|
292
|
+
const ww = c1 - c0, hh = r1 - r0;
|
|
293
|
+
if (ww <= 0 || hh <= 0) return null;
|
|
294
|
+
const buf = await this._assembleWindow(level, c0, r0, ww, hh);
|
|
295
|
+
|
|
296
|
+
const pal = this.palette;
|
|
297
|
+
const out = new Uint8ClampedArray(TILE * TILE * 4);
|
|
298
|
+
const grid = pal ? null : new Float64Array(TILE * TILE).fill(NaN);
|
|
299
|
+
for (let py = 0; py < TILE; py++) {
|
|
300
|
+
const fy = (py / TILE) * NG, gy0 = Math.min(NG - 1, Math.floor(fy)), ty = fy - gy0;
|
|
301
|
+
for (let px = 0; px < TILE; px++) {
|
|
302
|
+
const fx = (px / TILE) * NG, gx0 = Math.min(NG - 1, Math.floor(fx)), tx = fx - gx0;
|
|
303
|
+
const i00 = gy0 * (NG + 1) + gx0;
|
|
304
|
+
const sx = bilin(nx[i00], nx[i00 + 1], nx[i00 + NG + 1], nx[i00 + NG + 2], tx, ty);
|
|
305
|
+
const sy = bilin(ny[i00], ny[i00 + 1], ny[i00 + NG + 1], ny[i00 + NG + 2], tx, ty);
|
|
306
|
+
if (!isFinite(sx) || !isFinite(sy)) continue;
|
|
307
|
+
const col = Math.floor((sx - ox) / lpw) - c0;
|
|
308
|
+
const row = Math.floor((oy - sy) / lph) - r0;
|
|
309
|
+
if (col < 0 || col >= ww || row < 0 || row >= hh) continue;
|
|
310
|
+
const v = buf[row * ww + col];
|
|
311
|
+
if (!isFinite(v)) continue;
|
|
312
|
+
if (pal) {
|
|
313
|
+
const ci = v & 255;
|
|
314
|
+
if (ci === 0 || (this.nodata != null && v === this.nodata)) continue;
|
|
315
|
+
const o = (py * TILE + px) * 4;
|
|
316
|
+
out[o] = pal[ci * 4]; out[o + 1] = pal[ci * 4 + 1];
|
|
317
|
+
out[o + 2] = pal[ci * 4 + 2]; out[o + 3] = 255;
|
|
318
|
+
} else {
|
|
319
|
+
grid[py * TILE + px] = v;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (pal) return out;
|
|
324
|
+
return this.tiler.render(grid, TILE, TILE, min, max, colormap, true);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/** Encode a 256x256 RGBA buffer to PNG bytes (browser; uses OffscreenCanvas). */
|
|
329
|
+
export async function rgbaToPng(rgba) {
|
|
330
|
+
const img = new ImageData(new Uint8ClampedArray(rgba), TILE, TILE);
|
|
331
|
+
const cv = new OffscreenCanvas(TILE, TILE);
|
|
332
|
+
cv.getContext("2d").putImageData(img, 0, 0);
|
|
333
|
+
const blob = await cv.convertToBlob({ type: "image/png" });
|
|
334
|
+
return new Uint8Array(await blob.arrayBuffer());
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Register a MapLibre custom protocol (e.g. `cog://{z}/{x}/{y}`).
|
|
339
|
+
* `resolve()` is called per tile and returns `{ source, render }`, where
|
|
340
|
+
* `source` is a {@link CogSource} and `render` is `{ min, max, colormap }`.
|
|
341
|
+
*/
|
|
342
|
+
export function registerCogProtocol(maplibregl, name, resolve) {
|
|
343
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // literal protocol name
|
|
344
|
+
const re = new RegExp(`${escaped}://(\\d+)/(\\d+)/(\\d+)`);
|
|
345
|
+
maplibregl.addProtocol(name, async (params) => {
|
|
346
|
+
const ctx = resolve();
|
|
347
|
+
if (!ctx || !ctx.source) return { data: new Uint8Array() };
|
|
348
|
+
const m = params.url.match(re);
|
|
349
|
+
if (!m) return { data: new Uint8Array() };
|
|
350
|
+
const [z, x, y] = m.slice(1).map(Number);
|
|
351
|
+
try {
|
|
352
|
+
return { data: await ctx.source.renderTilePNG(z, x, y, ctx.render || {}) };
|
|
353
|
+
} catch (e) {
|
|
354
|
+
console.error(name, "tile", z, x, y, e);
|
|
355
|
+
return { data: new Uint8Array() };
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Tiling engine for a single COG.
|
|
6
|
+
*/
|
|
7
|
+
export class CogTiler {
|
|
8
|
+
free(): void;
|
|
9
|
+
[Symbol.dispose](): void;
|
|
10
|
+
/**
|
|
11
|
+
* Build a tiler from COG metadata (all of which `CogStream` exposes).
|
|
12
|
+
*
|
|
13
|
+
* * `geo_transform` - 6-element GDAL affine transform of the full-res raster.
|
|
14
|
+
* * `width` / `height` - full-resolution pixel dimensions.
|
|
15
|
+
* * `epsg` - source CRS code; must be `3857` in v1.
|
|
16
|
+
* * `nodata` - optional nodata value (pass `NaN`/`undefined` for none).
|
|
17
|
+
* * `levels_json` - JSON array of `{ "width", "height" }`, finest first,
|
|
18
|
+
* e.g. `[{"width":8192,"height":8192},{"width":4096,"height":4096}]`.
|
|
19
|
+
*/
|
|
20
|
+
constructor(geo_transform: Float64Array, width: number, height: number, epsg: number, nodata: number | null | undefined, levels_json: string);
|
|
21
|
+
/**
|
|
22
|
+
* Map an XYZ tile to the overview level and pixel window that cover it.
|
|
23
|
+
*
|
|
24
|
+
* Returns a [`PixelWindow`] (as a JS object). When the tile lies outside
|
|
25
|
+
* the raster, `empty` is `true` and `w == h == 0`. Errors if the source is
|
|
26
|
+
* not EPSG:3857 (v1 limitation).
|
|
27
|
+
*/
|
|
28
|
+
pixel_window_for_tile(z: number, x: number, y: number): any;
|
|
29
|
+
/**
|
|
30
|
+
* Render a decoded source window into a 256x256 RGBA tile.
|
|
31
|
+
*
|
|
32
|
+
* * `pixels` - row-major `f64` window of size `win_w * win_h`, as returned
|
|
33
|
+
* by assembling `CogStream.decode_tile_f64` outputs over the window from
|
|
34
|
+
* [`Self::pixel_window_for_tile`].
|
|
35
|
+
* * `min` / `max` - rescale range mapped to the colormap's `[0, 1]`.
|
|
36
|
+
* * `colormap` - `"viridis"`, `"magma"`, `"terrain"`, or `"gray"`.
|
|
37
|
+
* * `nodata_alpha` - when `true`, nodata pixels become fully transparent.
|
|
38
|
+
*
|
|
39
|
+
* Returns `256 * 256 * 4` bytes (RGBA). An empty window (`win_w == 0`)
|
|
40
|
+
* yields a fully transparent tile.
|
|
41
|
+
*/
|
|
42
|
+
render(pixels: Float64Array, win_w: number, win_h: number, min: number, max: number, colormap: string, nodata_alpha: boolean): Uint8Array;
|
|
43
|
+
/**
|
|
44
|
+
* Source CRS EPSG code.
|
|
45
|
+
*/
|
|
46
|
+
readonly epsg: number;
|
|
47
|
+
/**
|
|
48
|
+
* Number of overview levels (including full resolution).
|
|
49
|
+
*/
|
|
50
|
+
readonly num_levels: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* EPSG:3857 bounds `[min_x, min_y, max_x, max_y]` of an XYZ tile.
|
|
55
|
+
*/
|
|
56
|
+
export function tile_bounds_3857(z: number, x: number, y: number): Float64Array;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Crate version (from `Cargo.toml`).
|
|
60
|
+
*/
|
|
61
|
+
export function version(): string;
|
|
62
|
+
|
|
63
|
+
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
64
|
+
|
|
65
|
+
export interface InitOutput {
|
|
66
|
+
readonly memory: WebAssembly.Memory;
|
|
67
|
+
readonly __wbg_cogtiler_free: (a: number, b: number) => void;
|
|
68
|
+
readonly cogtiler_epsg: (a: number) => number;
|
|
69
|
+
readonly cogtiler_new: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number) => void;
|
|
70
|
+
readonly cogtiler_num_levels: (a: number) => number;
|
|
71
|
+
readonly cogtiler_pixel_window_for_tile: (a: number, b: number, c: number, d: number, e: number) => void;
|
|
72
|
+
readonly cogtiler_render: (a: number, b: number, c: number, d: number, e: number, f: number, g: number, h: number, i: number, j: number, k: number) => void;
|
|
73
|
+
readonly tile_bounds_3857: (a: number, b: number, c: number, d: number) => void;
|
|
74
|
+
readonly version: (a: number) => void;
|
|
75
|
+
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
76
|
+
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
77
|
+
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
78
|
+
readonly __wbindgen_export3: (a: number, b: number, c: number) => void;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Instantiates the given `module`, which can either be bytes or
|
|
85
|
+
* a precompiled `WebAssembly.Module`.
|
|
86
|
+
*
|
|
87
|
+
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
88
|
+
*
|
|
89
|
+
* @returns {InitOutput}
|
|
90
|
+
*/
|
|
91
|
+
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
95
|
+
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
96
|
+
*
|
|
97
|
+
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
98
|
+
*
|
|
99
|
+
* @returns {Promise<InitOutput>}
|
|
100
|
+
*/
|
|
101
|
+
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
/* @ts-self-types="./cog_tiler_wasm.d.ts" */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tiling engine for a single COG.
|
|
5
|
+
*/
|
|
6
|
+
export class CogTiler {
|
|
7
|
+
__destroy_into_raw() {
|
|
8
|
+
const ptr = this.__wbg_ptr;
|
|
9
|
+
this.__wbg_ptr = 0;
|
|
10
|
+
CogTilerFinalization.unregister(this);
|
|
11
|
+
return ptr;
|
|
12
|
+
}
|
|
13
|
+
free() {
|
|
14
|
+
const ptr = this.__destroy_into_raw();
|
|
15
|
+
wasm.__wbg_cogtiler_free(ptr, 0);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Source CRS EPSG code.
|
|
19
|
+
* @returns {number}
|
|
20
|
+
*/
|
|
21
|
+
get epsg() {
|
|
22
|
+
const ret = wasm.cogtiler_epsg(this.__wbg_ptr);
|
|
23
|
+
return ret >>> 0;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build a tiler from COG metadata (all of which `CogStream` exposes).
|
|
27
|
+
*
|
|
28
|
+
* * `geo_transform` - 6-element GDAL affine transform of the full-res raster.
|
|
29
|
+
* * `width` / `height` - full-resolution pixel dimensions.
|
|
30
|
+
* * `epsg` - source CRS code; must be `3857` in v1.
|
|
31
|
+
* * `nodata` - optional nodata value (pass `NaN`/`undefined` for none).
|
|
32
|
+
* * `levels_json` - JSON array of `{ "width", "height" }`, finest first,
|
|
33
|
+
* e.g. `[{"width":8192,"height":8192},{"width":4096,"height":4096}]`.
|
|
34
|
+
* @param {Float64Array} geo_transform
|
|
35
|
+
* @param {number} width
|
|
36
|
+
* @param {number} height
|
|
37
|
+
* @param {number} epsg
|
|
38
|
+
* @param {number | null | undefined} nodata
|
|
39
|
+
* @param {string} levels_json
|
|
40
|
+
*/
|
|
41
|
+
constructor(geo_transform, width, height, epsg, nodata, levels_json) {
|
|
42
|
+
try {
|
|
43
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
44
|
+
const ptr0 = passArrayF64ToWasm0(geo_transform, wasm.__wbindgen_export);
|
|
45
|
+
const len0 = WASM_VECTOR_LEN;
|
|
46
|
+
const ptr1 = passStringToWasm0(levels_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
47
|
+
const len1 = WASM_VECTOR_LEN;
|
|
48
|
+
wasm.cogtiler_new(retptr, ptr0, len0, width, height, epsg, !isLikeNone(nodata), isLikeNone(nodata) ? 0 : nodata, ptr1, len1);
|
|
49
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
50
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
51
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
52
|
+
if (r2) {
|
|
53
|
+
throw takeObject(r1);
|
|
54
|
+
}
|
|
55
|
+
this.__wbg_ptr = r0;
|
|
56
|
+
CogTilerFinalization.register(this, this.__wbg_ptr, this);
|
|
57
|
+
return this;
|
|
58
|
+
} finally {
|
|
59
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Number of overview levels (including full resolution).
|
|
64
|
+
* @returns {number}
|
|
65
|
+
*/
|
|
66
|
+
get num_levels() {
|
|
67
|
+
const ret = wasm.cogtiler_num_levels(this.__wbg_ptr);
|
|
68
|
+
return ret >>> 0;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Map an XYZ tile to the overview level and pixel window that cover it.
|
|
72
|
+
*
|
|
73
|
+
* Returns a [`PixelWindow`] (as a JS object). When the tile lies outside
|
|
74
|
+
* the raster, `empty` is `true` and `w == h == 0`. Errors if the source is
|
|
75
|
+
* not EPSG:3857 (v1 limitation).
|
|
76
|
+
* @param {number} z
|
|
77
|
+
* @param {number} x
|
|
78
|
+
* @param {number} y
|
|
79
|
+
* @returns {any}
|
|
80
|
+
*/
|
|
81
|
+
pixel_window_for_tile(z, x, y) {
|
|
82
|
+
try {
|
|
83
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
84
|
+
wasm.cogtiler_pixel_window_for_tile(retptr, this.__wbg_ptr, z, x, y);
|
|
85
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
86
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
87
|
+
var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
|
|
88
|
+
if (r2) {
|
|
89
|
+
throw takeObject(r1);
|
|
90
|
+
}
|
|
91
|
+
return takeObject(r0);
|
|
92
|
+
} finally {
|
|
93
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Render a decoded source window into a 256x256 RGBA tile.
|
|
98
|
+
*
|
|
99
|
+
* * `pixels` - row-major `f64` window of size `win_w * win_h`, as returned
|
|
100
|
+
* by assembling `CogStream.decode_tile_f64` outputs over the window from
|
|
101
|
+
* [`Self::pixel_window_for_tile`].
|
|
102
|
+
* * `min` / `max` - rescale range mapped to the colormap's `[0, 1]`.
|
|
103
|
+
* * `colormap` - `"viridis"`, `"magma"`, `"terrain"`, or `"gray"`.
|
|
104
|
+
* * `nodata_alpha` - when `true`, nodata pixels become fully transparent.
|
|
105
|
+
*
|
|
106
|
+
* Returns `256 * 256 * 4` bytes (RGBA). An empty window (`win_w == 0`)
|
|
107
|
+
* yields a fully transparent tile.
|
|
108
|
+
* @param {Float64Array} pixels
|
|
109
|
+
* @param {number} win_w
|
|
110
|
+
* @param {number} win_h
|
|
111
|
+
* @param {number} min
|
|
112
|
+
* @param {number} max
|
|
113
|
+
* @param {string} colormap
|
|
114
|
+
* @param {boolean} nodata_alpha
|
|
115
|
+
* @returns {Uint8Array}
|
|
116
|
+
*/
|
|
117
|
+
render(pixels, win_w, win_h, min, max, colormap, nodata_alpha) {
|
|
118
|
+
try {
|
|
119
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
120
|
+
const ptr0 = passArrayF64ToWasm0(pixels, wasm.__wbindgen_export);
|
|
121
|
+
const len0 = WASM_VECTOR_LEN;
|
|
122
|
+
const ptr1 = passStringToWasm0(colormap, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
123
|
+
const len1 = WASM_VECTOR_LEN;
|
|
124
|
+
wasm.cogtiler_render(retptr, this.__wbg_ptr, ptr0, len0, win_w, win_h, min, max, ptr1, len1, nodata_alpha);
|
|
125
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
126
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
127
|
+
var v3 = getArrayU8FromWasm0(r0, r1).slice();
|
|
128
|
+
wasm.__wbindgen_export3(r0, r1 * 1, 1);
|
|
129
|
+
return v3;
|
|
130
|
+
} finally {
|
|
131
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (Symbol.dispose) CogTiler.prototype[Symbol.dispose] = CogTiler.prototype.free;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* EPSG:3857 bounds `[min_x, min_y, max_x, max_y]` of an XYZ tile.
|
|
139
|
+
* @param {number} z
|
|
140
|
+
* @param {number} x
|
|
141
|
+
* @param {number} y
|
|
142
|
+
* @returns {Float64Array}
|
|
143
|
+
*/
|
|
144
|
+
export function tile_bounds_3857(z, x, y) {
|
|
145
|
+
try {
|
|
146
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
147
|
+
wasm.tile_bounds_3857(retptr, z, x, y);
|
|
148
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
149
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
150
|
+
var v1 = getArrayF64FromWasm0(r0, r1).slice();
|
|
151
|
+
wasm.__wbindgen_export3(r0, r1 * 8, 8);
|
|
152
|
+
return v1;
|
|
153
|
+
} finally {
|
|
154
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Crate version (from `Cargo.toml`).
|
|
160
|
+
* @returns {string}
|
|
161
|
+
*/
|
|
162
|
+
export function version() {
|
|
163
|
+
let deferred1_0;
|
|
164
|
+
let deferred1_1;
|
|
165
|
+
try {
|
|
166
|
+
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
|
167
|
+
wasm.version(retptr);
|
|
168
|
+
var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
|
|
169
|
+
var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
|
|
170
|
+
deferred1_0 = r0;
|
|
171
|
+
deferred1_1 = r1;
|
|
172
|
+
return getStringFromWasm0(r0, r1);
|
|
173
|
+
} finally {
|
|
174
|
+
wasm.__wbindgen_add_to_stack_pointer(16);
|
|
175
|
+
wasm.__wbindgen_export3(deferred1_0, deferred1_1, 1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function __wbg_get_imports() {
|
|
179
|
+
const import0 = {
|
|
180
|
+
__proto__: null,
|
|
181
|
+
__wbg_Error_fdd633d4bb5dd76a: function(arg0, arg1) {
|
|
182
|
+
const ret = Error(getStringFromWasm0(arg0, arg1));
|
|
183
|
+
return addHeapObject(ret);
|
|
184
|
+
},
|
|
185
|
+
__wbg_String_8564e559799eccda: function(arg0, arg1) {
|
|
186
|
+
const ret = String(getObject(arg1));
|
|
187
|
+
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
|
|
188
|
+
const len1 = WASM_VECTOR_LEN;
|
|
189
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
|
|
190
|
+
getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
|
|
191
|
+
},
|
|
192
|
+
__wbg___wbindgen_throw_ea4887a5f8f9a9db: function(arg0, arg1) {
|
|
193
|
+
throw new Error(getStringFromWasm0(arg0, arg1));
|
|
194
|
+
},
|
|
195
|
+
__wbg_new_2e117a478906f062: function() {
|
|
196
|
+
const ret = new Object();
|
|
197
|
+
return addHeapObject(ret);
|
|
198
|
+
},
|
|
199
|
+
__wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
|
|
200
|
+
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
|
|
201
|
+
},
|
|
202
|
+
__wbindgen_cast_0000000000000001: function(arg0) {
|
|
203
|
+
// Cast intrinsic for `F64 -> Externref`.
|
|
204
|
+
const ret = arg0;
|
|
205
|
+
return addHeapObject(ret);
|
|
206
|
+
},
|
|
207
|
+
__wbindgen_cast_0000000000000002: function(arg0, arg1) {
|
|
208
|
+
// Cast intrinsic for `Ref(String) -> Externref`.
|
|
209
|
+
const ret = getStringFromWasm0(arg0, arg1);
|
|
210
|
+
return addHeapObject(ret);
|
|
211
|
+
},
|
|
212
|
+
__wbindgen_cast_0000000000000003: function(arg0) {
|
|
213
|
+
// Cast intrinsic for `U64 -> Externref`.
|
|
214
|
+
const ret = BigInt.asUintN(64, arg0);
|
|
215
|
+
return addHeapObject(ret);
|
|
216
|
+
},
|
|
217
|
+
__wbindgen_object_clone_ref: function(arg0) {
|
|
218
|
+
const ret = getObject(arg0);
|
|
219
|
+
return addHeapObject(ret);
|
|
220
|
+
},
|
|
221
|
+
__wbindgen_object_drop_ref: function(arg0) {
|
|
222
|
+
takeObject(arg0);
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
return {
|
|
226
|
+
__proto__: null,
|
|
227
|
+
"./cog_tiler_wasm_bg.js": import0,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const CogTilerFinalization = (typeof FinalizationRegistry === 'undefined')
|
|
232
|
+
? { register: () => {}, unregister: () => {} }
|
|
233
|
+
: new FinalizationRegistry(ptr => wasm.__wbg_cogtiler_free(ptr, 1));
|
|
234
|
+
|
|
235
|
+
function addHeapObject(obj) {
|
|
236
|
+
if (heap_next === heap.length) heap.push(heap.length + 1);
|
|
237
|
+
const idx = heap_next;
|
|
238
|
+
heap_next = heap[idx];
|
|
239
|
+
|
|
240
|
+
heap[idx] = obj;
|
|
241
|
+
return idx;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function dropObject(idx) {
|
|
245
|
+
if (idx < 1028) return;
|
|
246
|
+
heap[idx] = heap_next;
|
|
247
|
+
heap_next = idx;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function getArrayF64FromWasm0(ptr, len) {
|
|
251
|
+
ptr = ptr >>> 0;
|
|
252
|
+
return getFloat64ArrayMemory0().subarray(ptr / 8, ptr / 8 + len);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function getArrayU8FromWasm0(ptr, len) {
|
|
256
|
+
ptr = ptr >>> 0;
|
|
257
|
+
return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let cachedDataViewMemory0 = null;
|
|
261
|
+
function getDataViewMemory0() {
|
|
262
|
+
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
|
263
|
+
cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
|
|
264
|
+
}
|
|
265
|
+
return cachedDataViewMemory0;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
let cachedFloat64ArrayMemory0 = null;
|
|
269
|
+
function getFloat64ArrayMemory0() {
|
|
270
|
+
if (cachedFloat64ArrayMemory0 === null || cachedFloat64ArrayMemory0.byteLength === 0) {
|
|
271
|
+
cachedFloat64ArrayMemory0 = new Float64Array(wasm.memory.buffer);
|
|
272
|
+
}
|
|
273
|
+
return cachedFloat64ArrayMemory0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function getStringFromWasm0(ptr, len) {
|
|
277
|
+
return decodeText(ptr >>> 0, len);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
let cachedUint8ArrayMemory0 = null;
|
|
281
|
+
function getUint8ArrayMemory0() {
|
|
282
|
+
if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
|
|
283
|
+
cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
|
|
284
|
+
}
|
|
285
|
+
return cachedUint8ArrayMemory0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function getObject(idx) { return heap[idx]; }
|
|
289
|
+
|
|
290
|
+
let heap = new Array(1024).fill(undefined);
|
|
291
|
+
heap.push(undefined, null, true, false);
|
|
292
|
+
|
|
293
|
+
let heap_next = heap.length;
|
|
294
|
+
|
|
295
|
+
function isLikeNone(x) {
|
|
296
|
+
return x === undefined || x === null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function passArrayF64ToWasm0(arg, malloc) {
|
|
300
|
+
const ptr = malloc(arg.length * 8, 8) >>> 0;
|
|
301
|
+
getFloat64ArrayMemory0().set(arg, ptr / 8);
|
|
302
|
+
WASM_VECTOR_LEN = arg.length;
|
|
303
|
+
return ptr;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function passStringToWasm0(arg, malloc, realloc) {
|
|
307
|
+
if (realloc === undefined) {
|
|
308
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
309
|
+
const ptr = malloc(buf.length, 1) >>> 0;
|
|
310
|
+
getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
|
|
311
|
+
WASM_VECTOR_LEN = buf.length;
|
|
312
|
+
return ptr;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
let len = arg.length;
|
|
316
|
+
let ptr = malloc(len, 1) >>> 0;
|
|
317
|
+
|
|
318
|
+
const mem = getUint8ArrayMemory0();
|
|
319
|
+
|
|
320
|
+
let offset = 0;
|
|
321
|
+
|
|
322
|
+
for (; offset < len; offset++) {
|
|
323
|
+
const code = arg.charCodeAt(offset);
|
|
324
|
+
if (code > 0x7F) break;
|
|
325
|
+
mem[ptr + offset] = code;
|
|
326
|
+
}
|
|
327
|
+
if (offset !== len) {
|
|
328
|
+
if (offset !== 0) {
|
|
329
|
+
arg = arg.slice(offset);
|
|
330
|
+
}
|
|
331
|
+
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
|
|
332
|
+
const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
|
|
333
|
+
const ret = cachedTextEncoder.encodeInto(arg, view);
|
|
334
|
+
|
|
335
|
+
offset += ret.written;
|
|
336
|
+
ptr = realloc(ptr, len, offset, 1) >>> 0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
WASM_VECTOR_LEN = offset;
|
|
340
|
+
return ptr;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function takeObject(idx) {
|
|
344
|
+
const ret = getObject(idx);
|
|
345
|
+
dropObject(idx);
|
|
346
|
+
return ret;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
350
|
+
cachedTextDecoder.decode();
|
|
351
|
+
const MAX_SAFARI_DECODE_BYTES = 2146435072;
|
|
352
|
+
let numBytesDecoded = 0;
|
|
353
|
+
function decodeText(ptr, len) {
|
|
354
|
+
numBytesDecoded += len;
|
|
355
|
+
if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {
|
|
356
|
+
cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
|
|
357
|
+
cachedTextDecoder.decode();
|
|
358
|
+
numBytesDecoded = len;
|
|
359
|
+
}
|
|
360
|
+
return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const cachedTextEncoder = new TextEncoder();
|
|
364
|
+
|
|
365
|
+
if (!('encodeInto' in cachedTextEncoder)) {
|
|
366
|
+
cachedTextEncoder.encodeInto = function (arg, view) {
|
|
367
|
+
const buf = cachedTextEncoder.encode(arg);
|
|
368
|
+
view.set(buf);
|
|
369
|
+
return {
|
|
370
|
+
read: arg.length,
|
|
371
|
+
written: buf.length
|
|
372
|
+
};
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
let WASM_VECTOR_LEN = 0;
|
|
377
|
+
|
|
378
|
+
let wasmModule, wasmInstance, wasm;
|
|
379
|
+
function __wbg_finalize_init(instance, module) {
|
|
380
|
+
wasmInstance = instance;
|
|
381
|
+
wasm = instance.exports;
|
|
382
|
+
wasmModule = module;
|
|
383
|
+
cachedDataViewMemory0 = null;
|
|
384
|
+
cachedFloat64ArrayMemory0 = null;
|
|
385
|
+
cachedUint8ArrayMemory0 = null;
|
|
386
|
+
return wasm;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function __wbg_load(module, imports) {
|
|
390
|
+
if (typeof Response === 'function' && module instanceof Response) {
|
|
391
|
+
if (typeof WebAssembly.instantiateStreaming === 'function') {
|
|
392
|
+
try {
|
|
393
|
+
return await WebAssembly.instantiateStreaming(module, imports);
|
|
394
|
+
} catch (e) {
|
|
395
|
+
const validResponse = module.ok && expectedResponseType(module.type);
|
|
396
|
+
|
|
397
|
+
if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') {
|
|
398
|
+
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
|
|
399
|
+
|
|
400
|
+
} else { throw e; }
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const bytes = await module.arrayBuffer();
|
|
405
|
+
return await WebAssembly.instantiate(bytes, imports);
|
|
406
|
+
} else {
|
|
407
|
+
const instance = await WebAssembly.instantiate(module, imports);
|
|
408
|
+
|
|
409
|
+
if (instance instanceof WebAssembly.Instance) {
|
|
410
|
+
return { instance, module };
|
|
411
|
+
} else {
|
|
412
|
+
return instance;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function expectedResponseType(type) {
|
|
417
|
+
switch (type) {
|
|
418
|
+
case 'basic': case 'cors': case 'default': return true;
|
|
419
|
+
}
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function initSync(module) {
|
|
425
|
+
if (wasm !== undefined) return wasm;
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
if (module !== undefined) {
|
|
429
|
+
if (Object.getPrototypeOf(module) === Object.prototype) {
|
|
430
|
+
({module} = module)
|
|
431
|
+
} else {
|
|
432
|
+
console.warn('using deprecated parameters for `initSync()`; pass a single object instead')
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
const imports = __wbg_get_imports();
|
|
437
|
+
if (!(module instanceof WebAssembly.Module)) {
|
|
438
|
+
module = new WebAssembly.Module(module);
|
|
439
|
+
}
|
|
440
|
+
const instance = new WebAssembly.Instance(module, imports);
|
|
441
|
+
return __wbg_finalize_init(instance, module);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
async function __wbg_init(module_or_path) {
|
|
445
|
+
if (wasm !== undefined) return wasm;
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
if (module_or_path !== undefined) {
|
|
449
|
+
if (Object.getPrototypeOf(module_or_path) === Object.prototype) {
|
|
450
|
+
({module_or_path} = module_or_path)
|
|
451
|
+
} else {
|
|
452
|
+
console.warn('using deprecated parameters for the initialization function; pass a single object instead')
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
if (module_or_path === undefined) {
|
|
457
|
+
module_or_path = new URL('cog_tiler_wasm_bg.wasm', import.meta.url);
|
|
458
|
+
}
|
|
459
|
+
const imports = __wbg_get_imports();
|
|
460
|
+
|
|
461
|
+
if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) {
|
|
462
|
+
module_or_path = fetch(module_or_path);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const { instance, module } = await __wbg_load(await module_or_path, imports);
|
|
466
|
+
|
|
467
|
+
return __wbg_finalize_init(instance, module);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export { initSync, __wbg_init as default };
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "cog-tiler-wasm",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"collaborators": [
|
|
5
|
+
"Qiusheng Wu <giswqs@gmail.com>"
|
|
6
|
+
],
|
|
7
|
+
"description": "Serverless Cloud Optimized GeoTIFF (COG) dynamic tiling in WebAssembly. TiTiler-style XYZ tiles, no backend.",
|
|
8
|
+
"version": "0.1.0",
|
|
9
|
+
"license": "MIT OR Apache-2.0",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/opengeos/cog-tiler-wasm"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"cog_tiler_wasm_bg.wasm",
|
|
16
|
+
"cog_tiler_wasm.js",
|
|
17
|
+
"cog_tiler_wasm.d.ts",
|
|
18
|
+
"cog-tiler.js",
|
|
19
|
+
"cog-tiler.d.ts"
|
|
20
|
+
],
|
|
21
|
+
"main": "cog-tiler.js",
|
|
22
|
+
"types": "cog-tiler.d.ts",
|
|
23
|
+
"sideEffects": [
|
|
24
|
+
"./snippets/*"
|
|
25
|
+
],
|
|
26
|
+
"module": "cog-tiler.js",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./cog-tiler.d.ts",
|
|
30
|
+
"default": "./cog-tiler.js"
|
|
31
|
+
},
|
|
32
|
+
"./wasm": {
|
|
33
|
+
"types": "./cog_tiler_wasm.d.ts",
|
|
34
|
+
"default": "./cog_tiler_wasm.js"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"whitebox-wasm": "^0.4.0",
|
|
39
|
+
"proj4": "^2.15.0",
|
|
40
|
+
"geotiff": "^2.1.0",
|
|
41
|
+
"geotiff-geokeys-to-proj4": "^2024.4.13"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"cog",
|
|
45
|
+
"geotiff",
|
|
46
|
+
"tiler",
|
|
47
|
+
"webassembly",
|
|
48
|
+
"wasm",
|
|
49
|
+
"maplibre",
|
|
50
|
+
"xyz",
|
|
51
|
+
"web-mercator",
|
|
52
|
+
"titiler",
|
|
53
|
+
"raster"
|
|
54
|
+
],
|
|
55
|
+
"homepage": "https://opengeos.github.io/cog-tiler-wasm/"
|
|
56
|
+
}
|