/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2016, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * */ package org.geotools.gce.geotiff; import java.awt.Color; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Logger; import javax.imageio.stream.FileImageInputStream; import javax.media.jai.ImageLayout; import javax.media.jai.Interpolation; import javax.media.jai.PlanarImage; import javax.media.jai.ROI; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridEnvelope2D; import org.geotools.coverage.grid.GridGeometry2D; import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader; import org.geotools.coverage.grid.io.AbstractGridFormat; import org.geotools.coverage.grid.io.GroundControlPoints; import org.geotools.coverage.grid.io.OverviewPolicy; import org.geotools.coverage.grid.io.imageio.IIOMetadataDumper; import org.geotools.coverage.grid.io.imageio.geotiff.TiePoint; import org.geotools.coverage.processing.CoverageProcessor; import org.geotools.coverage.processing.operation.Scale; import org.geotools.data.DataSourceException; import org.geotools.data.PrjFileReader; import org.geotools.factory.Hints; import org.geotools.geometry.DirectPosition2D; import org.geotools.geometry.GeneralEnvelope; import org.geotools.referencing.CRS; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.referencing.operation.matrix.XAffineTransform; import org.geotools.referencing.operation.projection.Sinusoidal; import org.geotools.referencing.operation.transform.ProjectiveTransform; import org.geotools.resources.coverage.CoverageUtilities; import org.geotools.test.TestData; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.opengis.parameter.GeneralParameterValue; import org.opengis.parameter.ParameterValue; import org.opengis.parameter.ParameterValueGroup; import org.opengis.referencing.FactoryException; import org.opengis.referencing.NoSuchAuthorityCodeException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.crs.GeographicCRS; import org.opengis.referencing.crs.ProjectedCRS; import org.opengis.referencing.datum.Ellipsoid; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.Projection; import it.geosolutions.imageio.maskband.DatasetLayout; import it.geosolutions.imageio.utilities.ImageIOUtilities; import it.geosolutions.jaiext.JAIExt; import it.geosolutions.jaiext.range.NoDataContainer; import it.geosolutions.jaiext.range.Range; /** * Testing {@link GeoTiffReader} as well as {@link IIOMetadataDumper}. * * @author Simone Giannecchini * * @source $URL$ */ public class GeoTiffReaderTest extends org.junit.Assert { private final static Logger LOGGER = org.geotools.util.logging.Logging .getLogger(GeoTiffReaderTest.class.toString()); static boolean oldOverrideInnerCRS; @Before public void saveGlobals() { oldOverrideInnerCRS = GeoTiffReader.OVERRIDE_INNER_CRS; GeoTiffReader.OVERRIDE_INNER_CRS = true; JAIExt.initJAIEXT(true, true); } @After public void cleanupGlobals() { System.clearProperty(GeoTiffReader.OVERRIDE_CRS_SWITCH); GeoTiffReader.OVERRIDE_INNER_CRS = oldOverrideInnerCRS; JAIExt.initJAIEXT(false, true); } /** * Testing proper CRS override with PRJ. * * @throws IllegalArgumentException * @throws IOException * @throws FactoryException */ @Test public void prjOverrideTesting1() throws IllegalArgumentException, IOException, FactoryException { // // PRJ override // final File noCrs = TestData.file(GeoTiffReaderTest.class, "override/sample.tif"); final AbstractGridFormat format = new GeoTiffFormat(); assertTrue(format.accepts(noCrs)); GeoTiffReader reader = (GeoTiffReader) format.getReader(noCrs); CoordinateReferenceSystem crs=reader.getCoordinateReferenceSystem(); final File prj= TestData.file(GeoTiffReaderTest.class, "override/sample.prj"); final CoordinateReferenceSystem crs_=new PrjFileReader(new FileInputStream(prj).getChannel()).getCoordinateReferenceSystem(); assertTrue(CRS.equalsIgnoreMetadata(crs, crs_)); GridCoverage2D coverage=reader.read(null); assertTrue(CRS.equalsIgnoreMetadata(coverage.getCoordinateReferenceSystem(), crs_)); coverage.dispose(true); } /** * Testing proper CRS override with PRJ. * * @throws IllegalArgumentException * @throws IOException * @throws FactoryException */ @Test public void prjOverrideTesting2() throws IllegalArgumentException, IOException, FactoryException { // // PRJ override // final File noCrs = TestData.file(GeoTiffReaderTest.class, "override/sample.tif"); final File prj= TestData.file(GeoTiffReaderTest.class, "override/sample.prj"); final CoordinateReferenceSystem crs_=new PrjFileReader(new FileInputStream(prj).getChannel()).getCoordinateReferenceSystem(); // NO override GeoTiffReader.OVERRIDE_INNER_CRS=false; // getting a reader GeoTiffReader reader = new GeoTiffReader(noCrs); if(TestData.isInteractiveTest()){ IIOMetadataDumper iIOMetadataDumper = new IIOMetadataDumper( reader.getMetadata() .getRootNode()); System.out.println(iIOMetadataDumper.getMetadata()); } // reading the coverage GridCoverage2D coverage1 = reader.read(null); // check coverage and crs assertNotNull(coverage1); assertNotNull(coverage1.getCoordinateReferenceSystem()); assertNotSame(coverage1.getCoordinateReferenceSystem(),crs_); reader.dispose(); coverage1.dispose(true); } /** * Test for reading bad/strange geotiff files * * @throws IllegalArgumentException * @throws IOException * @throws FactoryException */ @Test // @Ignore public void testReaderBadGeotiff() throws IllegalArgumentException, IOException, FactoryException { // // no crs geotiff // final File noCrs = TestData.file(GeoTiffReaderTest.class, "no_crs.tif"); final AbstractGridFormat format = new GeoTiffFormat(); assertTrue(format.accepts(noCrs)); GeoTiffReader reader = (GeoTiffReader) format.getReader(noCrs); CoordinateReferenceSystem crs=reader.getCoordinateReferenceSystem(); assertTrue(CRS.equalsIgnoreMetadata(crs, AbstractGridFormat.getDefaultCRS())); GridCoverage2D coverage=reader.read(null); assertTrue(CRS.equalsIgnoreMetadata(coverage.getCoordinateReferenceSystem(), AbstractGridFormat.getDefaultCRS())); // hint for CRS crs = CRS.decode("EPSG:32632", true); final Hints hint = new Hints(); hint.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs); // getting a reader reader = new GeoTiffReader(noCrs, hint); // reading the coverage GridCoverage2D coverage1 = reader.read(null); // check coverage and crs assertNotNull(coverage1); assertNotNull(coverage1.getCoordinateReferenceSystem()); assertEquals(CRS.lookupIdentifier(coverage1.getCoordinateReferenceSystem(), true), "EPSG:32632"); reader.dispose(); // // use prj and wld // final File wldprjFile = TestData.file(GeoTiffReaderTest.class, "no_crs_no_envelope.tif"); assertTrue(format.accepts(wldprjFile)); // getting a reader reader = new GeoTiffReader(wldprjFile); // reading the coverage GridCoverage2D coverage2 = reader.read(null); // check coverage and crs assertNotNull(coverage2); assertNotNull(coverage2.getCoordinateReferenceSystem()); assertEquals(CRS.lookupIdentifier(coverage2.getCoordinateReferenceSystem(), true), "EPSG:32632"); reader.dispose(); // // use prj and hint // final File wldFile = TestData.file(GeoTiffReaderTest.class, "no_crs_no_envelope2.tif"); assertTrue(format.accepts(wldFile)); // getting a reader reader = new GeoTiffReader(wldFile, hint); // reading the coverage GridCoverage2D coverage3 = reader.read(null); // check coverage and crs assertNotNull(coverage3); assertNotNull(coverage3.getCoordinateReferenceSystem()); assertEquals(CRS.lookupIdentifier(coverage3.getCoordinateReferenceSystem(), true), "EPSG:32632"); reader.dispose(); coverage1.dispose(true); coverage2.dispose(true); coverage3.dispose(true); } /** * Test for reading geotiff files * * @throws IllegalArgumentException * @throws IOException * @throws NoSuchAuthorityCodeException */ @Test public void testReader() throws Exception { final File baseDirectory = TestData.file(GeoTiffReaderTest.class, "."); final File writeDirectory =new File(baseDirectory,Long.toString(System.currentTimeMillis())); writeDirectory.mkdir(); final File files[] = baseDirectory.listFiles(); final int numFiles = files.length; final AbstractGridFormat format = new GeoTiffFormat(); for (int i = 0; i < numFiles; i++) { StringBuilder buffer = new StringBuilder(); final String path = files[i].getAbsolutePath().toLowerCase(); if (!path.endsWith("tif") && !path.endsWith("tiff")||path.contains("no_crs")) continue; buffer.append(files[i].getAbsolutePath()).append("\n"); Object o; if (i % 2 == 0) // testing file o = files[i]; else // testing url o = files[i].toURI().toURL(); if (format.accepts(o)) { buffer.append("ACCEPTED").append("\n"); // getting a reader GeoTiffReader reader = new GeoTiffReader(o, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); if (reader != null) { // reading the coverage final GridCoverage2D coverage = reader.read(null); // Crs and envelope if (TestData.isInteractiveTest()) { buffer.append("CRS: ").append( coverage.getCoordinateReferenceSystem2D() .toWKT()).append("\n"); buffer.append("GG: ").append( coverage.getGridGeometry().toString()).append("\n"); } // display metadata if (org.geotools.TestData.isExtensiveTest()) { IIOMetadataDumper iIOMetadataDumper = new IIOMetadataDumper( reader.getMetadata() .getRootNode()); buffer.append("TIFF metadata: ").append( iIOMetadataDumper.getMetadata()).append("\n"); } // layout checks final ImageLayout layout = reader.getImageLayout(); assertNotNull(layout); assertNotNull(layout.getColorModel(null)); assertNotNull(layout.getSampleModel(null)); assertEquals(0,layout.getMinX(null)); assertEquals(0,layout.getMinY(null)); assertTrue(layout.getWidth(null) > 0); assertTrue(layout.getHeight(null) > 0); assertEquals(0,layout.getTileGridXOffset(null)); assertEquals(0,layout.getTileGridYOffset(null)); assertTrue(layout.getTileHeight(null) > 0); assertTrue(layout.getTileWidth(null) > 0); // showing it if (TestData.isInteractiveTest()){ coverage.show(); } else { PlanarImage.wrapRenderedImage(coverage.getRenderedImage()).getTiles(); } if (reader.getGroundControlPoints() != null) { // we cannot write GCPs yet continue; } // write and read back writeAndReadBackCheck(coverage, format, writeDirectory, o); } } else buffer.append("NOT ACCEPTED").append("\n"); if (TestData.isInteractiveTest()) LOGGER.info(buffer.toString()); } } private void writeAndReadBackCheck(GridCoverage2D coverage, AbstractGridFormat format, File writeDirectory, Object o) throws IOException, FactoryException { final File destFile = File.createTempFile("test", ".tif",writeDirectory); final GeoTiffWriter writer= new GeoTiffWriter(destFile); writer.write(coverage, null); writer.dispose(); // read back assertTrue(format.accepts(destFile)); GeoTiffReader reader = new GeoTiffReader(destFile, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); final GridCoverage2D destCoverage = reader.read(null); reader.dispose(); final double eps=XAffineTransform.getScaleX0((AffineTransform)coverage.getGridGeometry().getGridToCRS())*1E-2; String toString = o.toString(); assertTrue("CRS comparison failed:" + toString, CRS.findMathTransform(coverage.getCoordinateReferenceSystem(), destCoverage.getCoordinateReferenceSystem(), true).isIdentity()); assertTrue("CRS comparison failed:" + toString, CRS.equalsIgnoreMetadata(coverage.getCoordinateReferenceSystem(), destCoverage.getCoordinateReferenceSystem())); assertTrue("GridRange comparison failed:" + toString, coverage.getGridGeometry().getGridRange().equals(destCoverage.getGridGeometry().getGridRange())); assertTrue("Envelope comparison failed:" + toString,((GeneralEnvelope)coverage.getGridGeometry().getEnvelope()).equals(destCoverage.getGridGeometry().getEnvelope(),eps,false)); coverage.dispose(true); destCoverage.dispose(true); } @Test public void testBandNames() throws Exception { final File file = TestData.file(GeoTiffReaderTest.class, "wind.tiff"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); GridCoverage2D coverage = format.getReader(file).read(null); String band1Name = coverage.getSampleDimension(0).getDescription().toString(); String band2Name = coverage.getSampleDimension(1).getDescription().toString(); assertEquals("Band1", band1Name); assertEquals("Band2", band2Name); } @Test public void testThreadedTransformations() throws Exception { Callable<Void> callable = new Callable<Void>() { @Override public Void call() throws Exception { final File baseDirectory = TestData.file(GeoTiffReaderTest.class, "."); final File files[] = baseDirectory.listFiles(new FilenameFilter() { @Override public boolean accept(File dir, String name) { String lcName = name.toLowerCase(); return lcName.endsWith("tif") || lcName.endsWith("tiff"); } }); final AbstractGridFormat format = new GeoTiffFormat(); for (File file : files) { AbstractGridCoverage2DReader reader = null; try { reader = format.getReader(file); if(reader != null) { GridCoverage2D coverage = reader.read(null); ImageIOUtilities.disposeImage(coverage.getRenderedImage()); coverage.dispose(true); } } finally { if(reader != null) { reader.dispose(); } } } return null; } }; // used to deadlock under load, check it does not now ExecutorService executor = Executors.newCachedThreadPool(); try { List<Future<Void>> futures = new ArrayList<>(); for (int i = 0; i < 8; i++) { Future<Void> f = executor.submit(callable); futures.add(f); } for (Future<Void> f : futures) { f.get(); } } finally { executor.shutdown(); } } /** * Test that the reader is able to read NoData */ @Test public void testNoData() throws Exception { final File file = TestData.file(GeoTiffReaderTest.class, "nodata.tiff"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); GridCoverage2D coverage = format.getReader(file).read(null); // Ensure proper NoData is set NoDataContainer noDataProperty = CoverageUtilities.getNoDataProperty(coverage); assertNotNull(noDataProperty); Range nd = noDataProperty.getAsRange(); assertNotNull(nd); assertTrue(nd.isPoint()); assertEquals(nd.getMin().doubleValue(), -9999, 0.001); assertEquals(nd.getMax().doubleValue(), -9999, 0.001); } /** * Test that the reader sets a Meters as default UoM definition for CRS with an undefined UoM definition */ @Test public void testUoMDefault() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class,"no_uom.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); GridCoverage2D coverage = format.getReader(file).read(null); // Getting CRS CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem(); // Getting its string definition String crsDef = crs.toWKT(); // Ensure the Unit of Measure define is Meter assertTrue(crsDef.contains("UNIT[\"m\", 1.0]")); } /** * Test that the reader sets a ROI property based on the input internal masks */ @Test public void testMasking() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "mask/masked.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); AbstractGridCoverage2DReader reader = format.getReader(file); GridCoverage2D coverage = reader.read(null); // Checking if ROI is present checkCoverageROI(coverage); // Getting DatasetLayout and testing it DatasetLayout layout = reader.getDatasetLayout(); Assert.assertEquals(5, layout.getNumInternalMasks()); Assert.assertEquals(-1, layout.getNumExternalMasks()); Assert.assertEquals(4, layout.getNumInternalOverviews()); Assert.assertEquals(-1, layout.getNumExternalOverviews()); Assert.assertEquals(-1, layout.getNumExternalMaskOverviews()); Assert.assertNull(layout.getExternalMasks()); Assert.assertNull(layout.getExternalOverviews()); Assert.assertNull(layout.getExternalMaskOverviews()); // Doing a minor Operation in order to make ROI available CoverageProcessor processor = CoverageProcessor.getInstance(); Scale scaleOp = (Scale) processor.getOperation("Scale"); // getting operation parameters ParameterValueGroup parameters = scaleOp.getParameters(); // Setting the parameters parameters.parameter("Source").setValue(coverage); parameters.parameter("xScale").setValue(Float.valueOf(3f)); parameters.parameter("yScale").setValue(Float.valueOf(3f)); parameters.parameter("xTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("yTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("Interpolation").setValue( Interpolation.getInstance(Interpolation.INTERP_NEAREST)); // Executing operation coverage = (GridCoverage2D) scaleOp.doOperation(parameters, null); // Checking if ROI is present checkCoverageROI(coverage); // Evaluate results byte[] results = new byte[3]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-87.517, 25.302); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-87.005, 26.336); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.891, 26.159); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-86.401, 26.297); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.411, 27.289); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); } /** * Test that the reader sets a ROI property based on the input internal masks, and that the ROI * is the expected one, taking into account the same subsampling factors during the read as the * image */ @Test public void testMaskSubsampling() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "mask/masked2.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); AbstractGridCoverage2DReader reader = format.getReader(file); // prepare to read a sub.sampled image GeneralParameterValue[] params = new GeneralParameterValue[1]; // Define a GridGeometry in order to reduce the output final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D .createValue(); final GeneralEnvelope envelope = reader.getOriginalEnvelope(); final Dimension dim = new Dimension(); dim.setSize(reader.getOriginalGridRange().getSpan(0) / 4, reader.getOriginalGridRange().getSpan(1) / 4); final Rectangle rasterArea = ((GridEnvelope2D) reader.getOriginalGridRange()); rasterArea.setSize(dim); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, envelope)); params[0] = gg; GridCoverage2D coverage = reader.read(params); // Checking if ROI is present checkCoverageROI(coverage); // check the ROI and the image are black in the same pixels ROI roi = CoverageUtilities.getROIProperty(coverage); Raster roiImage = roi.getAsImage().getData(); Raster image = coverage.getRenderedImage().getData(); int[] px = new int[3]; int[] rpx = new int[1]; for (int i = 0; i < image.getHeight(); i++) { for (int j = 0; j < image.getWidth(); j++) { image.getPixel(j, i, px); roiImage.getPixel(j, i, rpx); if (px[0] == 0 && px[1] == 0 && px[2] == 0) { assertEquals("Difference at " + i + "," + j, 0, rpx[0]); } else { assertEquals("Difference at " + i + "," + j, 1, rpx[0]); } } } } /** * Test that the reader sets a ROI property based on the input external masks */ @Test public void testMaskingExternal() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "mask/external.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); AbstractGridCoverage2DReader reader = format.getReader(file); GridCoverage2D coverage = reader.read(null); // Checking if ROI is present checkCoverageROI(coverage); // Getting DatasetLayout and testing it DatasetLayout layout = reader.getDatasetLayout(); Assert.assertEquals(0, layout.getNumInternalMasks()); Assert.assertEquals(1, layout.getNumExternalMasks()); Assert.assertEquals(4, layout.getNumInternalOverviews()); Assert.assertEquals(0, layout.getNumExternalOverviews()); Assert.assertEquals(0, layout.getNumExternalMaskOverviews()); Assert.assertTrue(!layout.getExternalMasks().getAbsolutePath().isEmpty()); Assert.assertNull(layout.getExternalOverviews()); Assert.assertNull(layout.getExternalMaskOverviews()); // Doing a minor Operation in order to make ROI available CoverageProcessor processor = CoverageProcessor.getInstance(); Scale scaleOp = (Scale) processor.getOperation("Scale"); // getting operation parameters ParameterValueGroup parameters = scaleOp.getParameters(); // Setting the parameters parameters.parameter("Source").setValue(coverage); parameters.parameter("xScale").setValue(Float.valueOf(3f)); parameters.parameter("yScale").setValue(Float.valueOf(3f)); parameters.parameter("xTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("yTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("Interpolation").setValue( Interpolation.getInstance(Interpolation.INTERP_NEAREST)); // Executing operation coverage = (GridCoverage2D) scaleOp.doOperation(parameters, null); // Checking if ROI is present checkCoverageROI(coverage); // Evaluate results byte[] results = new byte[3]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-87.517, 25.302); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-87.005, 26.336); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.891, 26.159); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-86.401, 26.297); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.411, 27.289); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); } /** * Test that the reader can read a GeoTIFF with GCPs (even if it cannot reference it) */ @Test public void testGCPs() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "box_gcp.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); assertTrue(format.accepts(file)); AbstractGridCoverage2DReader reader = format.getReader(file); GridCoverage2D coverage = reader.read(null); // Get CRS and transform, they should be 404000 and CoordinateReferenceSystem crs = coverage.getCoordinateReferenceSystem(); assertEquals(AbstractGridFormat.getDefaultCRS(), crs); assertEquals(ProjectiveTransform.create(new AffineTransform()), coverage.getGridGeometry() .getGridToCRS()); // Getting its string definition String crsDef = crs.toWKT(); // Ensure the Unit of Measure define is Meter assertTrue(crsDef.contains("UNIT[\"m\", 1.0]")); // Ground control points GroundControlPoints gcps = reader.getGroundControlPoints(); assertNotNull(gcps); // the tie point CRS has the same size as WGS84) GeographicCRS gcrs = (GeographicCRS) gcps.getCoordinateReferenceSystem(); Ellipsoid ellipsoid = gcrs.getDatum().getEllipsoid(); assertEquals(ellipsoid.getSemiMajorAxis(), DefaultGeographicCRS.WGS84.getDatum() .getEllipsoid().getSemiMajorAxis(), 1e-6); assertEquals(ellipsoid.getInverseFlattening(), DefaultGeographicCRS.WGS84.getDatum() .getEllipsoid().getInverseFlattening(), 1e-6); // check the tie points final double EPS = 1e-9; List<TiePoint> tiePoints = gcps.getTiePoints(); // t1 assertEquals(49.5005, tiePoints.get(0).getValueAt(0), EPS); assertEquals(250.909, tiePoints.get(0).getValueAt(1), EPS); assertEquals(-84, tiePoints.get(0).getValueAt(3), EPS); assertEquals(33, tiePoints.get(0).getValueAt(4), EPS); // t2 assertEquals(49.5005, tiePoints.get(1).getValueAt(0), EPS); assertEquals(51.8182, tiePoints.get(1).getValueAt(1), EPS); assertEquals(-84, tiePoints.get(1).getValueAt(3), EPS); assertEquals(34, tiePoints.get(1).getValueAt(4), EPS); // t3 assertEquals(248.824, tiePoints.get(2).getValueAt(0), EPS); assertEquals(51.8182, tiePoints.get(2).getValueAt(1), EPS); assertEquals(-83, tiePoints.get(2).getValueAt(3), EPS); assertEquals(34, tiePoints.get(2).getValueAt(4), EPS); } /** * Test that the reader can read a GeoTIFF with * Sinusoidal projection */ @Test public void testSinusoidalCRS() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "worldsinus.tif"); final AbstractGridFormat format = new GeoTiffFormat(); assertTrue(format.accepts(file)); AbstractGridCoverage2DReader reader = null; try { reader = format.getReader(file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); GridCoverage2D coverage = reader.read(null); CoordinateReferenceSystem crs = reader.getCoordinateReferenceSystem(); assertTrue(crs instanceof ProjectedCRS); Projection conversion = ((ProjectedCRS) crs).getConversionFromBase(); assertNotNull(conversion); MathTransform transform = conversion.getMathTransform(); assertNotNull(transform); assertTrue(transform instanceof Sinusoidal); final File writeDirectory = new File(TestData.file(GeoTiffReaderTest.class, "."), Long.toString(System.currentTimeMillis())); writeDirectory.mkdir(); writeAndReadBackCheck(coverage, format, writeDirectory, file); } finally { if (reader != null) { reader.dispose(); } } } /** * Test that the reader sets a ROI property based on the input external masks with external overviews */ @Test public void testMaskingExternalOverviews() throws Exception { // Reading file final File file = TestData.file(GeoTiffReaderTest.class, "mask/external2.tif"); assertNotNull(file); final AbstractGridFormat format = new GeoTiffFormat(); AbstractGridCoverage2DReader reader = format.getReader(file); GeneralParameterValue[] params = new GeneralParameterValue[2]; // Define a GridGeometry in order to reduce the output final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D .createValue(); final GeneralEnvelope envelope = reader.getOriginalEnvelope(); final Dimension dim = new Dimension(); dim.setSize(reader.getOriginalGridRange().getSpan(0) / 2.0, reader.getOriginalGridRange() .getSpan(1) / 2.0); final Rectangle rasterArea = ((GridEnvelope2D) reader.getOriginalGridRange()); rasterArea.setSize(dim); final GridEnvelope2D range = new GridEnvelope2D(rasterArea); gg.setValue(new GridGeometry2D(range, envelope)); params[0] = gg; // Define Overview Policy final ParameterValue<OverviewPolicy> policy = AbstractGridFormat.OVERVIEW_POLICY .createValue(); policy.setValue(OverviewPolicy.NEAREST); params[1] = policy; GridCoverage2D coverage = reader.read(params); // Checking if ROI is present checkCoverageROI(coverage); // Getting DatasetLayout and testing it DatasetLayout layout = reader.getDatasetLayout(); Assert.assertEquals(0, layout.getNumInternalMasks()); Assert.assertEquals(1, layout.getNumExternalMasks()); Assert.assertEquals(4, layout.getNumInternalOverviews()); Assert.assertEquals(0, layout.getNumExternalOverviews()); Assert.assertEquals(4, layout.getNumExternalMaskOverviews()); Assert.assertTrue(!layout.getExternalMasks().getAbsolutePath().isEmpty()); Assert.assertNull(layout.getExternalOverviews()); Assert.assertTrue(!layout.getExternalMaskOverviews().getAbsolutePath().isEmpty()); // Doing a minor Operation in order to make ROI available CoverageProcessor processor = CoverageProcessor.getInstance(); Scale scaleOp = (Scale) processor.getOperation("Scale"); // getting operation parameters ParameterValueGroup parameters = scaleOp.getParameters(); // Setting the parameters parameters.parameter("Source").setValue(coverage); parameters.parameter("xScale").setValue(Float.valueOf(3f)); parameters.parameter("yScale").setValue(Float.valueOf(3f)); parameters.parameter("xTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("yTrans").setValue(Float.valueOf(0.0f)); parameters.parameter("Interpolation").setValue( Interpolation.getInstance(Interpolation.INTERP_NEAREST)); // Executing operation coverage = (GridCoverage2D) scaleOp.doOperation(parameters, null); // Checking if ROI is present checkCoverageROI(coverage); // Evaluate results byte[] results = new byte[3]; DirectPosition2D position = new DirectPosition2D(); // Should be 0 position.setLocation(-87.517, 25.25); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-87.005, 26.336); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.891, 26.159); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); // Should be > 0 position.setLocation(-86.401, 26.297); results = coverage.evaluate(position, results); assertTrue(results[0] != 0); assertTrue(results[1] != 0); assertTrue(results[2] != 0); // Should be 0 position.setLocation(-87.411, 27.289); results = coverage.evaluate(position, results); assertEquals(results[0], 0); assertEquals(results[1], 0); assertEquals(results[2], 0); } /** * Private method for checking if ROI size and image size are equals * * @param coverage Input {@link GridCoverage2D} to test */ private void checkCoverageROI(GridCoverage2D coverage) { ROI roi = CoverageUtilities.getROIProperty(coverage); assertNotNull(roi); // Ensure has the same size of the input image checkROI(coverage, roi); // make sure the ROI is also present at the image level Object imageRoi = coverage.getRenderedImage().getProperty("ROI"); assertTrue(imageRoi instanceof ROI); checkROI(coverage, (ROI) imageRoi); } private void checkROI(GridCoverage2D coverage, ROI roi) { Rectangle roiBounds = roi.getBounds(); Rectangle imgBounds = coverage.getGridGeometry().getGridRange2D(); assertEquals(imgBounds.x, roiBounds.x); assertEquals(imgBounds.y, roiBounds.y); assertEquals(imgBounds.width, roiBounds.width); assertEquals(imgBounds.height, roiBounds.height); } /** * Test what we can do and what not with */ @Test // @Ignore public void testTransparencySettings() throws Exception { final AbstractGridFormat format = new GeoTiffFormat(); File file = TestData.file(GeoTiffReaderTest.class,"002025_0100_010722_l7_01_utm2.tiff"); if (format.accepts(file)) { // getting a reader GeoTiffReader reader = new GeoTiffReader(file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); if (reader != null) { // reading the coverage GridCoverage2D coverage = reader.read(null); assertNotNull(coverage); assertTrue(coverage.getRenderedImage().getSampleModel().getNumBands() == 1); final ParameterValue<Color> colorPV = AbstractGridFormat.INPUT_TRANSPARENT_COLOR.createValue(); colorPV.setValue(Color.BLACK); coverage = reader.read(new GeneralParameterValue[] { colorPV }); assertNotNull(coverage); assertTrue(coverage.getRenderedImage().getSampleModel().getNumBands() == 2); // showing it if (TestData.isInteractiveTest()) coverage.show(); else PlanarImage.wrapRenderedImage(coverage.getRenderedImage()).getTiles(); } } else assertFalse(true); // we should not get here file = TestData.file(GeoTiffReaderTest.class,"gaarc_subset.tiff"); if (format.accepts(file)) { // getting a reader GeoTiffReader reader = new GeoTiffReader(file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); if (reader != null) { // reading the coverage GridCoverage2D coverage = reader.read(null); assertNotNull(coverage); assertTrue(coverage.getRenderedImage().getSampleModel().getNumBands() == 3); final ParameterValue<Color> colorPV = AbstractGridFormat.INPUT_TRANSPARENT_COLOR.createValue(); colorPV.setValue(new Color(34,53,87)); coverage = reader.read(new GeneralParameterValue[] { colorPV }); assertNotNull(coverage); assertTrue(coverage.getRenderedImage().getSampleModel().getNumBands() == 4); // showing it if (TestData.isInteractiveTest()) coverage.show(); else PlanarImage.wrapRenderedImage(coverage.getRenderedImage()).getTiles(); } } else assertFalse(true); // we should not get here // now we test that we cannot do colormasking on a non-rendered output file = TestData.file(GeoTiffReaderTest.class,"wind.tiff"); if (format.accepts(file)) { // getting a reader GeoTiffReader reader = new GeoTiffReader(file, new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE)); if (reader != null) { // reading the coverage GridCoverage2D coverage = reader.read(null); assertNotNull(coverage); assertTrue(coverage.getRenderedImage().getSampleModel().getNumBands() == 2); final ParameterValue<Color> colorPV = AbstractGridFormat.INPUT_TRANSPARENT_COLOR.createValue(); colorPV.setValue(new Color(34,53,87)); try{ coverage = reader.read(new GeneralParameterValue[] { colorPV }); assertFalse(true); // we should not get here } catch (Exception e) { // TODO: handle exception } } } } @Test // @Ignore public void testExternalOverviews() throws Exception { final File file = TestData.file(GeoTiffReaderTest.class, "ovr.tif"); assertNotNull(file); assertEquals(true, file.exists()); GeoTiffReader reader = new GeoTiffReader(file); final int nOvrs = reader.getNumOverviews(); LOGGER.info("Number of external overviews: " + nOvrs); assertEquals(4, nOvrs); double[][] availableResolutions = reader.getResolutionLevels(); assertEquals(availableResolutions.length, 5); final ParameterValue<GridGeometry2D> gg = AbstractGridFormat.READ_GRIDGEOMETRY2D.createValue(); final GeneralEnvelope envelope = reader.getOriginalEnvelope(); final Dimension dim = new Dimension(); dim.setSize(reader.getOriginalGridRange().getSpan(0)/64.0, reader.getOriginalGridRange().getSpan(1)/64.0); final Rectangle rasterArea=(( GridEnvelope2D)reader.getOriginalGridRange()); rasterArea.setSize(dim); final GridEnvelope2D range= new GridEnvelope2D(rasterArea); GridGeometry2D gridGeometry = new GridGeometry2D(range,envelope); gg.setValue(gridGeometry); GridCoverage2D coverage = reader.read(new GeneralParameterValue[] {gg}); assertEquals(reader.getOriginalEnvelope(), coverage.getEnvelope()); RenderedImage image = coverage.getRenderedImage(); assertEquals(image.getWidth(), 2); assertEquals(image.getHeight(), 2); final double delta = 0.00001; assertEquals(availableResolutions[0][0], 5, delta); assertEquals(availableResolutions[0][1], 5, delta); assertEquals(availableResolutions[1][0], 10, delta); assertEquals(availableResolutions[1][1], 10, delta); assertEquals(availableResolutions[2][0], 20, delta); assertEquals(availableResolutions[2][1], 20, delta); assertEquals(availableResolutions[3][0], 40, delta); assertEquals(availableResolutions[3][1], 40, delta); assertEquals(availableResolutions[4][0], 80, delta); assertEquals(availableResolutions[4][1], 80, delta); MathTransform transform = gridGeometry.getGridToCRS(); AffineTransform affine = (AffineTransform) transform; double resX = XAffineTransform.getScaleX0(affine); double resY = XAffineTransform.getScaleY0(affine); // Using "poor" resolution (less than the worst available overview). double[] resolutions = reader.getReadingResolutions(OverviewPolicy.QUALITY, new double[]{resX, resY}); // Checking that the reading resolution will be the one of the worst (last) overview assertEquals(resolutions[0], availableResolutions[nOvrs][0], delta); assertEquals(resolutions[1], availableResolutions[nOvrs][1], delta); // Using a middle resolution resolutions = reader.getReadingResolutions(OverviewPolicy.QUALITY, new double[]{resX/8, resY/8}); assertEquals(resolutions[0], 40, delta); assertEquals(resolutions[1], 40, delta); // Using native resolution resolutions = reader.getReadingResolutions(OverviewPolicy.QUALITY, availableResolutions[0]); assertEquals(resolutions[0], availableResolutions[0][0], delta); assertEquals(resolutions[1], availableResolutions[0][1], delta); } /** * The leak geotiff is a strange geotiff with PixelScale and TiePoints that are all 0 * hence the matrix we come up with is all 0 and not invertibile. * * This is not acceptable as we need a transformation that allows us to go back and forth between * raster and model space. * * Side effect of this, we leak an open file due to the exception thrown during a read operation. * * @throws Exception */ @Test // @Ignore public void testLeakedOpenFileFix() throws Exception { final File file = TestData.file(GeoTiffReaderTest.class, "leak.tiff"); assertNotNull(file); assertEquals(true, file.exists()); try { @SuppressWarnings("unused") GeoTiffReader reader = new GeoTiffReader(file); assertTrue(false); } catch (Exception e) { assertTrue(true); } // this files if things went wrong and the fix is not working (on Windows especially) assertTrue(file.delete()); } /** * The GeoTiff reader should provide a useful error message when the user does * not have permissions to read the file. * * @throws Exception */ @Test public void testPermissionDeniedExceptionFix() throws Exception { final File file = TestData.file(GeoTiffReaderTest.class, "t.tiff"); file.setReadable(false); try { GeoTiffReader reader = new GeoTiffReader(file); } catch (DataSourceException e) { if(e.getCause() instanceof IOException) { IOException ioException = (IOException) e.getCause(); assertTrue(ioException.getMessage().contains("can not be read")); } else { assertFalse(true); } } finally { file.setReadable(true); } } /** * The GeoTiff reader should provide a useful error message when the * input file path does not exist. * * @throws Exception */ @Test(expected = FileNotFoundException.class) public void testFileDoesNotExist() throws Throwable { final File file = new File("/does/not/exist"); file.setReadable(false); try { GeoTiffReader reader = new GeoTiffReader(file); } catch (DataSourceException e) { // Throw the inner exception throw e.getCause(); } finally { file.setReadable(true); } } /** * The GeoTiffReader should be able to read from an InputStream */ @Test public void testCanReadInputStream() throws IOException { File rasterfile = TestData.file(GeoTiffReaderTest.class, "geo.tiff"); GeoTiffReader reader = null; try(FileInputStream is = new FileInputStream(rasterfile)) { // Read coverage reader = new GeoTiffReader(is); GridCoverage2D gridCoverage = reader.read(null); assertTrue(gridCoverage != null && gridCoverage.getNumSampleDimensions() == 1); gridCoverage.dispose(true); } finally { if(reader != null) { reader.dispose(); } } } /** * The GeoTiffReader should be able to read from an ImageInputStream */ @Test public void testCanReadImageInputStream() throws IOException { File rasterfile = TestData.file(GeoTiffReaderTest.class, "geo.tiff"); GeoTiffReader reader = null; try(FileImageInputStream is = new FileImageInputStream(rasterfile)) { // Read coverage reader = new GeoTiffReader(is); GridCoverage2D gridCoverage = reader.read(null); assertTrue(gridCoverage != null && gridCoverage.getNumSampleDimensions() == 1); gridCoverage.dispose(true); } finally { if(reader != null) { reader.dispose(); } } } }