Parsing GeoTIFF Files in Java
Published
Lately I have been interested in associating elevation data to roads, especially in hilly cities like San Francisco. Fortunately the USGS publishes elevation data for the US as part of The National Map. Data is made available in GeoTIFF format via the download interface, or direct file download (folder names are latitude/longitude pairs, so n38w123
is the SF Bay Area).
I set out to parse the GeoTIFF files as part of an existing Java project using the GeoTools library, which was a good balance between feature-set and ease-of-use. The code and project is discussed below!
Source Code Posted to GitHub
The code sampled in this post is available on GitHub, and demonstrates how to parse GeoTIFF files in Java using the GeoTools library. Another project was created to experiment with the Java GDAL bindings, and is posted on GitHub as well.
GeoTIFF Compression
GeoTIFF files are often compressed to reduce file size. I found that the Java libraries that parse GeoTIFF files have varying support for compression algorithms. In my case, the GeoTIFF files from The National Map were compressed with LZW compression, and could not be read directly by GeoTools. I had to use the following GDAL command to decompress the GeoTIFF file first:
// https://gis.stackexchange.com/questions/92608/decompress-a-lzw-compressed-geotiff
gdal_translate pathtoinput.tif pathforoutput.tif -co COMPRESS=NONE
I found that the Java GDAL bindings had better support for reading compressed GeoTIFF files directly.
Loading GeoTIFF in Java
Reading the GeoTIFF files in Java was straightforward. The application appears to read all of the raster data into memory, and I had to increase my Java heap size when working with larger files.
// load tiff file to memory
File tiffFile = new File("/development/workspace/USGS_13_n38w123_uncomp.tif");
GeoTiffReader reader = new GeoTiffReader(tiffFile);
GridCoverage2D cov = reader.read(null);
Raster tiffRaster = cov.getRenderedImage().getData();
Sampling GeoTIFF data by GPS Coordinate
I was interested in looking up the elevation for a particular GPS latitude/longitude coordinate. This required converting the GPS coordinates to the appropriate x/y
pixel in the GeoTIFF raster before reading the data.

// convert lat/lon gps coordinates to tiff x/y coordinates
double lat = 37.75497;
double lon = -122.44580;
CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
GridGeometry2D gg = cov.getGridGeometry();
DirectPosition2D posWorld = new DirectPosition2D(wgs84, lon, lat); // longitude supplied first
GridCoordinates2D posGrid = gg.worldToGrid(posWorld);
// sample tiff data with at pixel coordinate
double[] rasterData = new double[1];
tiffRaster.getPixel(posGrid.x, posGrid.y, rasterData);
System.out.println(String.format("GeoTIFF data at %s, %s: %s", lat, lon, rasterData[0]));
Once the x/y
pixel coordinates are available, the data is read from the GeoTIFF Raster
object. An array of values may be returned (representing the different bands of data that a GeoTIFF file can have), however only the first value is taken in the example above.
Confirming the Results
It was exciting to finally read a value from the GeoTIFF, but I had to confirm the value was accurate. This was done by querying the same location in QGIS, and also consulting the Elevation Finder website.
While there was some variance in the reported values, I found the best results when using either:
- An uncompressed GeoTIFF file with GeoTools
- GDAL Java bindings
The alternative libraries listed below had some support for compression, but reported values were not as accurate as with GeoTools.
Alternative Libraries for Reading GeoTIFF files
I came across a few other alternatives for reading GeoTIFF files. While they did not work as well as GeoTools in my experience, I wanted to share them just incase. Once the Raster
object is available, the same steps above can be followed to sample the data.
Java Advanced Imaging – no GeoTIFF LZW Compression support
// https://stackoverflow.com/questions/15429011/how-to-convert-tiff-to-jpeg-png-in-java
FileSeekableStream s = new FileSeekableStream(tiffFile);
TIFFDecodeParam param = null;
ImageDecoder dec = ImageCodec.createImageDecoder("tiff", s, param);
RenderedImage op = dec.decodeAsRenderedImage(0);
Raster tiffRaster = op.getData();
ImageIO – no GeoTIFF LZW Compression support
// https://stackoverflow.com/questions/64537498/get-tiff-tag-value-including-non-ascii-characters-from-tiff-images-in-java-11
try (ImageInputStream input = ImageIO.createImageInputStream(tiffFile)) {
ImageReader reader = ImageIO.getImageReaders(input).next(); // TODO: Handle reader not found
reader.setInput(input);
// IIOMetadata metadata = reader.getImageMetadata(0); // 0 is the index of first image
BufferedImage image = reader.read(0);
Raster tiffRaster = image.getData();
}
Apache Commons Imaging – support for GeoTiff LZW compression but samples not as accurate
// https://gis.stackexchange.com/questions/119134/looking-for-an-open-source-java-based-geotiff-library
final TiffImagingParameters params = new TiffImagingParameters();
TiffImageParser readerT = new TiffImageParser();
BufferedImage image = readerT.getBufferedImage(tiffFile, params);
Raster tiffRaster = image.getData();
Comments
No responses yet