Resample a raster and write to a file

This example reads a raster in a GeoTIFF file and reprojects it to a different Coordinate Reference System (CRS). The result is saved as a World File in PNG format.

Direct dependencies

Maven coordinates Module info Remarks
org.apache.sis.storage:sis-geotiff org.apache.sis.storage.geotiff
org.apache.sis.non-free:sis-embedded-data org.apache.sis.referencing.database Non-Apache license.

The EPSG dependency is necessary for this example because a Coordinate Reference System (CRS) is instantiated from its EPSG code. But it would also be possible to specify a CRS without EPSG code, for example using Well Known Text (WKT) format.

Code example

The file name in following code need to be updated for yours data.

import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Collection;
import javax.imageio.ImageIO;
import java.awt.image.ImagingOpException;
import org.apache.sis.storage.Resource;
import org.apache.sis.storage.Aggregate;
import org.apache.sis.storage.DataStore;
import org.apache.sis.storage.DataStores;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.GridCoverageResource;
import org.apache.sis.coverage.grid.GridCoverage;
import org.apache.sis.coverage.grid.GridCoverageProcessor;
import org.apache.sis.image.Interpolation;
import org.apache.sis.referencing.CRS;
import org.opengis.referencing.operation.TransformException;
import org.opengis.util.FactoryException;

public class ResampleAndSaveRaster {
    /**
     * Demo entry point.
     *
     * @param  args  ignored.
     * @throws DataStoreException if an error occurred while reading the raster.
     * @throws FactoryException   if an error occurred while creating the Coordinate Reference System (CRS).
     * @throws TransformException if an error occurred while transforming coordinates to the target CRS.
     * @throws ImagingOpException unchecked exception thrown if an error occurred while resampling a tile.
     */
    public static void main(String[] args) throws DataStoreException, FactoryException, TransformException, IOException {
        try (DataStore store = DataStores.open(Paths.get("Airport.tiff"))) {
            /*
             * This data store is an aggregate because a GeoTIFF file may contain many images.
             * Not all data stores are aggregate, so the following casts do not apply to all.
             * For this example, we know that the file is GeoTIFF and we take the first image.
             */
            Collection<? extends Resource> allImages = ((Aggregate) store).components();
            GridCoverageResource firstImage = (GridCoverageResource) allImages.iterator().next();
            /*
             * The following code read fully the specified resource.
             * For reading only a subset, or for handling data bigger
             * than memory, see "How to..." in Apache SIS web site.
             */
            GridCoverage data = firstImage.read(null, null);
            System.out.printf("Information about the selected image:%n%s%n", data);
            /*
             * Reproject to "WGS 84 / World Mercator" (EPSG::3395) using bilinear interpolation.
             * This example lets Apache SIS choose the output grid size and resolution.
             * But it is possible to specify those aspects if desired.
             */
            var processor = new GridCoverageProcessor();
            processor.setInterpolation(Interpolation.BILINEAR);
            data = processor.resample(data, CRS.forCode("EPSG::3395"));
            System.out.printf("Information about the image after reprojection:%n%s%n", data);
            /*
             * TODO: Apache SIS is missing a `DataStores.write(…)` convenience method.
             * Writing a TIFF World File is possible but requires use of internal API.
             * A public convenience method will be added in next version.
             * For now we use Java I/O API.
             */
            ImageIO.write(data.render(null), "png", new File("test.png"));
        }
    }
}

Output

The output depends on the raster data and the locale. Below is an example:

Information about the image after reprojection:
GridCoverage2D
  ├─Coverage domain
  │   ├─Grid extent
  │   │   ├─Column: [0 … 8191] (8192 cells)
  │   │   └─Row:    [0 … 8191] (8192 cells)
  │   ├─Geographic extent
  │   │   ├─Lower bound:  48°59′20″N  02°31′33″E
  │   │   └─Upper bound:  49°01′08″N  02°34′16″E
  │   ├─Envelope
  │   │   ├─Easting:    465,341.6 … 468,618.39999999997  ∆E = 0.4 m
  │   │   └─Northing: 5,426,352.8 … 5,429,629.6          ∆N = 0.4 m
  │   ├─Coordinate reference system
  │   │   └─EPSG:32631 — WGS 84 / UTM zone 31N
  │   └─Conversion (origin in a cell center)
  │       └─┌                      ┐
  │         │ 0.4   0     465341.8 │
  │         │ 0    -0.4  5429629.4 │
  │         │ 0     0          1   │
  │         └                      ┘
  └─Image layout
      ├─Origin: 0, 0
      ├─Tile size: 8,192 × 128
      ├─Data type: byte
      └─Image is opaque.

Information about the image after reprojection:
GridCoverage2D
  ├─Coverage domain
  │   ├─Grid extent
  │   │   ├─Dimension 0: [0 … 8239] (8240 cells)
  │   │   └─Dimension 1: [0 … 8240] (8241 cells)
  │   ├─Geographic extent
  │   │   ├─Lower bound:  48°59′20″N  02°31′33″E
  │   │   └─Upper bound:  49°01′08″N  02°34′16″E
  │   ├─Envelope
  │   │   ├─Easting:   281,190.4273301751 … 286,207.11249780044  ∆E = 0.60882102 m
  │   │   └─Northing: 6,240,752.860382801 … 6,245,770.154371441  ∆N = 0.60882102 m
  │   ├─Coordinate reference system
  │   │   └─EPSG:3395 — WGS 84 / World Mercator
  │   └─Conversion (origin in a cell center)
  │       └─┌                                                            ┐
  │         │ 0.6088210154885099   0                  281190.73174068285 │
  │         │ 0                   -0.60882101548851  6245769.8499609330  │
  │         │ 0                    0                       1             │
  │         └                                                            ┘
  └─Image layout
      ├─Origin: 0, 0
      ├─Tile size: 1,648 × 201
      ├─Data type: byte
      └─Image is opaque.