From 9cf6e2f6a14dc059e4afa62e103f5cd146297597 Mon Sep 17 00:00:00 2001 From: Wentao Kuang Date: Mon, 23 Dec 2024 11:20:36 +1300 Subject: [PATCH] Some refinements --- packages/cogify/src/cogify/cli/cli.config.ts | 2 +- packages/cogify/src/cogify/cli/cli.cover.ts | 11 +++-------- packages/cogify/src/cogify/gdal.command.ts | 10 +++++----- packages/cogify/src/cogify/parsers.ts | 4 ++-- packages/cogify/src/cogify/stac.ts | 4 ++-- packages/cogify/src/tile.cover.ts | 4 ++-- packages/config-loader/src/json/json.config.ts | 2 +- packages/config-loader/src/json/tiff.config.ts | 6 ++---- packages/config/src/color.ts | 4 ++-- packages/config/src/index.ts | 2 +- packages/server/src/config.ts | 2 +- 11 files changed, 22 insertions(+), 29 deletions(-) diff --git a/packages/cogify/src/cogify/cli/cli.config.ts b/packages/cogify/src/cogify/cli/cli.config.ts index 1c5f3fa83..6e1f35b9a 100644 --- a/packages/cogify/src/cogify/cli/cli.config.ts +++ b/packages/cogify/src/cogify/cli/cli.config.ts @@ -49,7 +49,7 @@ export const BasemapsCogifyConfigCommand = command({ const q = pLimit(args.concurrency); metrics.start('imagery:load'); - const im = await initImageryFromTiffUrl(args.path, q, undefined, undefined, logger); + const im = await initImageryFromTiffUrl(args.path, q, undefined, logger); const ts = ConfigProviderMemory.imageryToTileSet(im) as ConfigTileSetRaster; provider.put(im); metrics.end('imagery:load'); diff --git a/packages/cogify/src/cogify/cli/cli.cover.ts b/packages/cogify/src/cogify/cli/cli.cover.ts index cf606bae0..b13b6d0d3 100644 --- a/packages/cogify/src/cogify/cli/cli.cover.ts +++ b/packages/cogify/src/cogify/cli/cli.cover.ts @@ -11,7 +11,7 @@ import { CutlineOptimizer } from '../../cutline.js'; import { getLogger, logArguments } from '../../log.js'; import { Presets } from '../../preset.js'; import { createTileCover, TileCoverContext } from '../../tile.cover.js'; -import { Rgba, Url, UrlFolder } from '../parsers.js'; +import { RgbaType, Url, UrlFolder } from '../parsers.js'; import { createFileStats } from '../stac.js'; const SupportedTileMatrix = [GoogleTms, Nztm2000QuadTms]; @@ -62,13 +62,8 @@ export const BasemapsCogifyCoverCommand = command({ defaultValue: () => false, defaultValueIsSerializable: true, }), - name: option({ - type: optional(string), - long: 'name', - description: 'Define the name of the output imagery', - }), background: option({ - type: optional(Rgba), + type: optional(RgbaType), long: 'background', description: 'Replace all transparent COG pixels with this RGBA hexstring color', }), @@ -79,7 +74,7 @@ export const BasemapsCogifyCoverCommand = command({ const mem = new ConfigProviderMemory(); metrics.start('imagery:load'); - const cfg = await initConfigFromUrls(mem, args.paths, args.name); + const cfg = await initConfigFromUrls(mem, args.paths); const imageryLoadTime = metrics.end('imagery:load'); if (cfg.imagery.length === 0) throw new Error('No imagery found'); const im = cfg.imagery[0]; diff --git a/packages/cogify/src/cogify/gdal.command.ts b/packages/cogify/src/cogify/gdal.command.ts index b2244a95d..ae61833c0 100644 --- a/packages/cogify/src/cogify/gdal.command.ts +++ b/packages/cogify/src/cogify/gdal.command.ts @@ -1,4 +1,4 @@ -import { RGBA } from '@basemaps/config'; +import { Rgba } from '@basemaps/config'; import { Epsg, EpsgCode, TileMatrixSets } from '@basemaps/geo'; import { urlToString } from '@basemaps/shared'; @@ -6,6 +6,8 @@ import { Presets } from '../preset.js'; import { GdalCommand } from './gdal.runner.js'; import { CogifyCreationOptions } from './stac.js'; +const isPowerOfTwo = (x: number): boolean => (x & (x - 1)) === 0; + export function gdalBuildVrt(targetVrt: URL, source: URL[]): GdalCommand { if (source.length === 0) throw new Error('No source files given for :' + targetVrt.href); return { @@ -109,7 +111,7 @@ export function gdalBuildCog(targetTiff: URL, sourceVrt: URL, opt: CogifyCreatio * * @returns a 'gdal_create' GdalCommand object */ -export function gdalCreate(targetTiff: URL, color: RGBA, opt: CogifyCreationOptions): GdalCommand { +export function gdalCreate(targetTiff: URL, color: Rgba, opt: CogifyCreationOptions): GdalCommand { const cfg = { ...Presets[opt.preset], ...opt }; const tileMatrix = TileMatrixSets.find(cfg.tileMatrix); @@ -120,9 +122,7 @@ export function gdalCreate(targetTiff: URL, color: RGBA, opt: CogifyCreationOpti const size = Math.round(bounds.width / pixelScale); // if the value of 'size' is not a power of 2 - if ((Math.log(size) / Math.log(size)) % 1 !== 0) { - throw new Error('Size did not compute to a power of 2'); - } + if (!isPowerOfTwo(size)) throw new Error('Size did not compute to a power of 2'); return { command: 'gdal_create', diff --git a/packages/cogify/src/cogify/parsers.ts b/packages/cogify/src/cogify/parsers.ts index c4b1234c7..de06d21c1 100644 --- a/packages/cogify/src/cogify/parsers.ts +++ b/packages/cogify/src/cogify/parsers.ts @@ -1,6 +1,6 @@ import { pathToFileURL } from 'node:url'; -import { parseRgba, RGBA } from '@basemaps/config'; +import { parseRgba, Rgba } from '@basemaps/config'; import { fsa } from '@basemaps/shared'; import { Type } from 'cmd-ts'; @@ -9,7 +9,7 @@ import { Type } from 'cmd-ts'; * * Throws an error if the RGBA hexstring is invalid. **/ -export const Rgba: Type = { +export const RgbaType: Type = { from(str) { return Promise.resolve(parseRgba(str)); }, diff --git a/packages/cogify/src/cogify/stac.ts b/packages/cogify/src/cogify/stac.ts index fc83d6f25..d21f0f9cd 100644 --- a/packages/cogify/src/cogify/stac.ts +++ b/packages/cogify/src/cogify/stac.ts @@ -1,6 +1,6 @@ import { createHash } from 'node:crypto'; -import { RGBA } from '@basemaps/config'; +import { Rgba } from '@basemaps/config'; import { Tile } from '@basemaps/geo'; import { StacCollection, StacItem, StacLink } from 'stac-ts'; @@ -59,7 +59,7 @@ export interface CogifyCreationOptions { overviewResampling?: GdalResampling; /** Color with which to replace all transparent COG pixels */ - background?: RGBA; + background?: Rgba; } export type GdalResampling = 'nearest' | 'bilinear' | 'cubic' | 'cubicspline' | 'lanczos' | 'average' | 'mode'; diff --git a/packages/cogify/src/tile.cover.ts b/packages/cogify/src/tile.cover.ts index 7bc9622af..1115ad98a 100644 --- a/packages/cogify/src/tile.cover.ts +++ b/packages/cogify/src/tile.cover.ts @@ -1,4 +1,4 @@ -import { RGBA } from '@basemaps/config'; +import { Rgba } from '@basemaps/config'; import { ConfigImageryTiff } from '@basemaps/config-loader'; import { BoundingBox, Bounds, EpsgCode, Projection, ProjectionLoader, TileId, TileMatrixSet } from '@basemaps/geo'; import { fsa, LogType, urlToString } from '@basemaps/shared'; @@ -34,7 +34,7 @@ export interface TileCoverContext { /** GDAL configuration preset */ preset: string; /** Optional color with which to replace all transparent COG pixels */ - background?: RGBA; + background?: Rgba; /** * Override the base zoom to store the output COGS as */ diff --git a/packages/config-loader/src/json/json.config.ts b/packages/config-loader/src/json/json.config.ts index 5ff5444b9..c328583b9 100644 --- a/packages/config-loader/src/json/json.config.ts +++ b/packages/config-loader/src/json/json.config.ts @@ -274,7 +274,7 @@ export class ConfigJson { const id = ConfigId.prefix(ConfigPrefix.Imagery, imageId); this.logger.trace({ url: url.href, imageId: id }, 'Imagery:Fetch'); - const img = await initImageryFromTiffUrl(url, this.Q, undefined, this.imageryConfigCache, this.logger); + const img = await initImageryFromTiffUrl(url, this.Q, this.imageryConfigCache, this.logger); img.id = id; // TODO could we use img.collection.id for this? // TODO should we be overwriting the name and title when it is loaded from the STAC metadata? diff --git a/packages/config-loader/src/json/tiff.config.ts b/packages/config-loader/src/json/tiff.config.ts index d48d8bd86..9f3686375 100644 --- a/packages/config-loader/src/json/tiff.config.ts +++ b/packages/config-loader/src/json/tiff.config.ts @@ -346,7 +346,6 @@ export async function loadTiffsFromPaths(sourceFiles: URL[], Q: LimitFunction): export async function initImageryFromTiffUrl( target: URL, Q: LimitFunction, - name?: string, configCache?: URL, log?: LogType, ): Promise { @@ -365,7 +364,7 @@ export async function initImageryFromTiffUrl( if (stac == null) log?.warn({ target: target }, 'Tiff:StacNotFound'); const params = await computeTiffSummary(target, tiffs); - const imageryName = name ? name : getImageryName(target); + const imageryName = getImageryName(target); const title = stac?.title ?? imageryName; const tileMatrix = params.projection === EpsgCode.Nztm2000 ? Nztm2000QuadTms : TileMatrixSets.tryGet(params.projection); @@ -437,7 +436,6 @@ export async function initImageryFromTiffUrl( export async function initConfigFromUrls( provider: ConfigProviderMemory, targets: URL[], - name?: string, concurrency = 25, configCache?: URL, log?: LogType, @@ -445,7 +443,7 @@ export async function initConfigFromUrls( const q = pLimit(concurrency); const imageryConfig: Promise[] = []; - for (const target of targets) imageryConfig.push(initImageryFromTiffUrl(target, q, name, configCache, log)); + for (const target of targets) imageryConfig.push(initImageryFromTiffUrl(target, q, configCache, log)); const aerialTileSet: ConfigTileSetRaster = { id: 'ts_aerial', diff --git a/packages/config/src/color.ts b/packages/config/src/color.ts index 680cd2f27..fc274c109 100644 --- a/packages/config/src/color.ts +++ b/packages/config/src/color.ts @@ -11,7 +11,7 @@ export function parseHex(str: string): number { return val; } -export interface RGBA { +export interface Rgba { r: number; g: number; b: number; @@ -24,7 +24,7 @@ export interface RGBA { * Defaults to 0 if missing values * @param str string to parse */ -export function parseRgba(str: string): RGBA { +export function parseRgba(str: string): Rgba { if (str.startsWith('0x')) str = str.slice(2); else if (str.startsWith('#')) str = str.slice(1); if (str.length !== 6 && str.length !== 8) { diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index 95a40b13f..7f684234a 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -7,7 +7,7 @@ export { } from './base.config.js'; export { base58, isBase58 } from './base58.js'; export { ensureBase58, sha256base58 } from './base58.node.js'; -export { parseHex, parseRgba, RGBA } from './color.js'; +export { parseHex, parseRgba, Rgba } from './color.js'; export { ConfigBase as BaseConfig } from './config/base.js'; export { ConfigBundle } from './config/config.bundle.js'; export { ConfigImagery, ConfigImageryOverview, ImageryBandType, ImageryDataType } from './config/imagery.js'; diff --git a/packages/server/src/config.ts b/packages/server/src/config.ts index 46147f497..7e3e9e8db 100644 --- a/packages/server/src/config.ts +++ b/packages/server/src/config.ts @@ -29,7 +29,7 @@ export async function loadConfig(opts: ServerOptions, logger: LogType): Promise< // Load the config directly from the source tiff files if ('paths' in opts) { const mem = new ConfigProviderMemory(); - const ret = await initConfigFromUrls(mem, opts.paths, undefined, TiffLoadConcurrency, opts.configCache, logger); + const ret = await initConfigFromUrls(mem, opts.paths, TiffLoadConcurrency, opts.configCache, logger); for (const ts of ret.tileSets) { logger.info( { tileSet: ts.name, layers: ts.layers.length, outputs: ts.outputs?.map((f) => f.name) },