//$HeadURL$ /*---------------------------------------------------------------------------- This file is part of deegree, http://deegree.org/ Copyright (C) 2001-2011 by: - Department of Geography, University of Bonn - and - lat/lon GmbH - 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; either version 2.1 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Contact information: lat/lon GmbH Aennchenstr. 19, 53177 Bonn Germany http://lat-lon.de/ Department of Geography, University of Bonn Prof. Dr. Klaus Greve Postfach 1147, 53001 Bonn Germany http://www.geographie.uni-bonn.de/deegree/ e-mail: info@deegree.org ----------------------------------------------------------------------------*/ package org.deegree.securityproxy.wcs.responsefilter.clipping; import static com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet.TAG_COMPRESSION; import static com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet.TAG_RESOLUTION_UNIT; import static com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet.TAG_X_RESOLUTION; import static com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet.TAG_Y_RESOLUTION; import static org.deegree.matcher.image.ImageMatcher.hasNotSamePixels; import static org.deegree.matcher.image.ImageMatcher.hasSameDimension; import static org.deegree.matcher.image.ImageMatcher.hasSamePixels; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.imageio.metadata.IIOMetadataNode; import org.deegree.securityproxy.request.OwsRequest; import org.deegree.securityproxy.responsefilter.logging.ResponseClippingReport; import org.deegree.securityproxy.service.commons.responsefilter.clipping.exception.ClippingException; import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffIIOMetadataDecoder; import org.geotools.data.DataSourceException; import org.geotools.gce.geotiff.GeoTiffReader; import org.junit.Ignore; import org.junit.Test; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; /** * @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz</a> * @author last edited by: $Author: lyn $ * * @version $Revision: $, $Date: $ */ public class GeotiffClipperTest { /* * #calculateClippedImage() - Exceptions */ @Test(expected = IllegalArgumentException.class) public void testCalculateClippedImageWithNullImageStreamShouldFail() throws Exception { GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( null, mockClippingGeometry(), mockOutputStream(), mockOwsRequest() ); } @Test(expected = IllegalArgumentException.class) public void testCalculateClippedImageWithNullOutputStreamShouldFail() throws Exception { GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( mockInputStream(), mockClippingGeometry(), null, mockOwsRequest() ); } /* * #calculateClippedImage() - Dimension */ @Test public void testCalculateClippedImageWithNullClippingGeometryShouldReturnWholeImage() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); InputStream inputStream = createInputStreamFrom( sourceFile ); OutputStream outputStream = createOutputStreamFrom( destinationFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, null, outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasSamePixels( sourceFile ) ); } @Test public void testCalculateClippedImageInsideVisibleArea() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createEnvelopeWithImageInsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasSamePixels( sourceFile ) ); } @Test public void testCalculateClippedImageInsideAndOutsideVisibleArea() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); InputStream inputStream = createInputStreamFrom( sourceFile ); OutputStream outputStream = createOutputStreamFrom( destinationFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createGeometryWithImageInsideAndOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasNotSamePixels( sourceFile ) ); } @Test public void testCalculateClippedImageOutsideVisibleArea() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); InputStream inputStream = createInputStreamFrom( sourceFile ); OutputStream outputStream = createOutputStreamFrom( destinationFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createGeometryWithImageOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasNotSamePixels( sourceFile ) ); } @Test public void testCalculateClippedImageInsideAndOutsideVisiblePolygon() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createPolygonGeometryWithImageInsideAndOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasNotSamePixels( sourceFile ) ); } @Test public void testCalculateClippedImageInsideAndOutsideVisiblePolygonWithHole() throws Exception { File sourceFile = createNewFile( "dem90_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createPolygonWithHoleGeometryWithImageInsideAndOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( destinationFile, hasSameDimension( sourceFile ) ); assertThat( destinationFile, hasNotSamePixels( sourceFile ) ); } /* * #calculateClippedImage() - ReponseClippingReport */ @Test public void testCalculateClippedImageInsideVisibleShouldReturnReport() throws Exception { File sourceFile = createNewFile( "dem30_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); ResponseClippingReport report = geotiffClipper.calculateClippedImage( inputStream, createEnvelopeWithImageInsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( report.isFailed(), is( false ) ); assertThat( report.isFiltered(), is( false ) ); assertThat( report.getReturnedVisibleArea(), is( notNullValue() ) ); } @Test public void testCalculateClippedImageOutsideVisibleShouldReturnReport() throws Exception { File sourceFile = createNewFile( "dem30_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); ResponseClippingReport report = geotiffClipper.calculateClippedImage( inputStream, createGeometryWithImageOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( report.isFailed(), is( false ) ); assertThat( report.isFiltered(), is( true ) ); assertThat( report.getReturnedVisibleArea(), is( notNullValue() ) ); } @Test public void testCalculateClippedImageIntersectingVisibleShouldReturnReport() throws Exception { File sourceFile = createNewFile( "dem30_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); ResponseClippingReport report = geotiffClipper.calculateClippedImage( inputStream, createGeometryWithImageInsideAndOutsideInWgs84(), outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); assertThat( report.isFailed(), is( false ) ); assertThat( report.isFiltered(), is( true ) ); assertThat( report.getReturnedVisibleArea(), is( notNullValue() ) ); } /* * #calculateClippedImage() - ExceptionHandling */ @Test(expected = ClippingException.class) public void testCalculateClippedImageThrowingExceptionShouldReturnExceptionReport() throws Exception { File sourceFile = createExceptionFile(); File destinationFile = createNewTempFile(); OutputStream outputStream = createOutputStreamFrom( destinationFile ); InputStream inputStream = createInputStreamFrom( sourceFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, createGeometryWithImageInsideAndOutsideInWgs84(), outputStream, mockOwsRequest() ); } /* * #calculateClippedImage() - Compare metadata */ @Test public void testCalculateClippedImageShouldHaveSameCompression() throws Exception { File sourceFile = createNewFile( "dem30_geotiff_tiled.tiff" ); File destinationFile = createNewTempFile(); InputStream inputStream = createInputStreamFrom( sourceFile ); OutputStream outputStream = createOutputStreamFrom( destinationFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, null, outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); NodeList nodesSource = retrieveNodeWithTags( sourceFile ); NodeList nodesDestination = retrieveNodeWithTags( destinationFile ); String compressionSource = retrieveTagValue( TAG_COMPRESSION, nodesSource ); String compressionDestination = retrieveTagValue( TAG_COMPRESSION, nodesDestination ); assertThat( compressionDestination, is( compressionSource ) ); } @Ignore("A test tiff with resulution tags has to be added!") @Test public void testCalculateClippedImageShouldHaveCorrectResolutionMetadata() throws Exception { File sourceFile = createNewFile( "TODO.tif" ); File destinationFile = createNewTempFile(); InputStream inputStream = createInputStreamFrom( sourceFile ); OutputStream outputStream = createOutputStreamFrom( destinationFile ); GeotiffClipper geotiffClipper = new GeotiffClipper(); geotiffClipper.calculateClippedImage( inputStream, null, outputStream, mockOwsRequest() ); inputStream.close(); outputStream.close(); NodeList nodesSource = retrieveNodeWithTags( sourceFile ); NodeList nodesDestination = retrieveNodeWithTags( destinationFile ); String yResolutionSource = retrieveTagValue( TAG_Y_RESOLUTION, nodesSource ); String xResolutionSource = retrieveTagValue( TAG_X_RESOLUTION, nodesSource ); String resolutionUnitSource = retrieveTagValue( TAG_RESOLUTION_UNIT, nodesSource ); String yResolutionDestination = retrieveTagValue( TAG_Y_RESOLUTION, nodesDestination ); String xResolutionDestination = retrieveTagValue( TAG_X_RESOLUTION, nodesDestination ); String resolutionUnitDestination = retrieveTagValue( TAG_RESOLUTION_UNIT, nodesDestination ); assertThat( xResolutionDestination, is( xResolutionSource ) ); assertThat( yResolutionDestination, is( yResolutionSource ) ); assertThat( resolutionUnitDestination, is( resolutionUnitSource ) ); } private File createNewFile( String resourceName ) { return new File( GeotiffClipperTest.class.getResource( resourceName ).getPath() ); } private File createNewTempFile() throws IOException { return File.createTempFile( GeotiffClipperTest.class.getSimpleName(), ".tif" ); } private File createExceptionFile() { return new File( GeotiffClipperTest.class.getResource( "../service_exception.xml" ).getPath() ); } private InputStream createInputStreamFrom( File file ) throws Exception { return new FileInputStream( file ); } private OutputStream createOutputStreamFrom( File file ) throws Exception { return new FileOutputStream( file ); } private InputStream mockInputStream() { return mock( InputStream.class ); } private OutputStream mockOutputStream() { return mock( OutputStream.class ); } private Geometry mockClippingGeometry() { return mock( Geometry.class ); } private OwsRequest mockOwsRequest() { return mock( OwsRequest.class ); } private Geometry createEnvelopeWithImageInsideInWgs84() { Envelope envelope = new Envelope( -114, -108, 31.33, 84 ); return new GeometryFactory().toGeometry( envelope ); } private Geometry createGeometryWithImageInsideAndOutsideInWgs84() { Envelope smallEnvelope = new Envelope( -111.57, -111.53, 40, 40.1 ); return new GeometryFactory().toGeometry( smallEnvelope ); } private Geometry createGeometryWithImageOutsideInWgs84() { Envelope envelope = new Envelope( -111.57, -111.53, 43.57, 43.93 ); return new GeometryFactory().toGeometry( envelope ); } private Geometry createPolygonGeometryWithImageInsideAndOutsideInWgs84() { Coordinate coord1 = new Coordinate( -111.57, 40 ); Coordinate coord2 = new Coordinate( -111.53, 40 ); Coordinate coord3 = new Coordinate( -111.53, 40.1 ); Coordinate[] coordArray = { coord1, coord2, coord3, coord1 }; return new GeometryFactory().createPolygon( coordArray ); } private Geometry createPolygonWithHoleGeometryWithImageInsideAndOutsideInWgs84() { GeometryFactory geometryFactory = new GeometryFactory(); Coordinate coordShell1 = new Coordinate( -111.57, 40.0 ); Coordinate coordShell2 = new Coordinate( -111.53, 40.0 ); Coordinate coordShell3 = new Coordinate( -111.53, 40.3 ); Coordinate[] coordShellArray = { coordShell1, coordShell2, coordShell3, coordShell1 }; LinearRing shell = geometryFactory.createLinearRing( coordShellArray ); Coordinate coordHole1 = new Coordinate( -111.55, 40.04 ); Coordinate coordHole2 = new Coordinate( -111.54, 40.04 ); Coordinate coordHole3 = new Coordinate( -111.54, 40.06 ); Coordinate[] coordHoleArray = { coordHole1, coordHole2, coordHole3, coordHole1 }; LinearRing hole = geometryFactory.createLinearRing( coordHoleArray ); LinearRing holes[] = { hole }; return geometryFactory.createPolygon( shell, holes ); } private NodeList retrieveNodeWithTags( File file ) throws DataSourceException { GeoTiffReader reader = new GeoTiffReader( file ); GeoTiffIIOMetadataDecoder metadata = reader.getMetadata(); IIOMetadataNode rootNode = metadata.getRootNode(); Node firstChildNode = rootNode.getChildNodes().item( 0 ); return firstChildNode.getChildNodes(); } private String retrieveTagValue( int tiffId, NodeList nodeWithTags ) { for ( int indexTagNumber = 0; indexTagNumber < nodeWithTags.getLength(); indexTagNumber++ ) { Node nodeWithTag = nodeWithTags.item( indexTagNumber ); String tagNumber = retrieveTagNumber( nodeWithTag ); if ( Integer.toString( tiffId ).equals( tagNumber ) ) { return retrieveFirstValue( nodeWithTag ); } } return null; } private String retrieveTagNumber( Node nodeWithTag ) { Node firstAttribute = nodeWithTag.getAttributes().item( 0 ); return firstAttribute.getNodeValue(); } private String retrieveFirstValue( Node nodeWithTag ) { Node nodeWithValues = nodeWithTag.getChildNodes().item( 0 ); Node firstChildNode = nodeWithValues.getChildNodes().item( 0 ); Node firstAttribute = firstChildNode.getAttributes().item( 0 ); return firstAttribute.getNodeValue(); } }