From be34d81529989b449dfe0c4d28524d185b2b7c4e Mon Sep 17 00:00:00 2001 From: Kyle Barron Date: Wed, 4 Mar 2026 16:53:33 -0500 Subject: [PATCH] refactor: Cleaner type defs for DecodedPixels and RasterArray --- packages/geotiff/src/array.ts | 39 +++++++++++----------------- packages/geotiff/src/decode.ts | 27 ++++++++++++++++--- packages/geotiff/tests/array.test.ts | 13 ++++++---- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/packages/geotiff/src/array.ts b/packages/geotiff/src/array.ts index c7f0e573..c7bf6449 100644 --- a/packages/geotiff/src/array.ts +++ b/packages/geotiff/src/array.ts @@ -1,5 +1,10 @@ import type { Affine } from "@developmentseed/affine"; import type { ProjJson } from "./crs.js"; +import type { + DecodedBandSeparate, + DecodedPixelInterleaved, + DecodedPixels, +} from "./decode.js"; /** Typed arrays supported for raster sample storage. */ export type RasterTypedArray = @@ -38,36 +43,22 @@ type RasterArrayBase = { */ transform: Affine; + /** Coordinate reference system information. */ crs: number | ProjJson; + /** Nodata value from `GDAL_NODATA` TIFF tag. */ nodata: number | null; }; /** Raster stored in one typed array per band (band-major / planar). */ -export type BandRasterArray = RasterArrayBase & { - layout: "band-separate"; - /** - * One typed array per band, each length = width * height. - * - * This is the preferred representation when uploading one texture per band. - */ - bands: RasterTypedArray[]; -}; +export type RasterArrayBandSeparate = RasterArrayBase & DecodedBandSeparate; /** Raster stored in one pixel-interleaved typed array. */ -export type PixelRasterArray = RasterArrayBase & { - layout: "pixel-interleaved"; - /** - * Pixel-interleaved raster data: - * [p00_band0, p00_band1, ..., p01_band0, ...] - * - * Length = width * height * count. - */ - data: RasterTypedArray; -}; +export type RasterArrayPixelInterleaved = RasterArrayBase & + DecodedPixelInterleaved; /** Decoded raster data from a GeoTIFF region. */ -export type RasterArray = BandRasterArray | PixelRasterArray; +export type RasterArray = RasterArrayBase & DecodedPixels; /** Options for packing band data to a 4-channel pixel-interleaved array. */ export type PackBandsToRGBAOptions = { @@ -81,7 +72,7 @@ export type PackBandsToRGBAOptions = { }; /** Convert any raster layout to a band-separate representation. */ -export function toBandSeparate(array: RasterArray): BandRasterArray { +export function toBandSeparate(array: RasterArray): RasterArrayBandSeparate { validateRasterShape(array); if (array.layout === "band-separate") { return array; @@ -115,7 +106,7 @@ export function toBandSeparate(array: RasterArray): BandRasterArray { export function toPixelInterleaved( array: RasterArray, order?: readonly number[], -): PixelRasterArray { +): RasterArrayPixelInterleaved { validateRasterShape(array); const defaultOrder = Array.from({ length: array.count }, (_, i) => i); @@ -158,7 +149,7 @@ export function toPixelInterleaved( export function reorderBands( array: RasterArray, order: readonly number[], -): BandRasterArray { +): RasterArrayBandSeparate { validateRasterShape(array); validateBandOrder(order, array.count); const src = toBandSeparate(array); @@ -178,7 +169,7 @@ export function reorderBands( export function packBandsToRGBA( array: RasterArray, options: PackBandsToRGBAOptions = {}, -): PixelRasterArray { +): RasterArrayPixelInterleaved { const order = options.order ?? [0, 1, 2, null]; const fillValue = options.fillValue ?? 0; diff --git a/packages/geotiff/src/decode.ts b/packages/geotiff/src/decode.ts index 8420e307..db794393 100644 --- a/packages/geotiff/src/decode.ts +++ b/packages/geotiff/src/decode.ts @@ -4,10 +4,31 @@ import type { RasterTypedArray } from "./array.js"; import { decode as decodeViaCanvas } from "./codecs/canvas.js"; import { applyPredictor } from "./codecs/predictor.js"; +/** Raster stored in one pixel-interleaved typed array. */ +export type DecodedPixelInterleaved = { + layout: "pixel-interleaved"; + /** + * Pixel-interleaved raster data: + * [p00_band0, p00_band1, ..., p01_band0, ...] + * + * Length = width * height * count. + */ + data: RasterTypedArray; +}; + +/** Raster stored in one typed array per band (band-major / planar). */ +export type DecodedBandSeparate = { + layout: "band-separate"; + /** + * One typed array per band, each length = width * height. + * + * This is the preferred representation when uploading one texture per band. + */ + bands: RasterTypedArray[]; +}; + /** The result of a decoding process */ -export type DecodedPixels = - | { layout: "pixel-interleaved"; data: RasterTypedArray } - | { layout: "band-separate"; bands: RasterTypedArray[] }; +export type DecodedPixels = DecodedPixelInterleaved | DecodedBandSeparate; /** Metadata from the TIFF IFD, passed to decoders that need it. */ export type DecoderMetadata = { diff --git a/packages/geotiff/tests/array.test.ts b/packages/geotiff/tests/array.test.ts index 1fb1c91f..68dfca18 100644 --- a/packages/geotiff/tests/array.test.ts +++ b/packages/geotiff/tests/array.test.ts @@ -1,6 +1,9 @@ import type { Affine } from "@developmentseed/affine"; import { describe, expect, it } from "vitest"; -import type { BandRasterArray, PixelRasterArray } from "../src/array.js"; +import type { + RasterArrayBandSeparate, + RasterArrayPixelInterleaved, +} from "../src/array.js"; import { packBandsToRGBA, reorderBands, @@ -89,7 +92,7 @@ function baseMetadata() { describe("RasterArray helpers", () => { it("converts band-separate data to pixel-interleaved", () => { - const raster: BandRasterArray = { + const raster: RasterArrayBandSeparate = { ...baseMetadata(), layout: "band-separate", count: 3, @@ -108,7 +111,7 @@ describe("RasterArray helpers", () => { }); it("converts pixel-interleaved data to band-separate", () => { - const raster: PixelRasterArray = { + const raster: RasterArrayPixelInterleaved = { ...baseMetadata(), layout: "pixel-interleaved", count: 3, @@ -123,7 +126,7 @@ describe("RasterArray helpers", () => { }); it("reorders bands without repacking to pixel layout", () => { - const raster: BandRasterArray = { + const raster: RasterArrayBandSeparate = { ...baseMetadata(), layout: "band-separate", count: 3, @@ -142,7 +145,7 @@ describe("RasterArray helpers", () => { }); it("packs selected bands to RGBA", () => { - const raster: BandRasterArray = { + const raster: RasterArrayBandSeparate = { ...baseMetadata(), layout: "band-separate", count: 3,