Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions packages/geotiff/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@developmentseed/geotiff",
"version": "0.1.0",
"description": "High-level GeoTIFF reading library.",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"sideEffects": false,
"files": [
"dist"
],
"scripts": {
"build": "tsc --build tsconfig.build.json",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
"prepublishOnly": "npm run build"
},
"keywords": [
"geotiff",
"cog",
"cloud-optimized-geotiff",
"raster"
],
"author": "Development Seed",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/developmentseed/deck.gl-raster.git"
},
"devDependencies": {
"@types/node": "^25.1.0",
"typescript": "^5.9.3",
"vitest": "^4.0.18"
},
"volta": {
"extends": "../../package.json"
},
"dependencies": {
"@cogeotiff/core": "^9.1.2"
}
}
48 changes: 48 additions & 0 deletions packages/geotiff/src/affine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Affine geotransform: [a, b, c, d, e, f].
*
* Maps pixel (col, row) to geographic (x, y):
* x = a * col + b * row + c
* y = d * col + e * row + f
*/
export type Affine = [
a: number,
b: number,
c: number,
d: number,
e: number,
f: number,
];

/**
* Apply a geotransform to a coordinate.
*
* x_out = a * x + b * y + c
* y_out = d * x + e * y + f
*/
export function forward(
[a, b, c, d, e, f]: Affine,
x: number,
y: number,
): [number, number] {
return [a * x + b * y + c, d * x + e * y + f];
}

/**
* Compute the inverse of an Affine.
*/
export function invert([sa, sb, sc, sd, se, sf]: Affine): Affine {
const det = sa * se - sb * sd;

if (det === 0) {
throw new Error("Cannot invert degenerate transform");
}

const idet = 1.0 / det;
const ra = se * idet;
const rb = -sb * idet;
const rd = -sd * idet;
const re = sa * idet;

return [ra, rb, -sc * ra - sf * rb, rd, re, -sc * rd - sf * re];
}
40 changes: 40 additions & 0 deletions packages/geotiff/src/array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { Affine } from "./affine.js";

/**
* Decoded raster data from a GeoTIFF region.
*
* Data is stored in pixel-interleaved order: for each pixel in row-major
* order, all band values are contiguous. The flat array length is
* `height * width * bands`.
*/
export type RasterArray = {
/** Pixel-interleaved raster data. Length = height * width * bands. */
data: ArrayBuffer;

/**
* Optional validity mask. Length = height * width.
* 1 = valid pixel, 0 = nodata. null when no mask IFD is present.
*/
mask: Uint8Array | null;

/** Number of bands (samples per pixel). */
count: number;

/** Height in pixels. */
height: number;

/** Width in pixels. */
width: number;

/**
* Affine geotransform [a, b, c, d, e, f] mapping pixel (col, row) to
* geographic (x, y):
* x = a * col + b * row + c
* y = d * col + e * row + f
*/
transform: Affine;

crs: string;

nodata: number | null;
};
81 changes: 81 additions & 0 deletions packages/geotiff/src/fetch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import type {
Compression,
Tiff,
TiffImage,
TiffMimeType,
} from "@cogeotiff/core";
import type { Tile } from "./tile";
import type { HasTransform } from "./transform";

/** Protocol for objects that hold a TIFF reference and can request tiles. */
interface HasTiffReference extends HasTransform {
/** The data Image File Directory (IFD) */
ifd: TiffImage;

/** The mask Image File Directory (IFD), if any. */
maskIfd: TiffImage | null;

/** The underlying TIFF object. */
tiff: Tiff;

/** The coordinate reference system. */
crs: string;

/** The height of tiles in pixels. */
tileHeight: number;

/** The width of tiles in pixels. */
tileWidth: number;

/** The nodata value for the image, if any. */
nodata: number | null;
}

export async function fetchTile(
self: HasTiffReference,
x: number,
y: number,
): Promise<Tile> {
const tileFut = self.ifd.getTile(x, y);
let maskFut: Promise<{
mimeType: TiffMimeType;
bytes: ArrayBuffer;
compression: Compression;
} | null> | null = null;
if (self.maskIfd != null) {
maskFut = self.maskIfd.getTile(x, y);
const [tile, mask] = await Promise.all([tileFut, maskFut]);
console.log(tile, mask);
}

throw new Error("Not implemented");
}

// mask_data: AsyncTiffArray | None = None
// if self._mask_ifd is not None:
// mask_fut = self._mask_ifd.fetch_tile(x, y)
// tile, mask = await asyncio.gather(tile_fut, mask_fut)
// tile_data, mask_data = await asyncio.gather(tile.decode(), mask.decode())
// else:
// tile = await tile_fut
// tile_data = await tile.decode()

// tile_transform = self.transform * Affine.translation(
// x * self.tile_width,
// y * self.tile_height,
// )

// array = Array._create( # noqa: SLF001
// data=tile_data,
// mask=mask_data,
// planar_configuration=self._ifd.planar_configuration,
// crs=self.crs,
// transform=tile_transform,
// nodata=self.nodata,
// )
// return Tile(
// x=x,
// y=y,
// _ifd=self._ifd,
// array=array,
// )
Loading