Skip to content

Commit

Permalink
feat(tiler-sharp): support uint32 and uint8 source datasets
Browse files Browse the repository at this point in the history
  • Loading branch information
blacha committed Jan 21, 2025
1 parent 46f8fb8 commit 76d8ad1
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 19 deletions.
4 changes: 2 additions & 2 deletions packages/lambda-tiler/src/cli/render.tile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { extname } from 'path';
import { TileXyzRaster } from '../routes/tile.xyz.raster.js';

// Render configuration
const source = fsa.toUrl(`/home/blacha/data/elevation/christchurch_2020-2021/`);
const tile = fromPath('/14/7898/8615.webp');
const source = fsa.toUrl(`/home/blacha/data/nz-elevation/hillshade`);
const tile = fromPath('/9/250/256.png');
const pipeline: string | null = 'color-ramp';
let tileMatrix: TileMatrixSet | null = null;

Expand Down
38 changes: 28 additions & 10 deletions packages/tiler-sharp/src/pipeline/decompressor.lerc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,41 @@ export const LercDecompressor: Decompressor = {
await Lerc.load();
const bytes = Lerc.decode(tile);

if (bytes.pixelType !== 'F32') {
throw new Error(`Lerc: Invalid output pixelType:${bytes.pixelType} from:${source.source.url.href}`);
}
if (bytes.depthCount !== 1) {
throw new Error(`Lerc: Invalid output depthCount:${bytes.depthCount} from:${source.source.url.href}`);
}
if (bytes.pixels.length !== 1) {
throw new Error(`Lerc: Invalid output bandCount:${bytes.pixels.length} from:${source.source.url.href}`);
}

return {
pixels: bytes.pixels[0] as Float32Array,
width: bytes.width,
height: bytes.height,
channels: 1,
depth: 'float32',
};
switch (bytes.pixelType) {
case 'F32':
return {
pixels: bytes.pixels[0] as Float32Array,
width: bytes.width,
height: bytes.height,
channels: 1,
depth: 'float32',
};
case 'U32':
return {
pixels: bytes.pixels[0] as Uint32Array,
width: bytes.width,
height: bytes.height,
channels: 1,
depth: 'uint32',
};
case 'U8':
return {
pixels: bytes.pixels[0] as Uint8Array,
width: bytes.width,
height: bytes.height,
channels: 1,
depth: 'uint8',
};
}

throw new Error(`Lerc: Invalid output pixelType:${bytes.pixelType} from:${source.source.url.href}`);
},
};

Expand Down
13 changes: 12 additions & 1 deletion packages/tiler-sharp/src/pipeline/decompressor.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { CompositionTiff } from '@basemaps/tiler';
import { Tiff } from '@cogeotiff/core';

export interface DecompressedInterleavedUint32 {
pixels: Uint32Array;
depth: 'uint32';
channels: number;
width: number;
height: number;
}

export interface DecompressedInterleavedFloat {
pixels: Float32Array;
depth: 'float32';
Expand All @@ -18,7 +26,10 @@ export interface DecompressedInterleavedUint8 {
}

// One buffer containing all bands
export type DecompressedInterleaved = DecompressedInterleavedFloat | DecompressedInterleavedUint8;
export type DecompressedInterleaved =
| DecompressedInterleavedFloat
| DecompressedInterleavedUint8
| DecompressedInterleavedUint32;

export interface Decompressor {
type: 'image/webp' | 'application/lerc';
Expand Down
8 changes: 7 additions & 1 deletion packages/tiler-sharp/src/pipeline/pipeline.color.ramp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ export class ColorRamp {
}
}

export const ramp = new ColorRamp(DefaultColorRamp);
export const Ramps: Record<DecompressedInterleaved['depth'], ColorRamp> = {
float32: new ColorRamp(DefaultColorRamp),
uint8: new ColorRamp(`0 0 0 0 255\n255 255 255 255 255`),
uint32: new ColorRamp(`0 0 0 0 255\n${2 ** 32} 255 255 255 255`),
};

export const PipelineColorRamp: Pipeline = {
type: 'color-ramp',
Expand All @@ -56,6 +60,8 @@ export const PipelineColorRamp: Pipeline = {
height: data.height,
};

const ramp = Ramps[data.depth];

const size = data.width * data.height;
const noData = comp.asset.images[0].noData;

Expand Down
40 changes: 35 additions & 5 deletions packages/tiler-sharp/src/pipeline/pipeline.resize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export function cropResize(

// Currently very limited supported input parameters
if (data.channels !== 1) throw new Error('Unable to crop-resize more than one channel got:' + data.channels);
if (data.depth !== 'float32') throw new Error('Unable to crop-resize other than float32 got:' + data.depth);

// Area of the source data that needs to be resampled
const source = { x: 0, y: 0, width: data.width, height: data.height };
Expand Down Expand Up @@ -93,7 +92,8 @@ function resizeNearest(
const invScale = 1 / target.scale;

// Resample the input tile into the output tile using a nearest neighbor approach
const outputBuffer = new Float32Array(target.width * target.height);
const ret = getOutputBuffer(data, target);
const outputBuffer = ret.pixels;
for (let y = 0; y < target.height; y++) {
let sourceY = Math.round((y + 0.5) * invScale + source.y);
if (sourceY > maxHeight) sourceY = maxHeight;
Expand All @@ -106,7 +106,36 @@ function resizeNearest(
}
}

return { pixels: outputBuffer, width: target.width, height: target.height, depth: 'float32', channels: 1 };
return ret;
}

function getOutputBuffer(source: DecompressedInterleaved, target: Size & { scale: number }): DecompressedInterleaved {
switch (source.depth) {
case 'uint8':
return {
pixels: new Uint8Array(target.width * target.height),
width: target.width,
height: target.height,
depth: source.depth,
channels: 1,
};
case 'float32':
return {
pixels: new Float32Array(target.width * target.height),
width: target.width,
height: target.height,
depth: source.depth,
channels: 1,
};
case 'uint32':
return {
pixels: new Uint32Array(target.width * target.height),
width: target.width,
height: target.height,
depth: source.depth,
channels: 1,
};
}
}

function resizeBilinear(
Expand All @@ -120,7 +149,8 @@ function resizeBilinear(

const maxWidth = Math.min(comp.source.width, data.width) - 2;
const maxHeight = Math.min(comp.source.height, data.height) - 2;
const outputBuffer = new Float32Array(target.width * target.height);
const ret = getOutputBuffer(data, target);
const outputBuffer = ret.pixels;
for (let y = 0; y < target.height; y++) {
const sourceY = Math.min((y + 0.5) * invScale + source.y, maxHeight);
const minY = Math.floor(sourceY);
Expand Down Expand Up @@ -167,5 +197,5 @@ function resizeBilinear(
}
}

return { pixels: outputBuffer, width: target.width, height: target.height, depth: 'float32', channels: 1 };
return ret;
}

0 comments on commit 76d8ad1

Please sign in to comment.