@basemaps/cli 6.8.0 → 6.12.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/CHANGELOG.md +58 -0
- package/basemaps.js +2 -0
- package/build/cli/base.cli.d.ts +1 -1
- package/build/cli/base.cli.d.ts.map +1 -1
- package/build/cli/base.cli.js +22 -33
- package/build/cli/basemaps/action.invalidate.d.ts +1 -1
- package/build/cli/basemaps/action.invalidate.d.ts.map +1 -1
- package/build/cli/basemaps/action.invalidate.js +14 -18
- package/build/cli/basemaps/action.tileset.info.d.ts +1 -1
- package/build/cli/basemaps/action.tileset.info.d.ts.map +1 -1
- package/build/cli/basemaps/action.tileset.info.js +18 -23
- package/build/cli/basemaps/index.d.ts +2 -2
- package/build/cli/basemaps/index.d.ts.map +1 -1
- package/build/cli/basemaps/index.js +7 -16
- package/build/cli/basemaps/tileset.action.d.ts.map +1 -1
- package/build/cli/basemaps/tileset.action.js +4 -8
- package/build/cli/basemaps/tileset.util.d.ts +1 -1
- package/build/cli/basemaps/tileset.util.d.ts.map +1 -1
- package/build/cli/basemaps/tileset.util.js +20 -28
- package/build/cli/cli.table.d.ts.map +1 -1
- package/build/cli/cli.table.js +2 -7
- package/build/cli/cogify/__test__/action.batch.test.js +11 -14
- package/build/cli/cogify/__test__/semver.test.js +50 -53
- package/build/cli/cogify/action.batch.d.ts +2 -2
- package/build/cli/cogify/action.batch.d.ts.map +1 -1
- package/build/cli/cogify/action.batch.js +16 -22
- package/build/cli/cogify/action.cog.d.ts +1 -1
- package/build/cli/cogify/action.cog.d.ts.map +1 -1
- package/build/cli/cogify/action.cog.js +29 -33
- package/build/cli/cogify/action.job.d.ts.map +1 -1
- package/build/cli/cogify/action.job.js +21 -26
- package/build/cli/cogify/index.d.ts +2 -2
- package/build/cli/cogify/index.d.ts.map +1 -1
- package/build/cli/cogify/index.js +9 -13
- package/build/cli/cogify/semver.util.d.ts.map +1 -1
- package/build/cli/cogify/semver.util.js +2 -5
- package/build/cli/folder.js +6 -11
- package/build/cli/tag.action.js +1 -4
- package/build/cli/util.js +11 -16
- package/build/cog/__test__/builder.test.js +31 -35
- package/build/cog/__test__/cog.stac.job.test.js +59 -62
- package/build/cog/__test__/cog.test.js +26 -29
- package/build/cog/__test__/cog.vrt.test.js +90 -90
- package/build/cog/__test__/cutline.test.js +71 -71
- package/build/cog/__test__/source.tiff.testhelper.d.ts +1 -1
- package/build/cog/__test__/source.tiff.testhelper.d.ts.map +1 -1
- package/build/cog/__test__/source.tiff.testhelper.js +6 -9
- package/build/cog/builder.d.ts +3 -3
- package/build/cog/builder.d.ts.map +1 -1
- package/build/cog/builder.js +43 -48
- package/build/cog/cog.d.ts +2 -2
- package/build/cog/cog.d.ts.map +1 -1
- package/build/cog/cog.js +15 -19
- package/build/cog/cog.stac.job.d.ts +10 -10
- package/build/cog/cog.stac.job.d.ts.map +1 -1
- package/build/cog/cog.stac.job.js +48 -52
- package/build/cog/cog.vrt.d.ts +2 -2
- package/build/cog/cog.vrt.d.ts.map +1 -1
- package/build/cog/cog.vrt.js +16 -18
- package/build/cog/constants.js +2 -5
- package/build/cog/cutline.d.ts +21 -21
- package/build/cog/cutline.d.ts.map +1 -1
- package/build/cog/cutline.js +53 -58
- package/build/cog/job.factory.d.ts +2 -2
- package/build/cog/job.factory.d.ts.map +1 -1
- package/build/cog/job.factory.js +25 -41
- package/build/cog/stac.d.ts +1 -1
- package/build/cog/stac.d.ts.map +1 -1
- package/build/cog/stac.js +2 -5
- package/build/cog/types.d.ts +1 -1
- package/build/cog/types.d.ts.map +1 -1
- package/build/cog/types.js +1 -2
- package/build/gdal/__test__/gdal.progress.test.js +11 -14
- package/build/gdal/__test__/gdal.test.js +35 -38
- package/build/gdal/gdal.cog.d.ts +2 -2
- package/build/gdal/gdal.cog.d.ts.map +1 -1
- package/build/gdal/gdal.cog.js +14 -18
- package/build/gdal/gdal.command.d.ts +1 -1
- package/build/gdal/gdal.command.d.ts.map +1 -1
- package/build/gdal/gdal.command.js +4 -9
- package/build/gdal/gdal.config.d.ts.map +1 -1
- package/build/gdal/gdal.config.js +4 -7
- package/build/gdal/gdal.d.ts +1 -1
- package/build/gdal/gdal.d.ts.map +1 -1
- package/build/gdal/gdal.docker.d.ts +1 -1
- package/build/gdal/gdal.docker.d.ts.map +1 -1
- package/build/gdal/gdal.docker.js +8 -13
- package/build/gdal/gdal.js +7 -11
- package/build/gdal/gdal.local.d.ts +1 -1
- package/build/gdal/gdal.local.d.ts.map +1 -1
- package/build/gdal/gdal.local.js +2 -6
- package/build/gdal/gdal.progress.d.ts.map +1 -1
- package/build/gdal/gdal.progress.js +2 -6
- package/build/index.d.ts +5 -5
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -11
- package/{cogify → cogify.js} +1 -1
- package/package.json +15 -13
- package/basemaps +0 -2
package/build/cog/builder.js
CHANGED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
exports.InvalidProjectionCode = 32767;
|
|
13
|
-
exports.CacheVersion = 'v3'; // bump this number to invalidate the cache
|
|
14
|
-
exports.CacheFolder = './.cache';
|
|
1
|
+
import { Bounds, Epsg } from '@basemaps/geo';
|
|
2
|
+
import { CompositeError, fsa, LoggerFatalError, Projection } from '@basemaps/shared';
|
|
3
|
+
import { CogTiff, TiffTag, TiffTagGeo } from '@cogeotiff/core';
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import { existsSync, mkdirSync } from 'fs';
|
|
6
|
+
import pLimit from 'p-limit';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { basename } from 'path';
|
|
9
|
+
export const InvalidProjectionCode = 32767;
|
|
10
|
+
export const CacheVersion = 'v3'; // bump this number to invalidate the cache
|
|
11
|
+
export const CacheFolder = './.cache';
|
|
15
12
|
/**
|
|
16
13
|
* Attempt to guess the projection based off the WKT
|
|
17
14
|
*
|
|
@@ -22,18 +19,17 @@ exports.CacheFolder = './.cache';
|
|
|
22
19
|
*
|
|
23
20
|
* @param wkt
|
|
24
21
|
*/
|
|
25
|
-
function guessProjection(wkt) {
|
|
22
|
+
export function guessProjection(wkt) {
|
|
26
23
|
if (wkt == null)
|
|
27
24
|
return null;
|
|
28
25
|
const searchWkt = wkt.replace(/_/g, ' ');
|
|
29
26
|
if (searchWkt.includes('New Zealand Transverse Mercator'))
|
|
30
|
-
return
|
|
27
|
+
return Epsg.Nztm2000;
|
|
31
28
|
if (searchWkt.includes('Chatham Islands Transverse Mercator 2000'))
|
|
32
|
-
return
|
|
29
|
+
return Epsg.Citm2000;
|
|
33
30
|
return null;
|
|
34
31
|
}
|
|
35
|
-
|
|
36
|
-
class CogBuilder {
|
|
32
|
+
export class CogBuilder {
|
|
37
33
|
/**
|
|
38
34
|
* @param concurrency number of requests to run at a time
|
|
39
35
|
*/
|
|
@@ -42,7 +38,7 @@ class CogBuilder {
|
|
|
42
38
|
this.wktPreviousGuesses = new Set();
|
|
43
39
|
this.targetTms = targetTms;
|
|
44
40
|
this.logger = logger;
|
|
45
|
-
this.q =
|
|
41
|
+
this.q = pLimit(concurrency);
|
|
46
42
|
this.srcProj = srcProj;
|
|
47
43
|
}
|
|
48
44
|
/**
|
|
@@ -61,34 +57,34 @@ class CogBuilder {
|
|
|
61
57
|
if (count % 50 === 0)
|
|
62
58
|
this.logger.info({ count, total: sources.length }, 'BoundsProgress');
|
|
63
59
|
this.logger.trace({ source: source.uri }, 'Tiff:Load');
|
|
64
|
-
const tiff = new
|
|
60
|
+
const tiff = new CogTiff(source);
|
|
65
61
|
await tiff.init(true);
|
|
66
62
|
const image = tiff.getImage(0);
|
|
67
63
|
if (resX === -1 || image.resolution[0] < resX)
|
|
68
64
|
resX = image.resolution[0];
|
|
69
65
|
// Check number of bands to determine alpha layer
|
|
70
|
-
const tiffBandCount = image.value(
|
|
66
|
+
const tiffBandCount = image.value(TiffTag.BitsPerSample);
|
|
71
67
|
if (tiffBandCount != null && tiffBandCount.length > bands) {
|
|
72
68
|
if (bands > -1) {
|
|
73
69
|
this.logger.error({
|
|
74
|
-
firstImage: sources[0].
|
|
70
|
+
firstImage: basename(sources[0].uri),
|
|
75
71
|
bands,
|
|
76
|
-
currentImage: source.
|
|
72
|
+
currentImage: basename(source.uri),
|
|
77
73
|
currentBands: tiffBandCount,
|
|
78
74
|
}, 'Multiple Bands');
|
|
79
75
|
}
|
|
80
76
|
bands = tiffBandCount.length;
|
|
81
77
|
}
|
|
82
|
-
const output = { ...
|
|
78
|
+
const output = { ...Bounds.fromBbox(image.bbox).toJson(), name: source.uri };
|
|
83
79
|
if (source.close)
|
|
84
80
|
await source.close();
|
|
85
81
|
const imageProjection = this.findProjection(tiff);
|
|
86
82
|
if (imageProjection != null && (projection === null || projection === void 0 ? void 0 : projection.code) !== imageProjection.code) {
|
|
87
83
|
if (projection != null) {
|
|
88
84
|
this.logger.error({
|
|
89
|
-
firstImage: sources[0].
|
|
85
|
+
firstImage: basename(sources[0].uri),
|
|
90
86
|
projection,
|
|
91
|
-
currentImage: source.
|
|
87
|
+
currentImage: basename(source.uri),
|
|
92
88
|
currentProjection: imageProjection,
|
|
93
89
|
}, 'Multiple projections');
|
|
94
90
|
throw new Error('Multiple projections');
|
|
@@ -103,7 +99,7 @@ class CogBuilder {
|
|
|
103
99
|
}
|
|
104
100
|
return output;
|
|
105
101
|
}).catch((e) => {
|
|
106
|
-
throw new
|
|
102
|
+
throw new CompositeError('Failed to process image: ' + source.uri, 500, e);
|
|
107
103
|
});
|
|
108
104
|
});
|
|
109
105
|
const bounds = await Promise.all(queue);
|
|
@@ -119,25 +115,25 @@ class CogBuilder {
|
|
|
119
115
|
bands,
|
|
120
116
|
bounds,
|
|
121
117
|
pixelScale: resX,
|
|
122
|
-
resZoom:
|
|
118
|
+
resZoom: Projection.getTiffResZoom(this.targetTms, resX),
|
|
123
119
|
};
|
|
124
120
|
}
|
|
125
121
|
findProjection(tiff) {
|
|
126
122
|
const image = tiff.getImage(0);
|
|
127
|
-
const projection = image.valueGeo(
|
|
128
|
-
if (projection != null && projection !==
|
|
129
|
-
return
|
|
123
|
+
const projection = image.valueGeo(TiffTagGeo.ProjectedCSTypeGeoKey);
|
|
124
|
+
if (projection != null && projection !== InvalidProjectionCode) {
|
|
125
|
+
return Epsg.get(projection);
|
|
130
126
|
}
|
|
131
|
-
const imgWkt = image.value(
|
|
127
|
+
const imgWkt = image.value(TiffTag.GeoAsciiParams);
|
|
132
128
|
const epsg = guessProjection(imgWkt);
|
|
133
129
|
if (imgWkt != null && epsg != null) {
|
|
134
130
|
if (!this.wktPreviousGuesses.has(imgWkt)) {
|
|
135
|
-
this.logger.trace({ tiff: tiff.source.
|
|
131
|
+
this.logger.trace({ tiff: tiff.source.uri, imgWkt, projection }, 'GuessingProjection from GeoAsciiParams');
|
|
136
132
|
}
|
|
137
133
|
this.wktPreviousGuesses.add(imgWkt);
|
|
138
134
|
return epsg;
|
|
139
135
|
}
|
|
140
|
-
this.logger.error({ tiff: tiff.source.
|
|
136
|
+
this.logger.error({ tiff: tiff.source.uri, projection, imgWkt }, 'Failed find projection');
|
|
141
137
|
if (this.srcProj != null)
|
|
142
138
|
return this.srcProj;
|
|
143
139
|
throw new Error('Failed to find projection');
|
|
@@ -148,31 +144,31 @@ class CogBuilder {
|
|
|
148
144
|
* @param logger
|
|
149
145
|
*/
|
|
150
146
|
findNoData(tiff) {
|
|
151
|
-
const noData = tiff.getImage(0).value(
|
|
147
|
+
const noData = tiff.getImage(0).value(TiffTag.GDAL_NODATA);
|
|
152
148
|
if (noData == null)
|
|
153
149
|
return null;
|
|
154
150
|
const noDataNum = parseInt(noData);
|
|
155
151
|
if (isNaN(noDataNum) || noDataNum < 0 || noDataNum > 256) {
|
|
156
|
-
throw new
|
|
152
|
+
throw new LoggerFatalError({ tiff: tiff.source.uri, noData }, 'Failed converting GDAL_NODATA, defaulting to 255');
|
|
157
153
|
}
|
|
158
154
|
return noDataNum;
|
|
159
155
|
}
|
|
160
156
|
/** Cache the bounds lookup so we do not have to requery the bounds between CLI calls */
|
|
161
157
|
async getMetadata(tiffs) {
|
|
162
|
-
const cacheKey = path.join(
|
|
163
|
-
|
|
158
|
+
const cacheKey = path.join(CacheFolder, CacheVersion +
|
|
159
|
+
createHash('sha256')
|
|
164
160
|
.update(this.targetTms.projection.toString())
|
|
165
|
-
.update(tiffs.map((c) => c.
|
|
161
|
+
.update(tiffs.map((c) => c.uri).join('\n'))
|
|
166
162
|
.digest('hex')) + '.json';
|
|
167
|
-
if (
|
|
163
|
+
if (existsSync(cacheKey)) {
|
|
168
164
|
this.logger.debug({ path: cacheKey }, 'MetadataCacheHit');
|
|
169
|
-
const metadata = await
|
|
170
|
-
metadata.resZoom =
|
|
165
|
+
const metadata = await fsa.readJson(cacheKey);
|
|
166
|
+
metadata.resZoom = Projection.getTiffResZoom(this.targetTms, metadata.pixelScale);
|
|
171
167
|
return metadata;
|
|
172
168
|
}
|
|
173
169
|
const metadata = await this.bounds(tiffs);
|
|
174
|
-
|
|
175
|
-
await
|
|
170
|
+
mkdirSync(CacheFolder, { recursive: true });
|
|
171
|
+
await fsa.writeJson(cacheKey, metadata);
|
|
176
172
|
this.logger.debug({ path: cacheKey }, 'MetadataCacheMiss');
|
|
177
173
|
return metadata;
|
|
178
174
|
}
|
|
@@ -187,13 +183,12 @@ class CogBuilder {
|
|
|
187
183
|
let union = null;
|
|
188
184
|
for (const bounds of files) {
|
|
189
185
|
if (union == null)
|
|
190
|
-
union =
|
|
186
|
+
union = Bounds.fromJson(bounds);
|
|
191
187
|
else
|
|
192
|
-
union =
|
|
188
|
+
union = Bounds.fromJson(bounds).union(union);
|
|
193
189
|
}
|
|
194
190
|
if (union == null)
|
|
195
191
|
throw new Error('Bug! union can not be null');
|
|
196
192
|
return { ...metadata, files, targetBounds: union.toJson() };
|
|
197
193
|
}
|
|
198
194
|
}
|
|
199
|
-
exports.CogBuilder = CogBuilder;
|
package/build/cog/cog.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LogType } from '@basemaps/shared';
|
|
2
|
-
import { GdalCommand } from '../gdal/gdal.command';
|
|
3
|
-
import { CogJob } from './types';
|
|
2
|
+
import { GdalCommand } from '../gdal/gdal.command.js';
|
|
3
|
+
import { CogJob } from './types.js';
|
|
4
4
|
/**
|
|
5
5
|
* Create a onProgress logger
|
|
6
6
|
*
|
package/build/cog/cog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cog.d.ts","sourceRoot":"","sources":["../../src/cog/cog.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"cog.d.ts","sourceRoot":"","sources":["../../src/cog/cog.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,OAAO,EAAc,MAAM,kBAAkB,CAAC;AAEvE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAGpC;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAQ9F;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,MAAM,EAAE,OAAO,EACf,OAAO,UAAQ,GACd,OAAO,CAAC,IAAI,CAAC,CAuDf"}
|
package/build/cog/cog.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const gdal_cog_1 = require("../gdal/gdal.cog");
|
|
7
|
-
const gdal_progress_1 = require("../gdal/gdal.progress");
|
|
1
|
+
import { Bounds, TileMatrixSet } from '@basemaps/geo';
|
|
2
|
+
import { isConfigS3Role, Projection } from '@basemaps/shared';
|
|
3
|
+
import { GdalCogBuilder } from '../gdal/gdal.cog.js';
|
|
4
|
+
import { GdalProgressParser } from '../gdal/gdal.progress.js';
|
|
5
|
+
import { AwsCredentials } from '@chunkd/fs';
|
|
8
6
|
/**
|
|
9
7
|
* Create a onProgress logger
|
|
10
8
|
*
|
|
11
9
|
* @param keys additional keys to log
|
|
12
10
|
* @param logger base logger to use
|
|
13
11
|
*/
|
|
14
|
-
function onProgress(gdal, keys, logger) {
|
|
12
|
+
export function onProgress(gdal, keys, logger) {
|
|
15
13
|
let lastTime = Date.now();
|
|
16
|
-
gdal.parser = new
|
|
14
|
+
gdal.parser = new GdalProgressParser();
|
|
17
15
|
gdal.parser.on('progress', (p) => {
|
|
18
16
|
logger.trace({ ...keys, progress: parseFloat(p.toFixed(2)), progressTime: Date.now() - lastTime }, 'Progress');
|
|
19
17
|
lastTime = Date.now();
|
|
20
18
|
});
|
|
21
19
|
}
|
|
22
|
-
exports.onProgress = onProgress;
|
|
23
20
|
/**
|
|
24
21
|
* Build a COG for a given collection of tiffs
|
|
25
22
|
*
|
|
@@ -30,18 +27,18 @@ exports.onProgress = onProgress;
|
|
|
30
27
|
* @param logger Logger to use
|
|
31
28
|
* @param execute Whether to actually execute the transformation,
|
|
32
29
|
*/
|
|
33
|
-
async function buildCogForName(job, name, vrtLocation, outputTiffPath, logger, execute = false) {
|
|
30
|
+
export async function buildCogForName(job, name, vrtLocation, outputTiffPath, logger, execute = false) {
|
|
34
31
|
const startTime = Date.now();
|
|
35
32
|
const { targetZoom, tileMatrix } = job;
|
|
36
33
|
const nb = job.output.files.find((nb) => nb.name === name);
|
|
37
34
|
if (nb == null) {
|
|
38
35
|
throw new Error("Can't find COG named " + name);
|
|
39
36
|
}
|
|
40
|
-
const bounds =
|
|
41
|
-
const tile =
|
|
37
|
+
const bounds = Bounds.fromJson(nb);
|
|
38
|
+
const tile = TileMatrixSet.nameToTile(name);
|
|
42
39
|
const blockSize = tileMatrix.tileSize * 2; // FIXME is this blockFactor always 2
|
|
43
|
-
const alignmentLevels =
|
|
44
|
-
const cogBuild = new
|
|
40
|
+
const alignmentLevels = Projection.findAlignmentLevels(tileMatrix, tile, job.source.gsd);
|
|
41
|
+
const cogBuild = new GdalCogBuilder(vrtLocation, outputTiffPath, {
|
|
45
42
|
bbox: [bounds.x, bounds.bottom, bounds.right, bounds.y],
|
|
46
43
|
tileMatrix,
|
|
47
44
|
blockSize,
|
|
@@ -52,15 +49,15 @@ async function buildCogForName(job, name, vrtLocation, outputTiffPath, logger, e
|
|
|
52
49
|
});
|
|
53
50
|
onProgress(cogBuild.gdal, { name, target: 'tiff' }, logger);
|
|
54
51
|
logger.info({
|
|
55
|
-
imageSize:
|
|
52
|
+
imageSize: Projection.getImagePixelWidth(tileMatrix, tile, targetZoom),
|
|
56
53
|
name,
|
|
57
54
|
tile,
|
|
58
55
|
alignmentLevels,
|
|
59
56
|
}, 'CreateCog');
|
|
60
57
|
const sourceLocation = job.source.location;
|
|
61
58
|
// If required assume role
|
|
62
|
-
if (
|
|
63
|
-
const credentials =
|
|
59
|
+
if (isConfigS3Role(sourceLocation)) {
|
|
60
|
+
const credentials = AwsCredentials.role(sourceLocation.roleArn, sourceLocation.externalId);
|
|
64
61
|
cogBuild.gdal.setCredentials(credentials);
|
|
65
62
|
}
|
|
66
63
|
if (cogBuild.gdal.mount != null) {
|
|
@@ -72,4 +69,3 @@ async function buildCogForName(job, name, vrtLocation, outputTiffPath, logger, e
|
|
|
72
69
|
logger.info({ name, duration: Date.now() - startTime }, 'CogCreated');
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
|
-
exports.buildCogForName = buildCogForName;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Epsg, TileMatrixSet } from '@basemaps/geo';
|
|
2
2
|
import { FileConfig, FileConfigPath } from '@basemaps/shared';
|
|
3
3
|
import { MultiPolygon } from '@linzjs/geojson';
|
|
4
|
-
import { GdalCogBuilderResampling } from '../gdal/gdal.config';
|
|
5
|
-
import { CogBuilderMetadata, CogJob, CogJobJson, CogOutputProperties, CogSourceProperties, FeatureCollectionWithCrs } from './types';
|
|
4
|
+
import { GdalCogBuilderResampling } from '../gdal/gdal.config.js';
|
|
5
|
+
import { CogBuilderMetadata, CogJob, CogJobJson, CogOutputProperties, CogSourceProperties, FeatureCollectionWithCrs } from './types.js';
|
|
6
6
|
export declare const MaxConcurrencyDefault = 50;
|
|
7
7
|
export interface JobCreationContext {
|
|
8
8
|
/** Source config */
|
|
@@ -67,16 +67,16 @@ export declare class CogStacJob implements CogJob {
|
|
|
67
67
|
json: CogJobJson;
|
|
68
68
|
private cacheTargetZoom?;
|
|
69
69
|
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
* Load the job.json
|
|
71
|
+
|
|
72
|
+
* @param jobpath where to load the job.json from
|
|
73
|
+
*/
|
|
74
74
|
static load(jobpath: string): Promise<CogStacJob>;
|
|
75
75
|
/**
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
* Create job.json, collection.json, source.geojson, covering.geojson, cutlint.geojson.gz and
|
|
77
|
+
* stac descriptions of the target COGs
|
|
78
|
+
|
|
79
|
+
*/
|
|
80
80
|
static create({ id, imageryName, metadata, ctx, cutlinePoly, addAlpha, }: CogJobCreateParams): Promise<CogStacJob>;
|
|
81
81
|
/**
|
|
82
82
|
* build a FeatureCollection from MultiPolygon
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cog.stac.job.d.ts","sourceRoot":"","sources":["../../src/cog/cog.stac.job.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"cog.stac.job.d.ts","sourceRoot":"","sources":["../../src/cog/cog.stac.job.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,IAAI,EAKJ,aAAa,EAEd,MAAM,eAAe,CAAC;AACvB,OAAO,EAEL,UAAU,EACV,cAAc,EAKf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,YAAY,EAA8C,MAAM,iBAAiB,CAAC;AAE3F,OAAO,EAA0B,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE1F,OAAO,EACL,kBAAkB,EAClB,MAAM,EACN,UAAU,EACV,mBAAmB,EACnB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAEpB,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,cAAc,EAAE,UAAU,GAAG,cAAc,CAAC;IAE5C,oBAAoB;IACpB,cAAc,EAAE,UAAU,CAAC;IAE3B,6CAA6C;IAC7C,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IAEF,UAAU,EAAE,aAAa,CAAC;IAE1B,QAAQ,CAAC,EAAE;QACT,sBAAsB;QACtB,EAAE,CAAC,EAAE,MAAM,CAAC;QAEZ;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;QAEjB;;;WAGG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QAErB;;WAEG;QACH,UAAU,CAAC,EAAE,IAAI,CAAC;QAElB;;;WAGG;QACH,UAAU,CAAC,EAAE,wBAAwB,CAAC;KACvC,CAAC;IAEF;;;OAGG;IACH,KAAK,EAAE,OAAO,CAAC;IAEf,0FAA0F;IAC1F,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,mCAAmC;IACnC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,mCAAmC;IACnC,GAAG,EAAE,kBAAkB,CAAC;IACxB,oDAAoD;IACpD,WAAW,EAAE,YAAY,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,UAAW,YAAW,MAAM;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,OAAO,CAAC,eAAe,CAAC,CAGtB;IAEF;;;;SAIK;WACQ,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAIvD;;;;SAIK;WACQ,MAAM,CAAC,EAClB,EAAE,EACF,WAAW,EACX,QAAQ,EACR,GAAG,EACH,WAAW,EACX,QAAQ,GACT,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;IAmM3C;;OAEG;IACH,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,GAAG,wBAAwB;gBAS9D,IAAI,EAAE,UAAU;IAI5B,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,SAAS,CAEpC;IAED,IAAI,MAAM,IAAI,mBAAmB,CAEhC;IAED,IAAI,MAAM,IAAI,mBAAmB,CAEhC;IAED,IAAI,UAAU,IAAI,aAAa,CAO9B;IAED,IAAI,UAAU,IAAI,MAAM,CAMvB;IAED;;;;OAIG;IACH,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;CAOjC"}
|
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const gdal_config_1 = require("../gdal/gdal.config");
|
|
9
|
-
const stac_1 = require("./stac");
|
|
10
|
-
exports.MaxConcurrencyDefault = 50;
|
|
1
|
+
import { Bounds, Stac, TileMatrixSets, } from '@basemaps/geo';
|
|
2
|
+
import { extractYearRangeFromName, Projection, fsa, titleizeImageryName, CompositeError, } from '@basemaps/shared';
|
|
3
|
+
import { toFeatureCollection, toFeatureMultiPolygon } from '@linzjs/geojson';
|
|
4
|
+
import { CliInfo } from '../cli/base.cli.js';
|
|
5
|
+
import { GdalCogBuilderDefaults } from '../gdal/gdal.config.js';
|
|
6
|
+
import { CogStacItemExtensions, CogStacKeywords } from './stac.js';
|
|
7
|
+
export const MaxConcurrencyDefault = 50;
|
|
11
8
|
/**
|
|
12
9
|
* Information needed to create cogs
|
|
13
10
|
*/
|
|
14
|
-
class CogStacJob {
|
|
11
|
+
export class CogStacJob {
|
|
15
12
|
constructor(json) {
|
|
16
13
|
this.json = json;
|
|
17
14
|
}
|
|
18
15
|
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
* Load the job.json
|
|
17
|
+
|
|
18
|
+
* @param jobpath where to load the job.json from
|
|
19
|
+
*/
|
|
23
20
|
static async load(jobpath) {
|
|
24
|
-
return new CogStacJob(await
|
|
21
|
+
return new CogStacJob(await fsa.readJson(jobpath));
|
|
25
22
|
}
|
|
26
23
|
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
* Create job.json, collection.json, source.geojson, covering.geojson, cutlint.geojson.gz and
|
|
25
|
+
* stac descriptions of the target COGs
|
|
26
|
+
|
|
27
|
+
*/
|
|
31
28
|
static async create({ id, imageryName, metadata, ctx, cutlinePoly, addAlpha, }) {
|
|
32
29
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
33
30
|
let description;
|
|
34
31
|
const providers = [];
|
|
35
32
|
const links = [
|
|
36
33
|
{
|
|
37
|
-
href:
|
|
34
|
+
href: fsa.join(ctx.outputLocation.path, 'collection.json'),
|
|
38
35
|
type: 'application/json',
|
|
39
36
|
rel: 'self',
|
|
40
37
|
},
|
|
@@ -47,8 +44,8 @@ class CogStacJob {
|
|
|
47
44
|
let sourceStac = {};
|
|
48
45
|
const interval = [];
|
|
49
46
|
try {
|
|
50
|
-
const sourceCollectionPath =
|
|
51
|
-
sourceStac = await
|
|
47
|
+
const sourceCollectionPath = fsa.join(ctx.sourceLocation.path, 'collection.json');
|
|
48
|
+
sourceStac = await fsa.readJson(sourceCollectionPath);
|
|
52
49
|
description = sourceStac.description;
|
|
53
50
|
interval.push(...((_c = (_b = (_a = sourceStac.extent) === null || _a === void 0 ? void 0 : _a.temporal) === null || _b === void 0 ? void 0 : _b.interval) !== null && _c !== void 0 ? _c : []));
|
|
54
51
|
links.push({ href: sourceCollectionPath, rel: 'sourceImagery', type: 'application/json' });
|
|
@@ -65,13 +62,13 @@ class CogStacJob {
|
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
64
|
catch (err) {
|
|
68
|
-
if (!
|
|
65
|
+
if (!CompositeError.isCompositeError(err) || err.code !== 404) {
|
|
69
66
|
throw err;
|
|
70
67
|
}
|
|
71
68
|
}
|
|
72
|
-
const keywords = (_d = sourceStac.keywords) !== null && _d !== void 0 ? _d :
|
|
73
|
-
const license = (_e = sourceStac.license) !== null && _e !== void 0 ? _e :
|
|
74
|
-
const title = (_f = sourceStac.title) !== null && _f !== void 0 ? _f :
|
|
69
|
+
const keywords = (_d = sourceStac.keywords) !== null && _d !== void 0 ? _d : CogStacKeywords.slice();
|
|
70
|
+
const license = (_e = sourceStac.license) !== null && _e !== void 0 ? _e : Stac.License;
|
|
71
|
+
const title = (_f = sourceStac.title) !== null && _f !== void 0 ? _f : titleizeImageryName(imageryName);
|
|
75
72
|
if (description == null) {
|
|
76
73
|
description = 'No description';
|
|
77
74
|
}
|
|
@@ -92,8 +89,8 @@ class CogStacJob {
|
|
|
92
89
|
epsg: ctx.tileMatrix.projection.code,
|
|
93
90
|
files: metadata.files,
|
|
94
91
|
location: ctx.outputLocation,
|
|
95
|
-
resampling: (_h = (_g = ctx.override) === null || _g === void 0 ? void 0 : _g.resampling) !== null && _h !== void 0 ? _h :
|
|
96
|
-
quality: (_k = (_j = ctx.override) === null || _j === void 0 ? void 0 : _j.quality) !== null && _k !== void 0 ? _k :
|
|
92
|
+
resampling: (_h = (_g = ctx.override) === null || _g === void 0 ? void 0 : _g.resampling) !== null && _h !== void 0 ? _h : GdalCogBuilderDefaults.resampling,
|
|
93
|
+
quality: (_k = (_j = ctx.override) === null || _j === void 0 ? void 0 : _j.quality) !== null && _k !== void 0 ? _k : GdalCogBuilderDefaults.quality,
|
|
97
94
|
cutline: ctx.cutline,
|
|
98
95
|
addAlpha,
|
|
99
96
|
nodata: metadata.nodata,
|
|
@@ -102,12 +99,12 @@ class CogStacJob {
|
|
|
102
99
|
},
|
|
103
100
|
});
|
|
104
101
|
const nowStr = new Date().toISOString();
|
|
105
|
-
const sourceProj =
|
|
102
|
+
const sourceProj = Projection.get(job.source.epsg);
|
|
106
103
|
const bbox = [
|
|
107
|
-
sourceProj.boundsToWgs84BoundingBox(metadata.bounds.map((a) =>
|
|
104
|
+
sourceProj.boundsToWgs84BoundingBox(metadata.bounds.map((a) => Bounds.fromJson(a)).reduce((sum, a) => sum.union(a))),
|
|
108
105
|
];
|
|
109
106
|
if (interval.length === 0) {
|
|
110
|
-
const years =
|
|
107
|
+
const years = extractYearRangeFromName(imageryName);
|
|
111
108
|
if (years[0] === -1) {
|
|
112
109
|
throw new Error('Missing date in imagery name: ' + imageryName);
|
|
113
110
|
}
|
|
@@ -124,8 +121,8 @@ class CogStacJob {
|
|
|
124
121
|
id,
|
|
125
122
|
title,
|
|
126
123
|
description,
|
|
127
|
-
stac_version:
|
|
128
|
-
stac_extensions: [
|
|
124
|
+
stac_version: Stac.Version,
|
|
125
|
+
stac_extensions: [Stac.BaseMapsExtension],
|
|
129
126
|
extent: {
|
|
130
127
|
spatial: { bbox },
|
|
131
128
|
temporal,
|
|
@@ -138,8 +135,8 @@ class CogStacJob {
|
|
|
138
135
|
'proj:epsg': [ctx.tileMatrix.projection.code],
|
|
139
136
|
'linz:output': [
|
|
140
137
|
{
|
|
141
|
-
resampling: (_m = (_l = ctx.override) === null || _l === void 0 ? void 0 : _l.resampling) !== null && _m !== void 0 ? _m :
|
|
142
|
-
quality: (_p = (_o = ctx.override) === null || _o === void 0 ? void 0 : _o.quality) !== null && _p !== void 0 ? _p :
|
|
138
|
+
resampling: (_m = (_l = ctx.override) === null || _l === void 0 ? void 0 : _l.resampling) !== null && _m !== void 0 ? _m : GdalCogBuilderDefaults.resampling,
|
|
139
|
+
quality: (_p = (_o = ctx.override) === null || _o === void 0 ? void 0 : _o.quality) !== null && _p !== void 0 ? _p : GdalCogBuilderDefaults.quality,
|
|
143
140
|
cutlineBlend: (_q = ctx.cutline) === null || _q === void 0 ? void 0 : _q.blend,
|
|
144
141
|
addAlpha,
|
|
145
142
|
nodata: metadata.nodata,
|
|
@@ -147,15 +144,15 @@ class CogStacJob {
|
|
|
147
144
|
],
|
|
148
145
|
'linz:generated': [
|
|
149
146
|
{
|
|
150
|
-
...
|
|
147
|
+
...CliInfo,
|
|
151
148
|
datetime: nowStr,
|
|
152
149
|
},
|
|
153
150
|
],
|
|
154
151
|
},
|
|
155
152
|
links,
|
|
156
153
|
};
|
|
157
|
-
await
|
|
158
|
-
const covering =
|
|
154
|
+
await fsa.writeJson(jobFile, job.json);
|
|
155
|
+
const covering = Projection.get(job.tileMatrix).toGeoJson(metadata.files);
|
|
159
156
|
const roles = ['data'];
|
|
160
157
|
const collectionLink = { href: 'collection.json', rel: 'collection' };
|
|
161
158
|
for (const f of covering.features) {
|
|
@@ -166,8 +163,8 @@ class CogStacJob {
|
|
|
166
163
|
...f,
|
|
167
164
|
id: job.id + '/' + name,
|
|
168
165
|
collection: job.id,
|
|
169
|
-
stac_version:
|
|
170
|
-
stac_extensions:
|
|
166
|
+
stac_version: Stac.Version,
|
|
167
|
+
stac_extensions: CogStacItemExtensions,
|
|
171
168
|
properties: {
|
|
172
169
|
...f.properties,
|
|
173
170
|
datetime: nowStr,
|
|
@@ -183,24 +180,24 @@ class CogStacJob {
|
|
|
183
180
|
},
|
|
184
181
|
},
|
|
185
182
|
};
|
|
186
|
-
await
|
|
183
|
+
await fsa.writeJson(job.getJobPath(href), item);
|
|
187
184
|
}
|
|
188
185
|
if (ctx.cutline != null) {
|
|
189
186
|
const geoJsonCutlineOutput = job.getJobPath(`cutline.geojson.gz`);
|
|
190
|
-
await
|
|
187
|
+
await fsa.writeJson(geoJsonCutlineOutput, this.toGeoJson(cutlinePoly, ctx.tileMatrix.projection));
|
|
191
188
|
}
|
|
192
189
|
const geoJsonSourceOutput = job.getJobPath(`source.geojson`);
|
|
193
|
-
await
|
|
190
|
+
await fsa.writeJson(geoJsonSourceOutput, Projection.get(job.source.epsg).toGeoJson(metadata.bounds));
|
|
194
191
|
const geoJsonCoveringOutput = job.getJobPath(`covering.geojson`);
|
|
195
|
-
await
|
|
196
|
-
await
|
|
192
|
+
await fsa.writeJson(geoJsonCoveringOutput, covering);
|
|
193
|
+
await fsa.writeJson(job.getJobPath(`collection.json`), stac);
|
|
197
194
|
return job;
|
|
198
195
|
}
|
|
199
196
|
/**
|
|
200
197
|
* build a FeatureCollection from MultiPolygon
|
|
201
198
|
*/
|
|
202
199
|
static toGeoJson(poly, epsg) {
|
|
203
|
-
const feature =
|
|
200
|
+
const feature = toFeatureCollection([toFeatureMultiPolygon(poly)]);
|
|
204
201
|
feature.crs = {
|
|
205
202
|
type: 'name',
|
|
206
203
|
properties: { name: epsg.toUrn() },
|
|
@@ -227,18 +224,18 @@ class CogStacJob {
|
|
|
227
224
|
}
|
|
228
225
|
get tileMatrix() {
|
|
229
226
|
if (this.json.output.tileMatrix) {
|
|
230
|
-
const tileMatrix =
|
|
227
|
+
const tileMatrix = TileMatrixSets.find(this.json.output.tileMatrix);
|
|
231
228
|
if (tileMatrix == null)
|
|
232
229
|
throw new Error(`Failed to find TileMatrixSet "${this.json.output.tileMatrix}"`);
|
|
233
230
|
return tileMatrix;
|
|
234
231
|
}
|
|
235
|
-
return
|
|
232
|
+
return TileMatrixSets.get(this.json.output.epsg);
|
|
236
233
|
}
|
|
237
234
|
get targetZoom() {
|
|
238
235
|
var _a;
|
|
239
236
|
const { gsd } = this.source;
|
|
240
237
|
if (((_a = this.cacheTargetZoom) === null || _a === void 0 ? void 0 : _a.gsd) !== gsd) {
|
|
241
|
-
this.cacheTargetZoom = { gsd, zoom:
|
|
238
|
+
this.cacheTargetZoom = { gsd, zoom: Projection.getTiffResZoom(this.tileMatrix, gsd) };
|
|
242
239
|
}
|
|
243
240
|
return this.cacheTargetZoom.zoom;
|
|
244
241
|
}
|
|
@@ -252,7 +249,6 @@ class CogStacJob {
|
|
|
252
249
|
if (key != null) {
|
|
253
250
|
parts.push(key);
|
|
254
251
|
}
|
|
255
|
-
return
|
|
252
|
+
return fsa.join(this.output.location.path, parts.join('/'));
|
|
256
253
|
}
|
|
257
254
|
}
|
|
258
|
-
exports.CogStacJob = CogStacJob;
|
package/build/cog/cog.vrt.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LogType } from '@basemaps/shared';
|
|
2
|
-
import { Cutline } from './cutline';
|
|
3
|
-
import { CogJob } from './types';
|
|
2
|
+
import { Cutline } from './cutline.js';
|
|
3
|
+
import { CogJob } from './types.js';
|
|
4
4
|
export declare const CogVrt: {
|
|
5
5
|
/**
|
|
6
6
|
* Build a vrt file for a COG `name` that transforms the source imagery with a cutline
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cog.vrt.d.ts","sourceRoot":"","sources":["../../src/cog/cog.vrt.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"cog.vrt.d.ts","sourceRoot":"","sources":["../../src/cog/cog.vrt.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,OAAO,EAAa,MAAM,kBAAkB,CAAC;AAI3E,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAgEpC,eAAO,MAAM,MAAM;IACjB;;;;;;;;;;OAUG;wBAEU,MAAM,OACZ,MAAM,WACF,OAAO,QACV,MAAM,UACJ,OAAO,GACd,QAAQ,MAAM,GAAG,IAAI,CAAC;CAmD1B,CAAC"}
|