@developmentseed/geotiff 0.3.0-beta.3 → 0.3.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 +64 -0
- package/dist/array.d.ts +12 -27
- package/dist/array.d.ts.map +1 -1
- package/dist/array.js.map +1 -1
- package/dist/codecs/lerc.d.ts +2 -2
- package/dist/codecs/lerc.d.ts.map +1 -1
- package/dist/codecs/lerc.js +23 -2
- package/dist/codecs/lerc.js.map +1 -1
- package/dist/codecs/lzw.d.ts.map +1 -1
- package/dist/codecs/lzw.js +2 -1
- package/dist/codecs/lzw.js.map +1 -1
- package/dist/codecs/predictor.d.ts +1 -2
- package/dist/codecs/predictor.d.ts.map +1 -1
- package/dist/codecs/predictor.js +1 -2
- package/dist/codecs/predictor.js.map +1 -1
- package/dist/codecs/utils.d.ts +2 -0
- package/dist/codecs/utils.d.ts.map +1 -0
- package/dist/codecs/utils.js +11 -0
- package/dist/codecs/utils.js.map +1 -0
- package/dist/codecs/zstd.d.ts +2 -0
- package/dist/codecs/zstd.d.ts.map +1 -0
- package/dist/codecs/zstd.js +7 -0
- package/dist/codecs/zstd.js.map +1 -0
- package/dist/decode.d.ts +32 -6
- package/dist/decode.d.ts.map +1 -1
- package/dist/decode.js +35 -15
- package/dist/decode.js.map +1 -1
- package/dist/fetch.d.ts +6 -2
- package/dist/fetch.d.ts.map +1 -1
- package/dist/fetch.js +178 -34
- package/dist/fetch.js.map +1 -1
- package/dist/gdal-metadata.d.ts +17 -0
- package/dist/gdal-metadata.d.ts.map +1 -0
- package/dist/gdal-metadata.js +59 -0
- package/dist/gdal-metadata.js.map +1 -0
- package/dist/geotiff.d.ts +91 -11
- package/dist/geotiff.d.ts.map +1 -1
- package/dist/geotiff.js +140 -43
- package/dist/geotiff.js.map +1 -1
- package/dist/ifd.d.ts +8 -8
- package/dist/ifd.d.ts.map +1 -1
- package/dist/ifd.js +21 -13
- package/dist/ifd.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/overview.d.ts +33 -3
- package/dist/overview.d.ts.map +1 -1
- package/dist/overview.js +35 -2
- package/dist/overview.js.map +1 -1
- package/dist/pool/pool.d.ts +71 -0
- package/dist/pool/pool.d.ts.map +1 -0
- package/dist/pool/pool.js +100 -0
- package/dist/pool/pool.js.map +1 -0
- package/dist/pool/worker.d.ts +23 -0
- package/dist/pool/worker.d.ts.map +1 -0
- package/dist/pool/worker.js +37 -0
- package/dist/pool/worker.js.map +1 -0
- package/dist/pool/wrapper.d.ts +37 -0
- package/dist/pool/wrapper.d.ts.map +1 -0
- package/dist/pool/wrapper.js +46 -0
- package/dist/pool/wrapper.js.map +1 -0
- package/dist/tile-matrix-set.d.ts.map +1 -1
- package/dist/tile-matrix-set.js +12 -12
- package/dist/tile-matrix-set.js.map +1 -1
- package/dist/transform.d.ts +7 -0
- package/dist/transform.d.ts.map +1 -1
- package/dist/transform.js +40 -1
- package/dist/transform.js.map +1 -1
- package/package.json +18 -12
- package/dist/api.d.ts +0 -34
- package/dist/api.d.ts.map +0 -1
- package/dist/api.js +0 -84
- package/dist/api.js.map +0 -1
- package/dist/decode/api.d.ts +0 -28
- package/dist/decode/api.d.ts.map +0 -1
- package/dist/decode/api.js +0 -80
- package/dist/decode/api.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
package/dist/overview.js
CHANGED
|
@@ -8,6 +8,8 @@ import { index, xy } from "./transform.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export class Overview {
|
|
10
10
|
cachedTags;
|
|
11
|
+
/** The data source used for fetching tile data. */
|
|
12
|
+
dataSource;
|
|
11
13
|
/** A reference to the parent GeoTIFF object. */
|
|
12
14
|
geotiff;
|
|
13
15
|
/** The GeoKeyDirectory of the primary IFD. */
|
|
@@ -16,41 +18,72 @@ export class Overview {
|
|
|
16
18
|
image;
|
|
17
19
|
/** The IFD for the mask associated with this overview level, if any. */
|
|
18
20
|
maskImage = null;
|
|
19
|
-
constructor(geotiff, gkd, image, maskImage, cachedTags) {
|
|
21
|
+
constructor(geotiff, gkd, image, maskImage, cachedTags, dataSource) {
|
|
20
22
|
this.geotiff = geotiff;
|
|
21
23
|
this.gkd = gkd;
|
|
22
24
|
this.image = image;
|
|
23
25
|
this.maskImage = maskImage;
|
|
24
26
|
this.cachedTags = cachedTags;
|
|
27
|
+
this.dataSource = dataSource;
|
|
25
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* The CRS parsed from the GeoKeyDirectory.
|
|
31
|
+
*
|
|
32
|
+
* Returns an EPSG code (number) for EPSG-coded CRSes, or a PROJJSON object
|
|
33
|
+
* for user-defined CRSes. The result is cached after the first access.
|
|
34
|
+
*
|
|
35
|
+
* See also {@link GeoTIFF.epsg} for the EPSG code directly from the TIFF tags.
|
|
36
|
+
*/
|
|
26
37
|
get crs() {
|
|
27
38
|
return this.geotiff.crs;
|
|
28
39
|
}
|
|
40
|
+
/** Image height in pixels. */
|
|
29
41
|
get height() {
|
|
30
42
|
return this.image.size.height;
|
|
31
43
|
}
|
|
44
|
+
/** The no data value, or null if not set. */
|
|
32
45
|
get nodata() {
|
|
33
46
|
return this.geotiff.nodata;
|
|
34
47
|
}
|
|
48
|
+
/** The number of tiles in the x and y directions */
|
|
49
|
+
get tileCount() {
|
|
50
|
+
return this.image.tileCount;
|
|
51
|
+
}
|
|
52
|
+
/** Tile height in pixels. */
|
|
35
53
|
get tileHeight() {
|
|
36
54
|
return this.image.tileSize.height;
|
|
37
55
|
}
|
|
56
|
+
/** Tile width in pixels. */
|
|
38
57
|
get tileWidth() {
|
|
39
58
|
return this.image.tileSize.width;
|
|
40
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Return the dataset's georeferencing transformation matrix.
|
|
62
|
+
*/
|
|
41
63
|
get transform() {
|
|
42
64
|
const fullTransform = this.geotiff.transform;
|
|
43
65
|
const scaleX = this.geotiff.width / this.width;
|
|
44
66
|
const scaleY = this.geotiff.height / this.height;
|
|
45
67
|
return compose(fullTransform, scale(scaleX, scaleY));
|
|
46
68
|
}
|
|
69
|
+
/** Image width in pixels. */
|
|
47
70
|
get width() {
|
|
48
71
|
return this.image.size.width;
|
|
49
72
|
}
|
|
50
|
-
/** Fetch a single tile from the full-resolution image.
|
|
73
|
+
/** Fetch a single tile from the full-resolution image.
|
|
74
|
+
*
|
|
75
|
+
* @param x The tile column index (0-based).
|
|
76
|
+
* @param y The tile row index (0-based).
|
|
77
|
+
* @param options Optional parameters for fetching the tile.
|
|
78
|
+
* @param options.boundless Whether to clip tiles that are partially outside the image bounds. When `true`, no clipping is applied. Defaults to `true`.
|
|
79
|
+
* @param options.pool An optional {@link DecoderPool} for decoding the tile data. If not provided, a new decoder will be created for each tile.
|
|
80
|
+
* @param options.signal An optional {@link AbortSignal} to cancel the fetch request.
|
|
81
|
+
*/
|
|
51
82
|
async fetchTile(x, y, options = {}) {
|
|
52
83
|
return await fetchTile(this, x, y, options);
|
|
53
84
|
}
|
|
85
|
+
// TiledMixin
|
|
86
|
+
// Transform mixin
|
|
54
87
|
/**
|
|
55
88
|
* Get the (row, col) pixel index containing the geographic coordinate (x, y).
|
|
56
89
|
*
|
package/dist/overview.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../src/overview.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAEzD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"overview.js","sourceRoot":"","sources":["../src/overview.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Compression } from "@cogeotiff/core";
|
|
2
|
+
import type { DecodedPixels, DecoderMetadata } from "../decode.js";
|
|
3
|
+
export type DecoderPoolOptions = {
|
|
4
|
+
/**
|
|
5
|
+
* Number of workers to create. Defaults to `navigator.hardwareConcurrency`
|
|
6
|
+
* when available, otherwise 2. Set to 0 to disable workers and decode on
|
|
7
|
+
* the main thread.
|
|
8
|
+
*/
|
|
9
|
+
size?: number;
|
|
10
|
+
/**
|
|
11
|
+
* Factory that creates a Worker. When omitted, decoding runs on the main
|
|
12
|
+
* thread regardless of `size`. Provide this to enable off-main-thread
|
|
13
|
+
* decoding, e.g.:
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* {
|
|
17
|
+
* createWorker: () =>
|
|
18
|
+
* new Worker(new URL("./pool/worker.js", import.meta.url), { type: "module" }),
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
createWorker?: () => Worker;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Manages a pool of Web Workers for off-main-thread tile decoding.
|
|
26
|
+
*
|
|
27
|
+
* Use {@link defaultDecoderPool} to create a pool backed by the built-in,
|
|
28
|
+
* default decompressors.
|
|
29
|
+
*
|
|
30
|
+
* When no `createWorker` factory is provided, decoding falls back to the main
|
|
31
|
+
* thread. This lets the pool be constructed unconditionally and wired up with
|
|
32
|
+
* a worker later (or never, for SSR / Node environments).
|
|
33
|
+
*/
|
|
34
|
+
export declare class DecoderPool {
|
|
35
|
+
private readonly workerWrappers;
|
|
36
|
+
constructor(options?: DecoderPoolOptions);
|
|
37
|
+
/** True when workers are available for off-main-thread decoding. */
|
|
38
|
+
get hasWorkers(): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Decode a compressed tile buffer.
|
|
41
|
+
*
|
|
42
|
+
* When workers are available, the compressed `bytes` buffer is transferred
|
|
43
|
+
* zero-copy to the least-loaded worker. The returned `DecodedPixels` typed
|
|
44
|
+
* array buffers are transferred back to the main thread.
|
|
45
|
+
*
|
|
46
|
+
* When no workers are available, decoding runs on the main thread via the
|
|
47
|
+
* normal `decode()` path.
|
|
48
|
+
*/
|
|
49
|
+
decode(bytes: ArrayBuffer, compression: Compression, metadata: DecoderMetadata): Promise<DecodedPixels>;
|
|
50
|
+
/** Terminate all workers and release resources. */
|
|
51
|
+
destroy(): void;
|
|
52
|
+
private leastLoaded;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Create a default `DecoderPool` backed by the built-in worker.
|
|
56
|
+
*
|
|
57
|
+
* A cached decoder pool instance is returned on subsequent calls.
|
|
58
|
+
*
|
|
59
|
+
* You may want to create it lazily (rather than as a module-level singleton)
|
|
60
|
+
* to keep the `new URL(…, import.meta.url)` out of the module's static
|
|
61
|
+
* initialisation, so bundlers that build IIFE/UMD outputs don't try to inline
|
|
62
|
+
* the worker at build time.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* Create a default decoder pool:
|
|
66
|
+
* ```
|
|
67
|
+
* const pool = defaultDecoderPool();
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function defaultDecoderPool(): DecoderPool;
|
|
71
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/pool/pool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAKnE,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;;;;;;;;;OAWG;IACH,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B,CAAC;AAKF;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAkB;gBAErC,OAAO,GAAE,kBAAuB;IAW5C,oEAAoE;IACpE,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;;;;;;OASG;IACG,MAAM,CACV,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,aAAa,CAAC;IAezB,mDAAmD;IACnD,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,WAAW;CASpB;AASD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,IAAI,WAAW,CAUhD"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { decode } from "../decode.js";
|
|
2
|
+
import { WorkerWrapper } from "./wrapper.js";
|
|
3
|
+
const defaultSize = typeof navigator !== "undefined" ? (navigator.hardwareConcurrency ?? 2) : 2;
|
|
4
|
+
/**
|
|
5
|
+
* Manages a pool of Web Workers for off-main-thread tile decoding.
|
|
6
|
+
*
|
|
7
|
+
* Use {@link defaultDecoderPool} to create a pool backed by the built-in,
|
|
8
|
+
* default decompressors.
|
|
9
|
+
*
|
|
10
|
+
* When no `createWorker` factory is provided, decoding falls back to the main
|
|
11
|
+
* thread. This lets the pool be constructed unconditionally and wired up with
|
|
12
|
+
* a worker later (or never, for SSR / Node environments).
|
|
13
|
+
*/
|
|
14
|
+
export class DecoderPool {
|
|
15
|
+
workerWrappers;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
const { size = defaultSize, createWorker } = options;
|
|
18
|
+
this.workerWrappers = [];
|
|
19
|
+
if (createWorker && size > 0) {
|
|
20
|
+
for (let i = 0; i < size; i++) {
|
|
21
|
+
this.workerWrappers.push(new WorkerWrapper(createWorker()));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** True when workers are available for off-main-thread decoding. */
|
|
26
|
+
get hasWorkers() {
|
|
27
|
+
return this.workerWrappers.length > 0;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Decode a compressed tile buffer.
|
|
31
|
+
*
|
|
32
|
+
* When workers are available, the compressed `bytes` buffer is transferred
|
|
33
|
+
* zero-copy to the least-loaded worker. The returned `DecodedPixels` typed
|
|
34
|
+
* array buffers are transferred back to the main thread.
|
|
35
|
+
*
|
|
36
|
+
* When no workers are available, decoding runs on the main thread via the
|
|
37
|
+
* normal `decode()` path.
|
|
38
|
+
*/
|
|
39
|
+
async decode(bytes, compression, metadata) {
|
|
40
|
+
if (!this.hasWorkers) {
|
|
41
|
+
return decode(bytes, compression, metadata);
|
|
42
|
+
}
|
|
43
|
+
const worker = this.leastLoaded();
|
|
44
|
+
const request = {
|
|
45
|
+
compression: compression,
|
|
46
|
+
metadata,
|
|
47
|
+
buffer: bytes,
|
|
48
|
+
};
|
|
49
|
+
const array = await worker.submitJob(request, [bytes]);
|
|
50
|
+
return array;
|
|
51
|
+
}
|
|
52
|
+
/** Terminate all workers and release resources. */
|
|
53
|
+
destroy() {
|
|
54
|
+
for (const w of this.workerWrappers) {
|
|
55
|
+
w.terminate();
|
|
56
|
+
}
|
|
57
|
+
this.workerWrappers.length = 0;
|
|
58
|
+
}
|
|
59
|
+
leastLoaded() {
|
|
60
|
+
let best = this.workerWrappers[0];
|
|
61
|
+
for (let i = 1; i < this.workerWrappers.length; i++) {
|
|
62
|
+
if (this.workerWrappers[i].jobCount < best.jobCount) {
|
|
63
|
+
best = this.workerWrappers[i];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return best;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* A default DecoderPool instance.
|
|
71
|
+
*
|
|
72
|
+
* It will be created on first call of `defaultDecoderPool`.
|
|
73
|
+
*/
|
|
74
|
+
let DEFAULT_POOL = null;
|
|
75
|
+
/**
|
|
76
|
+
* Create a default `DecoderPool` backed by the built-in worker.
|
|
77
|
+
*
|
|
78
|
+
* A cached decoder pool instance is returned on subsequent calls.
|
|
79
|
+
*
|
|
80
|
+
* You may want to create it lazily (rather than as a module-level singleton)
|
|
81
|
+
* to keep the `new URL(…, import.meta.url)` out of the module's static
|
|
82
|
+
* initialisation, so bundlers that build IIFE/UMD outputs don't try to inline
|
|
83
|
+
* the worker at build time.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* Create a default decoder pool:
|
|
87
|
+
* ```
|
|
88
|
+
* const pool = defaultDecoderPool();
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export function defaultDecoderPool() {
|
|
92
|
+
if (DEFAULT_POOL !== null) {
|
|
93
|
+
return DEFAULT_POOL;
|
|
94
|
+
}
|
|
95
|
+
DEFAULT_POOL = new DecoderPool({
|
|
96
|
+
createWorker: () => new Worker(new URL("./worker.js", import.meta.url), { type: "module" }),
|
|
97
|
+
});
|
|
98
|
+
return DEFAULT_POOL;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/pool/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default worker entry point for DecoderPool.
|
|
3
|
+
*
|
|
4
|
+
* In most cases you don't need to reference this file directly — call
|
|
5
|
+
* `defaultDecoderPool()` instead, which creates a pool backed by this worker.
|
|
6
|
+
*
|
|
7
|
+
* To override codecs (e.g. swap in a WASM zstd decoder), create your own
|
|
8
|
+
* worker file that mutates `registry` before importing this handler:
|
|
9
|
+
*
|
|
10
|
+
* import { registry } from "@developmentseed/geotiff";
|
|
11
|
+
* import { Compression } from "@cogeotiff/core";
|
|
12
|
+
* registry.set(Compression.Zstd, () => import("./my-wasm-zstd.js").then(m => m.decode));
|
|
13
|
+
* import "@developmentseed/geotiff/pool/worker";
|
|
14
|
+
*
|
|
15
|
+
* Then pass a custom `createWorker` factory to `DecoderPool`:
|
|
16
|
+
*
|
|
17
|
+
* new DecoderPool({
|
|
18
|
+
* createWorker: () =>
|
|
19
|
+
* new Worker(new URL("./my-worker.js", import.meta.url), { type: "module" }),
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/pool/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default worker entry point for DecoderPool.
|
|
3
|
+
*
|
|
4
|
+
* In most cases you don't need to reference this file directly — call
|
|
5
|
+
* `defaultDecoderPool()` instead, which creates a pool backed by this worker.
|
|
6
|
+
*
|
|
7
|
+
* To override codecs (e.g. swap in a WASM zstd decoder), create your own
|
|
8
|
+
* worker file that mutates `registry` before importing this handler:
|
|
9
|
+
*
|
|
10
|
+
* import { registry } from "@developmentseed/geotiff";
|
|
11
|
+
* import { Compression } from "@cogeotiff/core";
|
|
12
|
+
* registry.set(Compression.Zstd, () => import("./my-wasm-zstd.js").then(m => m.decode));
|
|
13
|
+
* import "@developmentseed/geotiff/pool/worker";
|
|
14
|
+
*
|
|
15
|
+
* Then pass a custom `createWorker` factory to `DecoderPool`:
|
|
16
|
+
*
|
|
17
|
+
* new DecoderPool({
|
|
18
|
+
* createWorker: () =>
|
|
19
|
+
* new Worker(new URL("./my-worker.js", import.meta.url), { type: "module" }),
|
|
20
|
+
* });
|
|
21
|
+
*/
|
|
22
|
+
import { decode } from "../decode.js";
|
|
23
|
+
import { collectTransferables } from "./wrapper.js";
|
|
24
|
+
self.addEventListener("message", async (e) => {
|
|
25
|
+
const { jobId, compression, metadata, buffer } = e.data;
|
|
26
|
+
try {
|
|
27
|
+
const array = await decode(buffer, compression, metadata);
|
|
28
|
+
const transferables = collectTransferables(array);
|
|
29
|
+
const response = { jobId, pixels: array };
|
|
30
|
+
self.postMessage(response, { transfer: transferables });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const response = { jobId, error: String(err) };
|
|
34
|
+
self.postMessage(response);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/pool/worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAMtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,CAA8B,EAAE,EAAE;IACxE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;IAExD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC1D,MAAM,aAAa,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAClD,MAAM,QAAQ,GAAmB,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QAC1D,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,QAAQ,GAAwB,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACpE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Compression } from "@cogeotiff/core";
|
|
2
|
+
import type { DecodedPixels, DecoderMetadata } from "../decode.js";
|
|
3
|
+
/** Message sent from main thread to worker. */
|
|
4
|
+
export type WorkerRequest = {
|
|
5
|
+
jobId: number;
|
|
6
|
+
compression: Compression;
|
|
7
|
+
metadata: DecoderMetadata;
|
|
8
|
+
buffer: ArrayBuffer;
|
|
9
|
+
};
|
|
10
|
+
/** Successful response from worker. */
|
|
11
|
+
export type WorkerResponse = {
|
|
12
|
+
jobId: number;
|
|
13
|
+
pixels: DecodedPixels;
|
|
14
|
+
error?: never;
|
|
15
|
+
};
|
|
16
|
+
/** Error response from worker. */
|
|
17
|
+
export type WorkerErrorResponse = {
|
|
18
|
+
jobId: number;
|
|
19
|
+
error: string;
|
|
20
|
+
pixels?: never;
|
|
21
|
+
};
|
|
22
|
+
/** Collect the transferable ArrayBuffers from a DecodedPixels. */
|
|
23
|
+
export declare function collectTransferables(pixels: DecodedPixels): Transferable[];
|
|
24
|
+
/**
|
|
25
|
+
* Wraps a Worker, tracking in-flight jobs and routing responses via jobId.
|
|
26
|
+
*/
|
|
27
|
+
export declare class WorkerWrapper {
|
|
28
|
+
readonly worker: Worker;
|
|
29
|
+
private jobIdCounter;
|
|
30
|
+
private jobs;
|
|
31
|
+
constructor(worker: Worker);
|
|
32
|
+
get jobCount(): number;
|
|
33
|
+
private onMessage;
|
|
34
|
+
submitJob(request: Omit<WorkerRequest, "jobId">, transferables: Transferable[]): Promise<DecodedPixels>;
|
|
35
|
+
terminate(): void;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=wrapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../src/pool/wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEnE,+CAA+C;AAC/C,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,WAAW,CAAC;IACzB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,kCAAkC;AAClC,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,KAAK,CAAC;CAChB,CAAC;AAEF,kEAAkE;AAClE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,EAAE,CAK1E;AAOD;;GAEG;AACH,qBAAa,aAAa;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,IAAI,CAAiC;gBAEjC,MAAM,EAAE,MAAM;IAO1B,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,OAAO,CAAC,SAAS;IAejB,SAAS,CACP,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,EACrC,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CAAC,aAAa,CAAC;IAWzB,SAAS,IAAI,IAAI;CAGlB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/** Collect the transferable ArrayBuffers from a DecodedPixels. */
|
|
2
|
+
export function collectTransferables(pixels) {
|
|
3
|
+
if (pixels.layout === "pixel-interleaved") {
|
|
4
|
+
return [pixels.data.buffer];
|
|
5
|
+
}
|
|
6
|
+
return pixels.bands.map((b) => b.buffer);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wraps a Worker, tracking in-flight jobs and routing responses via jobId.
|
|
10
|
+
*/
|
|
11
|
+
export class WorkerWrapper {
|
|
12
|
+
worker;
|
|
13
|
+
jobIdCounter = 0;
|
|
14
|
+
jobs = new Map();
|
|
15
|
+
constructor(worker) {
|
|
16
|
+
this.worker = worker;
|
|
17
|
+
this.worker.addEventListener("message", (e) => this.onMessage(e));
|
|
18
|
+
}
|
|
19
|
+
get jobCount() {
|
|
20
|
+
return this.jobs.size;
|
|
21
|
+
}
|
|
22
|
+
onMessage(e) {
|
|
23
|
+
const { jobId, error, pixels } = e.data;
|
|
24
|
+
const job = this.jobs.get(jobId);
|
|
25
|
+
this.jobs.delete(jobId);
|
|
26
|
+
if (!job)
|
|
27
|
+
return;
|
|
28
|
+
if (error) {
|
|
29
|
+
job.reject(new Error(error));
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
job.resolve(pixels);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
submitJob(request, transferables) {
|
|
36
|
+
const jobId = this.jobIdCounter++;
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
this.jobs.set(jobId, { resolve, reject });
|
|
39
|
+
this.worker.postMessage({ ...request, jobId }, { transfer: transferables });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
terminate() {
|
|
43
|
+
this.worker.terminate();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../src/pool/wrapper.ts"],"names":[],"mappings":"AAyBA,kEAAkE;AAClE,MAAM,UAAU,oBAAoB,CAAC,MAAqB;IACxD,IAAI,MAAM,CAAC,MAAM,KAAK,mBAAmB,EAAE,CAAC;QAC1C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAC3C,CAAC;AAOD;;GAEG;AACH,MAAM,OAAO,aAAa;IACf,MAAM,CAAS;IAChB,YAAY,GAAG,CAAC,CAAC;IACjB,IAAI,GAAG,IAAI,GAAG,EAAsB,CAAC;IAE7C,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,CAAe,EAAE,EAAE,CAC1D,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAClB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAEO,SAAS,CACf,CAAqD;QAErD,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;QACxC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG;YAAE,OAAO;QAEjB,IAAI,KAAK,EAAE,CAAC;YACV,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,SAAS,CACP,OAAqC,EACrC,aAA6B;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,WAAW,CACrB,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,EACrB,EAAE,QAAQ,EAAE,aAAa,EAAE,CAC5B,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,SAAS;QACP,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tile-matrix-set.d.ts","sourceRoot":"","sources":["../src/tile-matrix-set.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,aAAa,EACd,MAAM,8BAA8B,CAAC;AAItC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;GAKG;AACH,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE;QACN,wCAAwC;QACxC,CAAC,EAAE,MAAM,CAAC;KACX,CAAC;IACF,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;
|
|
1
|
+
{"version":3,"file":"tile-matrix-set.d.ts","sourceRoot":"","sources":["../src/tile-matrix-set.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAIV,aAAa,EACd,MAAM,8BAA8B,CAAC;AAItC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C;;;;;GAKG;AACH,UAAU,oBAAoB;IAC5B,KAAK,CAAC,EAAE;QACN,wCAAwC;QACxC,CAAC,EAAE,MAAM,CAAC;KACX,CAAC;IACF,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA0CD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,oBAAoB,EACzB,EAAE,EAAa,EAAE,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAO,GACtC,aAAa,CAkFf"}
|
package/dist/tile-matrix-set.js
CHANGED
|
@@ -16,17 +16,17 @@ function buildCrs(crs) {
|
|
|
16
16
|
/**
|
|
17
17
|
* Build a TileMatrix entry for a single resolution level.
|
|
18
18
|
*/
|
|
19
|
-
function buildTileMatrix(id, transform, mpu,
|
|
19
|
+
function buildTileMatrix(id, transform, mpu, tileWidth, tileHeight, matrixWidth, matrixHeight) {
|
|
20
20
|
return {
|
|
21
21
|
id,
|
|
22
22
|
scaleDenominator: (affine.a(transform) * mpu) / SCREEN_PIXEL_SIZE,
|
|
23
23
|
cellSize: affine.a(transform),
|
|
24
|
-
cornerOfOrigin,
|
|
24
|
+
cornerOfOrigin: affine.e(transform) > 0 ? "bottomLeft" : "topLeft",
|
|
25
25
|
pointOfOrigin: [affine.c(transform), affine.f(transform)],
|
|
26
26
|
tileWidth,
|
|
27
27
|
tileHeight,
|
|
28
|
-
matrixWidth
|
|
29
|
-
matrixHeight
|
|
28
|
+
matrixWidth,
|
|
29
|
+
matrixHeight,
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
@@ -45,15 +45,10 @@ function buildTileMatrix(id, transform, mpu, cornerOfOrigin, tileWidth, tileHeig
|
|
|
45
45
|
*/
|
|
46
46
|
export function generateTileMatrixSet(geotiff, crs, { id = uuidv4() } = {}) {
|
|
47
47
|
const bbox = geotiff.bbox;
|
|
48
|
-
const tr = geotiff.transform;
|
|
49
48
|
// Full-resolution level is appended last.
|
|
50
49
|
if (!geotiff.isTiled) {
|
|
51
50
|
throw new Error("GeoTIFF must be tiled to generate a TMS.");
|
|
52
51
|
}
|
|
53
|
-
if (tr[1] !== 0 || tr[3] !== 0) {
|
|
54
|
-
// TileMatrixSet assumes orthogonal axes
|
|
55
|
-
throw new Error("COG TileMatrixSet with rotation/skewed geotransform is not supported");
|
|
56
|
-
}
|
|
57
52
|
// Perhaps we should allow metersPerUnit to take any string
|
|
58
53
|
const crsUnit = crs.units;
|
|
59
54
|
if (!crsUnit) {
|
|
@@ -61,15 +56,20 @@ export function generateTileMatrixSet(geotiff, crs, { id = uuidv4() } = {}) {
|
|
|
61
56
|
}
|
|
62
57
|
const semiMajorAxis = crs.a || crs.datum?.a;
|
|
63
58
|
const mpu = metersPerUnit(crsUnit, { semiMajorAxis });
|
|
64
|
-
const cornerOfOrigin = affine.e(tr) > 0 ? "bottomLeft" : "topLeft";
|
|
65
59
|
const tileMatrices = [];
|
|
66
60
|
// Overviews are sorted finest-to-coarsest; reverse to emit coarsest first.
|
|
67
61
|
const overviewsCoarseFirst = [...geotiff.overviews].reverse();
|
|
68
62
|
for (let idx = 0; idx < overviewsCoarseFirst.length; idx++) {
|
|
69
63
|
const overview = overviewsCoarseFirst[idx];
|
|
70
|
-
|
|
64
|
+
const { x: matrixWidth, y: matrixHeight } = overview.tileCount;
|
|
65
|
+
tileMatrices.push(buildTileMatrix(String(idx), overview.transform, mpu, overview.tileWidth, overview.tileHeight, matrixWidth, matrixHeight));
|
|
66
|
+
}
|
|
67
|
+
if (geotiff.transform[1] !== 0 || geotiff.transform[3] !== 0) {
|
|
68
|
+
// TileMatrixSet assumes orthogonal axes
|
|
69
|
+
throw new Error("COG TileMatrixSet with rotation/skewed geotransform is not supported");
|
|
71
70
|
}
|
|
72
|
-
|
|
71
|
+
const { x: matrixWidth, y: matrixHeight } = geotiff.tileCount;
|
|
72
|
+
tileMatrices.push(buildTileMatrix(String(geotiff.overviews.length), geotiff.transform, mpu, geotiff.tileWidth, geotiff.tileHeight, matrixWidth, matrixHeight));
|
|
73
73
|
const tmsCrs = buildCrs(geotiff.crs);
|
|
74
74
|
const boundingBox = {
|
|
75
75
|
lowerLeft: [bbox[0], bbox[1]],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tile-matrix-set.js","sourceRoot":"","sources":["../src/tile-matrix-set.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,yBAAyB,CAAC;AAOlD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAoBpC,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC,SAAS,QAAQ,CAAC,GAAsB;IACtC,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,GAAG,EAAE,yCAAyC,GAAG,EAAE;SACpD,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,OAAO;QACL,GAAG,EAAE,GAAG;KACT,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CACtB,EAAU,EACV,SAAiB,EACjB,GAAW,EACX,
|
|
1
|
+
{"version":3,"file":"tile-matrix-set.js","sourceRoot":"","sources":["../src/tile-matrix-set.ts"],"names":[],"mappings":"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"}
|
package/dist/transform.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { RasterTypeKey } from "@cogeotiff/core";
|
|
1
2
|
import type { Affine } from "@developmentseed/affine";
|
|
3
|
+
export declare function createTransform({ modelTiepoint, modelPixelScale, modelTransformation, rasterType, }: {
|
|
4
|
+
modelTiepoint: number[] | null;
|
|
5
|
+
modelPixelScale: number[] | null;
|
|
6
|
+
modelTransformation: number[] | null;
|
|
7
|
+
rasterType: RasterTypeKey | null;
|
|
8
|
+
}): Affine;
|
|
2
9
|
/**
|
|
3
10
|
* Interface for objects that have an affine transform.
|
|
4
11
|
*/
|
package/dist/transform.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CACnB,IAAI,EAAE,YAAY,EAClB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,EAAE,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAmB,GACrC,CAAC,MAAM,EAAE,MAAM,CAAC,CAIlB;AAED;;;;;;;GAOG;AACH,wBAAgB,EAAE,CAChB,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAe,GACtD,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BlB"}
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAGtD,wBAAgB,eAAe,CAAC,EAC9B,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,UAAU,GACX,EAAE;IACD,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC/B,eAAe,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;CAClC,GAAG,MAAM,CAmBT;AA8BD;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4BAA4B;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,KAAK,CACnB,IAAI,EAAE,YAAY,EAClB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,EAAE,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAmB,GACrC,CAAC,MAAM,EAAE,MAAM,CAAC,CAIlB;AAED;;;;;;;GAOG;AACH,wBAAgB,EAAE,CAChB,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,MAAM,GAAE,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAe,GACtD,CAAC,MAAM,EAAE,MAAM,CAAC,CA4BlB"}
|
package/dist/transform.js
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RasterTypeKey } from "@cogeotiff/core";
|
|
2
|
+
import { apply, compose, invert, translation } from "@developmentseed/affine";
|
|
3
|
+
export function createTransform({ modelTiepoint, modelPixelScale, modelTransformation, rasterType, }) {
|
|
4
|
+
let transform;
|
|
5
|
+
if (modelTiepoint && modelPixelScale) {
|
|
6
|
+
transform = createFromModelTiepointAndPixelScale(modelTiepoint, modelPixelScale);
|
|
7
|
+
}
|
|
8
|
+
else if (modelTransformation) {
|
|
9
|
+
transform = createFromModelTransformation(modelTransformation);
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
throw new Error("The image does not have an affine transformation.");
|
|
13
|
+
}
|
|
14
|
+
// Offset transform by half pixel for point-interpreted rasters.
|
|
15
|
+
if (rasterType === RasterTypeKey.PixelIsPoint) {
|
|
16
|
+
transform = compose(transform, translation(-0.5, -0.5));
|
|
17
|
+
}
|
|
18
|
+
return transform;
|
|
19
|
+
}
|
|
20
|
+
function createFromModelTiepointAndPixelScale(modelTiepoint, modelPixelScale) {
|
|
21
|
+
const xOrigin = modelTiepoint[3];
|
|
22
|
+
const yOrigin = modelTiepoint[4];
|
|
23
|
+
const xResolution = modelPixelScale[0];
|
|
24
|
+
const yResolution = -modelPixelScale[1];
|
|
25
|
+
return [xResolution, 0, xOrigin, 0, yResolution, yOrigin];
|
|
26
|
+
}
|
|
27
|
+
function createFromModelTransformation(modelTransformation) {
|
|
28
|
+
// ModelTransformation is a 4x4 matrix in row-major order
|
|
29
|
+
// [0 1 2 3 ] [a b 0 c]
|
|
30
|
+
// [4 5 6 7 ] = [d e 0 f]
|
|
31
|
+
// [8 9 10 11] [0 0 1 0]
|
|
32
|
+
// [12 13 14 15] [0 0 0 1]
|
|
33
|
+
const xOrigin = modelTransformation[3];
|
|
34
|
+
const yOrigin = modelTransformation[7];
|
|
35
|
+
const rowRotation = modelTransformation[1];
|
|
36
|
+
const colRotation = modelTransformation[4];
|
|
37
|
+
const xResolution = modelTransformation[0];
|
|
38
|
+
const yResolution = modelTransformation[5];
|
|
39
|
+
return [xResolution, rowRotation, xOrigin, colRotation, yResolution, yOrigin];
|
|
40
|
+
}
|
|
2
41
|
/**
|
|
3
42
|
* Get the (row, col) pixel index containing the geographic coordinate (x, y).
|
|
4
43
|
*
|
package/dist/transform.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transform.js","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"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"}
|