@basemaps/cli-raster 8.9.0 → 8.11.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.
Files changed (33) hide show
  1. package/build/cogify/cli/__test__/cli.cover.test.js +13 -0
  2. package/build/cogify/cli/__test__/cli.cover.test.js.map +1 -1
  3. package/build/cogify/cli/__test__/cli.topo.test.js +1 -0
  4. package/build/cogify/cli/__test__/cli.topo.test.js.map +1 -1
  5. package/build/cogify/cli/cli.charts.d.ts +0 -2
  6. package/build/cogify/cli/cli.charts.js +86 -44
  7. package/build/cogify/cli/cli.charts.js.map +1 -1
  8. package/build/cogify/cli/cli.cog.js +6 -5
  9. package/build/cogify/cli/cli.cog.js.map +1 -1
  10. package/build/cogify/cli/cli.cover.d.ts +4 -2
  11. package/build/cogify/cli/cli.cover.js +24 -3
  12. package/build/cogify/cli/cli.cover.js.map +1 -1
  13. package/build/cogify/cli/cli.topo.d.ts +6 -1
  14. package/build/cogify/cli/cli.topo.js +10 -2
  15. package/build/cogify/cli/cli.topo.js.map +1 -1
  16. package/build/cogify/cli.d.ts +6 -4
  17. package/build/cogify/covering/tile.cover.d.ts +6 -1
  18. package/build/cogify/covering/tile.cover.js +24 -8
  19. package/build/cogify/covering/tile.cover.js.map +1 -1
  20. package/build/cogify/gdal/gdal.command.d.ts +1 -1
  21. package/build/cogify/gdal/gdal.command.js +26 -10
  22. package/build/cogify/gdal/gdal.command.js.map +1 -1
  23. package/build/cogify/gdal/gdal.runner.js +1 -1
  24. package/build/cogify/gdal/gdal.runner.js.map +1 -1
  25. package/build/cogify/stac.d.ts +32 -18
  26. package/build/cogify/stac.js.map +1 -1
  27. package/build/cogify/topo/extract.js +4 -4
  28. package/build/cogify/topo/extract.js.map +1 -1
  29. package/build/preset.d.ts +67 -6
  30. package/build/preset.js +41 -0
  31. package/build/preset.js.map +1 -1
  32. package/dist/index.cjs +443 -113
  33. package/package.json +6 -6
package/dist/index.cjs CHANGED
@@ -4554,7 +4554,7 @@ var require_oneOf = __commonJS({
4554
4554
  Object.defineProperty(exports, "__esModule", { value: true });
4555
4555
  exports.oneOf = void 0;
4556
4556
  var util_1 = require("util");
4557
- function oneOf4(literals) {
4557
+ function oneOf3(literals) {
4558
4558
  const examples = literals.map((x) => (0, util_1.inspect)(x)).join(", ");
4559
4559
  return {
4560
4560
  async from(str) {
@@ -4567,7 +4567,7 @@ var require_oneOf = __commonJS({
4567
4567
  description: `One of ${examples}`
4568
4568
  };
4569
4569
  }
4570
- exports.oneOf = oneOf4;
4570
+ exports.oneOf = oneOf3;
4571
4571
  }
4572
4572
  });
4573
4573
 
@@ -75271,9 +75271,9 @@ var ulid2 = __toESM(require_index_umd(), 1);
75271
75271
  var CliInfo = {
75272
75272
  // Detect unlinked packages looks for this string since its a package name, slightly work around it
75273
75273
  package: "@basemaps/cli",
75274
- version: "v8.9.0",
75275
- hash: "55cd25b9f2c402fde88fcef9c43cec3f8eca9e60",
75276
- buildId: "17570995768-1"
75274
+ version: "v8.13.0",
75275
+ hash: "5a1984ab0e9b3939aab0db451d2f5e7aee1919af",
75276
+ buildId: "18264739226-1"
75277
75277
  };
75278
75278
  var CliDate = (/* @__PURE__ */ new Date()).toISOString();
75279
75279
  var CliId = ulid2.ulid();
@@ -79554,6 +79554,12 @@ var DefaultColorRampOutput = {
79554
79554
  // Taken from 0 of DefaultColorRamp
79555
79555
  background: { r: 172, g: 204, b: 226, alpha: 1 }
79556
79556
  };
79557
+ var DefaultBandExpandOutput = {
79558
+ title: "Gray",
79559
+ name: "expand",
79560
+ pipeline: [{ type: "color-ramp" }],
79561
+ background: { r: 255, g: 255, b: 255, alpha: 1 }
79562
+ };
79557
79563
 
79558
79564
  // ../config/build/config/tile.set.pipeline.js
79559
79565
  var ConfigImageFormatParser = z.union([
@@ -79563,15 +79569,39 @@ var ConfigImageFormatParser = z.union([
79563
79569
  z.literal("avif")
79564
79570
  ]);
79565
79571
  var ConfigResizeKernelParser = z.union([z.literal("nearest"), z.literal("lanczos3"), z.literal("lanczos2")]);
79566
- var ConfigTileSetPipelineParser = z.object({
79567
- /**
79568
- * type of pipeline function
79569
- *
79570
- * @example "terrain-rgb"
79571
- */
79572
- type: z.string()
79573
- // TODO allow custom arguments
79572
+ var ColorParser = z.object({
79573
+ r: z.number(),
79574
+ g: z.number(),
79575
+ b: z.number(),
79576
+ alpha: z.number()
79577
+ });
79578
+ var PipelineTerrainRgbParser = z.object({ type: z.literal("terrain-rgb") });
79579
+ var PipelineColorRampParser = z.object({ type: z.literal("color-ramp") });
79580
+ var PipelineNdviParser = z.object({
79581
+ type: z.literal("ndvi"),
79582
+ nir: z.number(),
79583
+ r: z.number(),
79584
+ alpha: z.number(),
79585
+ scale: z.object({
79586
+ nir: z.number(),
79587
+ r: z.number(),
79588
+ alpha: z.number()
79589
+ }).optional()
79574
79590
  });
79591
+ var PipelineExtractParser = z.object({
79592
+ type: z.literal("extract"),
79593
+ r: z.number(),
79594
+ g: z.number(),
79595
+ b: z.number(),
79596
+ alpha: z.number(),
79597
+ scale: ColorParser.optional()
79598
+ });
79599
+ var ConfigTileSetPipelineParser = z.discriminatedUnion("type", [
79600
+ PipelineExtractParser,
79601
+ PipelineTerrainRgbParser,
79602
+ PipelineColorRampParser,
79603
+ PipelineNdviParser
79604
+ ]);
79575
79605
  var ConfigRgbaParser = z.object({ r: z.number(), g: z.number(), b: z.number(), alpha: z.number() });
79576
79606
  var ConfigTileSetOutputParser = z.object({
79577
79607
  /**
@@ -79620,6 +79650,20 @@ var ConfigTileSetOutputParser = z.object({
79620
79650
  // ../config/build/memory/memory.config.js
79621
79651
  var import_ulid2 = __toESM(require_index_umd(), 1);
79622
79652
 
79653
+ // ../config/build/config/migration/imagery.js
79654
+ function migrateConfigImagery(img) {
79655
+ if (img.v === 2)
79656
+ return img;
79657
+ return {
79658
+ ...img,
79659
+ v: 2,
79660
+ title: img.title ?? img.name,
79661
+ bands: (img.bands ?? []).map((m) => {
79662
+ return { type: m };
79663
+ })
79664
+ };
79665
+ }
79666
+
79623
79667
  // ../config/build/name.convertor.js
79624
79668
  function fixChunkGsd(chunk) {
79625
79669
  if (!chunk.endsWith("m"))
@@ -79666,6 +79710,98 @@ function standardizeLayerName(name) {
79666
79710
  return output.join("-");
79667
79711
  }
79668
79712
 
79713
+ // ../config/build/memory/imagery.outputs.js
79714
+ function addDefaultOutputPipelines(ts, img) {
79715
+ if (ts.outputs != null)
79716
+ return ts.outputs;
79717
+ if (img.bands == null || img.bands.length === 0)
79718
+ return void 0;
79719
+ if (img.bands.length === 1) {
79720
+ if (img.bands[0].color === "gray")
79721
+ return [DefaultBandExpandOutput];
79722
+ return [DefaultTerrainRgbOutput, DefaultColorRampOutput];
79723
+ }
79724
+ const colors = { red: -1, green: -1, blue: -1, nir: -1, alpha: -1 };
79725
+ for (let i = 0; i < img.bands.length; i++) {
79726
+ const band = img.bands[i];
79727
+ if (band.color)
79728
+ colors[band.color] = i;
79729
+ }
79730
+ if (img.bands.length === 3 && colors.red >= 0 && colors.green >= 0 && colors.blue >= 0)
79731
+ return;
79732
+ if (img.bands.length === 4 && colors.red >= 0 && colors.green >= 0 && colors.blue >= 0 && colors.alpha >= 0)
79733
+ return;
79734
+ const pipelines = [];
79735
+ if (colors.red >= 0 && colors.green >= 0 && colors.blue >= 0) {
79736
+ const rgbExtract = {
79737
+ type: "extract",
79738
+ r: colors.red,
79739
+ g: colors.green,
79740
+ b: colors.blue,
79741
+ alpha: colors.alpha
79742
+ };
79743
+ const pipeline2 = { name: "rgb", title: "RGBA", pipeline: [rgbExtract] };
79744
+ rgbExtract.scale = getBandScales(img.bands, rgbExtract);
79745
+ pipelines.push(pipeline2);
79746
+ }
79747
+ if (colors.nir >= 0 && colors.red >= 0) {
79748
+ const ndviArgs = { type: "ndvi", r: colors.red, nir: colors.nir, alpha: colors.alpha };
79749
+ const scale = {
79750
+ r: getScale(img.bands[colors.red], "red"),
79751
+ nir: getScale(img.bands[colors.nir], "nir"),
79752
+ alpha: getAlphaScale(img.bands[colors.alpha])
79753
+ };
79754
+ if (scale.r && scale.nir && scale.alpha)
79755
+ ndviArgs.scale = scale;
79756
+ pipelines.push({
79757
+ name: "ndvi",
79758
+ title: "NDVI",
79759
+ pipeline: [ndviArgs]
79760
+ });
79761
+ }
79762
+ if (colors.red >= 0 && colors.green >= 0 && colors.nir >= 0) {
79763
+ const falseColorExtract = {
79764
+ type: "extract",
79765
+ r: colors.nir,
79766
+ g: colors.red,
79767
+ b: colors.green,
79768
+ alpha: colors.alpha
79769
+ };
79770
+ const pipeline2 = { name: "false-color", title: "FalseColor", pipeline: [falseColorExtract] };
79771
+ falseColorExtract.scale = getBandScales(img.bands, falseColorExtract);
79772
+ pipelines.push(pipeline2);
79773
+ }
79774
+ if (pipelines.length > 0)
79775
+ return pipelines;
79776
+ return void 0;
79777
+ }
79778
+ function getBandScales(bands, pipe) {
79779
+ const scale = {
79780
+ r: getScale(bands[pipe.r], "red"),
79781
+ g: getScale(bands[pipe.g], "green"),
79782
+ b: getScale(bands[pipe.b], "blue"),
79783
+ alpha: getAlphaScale(bands[pipe.alpha])
79784
+ };
79785
+ if (scale.r && scale.g && scale.b && scale.alpha)
79786
+ return scale;
79787
+ return void 0;
79788
+ }
79789
+ function getScale(band, color) {
79790
+ if (band.type === "uint8")
79791
+ return void 0;
79792
+ if (band.stats == null)
79793
+ return void 0;
79794
+ const stdDevs = color === "nir" ? 3 : 3;
79795
+ return Math.round(band.stats.mean + stdDevs * band.stats.stddev);
79796
+ }
79797
+ function getAlphaScale(band) {
79798
+ if (band.type === "uint8")
79799
+ return void 0;
79800
+ if (band.stats == null)
79801
+ return void 0;
79802
+ return Math.round(band.stats.max);
79803
+ }
79804
+
79669
79805
  // ../config/build/memory/memory.config.js
79670
79806
  function isConfigImagery(i) {
79671
79807
  return ConfigId.getPrefix(i.id) === ConfigPrefix.Imagery;
@@ -79769,14 +79905,14 @@ var ConfigProviderMemory = class _ConfigProviderMemory extends BasemapsConfigPro
79769
79905
  }
79770
79906
  toJson() {
79771
79907
  const cfg = {
79908
+ v: 2,
79772
79909
  id: "",
79773
79910
  hash: "",
79774
79911
  assets: this.assets,
79775
79912
  imagery: [],
79776
79913
  style: [],
79777
79914
  provider: [],
79778
- tileSet: [],
79779
- duplicateImagery: this.duplicateImagery
79915
+ tileSet: []
79780
79916
  };
79781
79917
  for (const val2 of this.objects.values()) {
79782
79918
  const prefix = val2.id.slice(0, val2.id.indexOf("_"));
@@ -79867,9 +80003,9 @@ var ConfigProviderMemory = class _ConfigProviderMemory extends BasemapsConfigPro
79867
80003
  };
79868
80004
  removeUndefined(existing);
79869
80005
  this.put(existing);
79870
- if (i.bands?.length === 1) {
79871
- existing.outputs = [DefaultTerrainRgbOutput, DefaultColorRampOutput];
79872
- }
80006
+ const outputs = addDefaultOutputPipelines(existing, i);
80007
+ if (outputs != null)
80008
+ existing.outputs = outputs;
79873
80009
  }
79874
80010
  const existingImageryId = existing.layers[0][i.projection];
79875
80011
  if (existingImageryId) {
@@ -79895,9 +80031,9 @@ var ConfigProviderMemory = class _ConfigProviderMemory extends BasemapsConfigPro
79895
80031
  background: { r: 0, g: 0, b: 0, alpha: 0 },
79896
80032
  updatedAt: Date.now()
79897
80033
  };
79898
- if (i.bands?.length === 1) {
79899
- ts.outputs = [DefaultTerrainRgbOutput, DefaultColorRampOutput];
79900
- }
80034
+ const outputs = addDefaultOutputPipelines(ts, i);
80035
+ if (outputs != null)
80036
+ ts.outputs = outputs;
79901
80037
  return ts;
79902
80038
  }
79903
80039
  /** Load a bundled configuration creating virtual tilesets for all imagery */
@@ -79912,8 +80048,10 @@ var ConfigProviderMemory = class _ConfigProviderMemory extends BasemapsConfigPro
79912
80048
  mem.put(st);
79913
80049
  for (const pv of cfg.provider)
79914
80050
  mem.put(pv);
79915
- for (const img of cfg.imagery)
79916
- mem.put(img);
80051
+ for (const img of cfg.imagery) {
80052
+ const parsed = migrateConfigImagery(img);
80053
+ mem.put(parsed);
80054
+ }
79917
80055
  const updatedAt = (0, import_ulid2.decodeTime)(ConfigId.unprefix(ConfigPrefix.ConfigBundle, cfg.id));
79918
80056
  for (const obj of mem.objects.values())
79919
80057
  obj.updatedAt = updatedAt;
@@ -81925,11 +82063,11 @@ var Bounds = class _Bounds {
81925
82063
 
81926
82064
  // ../geo/build/epsg.js
81927
82065
  var EpsgCode;
81928
- (function(EpsgCode4) {
81929
- EpsgCode4[EpsgCode4["Google"] = 3857] = "Google";
81930
- EpsgCode4[EpsgCode4["Wgs84"] = 4326] = "Wgs84";
81931
- EpsgCode4[EpsgCode4["Nztm2000"] = 2193] = "Nztm2000";
81932
- EpsgCode4[EpsgCode4["Citm2000"] = 3793] = "Citm2000";
82066
+ (function(EpsgCode3) {
82067
+ EpsgCode3[EpsgCode3["Google"] = 3857] = "Google";
82068
+ EpsgCode3[EpsgCode3["Wgs84"] = 4326] = "Wgs84";
82069
+ EpsgCode3[EpsgCode3["Nztm2000"] = 2193] = "Nztm2000";
82070
+ EpsgCode3[EpsgCode3["Citm2000"] = 3793] = "Citm2000";
81933
82071
  })(EpsgCode || (EpsgCode = {}));
81934
82072
  var EpsgText = {
81935
82073
  google: EpsgCode.Google,
@@ -86720,17 +86858,59 @@ var lzw = {
86720
86858
  overviewResampling: "bilinear"
86721
86859
  }
86722
86860
  };
86861
+ var zstd_17 = {
86862
+ name: "zstd_17",
86863
+ options: {
86864
+ blockSize: 512,
86865
+ compression: "zstd",
86866
+ predictor: 2,
86867
+ level: 17,
86868
+ warpResampling: "bilinear",
86869
+ overviewResampling: "lanczos"
86870
+ }
86871
+ };
86723
86872
  var Presets = {
86724
86873
  [webP.name]: webP,
86725
86874
  [webP80.name]: webP80,
86726
86875
  [lerc1mm.name]: lerc1mm,
86727
86876
  [lerc10mm.name]: lerc10mm,
86728
- [lzw.name]: lzw
86877
+ [lzw.name]: lzw,
86878
+ [zstd_17.name]: zstd_17
86879
+ };
86880
+ var BandPresets = {
86881
+ /**
86882
+ * 4 band image, generally [uint8,uint8,uint8,uint8]
86883
+ * - Red,Green,Blue,Alpha
86884
+ */
86885
+ rgba: ["red", "green", "blue", "alpha"],
86886
+ /**
86887
+ * 4 Band image, generally [uint8/16,uint8/16,uint8/16,uint8/16]
86888
+ * - Red,Green,Blue,Near Infrared
86889
+ */
86890
+ rgbi: ["red", "green", "blue", "nir", "alpha"],
86891
+ rgbna: ["red", "green", "blue", "nir", "alpha"],
86892
+ /**
86893
+ * One band image, generally [float32]
86894
+ */
86895
+ elevation: ["undefined"],
86896
+ /** One band image, generally 0-255 greyscale */
86897
+ hillshade: ["gray"]
86898
+ };
86899
+ var allPresets = Object.keys(BandPresets);
86900
+ var AllowedPresets = {
86901
+ // Webp is only suitable for RGB(A) images
86902
+ [webP.name]: ["rgba"],
86903
+ [webP80.name]: ["rgba"],
86904
+ [lerc1mm.name]: allPresets,
86905
+ [lerc10mm.name]: allPresets,
86906
+ [lzw.name]: allPresets,
86907
+ [zstd_17.name]: allPresets
86729
86908
  };
86730
86909
 
86731
86910
  // src/cogify/gdal/gdal.command.ts
86732
86911
  var isPowerOfTwo = (x) => (x & x - 1) === 0;
86733
- var DefaultTrimPixelRight = 1.7;
86912
+ var PixelTrimTop = 1;
86913
+ var PixelTrimRight = 4;
86734
86914
  function gdalBuildVrt(targetVrt, source, addalpha) {
86735
86915
  if (source.length === 0)
86736
86916
  throw new Error("No source files given for :" + targetVrt.href);
@@ -86751,8 +86931,6 @@ function gdalBuildVrtWarp(targetVrt, sourceVrt, sourceProjection, cutline, opt)
86751
86931
  args: [
86752
86932
  ["-of", "vrt"],
86753
86933
  // Output as a VRT
86754
- // ['-co', 'compress=lzw'],
86755
- // ['-co', 'bigtiff=yes'],
86756
86934
  "-multi",
86757
86935
  // Mutithread IO
86758
86936
  ["-wo", "NUM_THREADS=ALL_CPUS"],
@@ -86769,6 +86947,24 @@ function gdalBuildVrtWarp(targetVrt, sourceVrt, sourceProjection, cutline, opt)
86769
86947
  ].filter((f) => f != null).flat().map(String)
86770
86948
  };
86771
86949
  }
86950
+ function getCompressionArgs(cfg) {
86951
+ if (cfg.compression === "lerc") {
86952
+ return [
86953
+ ["-co", `MAX_Z_ERROR=${cfg.maxZError}`],
86954
+ ["-co", `MAX_Z_ERROR_OVERVIEW=${cfg.maxZErrorOverview}`]
86955
+ ];
86956
+ }
86957
+ if (cfg.compression === "zstd") {
86958
+ return [cfg.predictor ? ["-co", `PREDICTOR=${cfg.predictor}`] : [], ["-co", `LEVEL=${cfg.level}`]];
86959
+ }
86960
+ if (cfg.compression === "webp" || cfg.compression === "jpeg") {
86961
+ return [["-co", `QUALITY=${cfg.quality}`]];
86962
+ }
86963
+ if (cfg.compression === "lzw") {
86964
+ return [cfg.predictor ? ["-co", `PREDICTOR=${cfg.predictor}`] : []];
86965
+ }
86966
+ throw new Error("Unknown compression preset:" + String(cfg["compression"]));
86967
+ }
86772
86968
  function gdalBuildCog(targetTiff, sourceVrt, opt) {
86773
86969
  const cfg = { ...Presets[opt.preset], ...opt };
86774
86970
  const tileMatrix = TileMatrixSets.find(cfg.tileMatrix);
@@ -86789,8 +86985,6 @@ function gdalBuildCog(targetTiff, sourceVrt, opt) {
86789
86985
  ["-of", "COG"],
86790
86986
  ["-co", "NUM_THREADS=ALL_CPUS"],
86791
86987
  // Use all CPUS
86792
- ["--config", "GDAL_NUM_THREADS", "all_cpus"],
86793
- // Also required to NUM_THREADS till gdal 3.7.x
86794
86988
  ["-co", "BIGTIFF=IF_NEEDED"],
86795
86989
  // BigTiff is somewhat slower and most (All?) of the COGS should be well below 4GB
86796
86990
  ["-co", "ADD_ALPHA=YES"],
@@ -86800,16 +86994,15 @@ function gdalBuildCog(targetTiff, sourceVrt, opt) {
86800
86994
  */
86801
86995
  ["-co", "OVERVIEWS=IGNORE_EXISTING"],
86802
86996
  ["-co", `BLOCKSIZE=${cfg.blockSize}`],
86803
- // ['-co', 'RESAMPLING=cubic'],
86804
86997
  ["-co", `WARP_RESAMPLING=${cfg.warpResampling}`],
86805
86998
  ["-co", `OVERVIEW_RESAMPLING=${cfg.overviewResampling}`],
86806
86999
  ["-co", `COMPRESS=${cfg.compression}`],
86807
- cfg.quality ? ["-co", `QUALITY=${cfg.quality}`] : void 0,
86808
- cfg.maxZError ? ["-co", `MAX_Z_ERROR=${cfg.maxZError}`] : void 0,
86809
- cfg.maxZErrorOverview ? ["-co", `MAX_Z_ERROR_OVERVIEW=${cfg.maxZErrorOverview}`] : void 0,
87000
+ ...getCompressionArgs(cfg),
87001
+ cfg.presetBands ? ["-colorinterp", cfg.presetBands.join(",")] : void 0,
86810
87002
  ["-co", "SPARSE_OK=YES"],
86811
87003
  ["-co", `TARGET_SRS=${tileMatrix.projection.toEpsgString()}`],
86812
87004
  ["-co", `EXTENT=${tileExtent.join(",")},`],
87005
+ ["-stats"],
86813
87006
  ["-tr", targetResolution, targetResolution],
86814
87007
  urlToString(sourceVrt),
86815
87008
  urlToString(targetTiff)
@@ -86854,7 +87047,7 @@ function gdalBuildTopoRasterCommands(targetTiff, sourceVrt, opt, width, height)
86854
87047
  // Force stats (re)computation
86855
87048
  ["-of", "COG"],
86856
87049
  // Output format
86857
- ["-srcwin", "0", "0", `${width - DefaultTrimPixelRight}`, `${height}`],
87050
+ ["-srcwin", 0, PixelTrimTop, width - PixelTrimRight, height - PixelTrimTop],
86858
87051
  ["-a_srs", `EPSG:${opt.sourceEpsg}`],
86859
87052
  // https://gdal.org/en/latest/drivers/raster/cog.html#creation-options
86860
87053
  ["-co", "BIGTIFF=NO"],
@@ -86886,7 +87079,9 @@ function gdalBuildChartsCommand(target, source, cutline, tileMatrix) {
86886
87079
  "-multi",
86887
87080
  ["-wo", "NUM_THREADS=ALL_CPUS"],
86888
87081
  ["-t_srs", tileMatrix.projection.toEpsgString()],
86889
- "-dstalpha",
87082
+ ["-b", "1", "-b", "2", "-b", "3"],
87083
+ // Drop dummy band 4 if it exists
87084
+ ["-dstalpha"],
86890
87085
  ["-cutline", urlToString(cutline)],
86891
87086
  ["-crop_to_cutline"],
86892
87087
  ["-co", "BIGTIFF=NO"],
@@ -86903,7 +87098,7 @@ var import_events = require("events");
86903
87098
  var import_path = require("path");
86904
87099
  function getDockerContainer() {
86905
87100
  const containerPath = process.env["GDAL_DOCKER_CONTAINER"] ?? "ghcr.io/osgeo/gdal";
86906
- const tag = process.env["GDAL_DOCKER_CONTAINER_TAG"] ?? "ubuntu-small-3.8.0";
87101
+ const tag = process.env["GDAL_DOCKER_CONTAINER_TAG"] ?? "ubuntu-small-3.11.3";
86907
87102
  return `${containerPath}:${tag}`;
86908
87103
  }
86909
87104
  function toDockerArgs(cmd) {
@@ -87095,13 +87290,6 @@ var ChartsCreationCommand = (0, import_cmd_ts2.command)({
87095
87290
  long: "target",
87096
87291
  description: "Target location for the output files"
87097
87292
  }),
87098
- tileMatrix: (0, import_cmd_ts2.option)({
87099
- type: (0, import_cmd_ts2.oneOf)([Nztm2000QuadTms.identifier, GoogleTms.identifier]),
87100
- long: "tile-matrix",
87101
- description: `Output TileMatrix to use. Either: ${Nztm2000QuadTms.identifier}, or ${GoogleTms.identifier}.`,
87102
- defaultValue: () => GoogleTms.identifier,
87103
- defaultValueIsSerializable: true
87104
- }),
87105
87293
  cutline: (0, import_cmd_ts2.option)({
87106
87294
  type: UrlFolder,
87107
87295
  long: "cutline",
@@ -87129,9 +87317,6 @@ var ChartsCreationCommand = (0, import_cmd_ts2.command)({
87129
87317
  const logger = getLogger(this, args, "cli-raster");
87130
87318
  logger.info("Charts:Start");
87131
87319
  const files = args.source ? await Fsa.toArray(Fsa.list(args.source)) : args.paths;
87132
- const tileMatrix = TileMatrixSets.find(args.tileMatrix);
87133
- if (tileMatrix == null)
87134
- throw new Error(`Tile matrix ${args.tileMatrix} is not supported`);
87135
87320
  await (0, import_promises.mkdir)(tmpFolder, { recursive: true });
87136
87321
  const outputs = /* @__PURE__ */ new Set();
87137
87322
  const toProcess = files.map(
@@ -87150,39 +87335,15 @@ var ChartsCreationCommand = (0, import_cmd_ts2.command)({
87150
87335
  }
87151
87336
  const sourceTiff = await downloadCharts(file, filename, logger);
87152
87337
  const cutline = await downloadCutlines(new import_url2.URL(args.cutline.href), chartCode, logger);
87153
- logger.info({ file: file.href, tileMatrix: tileMatrix.identifier, chartCode }, "Charts:Processing");
87338
+ logger.info({ file: file.href, chartCode }, "Charts:Processing");
87154
87339
  const tiff = await new Tiff(Fsa.source(file)).init();
87155
87340
  const backUpUrl = new import_url2.URL(filename, args.backup);
87156
87341
  const metadata = await fetchMetadata(tiff, backUpUrl, logger);
87157
- const bufferedCutline = await prepareCutline(
87158
- cutline,
87159
- chartCode,
87160
- tileMatrix,
87161
- metadata.gsd,
87162
- args.bufferPixels,
87163
- logger
87164
- );
87165
- const { item, collection } = await createStacFiles(
87166
- chartCode,
87167
- tileMatrix,
87168
- metadata,
87169
- cutline,
87170
- bufferedCutline,
87171
- logger
87172
- );
87173
- logger.info({ file: file.href, chartCode, tileMatrix: tileMatrix.identifier }, "Charts:GdalBuildCharts");
87174
- const cogFile = new import_url2.URL(`${chartCode}-${tileMatrix.identifier}.tif`, tmpFolder);
87175
- await new GdalRunner(gdalBuildChartsCommand(cogFile, sourceTiff, bufferedCutline, tileMatrix)).run(logger);
87176
- const targetPath = new import_url2.URL(`${tileMatrix.projection.code}/${chartCode}/`, args.target);
87177
- logger.info({ file: file.href, target: targetPath.href }, "Charts:Uploading");
87342
+ const bufferedCutline = await prepareCutline(cutline, chartCode, metadata.gsd, args.bufferPixels, logger);
87343
+ const targetPath = new import_url2.URL(`${GoogleTms.projection.code}/${CliId}/${chartCode}/`, args.target);
87178
87344
  if (targetPath.protocol === "file:")
87179
87345
  await (0, import_promises.mkdir)(targetPath, { recursive: true });
87180
- const targetTiff = new import_url2.URL(filename, targetPath);
87181
- await Fsa.write(targetTiff, Fsa.readStream(cogFile));
87182
- const targetItem = new import_url2.URL(`${chartCode}.json`, targetPath);
87183
- await Fsa.write(targetItem, JSON.stringify(item, null, 2));
87184
- const targetCollection = new import_url2.URL("collection.json", targetPath);
87185
- await Fsa.write(targetCollection, JSON.stringify(collection, null, 2));
87346
+ await createCogs(sourceTiff, cutline, chartCode, bufferedCutline, metadata, targetPath, logger);
87186
87347
  outputs.add(urlToString(targetPath));
87187
87348
  await tiff.source.close?.();
87188
87349
  })
@@ -87215,17 +87376,17 @@ async function downloadCutlines(cutline, chartCode, logger) {
87215
87376
  }
87216
87377
  return new import_url2.URL(`${chartCode}.shp`, tmpFolder);
87217
87378
  }
87218
- async function prepareCutline(cutline, chartCode, tileMatrix, gsd, bufferPixels, logger) {
87379
+ async function prepareCutline(cutline, chartCode, gsd, bufferPixels, logger) {
87219
87380
  logger.info({ cutline: cutline.href, chartCode }, "Charts:WrapCutline");
87220
87381
  const wrappedCutline = new import_url2.URL(`${chartCode}-wrapped.shp`, tmpFolder);
87221
87382
  await new GdalRunner(wrapCutline(wrappedCutline, cutline)).run(logger);
87222
- logger.info({ cutline: cutline.href, chartCode, tileMatrix: tileMatrix.identifier }, "Charts:ReprojectCutline");
87223
- const reprojectedCutline = new import_url2.URL(`${chartCode}-${tileMatrix.identifier}.shp`, tmpFolder);
87224
- await new GdalRunner(reprojectCutline(reprojectedCutline, wrappedCutline, tileMatrix)).run(logger);
87383
+ logger.info({ cutline: cutline.href, chartCode, tileMatrix: GoogleTms.identifier }, "Charts:ReprojectCutline");
87384
+ const reprojectedCutline = new import_url2.URL(`${chartCode}-${GoogleTms.identifier}.shp`, tmpFolder);
87385
+ await new GdalRunner(reprojectCutline(reprojectedCutline, wrappedCutline, GoogleTms)).run(logger);
87225
87386
  logger.info({ cutline: cutline.href, chartCode, gsd, bufferPixels }, "Charts:BufferCutline");
87226
87387
  const bufferedCutline = new import_url2.URL(`${chartCode}-buffered.geojson`, tmpFolder);
87227
87388
  await new GdalRunner(
87228
- bufferCutline(bufferedCutline, reprojectedCutline, `${chartCode}-${tileMatrix.identifier}`, gsd, bufferPixels)
87389
+ bufferCutline(bufferedCutline, reprojectedCutline, `${chartCode}-${GoogleTms.identifier}`, gsd, bufferPixels)
87229
87390
  ).run(logger);
87230
87391
  return bufferedCutline;
87231
87392
  }
@@ -87276,9 +87437,9 @@ function geojsonToBbox(geojson) {
87276
87437
  throw new Error("No union found in GeoJSON features");
87277
87438
  return union2.toBbox();
87278
87439
  }
87279
- async function createStacFiles(chartCode, tileMatrix, metadata, sourceCutline, bufferedCutline, logger) {
87440
+ async function createStacItem(chartCode, metadata, sourceCutline, cutline, logger) {
87441
+ const geojson = await Fsa.readJson(cutline);
87280
87442
  logger.info({ chartCode }, "Charts:CreateStacItem");
87281
- const geojson = await Fsa.readJson(bufferedCutline);
87282
87443
  const item = {
87283
87444
  id: `${CliId}/${chartCode}`,
87284
87445
  type: "Feature",
@@ -87305,9 +87466,9 @@ async function createStacFiles(chartCode, tileMatrix, metadata, sourceCutline, b
87305
87466
  ],
87306
87467
  properties: {
87307
87468
  datetime: CliDate,
87308
- "proj:epsg": tileMatrix.projection.code,
87469
+ "proj:epsg": GoogleTms.projection.code,
87309
87470
  "linz_basemaps:options": {
87310
- tileMatrix: tileMatrix.identifier,
87471
+ tileMatrix: GoogleTms.identifier,
87311
87472
  sourceEpsg: metadata.epsg
87312
87473
  },
87313
87474
  "linz_basemaps:generated": {
@@ -87319,6 +87480,9 @@ async function createStacFiles(chartCode, tileMatrix, metadata, sourceCutline, b
87319
87480
  },
87320
87481
  assets: {}
87321
87482
  };
87483
+ return item;
87484
+ }
87485
+ function CreateStacCollection(chartCode, items, logger) {
87322
87486
  logger.info({ chartCode }, "Charts:CreateStacCollection");
87323
87487
  const collection = {
87324
87488
  id: CliId,
@@ -87327,21 +87491,73 @@ async function createStacFiles(chartCode, tileMatrix, metadata, sourceCutline, b
87327
87491
  stac_extensions: [],
87328
87492
  license: "CC-BY-4.0",
87329
87493
  title: `New Zealand Charts Mapsheets - ${chartCode}`,
87330
- description: `New Zealand Charts Mapsheets - ${chartCode} - ${tileMatrix.identifier}`,
87494
+ description: `New Zealand Charts Mapsheets - ${chartCode} - ${GoogleTms.identifier}`,
87331
87495
  extent: {
87332
- spatial: { bbox: [item.bbox] },
87496
+ spatial: { bbox: items.map((i) => i.bbox) },
87333
87497
  temporal: { interval: [[CliDate, null]] }
87334
87498
  },
87335
87499
  links: [
87336
87500
  { rel: "self", href: "./collection.json", type: "application/json" },
87337
- {
87501
+ ...items.map((item) => ({
87338
87502
  href: `./${item.id}.json`,
87339
87503
  rel: "item",
87340
87504
  type: "application/json"
87341
- }
87505
+ }))
87342
87506
  ]
87343
87507
  };
87344
- return { item, collection };
87508
+ for (const item of items) {
87509
+ collection.extent.spatial.bbox.push(item.bbox);
87510
+ }
87511
+ return collection;
87512
+ }
87513
+ async function createCogs(sourceTiff, sourceCutline, chartCode, bufferedCutline, metadata, targetPath, logger) {
87514
+ const geojson = await Fsa.readJson(bufferedCutline);
87515
+ let index = 0;
87516
+ const items = [];
87517
+ for (const feature of geojson.features) {
87518
+ if (feature.geometry.type === "Polygon") {
87519
+ const splitCutline = {
87520
+ type: "FeatureCollection",
87521
+ crs: { type: "name", properties: { name: "urn:ogc:def:crs:EPSG::3857" } },
87522
+ features: [feature]
87523
+ };
87524
+ const cutlineFile = new import_url2.URL(`cutline-${index}.geojson`, tmpFolder);
87525
+ await Fsa.write(cutlineFile, JSON.stringify(splitCutline));
87526
+ const item = await createStacItem(`${chartCode}-${index}`, metadata, sourceCutline, cutlineFile, logger);
87527
+ await Fsa.write(new import_url2.URL(`${chartCode}-${index}.json`, targetPath), JSON.stringify(item, null, 2));
87528
+ items.push(item);
87529
+ const cog = new import_url2.URL(`${chartCode}-${index}.tif`, tmpFolder);
87530
+ await new GdalRunner(gdalBuildChartsCommand(cog, sourceTiff, cutlineFile, GoogleTms)).run(logger);
87531
+ await Fsa.write(new import_url2.URL(`${chartCode}-${index}.tif`, targetPath), Fsa.readStream(cog));
87532
+ index++;
87533
+ } else if (feature.geometry.type === "MultiPolygon") {
87534
+ for (const coords of feature.geometry.coordinates) {
87535
+ const splitCutline = {
87536
+ type: "FeatureCollection",
87537
+ crs: { type: "name", properties: { name: "urn:ogc:def:crs:EPSG::3857" } },
87538
+ features: [
87539
+ {
87540
+ type: "Feature",
87541
+ geometry: { type: "Polygon", coordinates: coords }
87542
+ }
87543
+ ]
87544
+ };
87545
+ const cutlineFile = new import_url2.URL(`cutline-${index}.geojson`, tmpFolder);
87546
+ await Fsa.write(cutlineFile, JSON.stringify(splitCutline));
87547
+ const item = await createStacItem(`${chartCode}-${index}`, metadata, sourceCutline, cutlineFile, logger);
87548
+ await Fsa.write(new import_url2.URL(`${chartCode}-${index}.json`, targetPath), JSON.stringify(item, null, 2));
87549
+ items.push(item);
87550
+ const cog = new import_url2.URL(`${chartCode}-${index}.tif`, tmpFolder);
87551
+ await new GdalRunner(gdalBuildChartsCommand(cog, sourceTiff, cutlineFile, GoogleTms)).run(logger);
87552
+ await Fsa.write(new import_url2.URL(`${chartCode}-${index}.tif`, targetPath), Fsa.readStream(cog));
87553
+ index++;
87554
+ }
87555
+ } else {
87556
+ throw new Error("GeoJSON must contain Polygon or MultiPolygon geometries");
87557
+ }
87558
+ }
87559
+ const collection = CreateStacCollection(chartCode, items, logger);
87560
+ await Fsa.write(new import_url2.URL("collection.json", targetPath), JSON.stringify(collection, null, 2));
87345
87561
  }
87346
87562
 
87347
87563
  // ../config-loader/build/json/json.config.js
@@ -87511,8 +87727,15 @@ function ensureBandsSimilar(tiff, existingBands, newBands) {
87511
87727
  const bB = newBands[i];
87512
87728
  if (bA == null || bB == null)
87513
87729
  continue;
87514
- if (bA !== bB) {
87515
- throw new Error(`Band:${i} datatype mismatch: ${tiff.source.url.href} ${bA} vs ${bB}`);
87730
+ if (bA.type !== bB.type) {
87731
+ throw new Error(`Band:${i} datatype mismatch: ${tiff.source.url.href} ${bA.type} vs ${bB.type}`);
87732
+ }
87733
+ if (bA.stats == null && bB.stats) {
87734
+ bA.stats = bB.stats;
87735
+ } else if (bA.stats && bB.stats) {
87736
+ bA.stats.min = Math.min(bA.stats.min, bB.stats.min);
87737
+ bA.stats.max = Math.max(bA.stats.max, bB.stats.max);
87738
+ bA.stats.mean = (bA.stats.mean + bB.stats.mean) / 2;
87516
87739
  }
87517
87740
  }
87518
87741
  if (existingBands.length >= newBands.length)
@@ -87533,12 +87756,13 @@ async function computeTiffSummary(target, tiffs) {
87533
87756
  else if (res.projection !== epsg) {
87534
87757
  throw new Error(`ESPG projection mismatch on imagery ${res.projection} vs ${epsg} source: ${tiff.source.url.href}`);
87535
87758
  }
87536
- const [dataType, bitsPerSample, noData] = await Promise.all([
87759
+ const [dataType, bitsPerSample, noData, gdalMetadata] = await Promise.all([
87537
87760
  /** firstImage.fetch(TiffTag.Photometric), **/
87538
87761
  // TODO enable RGB detection
87539
87762
  firstImage.fetch(TiffTag.SampleFormat),
87540
87763
  firstImage.fetch(TiffTag.BitsPerSample),
87541
- firstImage.fetch(TiffTag.GdalNoData)
87764
+ firstImage.fetch(TiffTag.GdalNoData),
87765
+ firstImage.fetch(TiffTag.GdalMetadata)
87542
87766
  ]);
87543
87767
  if (bitsPerSample == null) {
87544
87768
  throw new Error(`Failed to extract band information from : ${tiff.source.url.href}`);
@@ -87550,8 +87774,9 @@ async function computeTiffSummary(target, tiffs) {
87550
87774
  for (let i = 0; i < bitsPerSample.length; i++) {
87551
87775
  const type = getDataType(dataType ? dataType[i] : SampleFormat.Uint);
87552
87776
  const bits = bitsPerSample[i];
87553
- imageBands.push(`${type}${bits}`);
87777
+ imageBands.push({ type: `${type}${bits}` });
87554
87778
  }
87779
+ parseGdalMetadata(gdalMetadata, imageBands);
87555
87780
  res.bands = ensureBandsSimilar(tiff, res.bands, imageBands);
87556
87781
  const imageNoData = noData ? Number(noData) : null;
87557
87782
  if (res.noData != null && imageNoData !== res.noData) {
@@ -87596,6 +87821,62 @@ async function computeTiffSummary(target, tiffs) {
87596
87821
  throw new Error(`Failed to extract imagery from: ${target.href}`);
87597
87822
  return res;
87598
87823
  }
87824
+ var MetadataSetter = {
87825
+ COLORINTERP: (val2, meta) => meta.color = val2.toLowerCase(),
87826
+ STATISTICS_MEAN: (val2, meta) => {
87827
+ meta.stats = meta.stats ?? { min: NaN, mean: NaN, max: NaN, stddev: NaN };
87828
+ meta.stats.mean = Number(val2);
87829
+ },
87830
+ STATISTICS_MAXIMUM: (val2, meta) => {
87831
+ meta.stats = meta.stats ?? { min: NaN, mean: NaN, max: NaN, stddev: NaN };
87832
+ meta.stats.max = Number(val2);
87833
+ },
87834
+ STATISTICS_MINIMUM: (val2, meta) => {
87835
+ meta.stats = meta.stats ?? { min: NaN, mean: NaN, max: NaN, stddev: NaN };
87836
+ meta.stats.min = Number(val2);
87837
+ },
87838
+ // Ignored
87839
+ STATISTICS_STDDEV: (val2, meta) => {
87840
+ meta.stats = meta.stats ?? { min: NaN, mean: NaN, max: NaN, stddev: NaN };
87841
+ meta.stats.stddev = Number(val2);
87842
+ },
87843
+ STATISTICS_VALIDPERCENT: () => {
87844
+ }
87845
+ };
87846
+ function parseGdalMetadata(dat, bands, log) {
87847
+ if (dat == null)
87848
+ return;
87849
+ const items = dat.split("\n").map((f) => f.trim()).filter((f) => f.startsWith("<Item"));
87850
+ for (const item of items) {
87851
+ const name = item.match(/name="([A-Z_]+)"/);
87852
+ if (name == null)
87853
+ continue;
87854
+ const sample = item.match(/sample="([0-9]+)"/);
87855
+ if (sample == null)
87856
+ continue;
87857
+ const value = item.match(/>(.*)<\/Item>/);
87858
+ if (value == null)
87859
+ continue;
87860
+ const sampleId = Number(sample[1]);
87861
+ if (isNaN(sampleId))
87862
+ continue;
87863
+ if (bands[sampleId] == null) {
87864
+ log?.warn({ sampleId }, "GdalMetadataParser:InvalidBand");
87865
+ return;
87866
+ }
87867
+ MetadataSetter[name[1]]?.(value[1], bands[sampleId]);
87868
+ if (MetadataSetter[name[1]] == null) {
87869
+ log?.debug({ gdalConfigName: name[1] }, "GdalMetadataParser:UnknownKey:" + name[1]);
87870
+ }
87871
+ }
87872
+ for (const band of bands) {
87873
+ if (band.stats == null)
87874
+ continue;
87875
+ if (isNaN(band.stats?.max) || isNaN(band.stats.min) || isNaN(band.stats.mean)) {
87876
+ delete band.stats;
87877
+ }
87878
+ }
87879
+ }
87599
87880
  function toRelative(base, other) {
87600
87881
  if (!other.href.startsWith(base.href))
87601
87882
  throw new Error("Paths are not relative");
@@ -87682,6 +87963,7 @@ async function initImageryFromTiffUrl(target, Q3, configCache, log) {
87682
87963
  const title = stac?.title ?? imageryName;
87683
87964
  const tileMatrix = params.projection === EpsgCode.Nztm2000 ? Nztm2000QuadTms : TileMatrixSets.tryGet(params.projection);
87684
87965
  const imagery = {
87966
+ v: 2,
87685
87967
  id: `im_${sha256base58(target.href)}`,
87686
87968
  name: imageryName,
87687
87969
  title,
@@ -87717,7 +87999,8 @@ async function initConfigFromUrls(provider, targets, concurrency = 25, configCac
87717
87999
  title: "Basemaps",
87718
88000
  category: "Basemaps",
87719
88001
  type: TileSetType.Raster,
87720
- layers: []
88002
+ layers: [],
88003
+ outputs: []
87721
88004
  };
87722
88005
  const elevationTileSet = {
87723
88006
  id: "ts_elevation",
@@ -87763,7 +88046,7 @@ function isRgbOrRgba(img) {
87763
88046
  if (img.bands.length > 4)
87764
88047
  return false;
87765
88048
  for (const b of img.bands) {
87766
- if (b !== "uint8")
88049
+ if (b.type !== "uint8")
87767
88050
  return false;
87768
88051
  }
87769
88052
  return true;
@@ -88618,7 +88901,11 @@ async function createCog(ctx) {
88618
88901
  if (tileMatrix == null)
88619
88902
  throw new Error("Failed to find tile matrix: " + options.tileMatrix);
88620
88903
  logger?.debug({ tileId }, "Cog:Create:VrtSource");
88621
- const vrtSourceCommand = gdalBuildVrt(new URL(`${tileId}-source.vrt`, ctx.tempFolder), ctx.sourceFiles);
88904
+ let addAlpha = false;
88905
+ if (options.presetBands?.includes("alpha") && options.presetBands.length > options.sourceBands.length) {
88906
+ addAlpha = true;
88907
+ }
88908
+ const vrtSourceCommand = gdalBuildVrt(new URL(`${tileId}-source.vrt`, ctx.tempFolder), ctx.sourceFiles, addAlpha);
88622
88909
  await new GdalRunner(vrtSourceCommand).run(logger);
88623
88910
  logger?.debug({ tileId }, "Cog:Create:VrtWarp");
88624
88911
  const cutlineProperties = { url: null, blend: ctx.cutline.blend };
@@ -88648,10 +88935,11 @@ async function createCog(ctx) {
88648
88935
  }
88649
88936
  const gdalCreateCommand = gdalCreate(new URL(`${tileId}-bg.tiff`, ctx.tempFolder), options.background, options);
88650
88937
  await new GdalRunner(gdalCreateCommand).run(logger);
88651
- const vrtMergeCommand = gdalBuildVrt(new URL(`${tileId}-merged.vrt`, ctx.tempFolder), [
88652
- gdalCreateCommand.output,
88653
- vrtWarpCommand.output
88654
- ]);
88938
+ const vrtMergeCommand = gdalBuildVrt(
88939
+ new URL(`${tileId}-merged.vrt`, ctx.tempFolder),
88940
+ [gdalCreateCommand.output, vrtWarpCommand.output],
88941
+ false
88942
+ );
88655
88943
  await new GdalRunner(vrtMergeCommand).run(logger);
88656
88944
  const cogCreateCommand = gdalBuildCog(new URL(`${tileId}.tiff`, ctx.tempFolder), vrtMergeCommand.output, options);
88657
88945
  await new GdalRunner(cogCreateCommand).run(logger);
@@ -88841,10 +89129,16 @@ function getTargetBaseZoom(tileMatrix, resolution, targetZoomOffset) {
88841
89129
  return Projection.getTiffResZoom(tileMatrix, resolution);
88842
89130
  return Projection.getTiffResZoom(tileMatrix, resolution) + targetZoomOffset;
88843
89131
  }
89132
+ var TargetZoomOffset = {
89133
+ zstd_17: 6,
89134
+ lzw: 6
89135
+ };
88844
89136
  async function createTileCover(ctx) {
88845
89137
  await ProjectionLoader.load(ctx.imagery.projection);
89138
+ await ProjectionLoader.load(EpsgCode.Wgs84);
88846
89139
  const targetBaseZoom = getTargetBaseZoom(ctx.tileMatrix, ctx.imagery.gsd, ctx.targetZoomOffset);
88847
- const optimalCoveringZoom = Math.max(1, targetBaseZoom - 7);
89140
+ const targetZoomOffset = TargetZoomOffset[ctx.preset] ?? 7;
89141
+ const optimalCoveringZoom = Math.max(1, targetBaseZoom - targetZoomOffset);
88848
89142
  ctx.logger?.debug({ targetBaseZoom, cogOverZoom: optimalCoveringZoom }, "Imagery:ZoomLevel");
88849
89143
  const sourceBounds = projectPolygon(
88850
89144
  polygonFromBounds(ctx.imagery.files),
@@ -88881,8 +89175,10 @@ async function createTileCover(ctx) {
88881
89175
  for (const tile of covering) {
88882
89176
  const bounds = ctx.tileMatrix.tileToSourceBounds(tile);
88883
89177
  const scaledBounds = bounds.scaleFromCenter(1.05);
88884
- const tileBounds = Projection.get(ctx.tileMatrix).projectMultipolygon(
88885
- [scaledBounds.toPolygon()],
89178
+ const projection = Projection.get(ctx.tileMatrix);
89179
+ const wsg84Bounds = multiPolygonToWgs84([scaledBounds.toPolygon()], projection.toWgs84, true);
89180
+ const tileBounds = Projection.get(EpsgCode.Wgs84).projectMultipolygon(
89181
+ wsg84Bounds,
88886
89182
  Projection.get(ctx.imagery.projection)
88887
89183
  );
88888
89184
  const source = imageryBounds.filter((f) => intersection(tileBounds, f.polygon).length > 0);
@@ -88909,9 +89205,11 @@ async function createTileCover(ctx) {
88909
89205
  "linz_basemaps:options": {
88910
89206
  preset: ctx.preset,
88911
89207
  ...Presets[ctx.preset].options,
89208
+ presetBands: ctx.presetBands,
88912
89209
  tile,
88913
89210
  tileMatrix: ctx.tileMatrix.identifier,
88914
89211
  sourceEpsg: ctx.imagery.projection,
89212
+ sourceBands: ctx.imagery.bands,
88915
89213
  zoomLevel: targetBaseZoom
88916
89214
  },
88917
89215
  "linz_basemaps:generated": {
@@ -89027,6 +89325,11 @@ var BasemapsCogifyCoverCommand = (0, import_cmd_ts4.command)({
89027
89325
  defaultValue: () => "webp",
89028
89326
  defaultValueIsSerializable: true
89029
89327
  }),
89328
+ presetBand: (0, import_cmd_ts4.option)({
89329
+ type: (0, import_cmd_ts4.optional)((0, import_cmd_ts4.oneOf)(Object.keys(BandPresets))),
89330
+ long: "preset-bands",
89331
+ description: "Tell GDAL what the bands in the source image represent see `-colorinterp` in GDAL"
89332
+ }),
89030
89333
  tileMatrix: (0, import_cmd_ts4.option)({
89031
89334
  type: import_cmd_ts4.string,
89032
89335
  long: "tile-matrix",
@@ -89052,6 +89355,9 @@ var BasemapsCogifyCoverCommand = (0, import_cmd_ts4.command)({
89052
89355
  async handler(args) {
89053
89356
  const metrics = new Metrics();
89054
89357
  const logger = getLogger(this, args, "cli-raster");
89358
+ if (args.presetBand != null && !AllowedPresets[args.preset].includes(args.presetBand)) {
89359
+ throw new Error(`Preset ${args.preset} does not support band option ${args.presetBand}`);
89360
+ }
89055
89361
  const mem = new ConfigProviderMemory();
89056
89362
  metrics.start("imagery:load");
89057
89363
  const cfg = await initConfigFromUrls(mem, args.paths);
@@ -89060,6 +89366,21 @@ var BasemapsCogifyCoverCommand = (0, import_cmd_ts4.command)({
89060
89366
  throw new Error("No imagery found");
89061
89367
  const im = cfg.imagery[0];
89062
89368
  logger.info({ files: im.files.length, title: im.title, duration: imageryLoadTime }, "Imagery:Loaded");
89369
+ if (args.presetBand != null && im.bands != null) {
89370
+ const bandList = BandPresets[args.presetBand];
89371
+ if (bandList && im.bands.length !== bandList.length) {
89372
+ if (bandList.includes("alpha") && im.bands.length === bandList.length - 1) {
89373
+ logger.warn(
89374
+ { title: im.title, bands: im.bands.length, expectedBands: bandList.length },
89375
+ `Imagery:Bands:MissingAlpha - Adding alpha to source`
89376
+ );
89377
+ } else {
89378
+ throw new Error(
89379
+ `Imagery has ${im.bands.length} bands, preset ${args.presetBand} requires ${bandList.join(", ")}`
89380
+ );
89381
+ }
89382
+ }
89383
+ }
89063
89384
  if (im.collection == null && args.requireStacCollection) {
89064
89385
  throw new Error(`No collection.json found with imagery: ${im.url.href}`);
89065
89386
  }
@@ -89081,6 +89402,7 @@ var BasemapsCogifyCoverCommand = (0, import_cmd_ts4.command)({
89081
89402
  metrics,
89082
89403
  cutline,
89083
89404
  preset: args.preset,
89405
+ presetBands: BandPresets[args.presetBand] ?? void 0,
89084
89406
  background: args.background,
89085
89407
  targetZoomOffset: args.baseZoomOffset
89086
89408
  };
@@ -89169,12 +89491,12 @@ function extractBoundsFromTiff(tiff, logger) {
89169
89491
  }
89170
89492
  var GeotagToEpsgCode = {
89171
89493
  // global
89172
- "Universal Transverse Mercator Zone": 4326,
89494
+ "Universal Transverse Mercator Zone": EpsgCode.Wgs84,
89173
89495
  // antarctic
89174
89496
  "McMurdo Sound Lambert Conformal 2000": 5479,
89175
89497
  // new zealand
89176
- "Chatham Islands Transverse Mercator 2000": 2193,
89177
- "New Zealand Transverse Mercator 2000": 3793,
89498
+ "New Zealand Transverse Mercator 2000": EpsgCode.Nztm2000,
89499
+ "Chatham Islands Transverse Mercator 2000": EpsgCode.Citm2000,
89178
89500
  // new zealand offshore islands
89179
89501
  "Auckland Islands Transverse Mercator": 3788,
89180
89502
  "Campbell Island Transverse Mercator": 3789,
@@ -89484,6 +89806,7 @@ async function writeStacFiles(target, items, collection, logger) {
89484
89806
 
89485
89807
  // src/cogify/cli/cli.topo.ts
89486
89808
  var Q2 = pLimit(10);
89809
+ var Format = ["gridded", "gridless"];
89487
89810
  var MapSeries = ["topo25", "topo50", "topo250"];
89488
89811
  var MapSeriesTitle = {
89489
89812
  topo25: "Raster Topographic Maps 25k",
@@ -89509,7 +89832,12 @@ var TopoStacCreationCommand = (0, import_cmd_ts5.command)({
89509
89832
  mapSeries: (0, import_cmd_ts5.option)({
89510
89833
  type: (0, import_cmd_ts5.oneOf)(MapSeries),
89511
89834
  long: "map-series",
89512
- description: `Map series name. Either ${MapSeries.join(", ")}`
89835
+ description: `Map series scale. Either ${MapSeries.join(", ")}`
89836
+ }),
89837
+ format: (0, import_cmd_ts5.option)({
89838
+ type: (0, import_cmd_ts5.oneOf)(Format),
89839
+ long: "format",
89840
+ description: `Map sheet format. Either ${Format.join(", ")}`
89513
89841
  }),
89514
89842
  latestOnly: (0, import_cmd_ts5.flag)({
89515
89843
  type: import_cmd_ts5.boolean,
@@ -89533,6 +89861,7 @@ var TopoStacCreationCommand = (0, import_cmd_ts5.command)({
89533
89861
  const startTime = performance.now();
89534
89862
  logger.info("TopoCogify:Start");
89535
89863
  const mapSeries = args.mapSeries;
89864
+ const format = args.format;
89536
89865
  const title = args.title ?? MapSeriesTitle[mapSeries];
89537
89866
  const ctx = {
89538
89867
  latestOnly: args.latestOnly,
@@ -89540,6 +89869,7 @@ var TopoStacCreationCommand = (0, import_cmd_ts5.command)({
89540
89869
  target: args.target,
89541
89870
  title,
89542
89871
  mapSeries,
89872
+ format,
89543
89873
  output: args.output,
89544
89874
  logger
89545
89875
  };
@@ -89583,7 +89913,7 @@ async function loadTiffsToCreateStacs(ctx) {
89583
89913
  const epsgDirectoryPaths = [];
89584
89914
  const stacItemPaths = [];
89585
89915
  const mapSeries = ctx.mapSeries;
89586
- const resolution = "gridless_600dpi";
89916
+ const resolution = `${ctx.format}_600dpi`;
89587
89917
  for (const [epsg, tiffItems] of allTiffItems.entries()) {
89588
89918
  logger?.info({ epsg }, "CreateStacFiles:Start");
89589
89919
  const latestTiffItems = extractLatestTiffItemsByMapCode(tiffItems);