/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2005-2008, 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 it.geosolutions.imageio.plugins.tiff.BaselineTIFFTagSet;
import java.awt.geom.AffineTransform;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.logging.Logger;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.TileCache;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridEnvelope2D;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.coverage.grid.io.imageio.GeoToolsWriteParams;
import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffIIOMetadataDecoder;
import org.geotools.coverage.grid.io.imageio.geotiff.GeoTiffIIOMetadataEncoder.TagSet;
import org.geotools.coverage.processing.CoverageProcessor;
import org.geotools.coverage.processing.Operations;
import org.geotools.factory.Hints;
import org.geotools.geometry.GeneralEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.operation.matrix.XAffineTransform;
import org.geotools.test.TestData;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.opengis.coverage.grid.GridCoverageReader;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.crs.ProjectedCRS;
import org.opengis.referencing.datum.PixelInCell;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
/**
* @author Simone Giannecchini, GeoSolutions SAS
* @author Daniele Romagnoli, GeoSolutions SAS
*
*
* @source $URL: http://svn.osgeo.org/geotools/trunk/modules/unsupported/geotiff_new/src/test/java/org/geotools/gce/geotiff/GeoTiffWriterTest.java $
*/
public class GeoTiffWriterTest extends Assert {
private static final Logger logger = org.geotools.util.logging.Logging
.getLogger(GeoTiffWriterTest.class.toString());
@Before
public void setup() throws IOException {
final JAI jaiDef = JAI.getDefaultInstance();
// using a big tile cache
final TileCache cache = jaiDef.getTileCache();
cache.setMemoryCapacity(64 * 1024 * 1024);
cache.setMemoryThreshold(0.75f);
}
/**
* Testing {@link GeoTiffWriter} capabilities to write a cropped coverage.
*
* @throws IllegalArgumentException
* @throws IOException
* @throws UnsupportedOperationException
* @throws ParseException
* @throws FactoryException
* @throws TransformException
*/
@Test
public void testWriteCroppedCoverage() throws IllegalArgumentException, IOException,
UnsupportedOperationException, ParseException, FactoryException, TransformException {
// /////////////////////////////////////////////////////////////////////
//
//
// READ
//
//
// /////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////
//
// Look for the original coverage that wew want to crop.
//
// /////////////////////////////////////////////////////////////////////
final File readdir = TestData.file(GeoTiffWriterTest.class, "");
final File writedir = new File(new StringBuilder(readdir.getAbsolutePath()).append(
"/testWriter/").toString());
writedir.mkdir();
final File tiff = new File(readdir, "latlon.tiff");
assert tiff.exists() && tiff.canRead() && tiff.isFile();
if (TestData.isInteractiveTest())
logger.info(tiff.getAbsolutePath());
// /////////////////////////////////////////////////////////////////////
//
// Create format and reader
//
// /////////////////////////////////////////////////////////////////////
final GeoTiffFormat format = new GeoTiffFormat();
// getting a reader
GridCoverageReader reader = format.getReader(tiff);
assertNotNull(reader);
// /////////////////////////////////////////////////////////////////////
//
// Read the original coverage.
//
// /////////////////////////////////////////////////////////////////////
GridCoverage2D gc = (GridCoverage2D) reader.read(null);
if (TestData.isInteractiveTest()) {
logger.info(new StringBuilder("Coverage before: ").append("\n")
.append(gc.getCoordinateReferenceSystem().toWKT())
.append(gc.getEnvelope().toString()).toString());
}
final CoordinateReferenceSystem sourceCRS = gc.getCoordinateReferenceSystem2D();
final GeneralEnvelope sourceEnvelope = (GeneralEnvelope) gc.getEnvelope();
final GridGeometry2D sourcedGG = (GridGeometry2D) gc.getGridGeometry();
final MathTransform sourceG2W = sourcedGG.getGridToCRS(PixelInCell.CELL_CENTER);
// /////////////////////////////////////////////////////////////////////
//
//
// CROP
//
//
// /////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////
//
// Crop the original coverage.
//
// /////////////////////////////////////////////////////////////////////
double xc = sourceEnvelope.getMedian(0);
double yc = sourceEnvelope.getMedian(1);
double xl = sourceEnvelope.getSpan(0);
double yl = sourceEnvelope.getSpan(1);
final GeneralEnvelope cropEnvelope = new GeneralEnvelope(new double[] { xc - xl / 4.0,
yc - yl / 4.0 }, new double[] { xc + xl / 4.0, yc + yl / 4.0 });
final CoverageProcessor processor = new CoverageProcessor();
final ParameterValueGroup param = processor.getOperation("CoverageCrop").getParameters();
param.parameter("Source").setValue(gc);
param.parameter("Envelope").setValue(cropEnvelope);
final GridCoverage2D cropped = (GridCoverage2D) processor.doOperation(param);
// /////////////////////////////////////////////////////////////////////
//
// Check that we got everything correctly after the crop.
//
// /////////////////////////////////////////////////////////////////////
// checking the ranges of the output image.
final GridGeometry2D croppedGG = (GridGeometry2D) cropped.getGridGeometry();
final GridEnvelope2D croppedGR = (GridEnvelope2D) croppedGG.getGridRange();
final MathTransform croppedG2W = croppedGG.getGridToCRS(PixelInCell.CELL_CENTER);
final GeneralEnvelope croppedEnvelope = (GeneralEnvelope) cropped.getEnvelope();
assertTrue("min x do not match after crop", 29 == croppedGR.x);
assertTrue("min y do not match after crop", 30 == croppedGR.y);
assertTrue("max x do not match after crop", 90 == croppedGR.getMaxX());
assertTrue("max y do not match after crop", 91 == croppedGR.getMaxY());
// check that the affine transform are the same thing
assertTrue("The Grdi2World tranformations of the original and the cropped covearage do not match",
sourceG2W.equals(croppedG2W));
// check that the envelope is correct
final GeneralEnvelope expectedEnvelope = new GeneralEnvelope(croppedGR,
PixelInCell.CELL_CENTER, croppedG2W, cropped.getCoordinateReferenceSystem2D());
assertTrue("Expected envelope is different from the computed one",
expectedEnvelope.equals(croppedEnvelope,
XAffineTransform.getScale((AffineTransform) croppedG2W) / 2.0, false));
// /////////////////////////////////////////////////////////////////////
//
//
// WRITING AND TESTING
//
//
// /////////////////////////////////////////////////////////////////////
final File writeFile = new File(writedir.getAbsolutePath() + File.separatorChar
+ cropped.getName().toString() + ".tiff");
final GridCoverageWriter writer = format.getWriter(writeFile);
// /////////////////////////////////////////////////////////////////////
//
// Create the writing params
//
// /////////////////////////////////////////////////////////////////////
try {
writer.write(cropped, null);
} catch (IOException e) {
} finally {
try {
writer.dispose();
} catch (Throwable e) {
}
}
// release things
cropped.dispose(true);
gc.dispose(true);
if (reader != null) {
try {
reader.dispose();
} catch (Throwable e) {
}
}
try {
reader = new GeoTiffReader(writeFile, null);
assertNotNull(reader);
gc = (GridCoverage2D) reader.read(null);
assertNotNull(gc);
final CoordinateReferenceSystem targetCRS = gc.getCoordinateReferenceSystem2D();
assertTrue("Source and Target coordinate reference systems do not match",
CRS.equalsIgnoreMetadata(sourceCRS, targetCRS));
assertEquals("Read-back and Cropped envelopes do not match", cropped.getEnvelope(),
croppedEnvelope);
if (TestData.isInteractiveTest()) {
logger.info(new StringBuilder("Coverage after: ").append("\n")
.append(gc.getCoordinateReferenceSystem().toWKT())
.append(gc.getEnvelope().toString()).toString());
gc.show();
} else {
gc.getRenderedImage().getData();
}
} finally {
if (reader != null) {
try {
reader.dispose();
} catch (Throwable e) {
}
}
if (!TestData.isInteractiveTest()) {
gc.dispose(true);
}
}
}
@Test
public void testWriteGoogleMercator() throws Exception {
final String google= "PROJCS[\"WGS84 / Google Mercator\", 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], AUTHORITY[\"EPSG\",\"4326\"]], PROJECTION[\"Mercator (1SP)\", AUTHORITY[\"EPSG\",\"9804\"]], PARAMETER[\"semi_major\", 6378137.0], PARAMETER[\"semi_minor\", 6378137.0], PARAMETER[\"latitude_of_origin\", 0.0], PARAMETER[\"central_meridian\", 0.0], PARAMETER[\"scale_factor\", 1.0], PARAMETER[\"false_easting\", 0.0], PARAMETER[\"false_northing\", 0.0], UNIT[\"m\", 1.0], AUTHORITY[\"EPSG\",\"900913\"]]";
final CoordinateReferenceSystem googleCRS= CRS.parseWKT(google);
//
// world geotiff
//
final File testFile = TestData.file(GeoTiffReaderTest.class, "latlon.tiff");
final AbstractGridFormat format = new GeoTiffFormat();
assertTrue(format.accepts(testFile));
// getting a reader
GeoTiffReader reader = new GeoTiffReader(testFile);
// reading the coverage
GridCoverage2D coverage = (GridCoverage2D) reader.read(null);
// check coverage and crs
assertNotNull(coverage);
assertNotNull(coverage.getCoordinateReferenceSystem());
assertEquals(CRS.lookupIdentifier(coverage.getCoordinateReferenceSystem(), true), "EPSG:4267");
reader.dispose();
// reproject
coverage=(GridCoverage2D) Operations.DEFAULT.resample(coverage, googleCRS);
// get a writer
final File mercator = new File(TestData.file(GeoTiffReaderTest.class, "."),"wms_900913.tif");
GeoTiffWriter writer = new GeoTiffWriter(mercator);
writer.write(coverage,null );
writer.dispose();
// getting a reader
reader = new GeoTiffReader(mercator);
// reading the coverage
GridCoverage2D coverageMercator = (GridCoverage2D) reader.read(null);
// check coverage and crs
assertNotNull(coverageMercator);
assertNotNull(coverageMercator.getCoordinateReferenceSystem());
assertTrue(CRS.equalsIgnoreMetadata(coverage.getCoordinateReferenceSystem(),googleCRS));
assertTrue(coverage.getEnvelope2D().getFrame().equals(coverageMercator.getEnvelope2D().getFrame()));
reader.dispose();
coverage.dispose(true);
coverage.dispose(true);
}
@Test
public void testWriteTFW() throws Exception {
//
// no crs geotiff
//
final File noCrs = TestData.file(GeoTiffReaderTest.class, "no_crs.tif");
final AbstractGridFormat format = new GeoTiffFormat();
assertTrue(format.accepts(noCrs));
// hint for CRS
final CoordinateReferenceSystem crs = CRS.decode("EPSG:32632", true);
final Hints hint = new Hints();
hint.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);
// getting a reader
GeoTiffReader reader = new GeoTiffReader(noCrs, hint);
// reading the coverage
GridCoverage2D coverage = (GridCoverage2D) reader.read(null);
// check coverage and crs
assertNotNull(coverage);
assertNotNull(coverage.getCoordinateReferenceSystem());
assertEquals(CRS.lookupIdentifier(coverage.getCoordinateReferenceSystem(), true), "EPSG:32632");
reader.dispose();
// get a writer
final File noCrsTFW = new File(TestData.file(GeoTiffReaderTest.class, "."), "no_crs_tfw.tif");
GeoTiffWriter writer = new GeoTiffWriter(noCrsTFW);
final ParameterValue<Boolean> tfw = GeoTiffFormat.WRITE_TFW.createValue();
tfw.setValue(true);
writer.write(coverage, new GeneralParameterValue[] { tfw });
writer.dispose();
coverage.dispose(true);
final File finalTFW = new File(noCrsTFW.getParent(), noCrsTFW.getName().replace("tif", "tfw"));
assertTrue(finalTFW.canRead());
}
@Test
public void testWriteWithMetadata() throws Exception {
//
// no crs geotiff
//
final File input = TestData.file(GeoTiffReaderTest.class, "geo.tiff");
final AbstractGridFormat format = new GeoTiffFormat();
assertTrue(format.accepts(input));
// getting a reader
GeoTiffReader reader = new GeoTiffReader(input);
// reading the coverage
GridCoverage2D coverage = (GridCoverage2D) reader.read(null);
// check coverage and crs
assertNotNull(coverage);
assertNotNull(coverage.getCoordinateReferenceSystem());
reader.dispose();
// get a writer
final File output = new File(TestData.file(GeoTiffReaderTest.class, "."), "outMetadata.tif");
GeoTiffWriter writer = new GeoTiffWriter(output);
// Setting a COPYRIGHT metadata
String copyrightInfo = "(C) GEOTOOLS sample writer";
String software = "GeoTools Coverage Writer test";
writer.setMetadataValue(Integer.toString(BaselineTIFFTagSet.TAG_COPYRIGHT), copyrightInfo);
writer.setMetadataValue(TagSet.BASELINE + ":" + Integer.toString(BaselineTIFFTagSet.TAG_SOFTWARE), software);
writer.write(coverage,null);
writer.dispose();
coverage.dispose(true);
// getting a reader
reader = new GeoTiffReader(output);
GeoTiffIIOMetadataDecoder metadata = reader.getMetadata();
String readSoftware = metadata.getAsciiTIFFTag(Integer.toString(BaselineTIFFTagSet.TAG_SOFTWARE));
assertTrue(software.equalsIgnoreCase(readSoftware));
String readCopyright = metadata.getAsciiTIFFTag(Integer.toString(BaselineTIFFTagSet.TAG_COPYRIGHT));
assertTrue(copyrightInfo.equalsIgnoreCase(readCopyright));
reader.dispose();
}
@Test
public void testWriteBigTiff() throws Exception {
String files[] = new String[]{"geo.tiff", "no_crs_no_envelope.tif"};
int i=0;
for (String file : files){
final File input = TestData.file(GeoTiffReaderTest.class, file);
final AbstractGridFormat format = new GeoTiffFormat();
assertTrue(format.accepts(input));
// getting a reader
GeoTiffReader reader = new GeoTiffReader(input);
// reading the coverage
GridCoverage2D coverage = (GridCoverage2D) reader.read(null);
// check coverage and crs
assertNotNull(coverage);
assertNotNull(coverage.getCoordinateReferenceSystem());
reader.dispose();
// get a writer
final File output = new File(TestData.file(GeoTiffReaderTest.class, "."), "bigtiff" + i + ".tif");
GeoTiffWriter writer = new GeoTiffWriter(output);
GeoTiffWriteParams params = new GeoTiffWriteParams();
params.setForceToBigTIFF(true);
ParameterValue<GeoToolsWriteParams> value = GeoTiffFormat.GEOTOOLS_WRITE_PARAMS.createValue();
value.setValue(params);
writer.write(coverage, new GeneralParameterValue[]{value});
writer.dispose();
coverage.dispose(true);
// getting a reader
reader = new GeoTiffReader(output);
RenderedImage ri = reader.read(null).getRenderedImage();
assertEquals(ri.getWidth(), i == 0 ? 120 : 12);
assertEquals(ri.getHeight(), i == 0 ? 120 : 12);
reader.dispose();
FileInputStream fis = null;
try {
fis = new FileInputStream(output);
byte[] bytes = new byte[6];
fis.read(bytes);
if (bytes[0] == 77 && bytes[1] == 77){
//Big Endian Case
assertEquals(bytes[3], 43); //43 is the magic number of BigTiff
} else {
//Little Endian Case
assertEquals(bytes[2], 43); //43 is the magic number of BigTiff
}
} finally {
if (fis != null){
try {
fis.close();
} catch (Throwable t){
}
}
}
i++;
}
}
}