geotiff.js - GeoTIFF Image Decoding
geotiff.js is a robust JavaScript library designed for decoding GeoTIFF and TIFF images in both browser and Node.js environments. It enables developers to read and parse these file formats, extract raw raster data across various data types and compressions (including Packbits, LZW, Deflate, JPEG, LERC, Zstandard, and WebP), and access rich geospatial metadata like GeoKeys and TIFF tags. The current stable version is 3.0.5, with ongoing active development and regular patch releases, alongside beta versions (e.g., 3.1.0-beta.0) that introduce new features like multi-stripped and tiled writing support. Key differentiators include its pure JavaScript implementation, configurable worker pools for efficient decoding, and selective reading of file portions to optimize bandwidth, making it an essential tool for web-based GIS applications that require client-side processing of georeferenced imagery.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/code/node_modules/quick-lru/index.js from /path/to/code/node_modules/geotiff/dist-node/source/blockedsource.js not supported.
cause Attempting to `require()` geotiff.js or its dependencies in a CommonJS module in Node.js, while geotiff.js (or its sub-dependencies) is an ES Module.fixConvert your Node.js project or the specific file to use ES Modules with `import` statements and ensure `"type": "module"` is set in your `package.json`, or use an explicit `.mjs` extension. -
TypeError: Cannot read properties of undefined (reading 'offset')
cause An error occurred in `BlockedSource.readSliceData` due to issues with how data blocks or slices are being read from the source, often triggered under specific conditions with the last block or slices equal to block size.fixUpdate `geotiff.js` to the latest patch release (e.g., 3.0.5 or 3.1.0-beta.0+) which includes fixes for these types of issues. If the problem persists, ensure your data source is correctly implemented if it's custom, or share the problematic GeoTIFF file with the maintainers for debugging. -
Property 'SomeTag' does not exist on type 'GeoTIFFImage'. Did you mean 'getTags'?
cause Direct synchronous access to TIFF tags or metadata properties on the `GeoTIFFImage` object after the v3.0.0 breaking change to deferred tag reading.fixUse the `getTags()` method and await its result, or consult the `GeoTIFFImage` API for the correct asynchronous access pattern for the specific tag you need. -
Argument of type 'GeoTIFFImage' is not assignable to parameter of type 'number'.
cause Incorrect usage of TypeScript types, often when attempting to pass an object where a primitive type (like a number or string) is expected, or misinterpreting a type import as a callable constructor.fixEnsure you are using type imports (`import type { GeoTIFFImage }`) only for type declarations, and not attempting to instantiate them as values. Verify the function signatures for the methods you are calling and provide arguments of the correct type.
Warnings
- breaking Version 3.0.0 introduced a breaking change with "deferred tag reading" (feat!: Implement deferred tag reading (#484)). This alters how TIFF tags and certain metadata (e.g., GeoKeys) are accessed, potentially requiring asynchronous handling (`await`) or different access patterns where direct synchronous property access might have worked previously.
- breaking Starting with v3, `geotiff.js` embraces ES Modules (ESM). While the `package.json` may support CommonJS (CJS) for some paths, direct `require()` calls for `geotiff` exports can lead to `ERR_REQUIRE_ESM` errors in Node.js, especially if underlying dependencies are ESM-only. A similar issue was seen in v2.0.5 with the `quick-lru` dependency.
- gotcha The library has shown sensitivity to data source handling and slicing, leading to `TypeError: Cannot read properties of undefined (reading 'offset')` errors in `BlockedSource.readSliceData` in previous versions (fixed in v2.1.4-beta.1) and a need to "Restore pre-3.0.4 behavior to create blocked sources" in v3.1.0-beta.0. This indicates potential edge cases with custom data sources or specific GeoTIFF structures that might not be handled robustly across all versions.
- gotcha The fix "Use node16 moduleResolution for strict imports" in v3.0.5 implies that older Node.js versions or non-standard TypeScript/build configurations might encounter module resolution issues, leading to failures to find modules or types.
- gotcha While `geotiff.js` provides comprehensive decoding, it does not offer a high-level API for advanced geospatial operations like coordinate re-projection or direct querying of raster cells by geographic coordinates (similar to GDAL). Users need to implement such functionalities using the extracted metadata.
Install
-
npm install geotiff -
yarn add geotiff -
pnpm add geotiff
Imports
- fromUrl
const { fromUrl } = require('geotiff');import { fromUrl } from 'geotiff' - fromArrayBuffer
const geotiff = require('geotiff'); const tiff = await geotiff.fromArrayBuffer(...);import { fromArrayBuffer } from 'geotiff' - Pool
import { Pool } from 'geotiff/src/Pool';import { Pool } from 'geotiff' - GeoTIFFImage
import { GeoTIFFImage } from 'geotiff'
Quickstart
import { fromUrl, GeoTIFFImage } from 'geotiff';
async function processGeoTIFF() {
try {
// Example URL for a small GeoTIFF file (e.g., a Cloud Optimized GeoTIFF).
// In a real application, ensure the URL is accessible and CORS-friendly.
const url = 'https://geotiffjs.github.io/geotiff.js/test/data/example.tif';
console.log(`Attempting to open GeoTIFF from URL: ${url}`);
const tiff = await fromUrl(url);
// Get the first image (most common case). GeoTIFFs can contain multiple images.
const image: GeoTIFFImage = await tiff.getImage();
console.log(`Opened image: Width = ${image.getWidth()}, Height = ${image.getHeight()}`);
// Read raster data for the first band. The 'readRasters' method returns an array of TypedArrays.
// 'interleave: false' returns separate arrays for each band.
const rasters = await image.readRasters({ interleave: false });
console.log(`Read raster data. Number of bands: ${rasters.length}`);
if (rasters.length > 0 && rasters[0].length > 0) {
console.log(`First pixel value (band 0): ${rasters[0][0]}`);
}
// Access image metadata, such as GeoKeys or other TIFF tags.
const geoKeys = image.getGeoKeys();
console.log('GeoKeys (if present):', geoKeys);
// Get the bounding box of the image in its projected coordinates.
const boundingBox = image.getBoundingBox();
console.log('Bounding Box [minX, minY, maxX, maxY]:', boundingBox);
console.log('Successfully processed GeoTIFF.');
} catch (error) {
console.error('Error processing GeoTIFF:', error);
}
}
processGeoTIFF();