# geotiff.js
[![Build Status](https://travis-ci.org/constantinius/geotiff.js.svg)](https://travis-ci.org/constantinius/geotiff.js) [![Dependency Status](https://www.versioneye.com/user/projects/566af91d4e049b0041000083/badge.svg?style=flat)](https://www.versioneye.com/user/projects/566af91d4e049b0041000083) [![npm version](https://badge.fury.io/js/geotiff.svg)](https://badge.fury.io/js/geotiff)

Read (geospatial) metadata and raw array data from a wide variety of different
(Geo)TIFF files types.

## Features

Currently available functionality:

  * 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
    * Float32/64
  * Enabled compressions:
    * no compression
    * Packbits
    * LZW
    * Deflate
  * Subsetting via an image window and selected bands
  * Reading of samples into separate arrays or a single pixel-interleaved array
  * Configurable tile/strip cache
  * Limited [bigTIFF](http://bigtiff.org/#FILE_FORMAT) support
  * Automated testing via PhantomJS

Further documentation can be found [here](http://constantinius.github.io/geotiff.js/).

## Example Usage

* [Slice view using Cesium.js (TAMP project)](http://www.youtube.com/watch?v=E6kFLtKgeJ8)

[![3D slice view](http://img.youtube.com/vi/E6kFLtKgeJ8/0.jpg)](http://www.youtube.com/watch?v=E6kFLtKgeJ8)

* [Contour generation using d3-contour](https://bl.ocks.org/mbostock/83c0be21dba7602ee14982b020b12f51)

[![contour](https://pbs.twimg.com/card_img/850410549196271616/ZKcdfREH?format=jpg&name=600x314)](https://bl.ocks.org/mbostock/83c0be21dba7602ee14982b020b12f51)

## Setup

To setup the repository do the following steps:

```bash
# clone repo
git clone https://github.com/constantinius/geotiff.js.git
cd geotiff.js/

# install development dependencies
npm install -g grunt-cli
npm install
```

## Testing and Building

In order to run the tests you first have to set up the test data. This requires
the [GDAL](http://gdal.org/) and [ImageMagick](http://imagemagick.org/) tools.
Installation of these tools varies according to the operating system, the
following listing shows the installation on Ubuntu (using the ubuntugis-unstable
repository):
```bash
sudo add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable
sudo apt-get update
sudo apt-get install -y gdal-bin imagemagick
```

When GDAL and ImageMagick is installed, the test data setup script can be run:
```bash
cd test/data
sh setup_data.sh
cd -
```

To test the library (using PhantomJS, karma, mocha and chai) do the following:

```bash
npm test
```

To do some in-browser testing do:

```bash
npm start
```

and navigate to `http://localhost:9000/test/`

To build the library do:

```bash
npm run build
```

The output is written to `dist/geotiff.browserify.js` and `dist/geotiff.browserify.min.js`.

## Usage

geotiff.js works with both browserify style `require` and the global variable
`GeoTIFF`:

```javascript
var GeoTIFF = require("geotiff");
```

or:

```html
<script src="dist/geotiff.browserify.js"></script>
<!-- or use the minified version:
  <script src="dist/geotiff.browserify.min.js"></script>
-->
<script>
  console.log(GeoTIFF);
</script>
```

To actually open a GeoTIFF image use the `parse` function. It works with both
`ArrayBuffer` and `String`:

```javascript
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function(e) {
  var tiff = GeoTIFF.parse(this.response);
  // ...
}
xhr.send();
```

Similarly, the `fetch()` API can be used:

```javascript
fetch(url)
  .then(function(response) { return response.arrayBuffer(); })
  .then(function(data) {
    const tiff = GeoTIFF.parse(data);
    // ...
  });
```

When using the parser in node, you have to convert the `Buffer` to an
`ArrayBuffer` first. See the following example for the conversion:

```javascript
var GeoTIFF = require("geotiff");
var fs = require("fs");

fs.readFile(path, function(err, data) {
  if (err) throw err;
  dataArray = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
  var tiff = GeoTIFF.parse(dataArray);
  // ...
});
```

Each TIFF file can be comprised of multiple "subfiles", containing the actual
raster data. To get the actual images, use the `getImage` method:

```javascript
var image = tiff.getImage(); // or use .getImage(n) where n is between 0 and
                             // tiff.getImageCount()

console.log(image.getWidth(), image.getHeight(), image.getSamplesPerPixel());
```

To actually read raster data the `readRasters` method does the job. It returns
an `Array` of `TypedArrays` for each of the requested samples of the requested
region:

```javascript
var rasterWindow = [50, 50, 100, 100]; // left, top, right, bottom
var samples = [0, 1, 2, 3];
var rasters = image.readRasters({window: rasterWindow, samples: samples});
for (var i = 0; i < rasters.length; ++i) {
  console.log(rasters[i]);
}
// to read all samples with no subsets:
rasters = image.readRasters();

// to read the data in a single interleaved array:
var array = image.readRasters({interleave: true});
```

To read TIFF or geo-spatial metadata, the methods `.getFileDirectory()` and
`.getGeoKeys()` provide the data:

```javascript
console.log(image.getFileDirectory(), image.getGeoKeys());
```

## What to do with the data?

There is a nice HTML 5/WebGL based rendering library called
[plotty](https://github.com/santilland/plotty), that allows for some really nice
on the fly rendering of the data contained in a GeoTIFF.

```html
<canvas id="plot"></canvas>
<script>
  // ...
  var tiff = GeoTIFF.parse(data);
  var image = tiff.getImage();
  var rasters = image.readRasters();
  var canvas = document.getElementById("plot");
  var plot = new plotty.plot({
    canvas: canvas, data: rasters[0],
    width: image.getWidth(), height: image.getHeight(),
    domain: [0, 256], colorScale: "viridis"
  });
  plot.render();
</script>
```

## RGB-data

When the TIFF file has color data stored, this can automatically extracted
using the `readRGB` method. This always resolves with an `Uint8Array` with
interleaved red, green, and blue values.

This method translates CMYK and YCbCr colorspaces to RGB, supports
color maps and two versions of grey-scale images (black is zero/white is zero).

The following example shows how to display such data in a browsers canvas:

    var parser = GeoTIFF.parse(data);
    var image = parser.getImage();
    image.readRGB(function(raster) {
      var canvas = document.getElementById('canvas');
      canvas.width = image.getWidth();
      canvas.height = image.getHeight();
      var ctx = canvas.getContext("2d");
      var imageData = ctx.createImageData(image.getWidth(), image.getHeight());
      var data = imageData.data;
      var o = 0;
      for (var i = 0; i < raster.length; i+=3) {
        data[o] = raster[i];
        data[o+1] = raster[i+1];
        data[o+2] = raster[i+2];
        data[o+3] = 255;
        o += 4;
      }
      ctx.putImageData(imageData, 0, 0);
    });


## 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.

## Planned stuff:

  * Better support of geospatial parameters:
    * Parsing of EPSG identifiers
    * WKT representation
    * Specifying of window in CRS coordinates
  * Improving support of CIEL*a*b* images
  * Support of "overview images" (i.e: images with reduced resolution)

## 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!

## Acknowledgements

This library was inspired by
[GeotiffParser](https://github.com/xlhomme/GeotiffParser.js). It provided a
great starting point, but lacked the capabilities to read the raw raster data
which is the aim of geotiff.js.
