cog-tiler-wasm 0.2.3 → 0.2.5

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 CHANGED
@@ -124,8 +124,8 @@ export declare function init(): Promise<unknown>;
124
124
 
125
125
  /**
126
126
  * Open a COG and return a {@link CogSource} ready to render XYZ tiles. Pass a URL
127
- * string (read via HTTP range) or in-memory bytes / a Blob / a File for a local
128
- * raster.
127
+ * string (read via HTTP range), a Blob / File (read via ranged slices, so
128
+ * multi-GB local rasters never load whole), or in-memory bytes.
129
129
  */
130
130
  export declare function openCog(source: string | ArrayBuffer | Uint8Array | Blob): Promise<CogSource>;
131
131
 
package/cog-tiler.js CHANGED
@@ -165,6 +165,43 @@ async function readTiffTag(img, name) {
165
165
  return undefined;
166
166
  }
167
167
 
168
+ // Root keyword of a projected WKT (OGC `PROJCS`/`PROJCRS`, including the ESRI PE
169
+ // string flavour ArcGIS writes). Matching the keyword lets us slice off any
170
+ // `ESRI PE String = ` prefix.
171
+ const PROJECTED_WKT_ROOT = /\b(?:PROJCS|PROJCRS)\s*\[/i;
172
+
173
+ /** Pull a projected WKT/ESRI-PE-string definition out of a GeoTIFF citation geo
174
+ * key, if one is present. Returns the WKT from the `PROJCS`/`PROJCRS` keyword
175
+ * onward, or `null`. */
176
+ function projectedWktFromGeoKeys(geoKeys) {
177
+ for (const citation of [geoKeys.PCSCitationGeoKey, geoKeys.GTCitationGeoKey]) {
178
+ if (typeof citation !== "string") continue;
179
+ const match = PROJECTED_WKT_ROOT.exec(citation);
180
+ if (match) return citation.slice(match.index);
181
+ }
182
+ return null;
183
+ }
184
+
185
+ /**
186
+ * Resolve the source CRS as a proj4 definition (a `+proj=...` string or a WKT).
187
+ *
188
+ * `geotiff-geokeys-to-proj4` builds the def from the numeric geo keys, but for a
189
+ * projection it cannot express (no `ProjCoordTransGeoKey`, e.g. ESRI world
190
+ * projections such as Mollweide/54009 written only as an `ESRI PE String`) it
191
+ * silently falls back to the bare geographic CRS (`+proj=longlat`, `isGCS`).
192
+ * That would place a projected raster at lon/lat where its metre coordinates
193
+ * are, so it never draws. When the keys carry a projected WKT, prefer it; proj4
194
+ * parses the ESRI/OGC WKT directly.
195
+ */
196
+ function sourceCrsDef(geoKeys) {
197
+ const result = geokeysToProj4.toProj4(geoKeys);
198
+ if (result.isGCS) {
199
+ const wkt = projectedWktFromGeoKeys(geoKeys);
200
+ if (wkt) return wkt;
201
+ }
202
+ return result.proj4;
203
+ }
204
+
168
205
  /** Build a 256-entry RGBA palette from a TIFF ColorMap (16-bit R,G,B blocks). */
169
206
  function buildPalette(colorMap) {
170
207
  if (!colorMap) return null;
@@ -203,18 +240,29 @@ function sampleWindowBilinear(buf, w, h, fc, fr) {
203
240
  return top + (bot - top) * ty;
204
241
  }
205
242
 
206
- // Build a byte reader from a URL string or an in-memory source (ArrayBuffer,
207
- // Uint8Array, or Blob/File). `range(a,b)` yields bytes [a..b]; `openTiff()`
243
+ // Build a byte reader from a URL string, a Blob/File, or an in-memory source
244
+ // (ArrayBuffer, Uint8Array). `range(a,b)` yields bytes [a..b]; `openTiff()`
208
245
  // returns a geotiff.js GeoTIFF for reading the CRS / color table from the header.
209
246
  async function makeReader(source) {
210
247
  if (typeof source === "string") {
211
248
  return { label: source, range: rangeFetcher(source), openTiff: () => GeoTIFF.fromUrl(source) };
212
249
  }
250
+ // Blob / File: read on demand via ranged slices, mirroring the URL path.
251
+ // Slurping the whole file (blob.arrayBuffer()) throws NotReadableError in
252
+ // Chromium for multi-GB rasters (e.g. the 7 GB GEBCO GeoTIFF) — and only the
253
+ // header prefix and the requested tiles are ever needed.
254
+ if (typeof Blob !== "undefined" && source instanceof Blob) {
255
+ return {
256
+ label: source.name || "(local file)",
257
+ range: async (a, b) => new Uint8Array(await source.slice(a, b + 1).arrayBuffer()),
258
+ openTiff: () => GeoTIFF.fromBlob(source),
259
+ };
260
+ }
213
261
  let bytes;
214
262
  if (source instanceof Uint8Array) bytes = source;
215
263
  else if (source instanceof ArrayBuffer) bytes = new Uint8Array(source);
216
264
  else if (source && typeof source.arrayBuffer === "function") {
217
- bytes = new Uint8Array(await source.arrayBuffer()); // Blob / File
265
+ bytes = new Uint8Array(await source.arrayBuffer()); // exotic Blob-likes
218
266
  } else {
219
267
  throw new Error("openCog: expected a URL string, ArrayBuffer, Uint8Array, or Blob");
220
268
  }
@@ -233,10 +281,11 @@ async function makeReader(source) {
233
281
 
234
282
  /**
235
283
  * Open a COG and return a {@link CogSource} ready to render XYZ tiles. `source`
236
- * is a URL string (read via HTTP range) or in-memory bytes / a Blob / a File for
237
- * a local raster. Detects EPSG:3857 (fast path) vs. any other CRS (warp path),
238
- * reading the source projection + color table from the GeoTIFF header (which
239
- * whitebox-wasm 0.4.0 does not expose).
284
+ * is a URL string (read via HTTP range), a Blob / File (read via ranged slices,
285
+ * so multi-GB local rasters never load whole), or in-memory bytes. Detects
286
+ * EPSG:3857 (fast path) vs. any other CRS (warp path), reading the source
287
+ * projection + color table from the GeoTIFF header (which whitebox-wasm 0.4.0
288
+ * does not expose).
240
289
  */
241
290
  export async function openCog(source) {
242
291
  await init();
@@ -282,7 +331,7 @@ export async function openCog(source) {
282
331
  }
283
332
 
284
333
  // Warp path: read the real source CRS + optional palette from the header.
285
- const srcDef = geokeysToProj4.toProj4(img.getGeoKeys()).proj4;
334
+ const srcDef = sourceCrsDef(img.getGeoKeys());
286
335
  if (!srcDef) throw new Error("could not derive source CRS from GeoTIFF geokeys");
287
336
  const toSource = proj4("EPSG:3857", srcDef); // forward: mercator -> source
288
337
  const toLonLat = proj4(srcDef, "EPSG:4326"); // forward: source -> lon/lat
@@ -304,10 +353,20 @@ export async function openCog(source) {
304
353
  toSource,
305
354
  palette,
306
355
  boundsLonLat: [Math.min(...lons), Math.min(...lats), Math.max(...lons), Math.max(...lats)],
307
- crsLabel: "warped from " + (srcDef.match(/\+proj=\w+/) || ["custom CRS"])[0],
356
+ crsLabel: "warped from " + crsLabelForDef(srcDef),
308
357
  });
309
358
  }
310
359
 
360
+ /** A short label for a proj4 def: the `+proj=...` token, or the WKT's CRS name,
361
+ * falling back to "custom CRS". */
362
+ function crsLabelForDef(srcDef) {
363
+ const projTag = srcDef.match(/\+proj=\w+/);
364
+ if (projTag) return projTag[0];
365
+ const wktName = srcDef.match(/\b(?:PROJCS|PROJCRS)\s*\[\s*"([^"]+)"/i);
366
+ if (wktName) return wktName[1];
367
+ return "custom CRS";
368
+ }
369
+
311
370
  /** A single opened COG. Renders XYZ tiles via {@link CogSource#renderTileRGBA}. */
312
371
  export class CogSource {
313
372
  constructor(fields) {
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "Qiusheng Wu <giswqs@gmail.com>"
6
6
  ],
7
7
  "description": "Serverless Cloud Optimized GeoTIFF (COG) dynamic tiling in WebAssembly. TiTiler-style XYZ tiles, no backend.",
8
- "version": "0.2.3",
8
+ "version": "0.2.5",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",