/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2009-2012, Geomatys
*
* 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.geotoolkit.image.io.plugin;
import java.awt.Rectangle;
import java.awt.image.Raster;
import java.io.File;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.PrintStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import java.util.Iterator;
import org.geotoolkit.test.TestData;
import org.geotoolkit.image.io.TextImageReaderTestBase;
import org.geotoolkit.image.io.metadata.SpatialMetadata;
import org.geotoolkit.internal.image.io.DimensionAccessor;
import org.junit.*;
import static org.geotoolkit.test.Assert.*;
import static org.geotoolkit.test.Commons.*;
import static org.geotoolkit.image.io.metadata.SpatialMetadataFormat.GEOTK_FORMAT_NAME;
/**
* Tests {@link AsciiGridReader}.
* <p>
* This class provides also a {@link #verify} static method for manual testings.
*
* @author Martin Desruisseaux (Geomatys)
* @version 3.20
*
* @since 3.07
*/
public strictfp class AsciiGridReaderTest extends TextImageReaderTestBase {
/**
* Creates a reader and sets its input if needed.
*/
@Override
protected void prepareImageReader(final boolean setInput) throws IOException {
if (reader == null) {
AsciiGridReader.Spi spi = new AsciiGridReader.Spi();
reader = new AsciiGridReader(spi);
}
if (setInput) {
reader.setInput(TestData.file(this, "grid.asc"));
}
}
/**
* Tests the metadata of the {@link "grid.asc"} file.
*
* @throws IOException if an error occurred while reading the file.
*/
@Test
public void testMetadata() throws IOException {
prepareImageReader(true);
assertEquals(20, reader.getWidth (0));
assertEquals(42, reader.getHeight(0));
assertNull(reader.getStreamMetadata());
final SpatialMetadata metadata = (SpatialMetadata) reader.getImageMetadata(0);
assertNotNull(metadata);
assertMultilinesEquals(decodeQuotes(
GEOTK_FORMAT_NAME + '\n' +
"├───RectifiedGridDomain\n" +
"│ ├───origin=“-9500.0 20500.0”\n" +
"│ ├───OffsetVectors\n" +
"│ │ ├───OffsetVector\n" +
"│ │ │ └───values=“1000.0 0.0”\n" +
"│ │ └───OffsetVector\n" +
"│ │ └───values=“0.0 -1000.0”\n" +
"│ └───Limits\n" +
"│ ├───low=“0 0”\n" +
"│ └───high=“19 41”\n" +
"├───SpatialRepresentation\n" +
"│ ├───numberOfDimensions=“2”\n" +
"│ ├───centerPoint=“0.0 0.0”\n" +
"│ └───pointInPixel=“center”\n" +
"└───ImageDescription\n" +
" └───Dimensions\n" +
" └───Dimension\n" +
" ├───minValue=“-1.893”\n" +
" ├───maxValue=“31.14”\n" +
" └───fillSampleValues=“-9999.0”\n"), metadata.toString());
/*
* Forces a scan of pixel values and test again.
*/
final DimensionAccessor helper = new DimensionAccessor(metadata);
assertFalse("Pixels scan should not be needed.", helper.isScanSuggested(reader, 0));
// Scan anyway, even if the above returned 'false'.
metadata.setReadOnly(false);
helper.scanValidSampleValue(reader, 0);
assertFalse("Pixels scan should not be needed.", helper.isScanSuggested(reader, 0));
assertMultilinesEquals(decodeQuotes(
GEOTK_FORMAT_NAME + '\n' +
"├───RectifiedGridDomain\n" +
"│ ├───origin=“-9500.0 20500.0”\n" +
"│ ├───OffsetVectors\n" +
"│ │ ├───OffsetVector\n" +
"│ │ │ └───values=“1000.0 0.0”\n" +
"│ │ └───OffsetVector\n" +
"│ │ └───values=“0.0 -1000.0”\n" +
"│ └───Limits\n" +
"│ ├───low=“0 0”\n" +
"│ └───high=“19 41”\n" +
"├───SpatialRepresentation\n" +
"│ ├───numberOfDimensions=“2”\n" +
"│ ├───centerPoint=“0.0 0.0”\n" +
"│ └───pointInPixel=“center”\n" +
"└───ImageDescription\n" +
" └───Dimensions\n" +
" └───Dimension\n" +
" ├───fillSampleValues=“-9999.0”\n" +
" └───validSampleValues=“[-1.893 … 31.139999]”\n"), metadata.toString());
}
/**
* Do not run this test for {@code AsciiGridReaderTest}. This is because the reader
* implementation tries to read numbers as integers (which is the wanted behavior),
* which result in an {@link IIOException} caused by a {@link NumberFormatException}:
* "Can not parse -1.123".
*/
@Test
@Override
public void testByteType() throws IOException {
if (getClass() != AsciiGridReaderTest.class) {
super.testByteType();
}
}
/**
* Tests the registration of the image reader in the Image I/O framework.
*/
@Test
public void testRegistrationByFormatName() {
Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("ascii-grid");
assertTrue("Expected a reader.", it.hasNext());
assertTrue(it.next() instanceof AsciiGridReader);
assertFalse("Expected no more reader.", it.hasNext());
}
/**
* Tests the registration by MIME type.
* Note that more than one writer may be registered.
*/
@Test
public void testRegistrationByMIMEType() {
Iterator<ImageReader> it = ImageIO.getImageReadersByMIMEType("text/plain");
while (it.hasNext()) {
if (it.next() instanceof AsciiGridReader) {
return;
}
}
fail("Reader not found.");
}
/**
* Compares the content of the given raster with the value read from the given file.
* Any mismatch found is printed to the standard output stream.
*
* @param input The file to read.
* @param width The image width.
* @param raster The raster from which to compare the values.
* @param region The region of the source file to compare.
* @param xSubsampling Subsampling along the <var>x</var> axis (1 if none).
* @param ySubsampling Subsampling along the <var>y</var> axis (1 if none).
* @param headerLineCount The number of header lines to skip.
* @throws IOException If an error occurred while reading the file.
*/
public static void verify(final File input, final int width, final Raster raster, final Rectangle region,
final int xSubsampling, final int ySubsampling, final int headerLineCount) throws IOException
{
assertEquals(0, raster.getMinX());
assertEquals(0, raster.getMinY());
assertEquals((region.width + xSubsampling-1) / xSubsampling, raster.getWidth());
assertEquals((region.height + ySubsampling-1) / ySubsampling, raster.getHeight());
String regionString = region.toString();
regionString = regionString.substring(regionString.indexOf('['));
final PrintStream out = System.out;
out.println("Comparing the values in region " + regionString);
int x=0, y=0;
final long timestamp = System.currentTimeMillis();
try (BufferedReader reader = new BufferedReader(new FileReader(input))) {
for (int i=1; i<=headerLineCount; i++) {
out.println("Header " + i + ": " + reader.readLine());
}
final StringBuilder buffer = new StringBuilder(20);
int c, errorCount=0;
while ((c = reader.read()) >= 0) {
if (c > ' ') {
buffer.append((char) c);
} else if (buffer.length() != 0) {
final float value = Float.parseFloat(buffer.toString());
if (region.contains(x, y)) {
int tx = x - region.x;
int ty = y - region.y;
if ((tx % xSubsampling) == 0 && (ty % ySubsampling) == 0) {
tx /= xSubsampling;
ty /= ySubsampling;
final float stored = raster.getSampleFloat(tx, ty, 0);
// Test only 'stored' for NaN because the values that we read from the
// file may be pad values like -9999, and we don't handle them in this
// simple test method.
if (value != stored && !Float.isNaN(stored)) {
out.println("Expected " + value + " but found " + stored +
" at coordinate (" + x + ',' + y + ") in the file," +
" which is (" + tx + ',' + ty + " in the raster.");
if (++errorCount >= 100) {
out.println("Too many errors.");
break;
}
}
}
}
if (++x == width) {
x = 0;
y++;
}
buffer.setLength(0);
}
}
}
out.println("Coordinate of the next pixel to read, if it existed: (" + x + ',' + y + ')');
out.println("Ellapsed time: " + (System.currentTimeMillis() - timestamp) / 1000f + " seconds.");
}
}