I've been having trouble getting the geotools StreamingRenderer
to display an image from a Geotiff correctly. I'm using a visible earth geotiff from nasa but I see this problem with other EPSGE:4326 geotiffs. Geotiffs that are not EPSG:4326 do not have this problem, and render beautifully. Geotools version is 31.1
This is the CRS WKT from the GeotiffReader
CRS toWKT()
method:
GEOGCS["WGS 84",
DATUM["World Geodetic System 1984",
SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]],
UNIT["degree", 0.017453292519943295],
AXIS["Geodetic latitude", NORTH],
AXIS["Geodetic longitude", EAST],
AUTHORITY["EPSG","4326"]]
My understanding is that StreamingRenderer
should read from the given reader and reproject/resample to the viewport bounds and image dimensions, but it produces an image that is flipped on it's side at best, or an image with no data at worst if I request the entire EPSG:4326 bounds.
@Test
public void testGeotiffReader() throws IOException, FactoryException {
Path path = TestSupport.classPathResourceAsFile("/testdata/grids/eo_base.tif").toPath();
GridCoverage2DReader reader = GridFormatFinder.findFormat(path.toFile()).getReader(path.toFile());
ParameterValue bands = GeoTiffFormat.BANDS.createValue();
bands.setValue(new int[]{0});
GridCoverage2D coverage = reader.read(new GeneralParameterValue[]{bands});
//at this point the coverage is rendered in the correct orientation
Path out = Paths.get("rendered-coverage.png");
try(FileOutputStream fos= new FileOutputStream(out.toFile())) {
ImageIO.write(coverage.getRenderedImage(),"PNG",fos);
}
ReferencedEnvelope envelope = new ReferencedEnvelope(-180,0,0,90,CRS.decode("EPSG:4326"));
Rectangle imageDim = new Rectangle(0, 0, 1200, 800);
MapViewport viewport = new MapViewport(envelope,false);
MapContent content = new MapContent();
content.setViewport(viewport);
StyleFactory sf = CommonFactoryFinder.getStyleFactory();
FilterFactory ff = CommonFactoryFinder.getFilterFactory();
ContrastEnhancement ce = sf.contrastEnhancement(ff.literal(1.0), ContrastMethod.NORMALIZE);
SelectedChannelType sct = sf.createSelectedChannelType(String.valueOf(1), ce);
RasterSymbolizer sym = sf.getDefaultRasterSymbolizer();
ChannelSelection sel = sf.channelSelection(sct);
sym.setChannelSelection(sel);
Style style = SLD.wrapSymbolizers(sym);
GridReaderLayer layer = new GridReaderLayer(reader, style);
content.addLayer(layer);
StreamingRenderer renderer = new StreamingRenderer();
renderer.setMapContent(content);
final BufferedImage image =
new BufferedImage(imageDim.width, imageDim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D graphics = image.createGraphics();
renderer.paint(graphics, imageDim, envelope);
final ImageWorker iw = new ImageWorker(image);
iw.prepareForRendering();
out = Paths.get("streaming-renderer.png");
/**
* At this point, the image will be flipped on it's side
*/
try(FileOutputStream fos = new FileOutputStream(out.toFile())) {
iw.writePNG(fos, null, 0, false, false);
}
}
rendered-coverage.png
as rendered without StreamingRenderer
is fine:
But when rendered with StreamingRenderer
to the viewport:
Or a completely blank image if requesting the full extent. I've tried forceXY, swapping around coordinate ordering in referenced envelope, nothing seems to work. What am I missing? How can I get EPSG:4326 geotiffs to render correct? I'm sure I'm missing something obvious here.
I've tried different EPSG:4326 geotiffs, forceXY system property, swapping coordinates in ReferencedEnvelope
I can't swear to it but I suspect it is a well knownish issue with using GeoTiffReader. I say this because our imagery tutorial contains the following code:
AbstractGridFormat format = GridFormatFinder.findFormat(rasterFile);
// this is a bit hacky but does make more geotiffs work
Hints hints = new Hints();
if (format instanceof GeoTiffFormat) {
hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
}
reader = format.getReader(rasterFile, hints);
To be honest anytime I have to deal with 4326 I feel the need to go and shower to get clean again.