- Notifications
You must be signed in to change notification settings - Fork209
geotiff.js is a small library to parse TIFF files for visualization or analysis. It is written in pure JavaScript, and is usable in both the browser and node.js applications.
License
geotiffjs/geotiff.js
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Read (geospatial) metadata and raw array data from a wide variety of different(Geo)TIFF files types.
Currently available functionality:
- Parsing TIFFs from various sources:
- remote (via
fetchor XHR) - from a local
ArrayBuffer - from the filesystem (on Browsers using the
FileReaderand on node using the filesystem functions)
- remote (via
- 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
- LERC (with additional Deflate compression support)
- Zstandard
- image formats supported via the browser (such as WebP)
- 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)
- LimitedbigTIFF support
- Automated testing via PhantomJS
Further documentation can be foundhere.
Geotiff gives you access to all GeoTIFF metadata, but does not offer any one specific higher level API (such as GDAL) for things like transforms or data extraction. However, you can write your own higher level API using this library, given your specific dataset needs.
As an example, here is how you would resolve GPS coordinates to elevation in a GeoTIFF that encodes WGS-84 compliant geo data:
import{fromUrl,fromArrayBuffer,fromBlob}from"geotiff";constlerp=(a,b,t)=>(1-t)*a+t*b;functiontransform(a,b,M,roundToInt=false){constround=(v)=>(roundToInt ?v|0 :v);return[round(M[0]+M[1]*a+M[2]*b),round(M[3]+M[4]*a+M[5]*b),];}// Load our data tile from url, arraybuffer, or blob, so we can work with it:consttiff=awaitfromArrayBuffer(...);constimage=awaittiff.getImage();// by default, the first image is read.// Construct the WGS-84 forward and inverse affine matrices:const{ModelPixelScale:s,ModelTiepoint:t}=image.fileDirectory;let[sx,sy,sz]=s;let[px,py,k,gx,gy,gz]=t;sy=-sy;// WGS-84 tiles have a "flipped" y componentconstpixelToGPS=[gx,sx,0,gy,0,sy];console.log(`pixel to GPS transform matrix:`,pixelToGPS);constgpsToPixel=[-gx/sx,1/sx,0,-gy/sy,0,1/sy];console.log(`GPS to pixel transform matrix:`,gpsToPixel);// Convert a GPS coordinate to a pixel coordinate in our tile:const[gx1,gy1,gx2,gy2]=image.getBoundingBox();constlat=lerp(gy1,gy2,Math.random());constlong=lerp(gx1,gx2,Math.random());console.log(`Looking up GPS coordinate (${lat.toFixed(6)},${long.toFixed(6)})`);const[x,y]=transform(long,lat,gpsToPixel,true);console.log(`Corresponding tile pixel coordinate: [${x}][${y}]`);// And as each pixel in the tile covers a geographic area, not a single// GPS coordinate, get the area that this pixel covers:constgpsBBox=[transform(x,y,pixelToGPS),transform(x+1,y+1,pixelToGPS)];console.log(`Pixel covers the following GPS area:`,gpsBBox);// Finally, retrieve the elevation associated with this pixel's geographic area:constrasters=awaitimage.readRasters();const{ width,[0]:raster}=rasters;constelevation=raster[x+y*width];console.log(`The elevation at (${lat.toFixed(6)},${long.toFixed(6)}) is${elevation}m`);
For more advanced examples ofgeotiff in larger codebases, please have a look at the following projects:
To setup the repository do the following steps:
# clone repogit clone https://github.com/constantinius/geotiff.js.gitcd geotiff.js/# install development dependenciesnpm install
In order to run the tests you first have to set up the test data. This requirestheGDAL andImageMagick tools.Installation of these tools varies according to the operating system, thefollowing listing shows the installation on Ubuntu (using the ubuntugis-unstablerepository):
sudo add-apt-repository -y ppa:ubuntugis/ubuntugis-unstablesudo apt-get updatesudo apt-get install -y gdal-bin imagemagick
To install GDAL and ImageMagick on MacOS X, please useHomebrew. The setup script also needswget on MacOS X
brew install wget gdal imagemagick
When GDAL and ImageMagick is installed, the test data setup script can be run:
cd test/datash setup_data.shcd -
To test the library (using PhantomJS, karma, mocha and chai) do the following:
npmtestTo do some in-browser testing do:
npm run dev
and navigate tohttp://localhost:8090/test/
To build the library do:
npm run build
The output is written todist-browser/main.js anddist-node/main.js.
You can install geotiff.js using npm:
npm install geotiffor you can use the prebuilt version with a CDN:
<scriptsrc="https://cdn.jsdelivr.net/npm/geotiff"></script>
geotiff.js works with bothrequire,import and the global variableGeoTIFF:
constGeoTIFF=require('geotiff');const{ fromUrl, fromUrls, fromArrayBuffer, fromBlob}=GeoTIFF;// orimportGeoTIFF,{fromUrl,fromUrls,fromArrayBuffer,fromBlob}from'geotiff';
or:
<scriptsrc="https://cdn.jsdelivr.net/npm/geotiff"></script><script>console.log(GeoTIFF);</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 aremote GeoTIFF referenced by a URL:
fromUrl(someUrl).then(tiff=>{/* ... */});// or when using async/await(asyncfunction(){consttiff=awaitfromUrl(someUrl);// ...})()
Note: the interactions with geotiff.js objects are oftentimes asynchronous. Forthe sake of brevity we will only show the async/await syntax and not thePromise based one in the following examples.
Accessing remote images is just one way to open TIFF images with geotiff.js. Otheroptions are reading from a localArrayBuffer:
// using local ArrayBufferconstresponse=awaitfetch(someUrl);constarrayBuffer=awaitresponse.arrayBuffer();consttiff=awaitfromArrayBuffer(arrayBuffer);
or aBlob/File:
<inputtype="file"id="file"><script>constinput=document.getElementById('file');input.onchange=asyncfunction(){consttiff=awaitfromBlob(input.files[0]);}</script>
Now that we have opened the TIFF file, we can inspect it. The TIFF is structuredin a small header and a list of one or more images (Image File Directory, IFD touse the TIFF nomenclature). To get one image by index thegetImage() functionmust be used. This is again an asynchronous operation, as the IFDs are loadedlazily:
constimage=awaittiff.getImage();// by default, the first image is read.
Now that we have obtained aGeoTIFFImage object we can inspect its metadata(like size, tiling, number of samples, geographical information, etc.). Allthe metadata is parsed once the IFD is first parsed, thus the access to thatis synchronous:
constwidth=image.getWidth();constheight=image.getHeight();consttileWidth=image.getTileWidth();consttileHeight=image.getTileHeight();constsamplesPerPixel=image.getSamplesPerPixel();// when we are actually dealing with geo-data the following methods return// meaningful results:constorigin=image.getOrigin();constresolution=image.getResolution();constbbox=image.getBoundingBox();
The actual raster data is not fetched and parsed automatically. This is becauseit is usually much more spacious and the decoding of the pixels can be timeconsuming due to the necessity of decompression.
To read a whole image into one big array of arrays the following method call can be used:
constdata=awaitimage.readRasters();
For convenience the result always has awidth andheight attribute:
constdata=awaitimage.readRasters();const{ width, height}=data;
By default, the raster is split to a separate array for each component. For an RGB imagefor example, we'd get three arrays, one for red, green and blue.
const[red,green,blue]=awaitimage.readRasters();
If we want instead all the bands interleaved in one big array, we have to pass theinterleave: true option:
const[r0,g0,b0,r1,g1,b1, ...]=awaitimage.readRasters({interleave:true});
If we are only interested in a specific region of the image, thewindow option can beused to limit reading in that bounding box. Note: the bounding box is in 'image coordinates'not geographical ones:
constleft=50;consttop=10;constright=150;constbottom=60;constdata=awaitimage.readRasters({window:[left,top,right,bottom]});
This image window can go beyond the image bounds. In that case it might be usefull to supplyafillValue: 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 onlyread the red component from an RGB image:
const[red]=awaitimage.readRasters({samples:[0]});
When you want your output in a specific size, you can use thewidth andheight options.This defaults of course to the size of your suppliedwindow or the image size if nowindow was supplied.
As the data now needs to be resampled, aresampleMethod can be specified. This defaults tothe nearest neighbour method, but also the'bilinear' method is supported:
constdata=awaitimage.readRasters({width:40,height:40,resampleMethod:'bilinear'});
Decoding compressed images can be a time consuming process. To minimize thisgeotiff.js provides thePool mechanism which uses WebWorkers to split the amountof work on multiple 'threads'.
constpool=newGeoTIFF.Pool();constdata=awaitimage.readRasters({ pool});
It is possible to provide a pool size (i.e: number of workers), by default the numberof available processors is used.
The TIFF specification provides various ways to encode visual data. In thespecification this is called photometric interpretation. The simplest case wealready 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 thereadRasters method withthe distinction that theinterleave option now defaults totrue and thesamples are automatically chosen.
constrgb=awaitimage.readRGB({// options...});
When dealing with images that have internal (or even external, see the next section)overviews,GeoTIFF objects provide a separatereadRasters method. This methodworks very similar to the method on theGeoTIFFImage objects with the same name.By default, it uses the larges image available (highest resolution), but when eitherwidth,height,resX, orresY are specified, then the best fitting image willbe used for reading.
Additionally, it allows thebbox instead of thewindow parameter. This workssimilarly, but uses geographic coordinates instead of pixel ones.
constdata=awaittiff.readRasters({bbox:[10.34,57.28,13.34,60.23],resX:0.1,resY:0.1});
Especially for certain kinds of high resolution images it is not uncommon to separatethe highest resolution from the lower resolution overviews (usually using the.ovrextension). With geotiff.js it is possible to use files of this setup, just as youwould use single-file images by taking advantage of theMultiGeoTIFF objects. Theybehave exactly the same as the before mentionedGeoTIFF objects: you can selectimages by index or read data usingreadRasters. Toget such a file use thefromUrlsfactory function:
constmultiTiff=awaitfromUrls('LC08_L1TP_189027_20170403_20170414_01_T1_B3.TIF',['LC08_L1TP_189027_20170403_20170414_01_T1_B3.TIF.ovr']);
Geotiff.js supports the use ofAbortControllers. Calls togetRasters,readRGB andgetTileOrStrip will throw anError with nameAbortSignal similar to the browser'sfetch behavior.
consttiff=awaitfromUrl(source);constabortController=newAbortController();const{ signal}=abortController;abortController.abort();try{constdata=awaittiff.readRasters({ signal});}catch(e){if(err.name==='AbortError'){// do stuff}}
You can create a binary representation of a GeoTIFF usingwriteArrayBuffer.This function returns an ArrayBuffer which you can then save as a .tif file.:warning: writeArrayBuffer currently writes the values uncompressed
importGeoTIFF,{writeArrayBuffer}from'geotiff';constvalues=[1,2,3,4,5,6,7,8,9];constmetadata={height:3,width:3};constarrayBuffer=awaitwriteArrayBuffer(values,metadata);
You can also customize the metadata using names found in theTIFF Spec andGeoTIFF spec.
import{writeArrayBuffer}from'geotiff';constvalues=[1,2,3,4,5,6,7,8,9];constmetadata={GeographicTypeGeoKey:4326,height:3,ModelPixelScale:[0.031355,0.031355,0],ModelTiepoint:[0,0,0,11.331755000000001,46.268645,0],width:3};constarrayBuffer=awaitwriteArrayBuffer(values,metadata);
There is a nice HTML 5/WebGL based rendering library calledplotty, that allows for some really niceon the fly rendering of the data contained in a GeoTIFF.
<canvasid="plot"></canvas><script>// ...(asyncfunction(){consttiff=awaitfromUrl(url);constimage=awaittiff.getImage();constdata=awaitimage.readRasters();constcanvas=document.getElementById("plot");constplot=newplotty.plot({ canvas,data:data[0],width:image.getWidth(),height:image.getHeight(),domain:[0,256],colorScale:"viridis"});plot.render();})();</script>
There's also a library calledgeotiff-geokeys-to-proj4, that allows for reprojecting pixel coordinates and, therefore, consuming geospatial data contained in GeoTIFF.
geotiff.js has a limited support for files in the BigTIFF format. The limitationsoriginate in the capabilities of current JavaScript implementations regarding64 bit integer parsers and structures: there are no functions to read 64 bitintegers from a stream and no such typed arrays. As BigTIFF relies on 64 bitoffsets and also allows tag values of those types. In order to still providea reasonable support, the following is implemented:
- 64 bit integers are read as two 32 bit integers and then combined. Asnumbers in JavaScript are typically implemented as 64 bit floats, theremight be inaccuracies forvery large values.
- For 64 bit integer arrays, the default
Arraytype is used. This mightcause problems for some compression algorithms if those arrays are used forpixel values.
geotiff.js has some n-bit support which means that it supports unsigned integerdata reading with each element using a non-multiple of 8 bit depth. This onlyworks with band interleaved images (seethis related issue).
- Better support of geospatial parameters:
- WKT representation
The open issues can be found onGitHub.
If you have an idea, found a bug or have a remark, please open a ticket, we willlook into it ASAP.
Pull requests are welcome as well!
A list of community packages can be found inCOMMUNITY.md
This library was inspired byGeotiffParser. It provided agreat starting point, but lacked the capabilities to read the raw raster datawhich is the aim of geotiff.js.
About
geotiff.js is a small library to parse TIFF files for visualization or analysis. It is written in pure JavaScript, and is usable in both the browser and node.js applications.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.


