I'm new to GeoTools and as a start I'm trying to display a small GeoTiff file on a map .

The GeoTiff files I'm using are under 10MB (for example a 1MB file at 720x360 pixels) and covers the entire world (it shows average temperature). The data points I would like to display on the map is at a much lower level (for example locations of trees in a city park), so I need to zoom in a lot.

I'm using GeoTiffReader to read the tif file which I then add to a GridReaderLayer. The map is displayed using JMapFrame.showMap(map).

public class QuickStart { public static void main(String[] args) throws Exception { File file = new File("C:\\temp.tif"); GeoTiffReader reader = new GeoTiffReader(file); MapContent map = new MapContent(); map.setTitle("GeoTiff Test"); Layer layer = new GridReaderLayer(reader, createRGBStyle(reader)); map.addLayer(layer); JMapFrame.showMap(map); } private static Style createRGBStyle(AbstractGridCoverage2DReader reader) { GridCoverage2D cov = null; try { cov = reader.read(null); } catch (IOException giveUp) { throw new RuntimeException(giveUp); } int numBands = cov.getNumSampleDimensions(); if (numBands < 3) { return null; } String[] sampleDimensionNames = new String[numBands]; for (int i = 0; i < numBands; i++) { GridSampleDimension dim = cov.getSampleDimension(i); sampleDimensionNames[i] = dim.getDescription().toString(); } final int RED = 0, GREEN = 1, BLUE = 2; int[] channelNum = { -1, -1, -1 }; for (int i = 0; i < numBands; i++) { String name = sampleDimensionNames[i].toLowerCase(); if (name != null) { if (name.matches("red.*")) { channelNum[RED] = i + 1; } else if (name.matches("green.*")) { channelNum[GREEN] = i + 1; } else if (name.matches("blue.*")) { channelNum[BLUE] = i + 1; } } } if (channelNum[RED] < 0 || channelNum[GREEN] < 0 || channelNum[BLUE] < 0) { channelNum[RED] = 1; channelNum[GREEN] = 2; channelNum[BLUE] = 3; } SelectedChannelType[] sct = new SelectedChannelType[cov.getNumSampleDimensions()]; StyleFactory sf = CommonFactoryFinder.getStyleFactory(); FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(); ContrastEnhancement ce = sf.contrastEnhancement(ff.literal(1.0), ContrastMethod.NORMALIZE); for (int i = 0; i < 3; i++) { sct[i] = sf.createSelectedChannelType(String.valueOf(channelNum[i]), ce); } RasterSymbolizer sym = sf.getDefaultRasterSymbolizer(); ChannelSelection sel = sf.channelSelection(sct[RED], sct[GREEN], sct[BLUE]); sym.setChannelSelection(sel); return SLD.wrapSymbolizers(sym); } }

When the Swing application opens I can see the map and interact with it without major delays. However as I zoom in more and more, the map becomes slower and slower, until it becomes unusable (eventually the JVM will start using a lot of CPU and memory and crash), but when I zoom out again the map becomes fast again.

I was expecting the performance to get better as I work with smaller and smaller parts of the image, because the system only needs to work with a small subset of data / pixels. Yet it feels like the GeoTools library is scaling up the entire image before cropping it to fit the displayed area, rather than first getting a "crop" of the displayed area (by lat/lon) and then scaling it up to fit the map display.

Why is the zoomed in GeoTiff so slow in GeoTools and how can I make the map more responsive?

PS. I don't see any performance impact when I load the same GeoTiff file in a number of different GIS tools QGIS, ArcGIS Explorer, MapWindows, etc.). Using these other tools I can even zoom in and show just 4 pixels from the original GeoTiff as 4 huge boxes on the map, something GeoTools can't even get close to doing.

Here is an example TIF file that results in a java.lang.OutOfMemoryError: Java heap space when I zoom in (for example to show only one of the British islands). UPDATE: Sorry it seems the file gets converted to a PNG when uploaded, but it shows the size of the original file.

enter image description here

UPDATE: Output from gdalinfo.

Driver: GTiff/GeoTIFF Files: temp.tif Size is 720, 360 Coordinate System is: GEOGCS["WGS 84", DATUM["WGS_1984", SPHEROID["WGS 84",6378137,298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich",0], UNIT["degree",0.0174532925199433], AUTHORITY["EPSG","4326"]] Origin = (-179.999999999999970,90.000000000000000) Pixel Size = (0.499999999999950,-0.499999999999950) Metadata: AREA_OR_POINT=Area Image Structure Metadata: INTERLEAVE=PIXEL Corner Coordinates: Upper Left (-180.0000000, 90.0000000) (180d 0' 0.00"W, 90d 0' 0.00"N) Lower Left (-180.0000000, -90.0000000) (180d 0' 0.00"W, 90d 0' 0.00"S) Upper Right ( 180.0000000, 90.0000000) (180d 0' 0.00"E, 90d 0' 0.00"N) Lower Right ( 180.0000000, -90.0000000) (180d 0' 0.00"E, 90d 0' 0.00"S) Center ( -0.0000000, 0.0000000) ( 0d 0' 0.00"W, 0d 0' 0.00"N) Band 1 Block=720x2 Type=Byte, ColorInterp=Red Mask Flags: PER_DATASET ALPHA Band 2 Block=720x2 Type=Byte, ColorInterp=Green Mask Flags: PER_DATASET ALPHA Band 3 Block=720x2 Type=Byte, ColorInterp=Blue Mask Flags: PER_DATASET ALPHA Band 4 Block=720x2 Type=Byte, ColorInterp=Alpha

UPDATE: I profiled the application and got the results below. If this is a problem / bug with GeoTools, what would be the best way to report it? enter image description here

  • 3
    Check with gdalinfo tool which kind of geotiff you have. I would guess that it is untiled. – user30184 Oct 2 '15 at 10:41
  • The fact you get OOM probably means you aren't closing a resource – Ian Turton Oct 2 '15 at 10:43
  • I added the output from gdalinfo. How can I make a GeoTiff tiled? (Can it be done easily with a tool like QGIS?) However, I still don't understand why all the other tools can handle the file without problems, and why/how can a 1MB file cause the GeoTools to use over 1GB of memory and then kill the JVM? – Kooning Oct 2 '15 at 11:57
  • Your image is tiny: Size is 720, 360. That can't be any problem. I wonder if you ask GeoTools somehow to render the whole image with smaller pixels when you zoom in, without telling it that you are interested only about the small subset that you have in the viewport? uDig runs GeoTools for rendering, open your image with it. If uDig works fine, consider that there is something to fix in your code. – user30184 Oct 2 '15 at 14:12
  • Thanks for the uDig suggestion. The good news is that the GeoTiff works fine in uDig. However I still don't know what is wrong with my basic example. I updated my question with the complete code I'm using. (The style is copied from a GeoTools tutorial.) I'm using GeoTools 13.2 and 14-RC1 with Java 8 and didn't do any additional installation of native libs (as far as I know JAI is not installed on my system - I'm a little confused about JAI but from what I understand it seems like JAI-Ext is a Java only replacement for JAI?). My POM uses gt-geotiff, gt-epsg-hsql and gt-swing. – Kooning Oct 2 '15 at 16:03

Thanks to the users that provided guidance in the comments above. I'm going to answer my own question here in the hopes that it will help somebody else in the future. After struggling much longer than expected, I finally seem to have a setup that might work for me going forward.

I'm now using GeoTools 11.5 (any major version higher seems to have the memory issues I'm encountering - unfortunately I still don't know why, but I'm not going to waste more time on this now).

To get rid of the com.sun.media.jai.mlib.MediaLibAccessor error message when running on Java 8 I added the following code to the top op the class.

static {
    System.setProperty("com.sun.media.jai.disableMediaLib", "true");

I also had to change the style to use ContrastMethod.NONE, otherwise it would change the colours as I zoom and pan.

After all of these changes the map now renders acceptably fast, can pan and zoom to any level, doesn't crash the JVM with OOM problems and doesn't change colour of the map randomly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.