geotiff.js
-
![Gitter chat](https://badges.gitter.im/geotiffjs/geotiff.js.png)
-Read (geospatial) metadata and raw array data from a wide variety of different
-(Geo)TIFF files types.
-Features
-Currently available functionality:
-
-- Parsing TIFFs from various sources:
-
-- remote (via
fetch
or XHR)
-- from a local
ArrayBuffer
-- from the filesystem (on Browsers using the
FileReader
and on node using the filesystem functions)
-
-
-- Parsing the headers of all possible TIFF files
-- Rudimentary extraction of geospatial metadata
-- Reading raster data from:
-
-- stripped images
-- tiled images
-- band interleaved images
-- pixel interleaved images
-
-
-- Supported data-types:
-
-- (U)Int8/16/32
-- UInt1-31 (with some drawbacks)
-- Float16/32/64
-
-
-- Enabled compressions:
-
-- no compression
-- Packbits
-- LZW
-- Deflate (with floating point or horizontal predictor support)
-- JPEG
-
-
-- Automatic selection of overview level to read from
-- Subsetting via an image window or bounding box and selected bands
-- Reading of samples into separate arrays or a single pixel-interleaved array
-- Configurable tile/strip cache
-- Configurable Pool of workers to increase decoding efficiency
-- Utility functions for geospatial parameters (Bounding Box, Origin, Resolution)
-- Limited bigTIFF support
-- Automated testing via PhantomJS
-
-Further documentation can be found here.
-Example Usage
-
-![3D slice view](http://img.youtube.com/vi/E6kFLtKgeJ8/0.jpg)
-
-![contour](https://pbs.twimg.com/card_img/850410549196271616/ZKcdfREH?format=jpg&name=600x314)
-Setup
-To setup the repository do the following steps:
-# clone repo
-git clone https://github.com/constantinius/geotiff.js.git
-cd geotiff.js/
-
-# install development dependencies
-npm install
-
-Testing and Building
-In order to run the tests you first have to set up the test data. This requires
-the GDAL and ImageMagick tools.
-Installation of these tools varies according to the operating system, the
-following listing shows the installation on Ubuntu (using the ubuntugis-unstable
-repository):
-sudo add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable
-sudo apt-get update
-sudo apt-get install -y gdal-bin imagemagick
-
-To install GDAL and ImageMagick on MacOS X, please use Homebrew. The setup script also needs wget
on MacOS X
-brew install wget gdal imagemagick
-
-When GDAL and ImageMagick is installed, the test data setup script can be run:
-cd test/data
-sh setup_data.sh
-cd -
-
-To test the library (using PhantomJS, karma, mocha and chai) do the following:
-npm test
-
-To do some in-browser testing do:
-npm run dev
-
-and navigate to http://localhost:8090/index.html
-To build the library do:
-npm run build
-
-The output is written to dist-browser/main.js
and dist-node/main.js
.
-Install
-You can install geotiff.js using npm:
-npm install geotiff
-
-or you can use the prebuilt version with a CDN:
-<script src="https://cdn.jsdelivr.net/npm/geotiff"></script>
-
-Note: Currently the CDN installation is not compatible with GeoTIFF workers pool GeoTIFF.Pool
.
-Usage
-geotiff.js works with both require
, import
and the global variable GeoTIFF
:
-const GeoTIFF = require('geotiff');
-const { fromUrl, fromUrls, fromArrayBuffer, fromBlob } = GeoTIFF;
-
-// or
-import GeoTIFF, { fromUrl, fromUrls, fromArrayBuffer, fromBlob } from 'geotiff';
-
-or:
-<script async src="https://cdn.jsdelivr.net/npm/geotiff"></script>
-<script>
- console.log(GeoTIFF);
- // Note: GeoTIFF.Pool will not work
-</script>
-
-To parse a GeoTIFF, first a data source is required. To help with the development,
-there are shortcuts available. The following creates a source that reads from a
-remote GeoTIFF referenced by a URL:
-fromUrl(someUrl)
- .then(tiff => { /* ... */});
-
-// or when using async/await
-(async function() {
- const tiff = await fromUrl(someUrl);
- // ...
-})()
-
-Note: the interactions with geotiff.js objects are oftentimes asynchronous. For
-the sake of brevity we will only show the async/await syntax and not the
-Promise
based one in the following examples.
-Accessing remote images is just one way to open TIFF images with geotiff.js. Other
-options are reading from a local ArrayBuffer
:
-// using local ArrayBuffer
-const response = await fetch(someUrl);
-const arrayBuffer = await response.arrayBuffer();
-const tiff = await fromArrayBuffer(arrayBuffer);
-
-or a Blob
/File
:
-<input type="file" id="file">
-<script>
- const input = document.getElementById('file'):
- input.onchange = async function() {
- const tiff = await fromBlob(input.files[0]);
- }
-</script>
-
-Now that we have opened the TIFF file, we can inspect it. The TIFF is structured
-in a small header and a list of one or more images (Image File Directory, IFD to
-use the TIFF nomenclature). To get one image by index the getImage()
function
-must be used. This is again an asynchronous operation, as the IFDs are loaded
-lazily:
-const image = await tiff.getImage(); // by default, the first image is read.
-
-Now that we have obtained a GeoTIFFImage
object we can inspect its metadata
-(like size, tiling, number of samples, geographical information, etc.). All
-the metadata is parsed once the IFD is first parsed, thus the access to that
-is synchronous:
-const width = image.getWidth();
-const height = image.getHeight();
-const tileWidth = image.getTileWidth();
-const tileHeight = image.getTileHeight();
-const samplesPerPixel = image.getSamplesPerPixel();
-
-// when we are actually dealing with geo-data the following methods return
-// meaningful results:
-const origin = image.getOrigin();
-const resolution = image.getResolution();
-const bbox = image.getBoundingBox();
-
-The actual raster data is not fetched and parsed automatically. This is because
-it is usually much more spacious and the decoding of the pixels can be time
-consuming due to the necessity of decompression.
-To read a whole image into one big array of arrays the following method call can be used:
-const data = await image.readRasters();
-
-For convenience the result always has a width
and height
attribute:
-const data = await image.readRasters();
-const { width, height } = data;
-
-By default, the raster is split to a separate array for each component. For an RGB image
-for example, we'd get three arrays, one for red, green and blue.
-const [red, green, blue] = await image.readRasters();
-
-If we want instead all the bands interleaved in one big array, we have to pass the
-interleave: true
option:
-const [r0, g0, b0, r1, g1, b1, ...] = await image.readRasters({ interleave: true });
-
-If we are only interested in a specific region of the image, the window
option can be
-used to limit reading in that bounding box. Note: the bounding box is in 'image coordinates'
-not geographical ones:
-const left = 50;
-const top = 10;
-const right = 150;
-const bottom = 60;
-
-const data = await image.readRasters({ window: [left, top, right, bottom] });
-
-This image window can go beyond the image bounds. In that case it might be usefull to supply
-a fillValue: value
option (can also be an array, one value for each sample).
-It is also possible to just read specific samples for each pixel. For example, we can only
-read the red component from an RGB image:
-const [red] = await image.readRasters({ samples: [0] });
-
-When you want your output in a specific size, you can use the width
and height
options.
-This defaults of course to the size of your supplied window
or the image size if no
-window
was supplied.
-As the data now needs to be resampled, a resampleMethod
can be specified. This defaults to
-the nearest neighbour method, but also the 'bilinear'
method is supported:
-const data = await image.readRasters({ width: 40, height: 40, resampleMethod: 'bilinear' });
-
-Using decoder pools to improve parsing performance
-Decoding compressed images can be a time consuming process. To minimize this
-geotiff.js provides the Pool
mechanism which uses WebWorkers to split the amount
-of work on multiple 'threads'.
-const pool = new GeoTIFF.Pool();
-const data = await image.readRasters({ pool });
-
-It is possible to provide a pool size (i.e: number of workers), by default the number
-of available processors is used.
-Because of the way WebWorker work (pun intended), there is a considerable overhead
-involved when using the Pool
, as all the data must be copied and cannot be simply be
-shared. But the benefits are two-fold. First: for larger image reads the overall time
-is still likely to be reduced and second: the main thread is relieved which helps to
-uphold responsiveness.
-If you want to use the Worker Pool in a project built with webpack (ex: VueJS or React) you have to install threads-plugin
and add the plugin to your webpack.config.js
:
-npm install -D threads-plugin
-
-const ThreadsPlugin = require('threads-plugin')
-
-module.exports = {
- // ...
- plugins: [
- new ThreadsPlugin()
- ]
-}
-
-Dealing with visual data
-The TIFF specification provides various ways to encode visual data. In the
-specification this is called photometric interpretation. The simplest case we
-already dealt with is the RGB one. Others are grayscale, paletted images, CMYK,
-YCbCr, and CIE Lab.
-geotiff.js provides a method to automatically convert these images to RGB:
-readRGB()
. This method is very similar to the readRasters
method with
-distinction that the interleave
option is now always true
and the
-samples
are automatically chosen.
-const rgb = await image.readRGB({
- // options...
-});
-
-Automatic image selection (experimental)
-When dealing with images that have internal (or even external, see the next section)
-overviews, GeoTIFF
objects provide a separate readRasters
method. This method
-works very similar to the method on the GeoTIFFImage
objects with the same name.
-By default, it uses the larges image available (highest resolution), but when either
-width
, height
, resX
, or resY
are specified, then the best fitting image will
-be used for reading.
-Additionally, it allows the bbox
instead of the window
parameter. This works
-similarly, but uses geographic coordinates instead of pixel ones.
-const data = await tiff.readRasters({
- bbox: [10.34, 57.28, 13.34, 60.23],
- resX: 0.1,
- resY: 0.1
-});
-
-External overviews
-Especially for certain kinds of high resolution images it is not uncommon to separate
-the highest resolution from the lower resolution overviews (usually using the .ovr
-extension). With geotiff.js it is possible to use files of this setup, just as you
-would use single-file images by taking advantage of the MultiGeoTIFF
objects. They
-behave exactly the same as the before mentioned GeoTIFF
objects: you can select
-images by index or read data using readRasters
. Toget such a file use the fromUrls
-factory function:
-const multiTiff = await fromUrls(
- 'LC08_L1TP_189027_20170403_20170414_01_T1_B3.TIF',
- ['LC08_L1TP_189027_20170403_20170414_01_T1_B3.TIF.ovr']
-);
-
-AbortController Support
-Geotiff.js supports the use of AbortController
s. Calls to getRasters
, readRGB
and getTileOrStrip
will throw an Error
with name AbortSignal
similar to the browser's fetch
behavior.
-const abortController = new AbortController();
-const { signal } = abortController;
-abortController.abort();
-try {
- const data = await tiff.readRasters({ signal });
-} catch(e) {
- if (err.name === 'AbortError') {
- // do stuff
- }
-}
-
-Writing GeoTIFFs (Beta Version)
-You can create a binary representation of a GeoTIFF using writeArrayBuffer
.
-This function returns an ArrayBuffer which you can then save as a .tif file.
-:warning: writeArrayBuffer currently writes the values uncompressed
-import GeoTIFF, { writeArrayBuffer } from 'geotiff';
-
-const values = [1, 2, 3, 4, 5, 6, 7, 8, 9];
-const metadata = {
- height: 3,
- width: 3
-};
-const arrayBuffer = await writeArrayBuffer(values, metadata);
-
-You can also customize the metadata using names found in the TIFF Spec and GeoTIFF spec.
-import { writeArrayBuffer } from 'geotiff';
-
-const values = [1, 2, 3, 4, 5, 6, 7, 8, 9];
-const metadata = {
- height: 3,
- ModelPixelScale: [0.031355, 0.031355, 0],
- ModelTiepoint: [0, 0, 0, 11.331755000000001, 46.268645, 0],
- width: 3
-};
-const arrayBuffer = await writeArrayBuffer(values, metadata);
-
-What to do with the data?
-There is a nice HTML 5/WebGL based rendering library called
-plotty, that allows for some really nice
-on the fly rendering of the data contained in a GeoTIFF.
-<canvas id="plot"></canvas>
-<script>
- // ...
-
- (async function() {
- const tiff = await fromUrl(url);
- const image = await tiff.getImage();
- const data = await image.readRasters();
-
- const canvas = document.getElementById("plot");
- const plot = new plotty.plot({
- canvas,
- data: data[0],
- width: image.getWidth(),
- height: image.getHeight(),
- domain: [0, 256],
- colorScale: "viridis"
- });
- plot.render();
- })();
-</script>
-
-BigTIFF support
-geotiff.js has a limited support for files in the BigTIFF format. The limitations
-originate in the capabilities of current JavaScript implementations regarding
-64 bit integer parsers and structures: there are no functions to read 64 bit
-integers from a stream and no such typed arrays. As BigTIFF relies on 64 bit
-offsets and also allows tag values of those types. In order to still provide
-a reasonable support, the following is implemented:
-
-- 64 bit integers are read as two 32 bit integers and then combined. As
-numbers in JavaScript are typically implemented as 64 bit floats, there
-might be inaccuracies for very large values.
-- For 64 bit integer arrays, the default
Array
type is used. This might
-cause problems for some compression algorithms if those arrays are used for
-pixel values.
-
-n-bit Support
-geotiff.js has some n-bit support which means that it supports unsigned integer
-data reading with each element using a non-multiple of 8 bit depth. This only
-works with band interleaved images (see
-this related issue).
-Planned stuff:
-
-- Better support of geospatial parameters:
-
-- Parsing of EPSG identifiers
-- WKT representation
-
-
-
-Known Issues
-The open issues can be found on GitHub.
-Contribution
-If you have an idea, found a bug or have a remark, please open a ticket, we will
-look into it ASAP.
-Pull requests are welcome as well!
-Community Packages
-A list of community packages can be found in COMMUNITY.md
-Acknowledgements
-This library was inspired by
-GeotiffParser. It provided a
-great starting point, but lacked the capabilities to read the raw raster data
-which is the aim of geotiff.js.
-