gisgeotoolsgeotiff

Using StreamingRenderer with GeotiffReader


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: enter image description here

But when rendered with StreamingRenderer to the viewport: enter image description here

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


Solution

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