/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2007-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.imagecollection;
import it.geosolutions.imageioimpl.plugins.tiff.TIFFImageReaderSpi;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.BandedSampleModel;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.media.jai.RasterFactory;
import org.apache.commons.io.FilenameUtils;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataUtilities;
import org.geotools.referencing.factory.epsg.CartesianAuthorityFactory;
import org.geotools.referencing.factory.epsg.DisplayCRSAuthorityFactory;
import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.geotools.util.Utilities;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
/**
* Sparse utilities for the various classes.
*
* @author Simone Giannecchini, GeoSolutions S.A.S.
* @author Daniele Romagnoli, GeoSolutions S.A.S.
*
*/
class Utils {
final static String FAKE_IMAGE_PATH = "$_!FAKE!_$";
final static CoordinateReferenceSystem DISPLAY_CRS = DisplayCRSAuthorityFactory.DISPLAY;
final static CoordinateReferenceSystem GENERIC2D_CRS = CartesianAuthorityFactory.GENERIC_2D;
final static String SEPARATOR = File.separator;
final static String CONFIG_FILE = "config.properties";
final static RenderedImage DEFAULT_IMAGE;
final static TIFFImageReaderSpi TIFF_SPI = new TIFFImageReaderSpi();
final static int IMAGE_EPSG = 404000;
final static FilenameFilter FILE_FILTER = new FilenameFilter() {
//TODO: ADD MORE
public boolean accept(File dir, String name) {
if (name.endsWith(".tif") || name.endsWith(".TIF")
|| name.endsWith(".tiff") || name.endsWith(".TIFF")
|| name.endsWith(".jpg") || name.endsWith(".JPG")
|| name.endsWith(".jpeg") || name.endsWith(".JPEG")
|| name.endsWith(".bmp") || name.endsWith(".BMP")
|| name.endsWith(".png") || name.endsWith(".PNG")) {
return true;
} else {
final String fullPath = dir.getAbsolutePath() + SEPARATOR + name;
final File file = new File(fullPath);
if (file.isDirectory()){
return true;
}
}
return false;
}
};
/**
* Recursively get a fileList from the specified startingDir, using the provided {@link FilenameFilter},
* optionally stop at the first occurrence if the {@code stopAtFirst} flag is {@code true}.
* @param startingDir
* @param filter
* @param stopAtFirst
* @return
* @throws FileNotFoundException
*/
static List<File> getFileList(final File startingDir, final FilenameFilter fileFilter, final boolean stopAtFirst)
throws FileNotFoundException {
List<File> result = new ArrayList<File>();
File[] filesAndDirs = startingDir.listFiles(fileFilter);
List<File> filesDirs = Arrays.asList(filesAndDirs);
for (File file : filesDirs) {
if (!file.isFile()) {
// must be a directory
// recursive call!
List<File> deeperList = getFileList(file, fileFilter, stopAtFirst);
result.addAll(deeperList);
if (stopAtFirst && !result.isEmpty()) {
return result;
}
} else {
result.add(file);
if (stopAtFirst) {
return result;
}
}
}
return result;
}
static class ImageCollectionProperties {
final static String COVERAGE_NAME = "coverageName";
final static String DEFAULT_PATH = "defaultPath";
final static String EXPAND_RGB = "expand";
final static String EPSG_CODE = "epsg";
final static String TIME_BETWEEN_CHECKS = "timeBetweenChecks";
final static String MAX_WIDTH = "maxWidth";
final static String MAX_HEIGHT = "maxHeight";
final static String ENVELOPE = "envelope";
}
static {
final SampleModel sm = new BandedSampleModel(DataBuffer.TYPE_BYTE, 1, 1, 1);
final ColorModel cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
final WritableRaster raster = RasterFactory.createWritableRaster(sm, null);
final BufferedImage sampleImage = new BufferedImage(cm, raster, false, null);
DEFAULT_IMAGE = sampleImage;
}
final static AffineTransform IDENTITY = new AffineTransform(1, 0, 0, 1, -0.5, -0.5);
final static AffineTransform IDENTITY_FLIP = new AffineTransform(1, 0, 0, -1, -0.5, -0.5);
final static AffineTransform2D IDENTITY_2D = new AffineTransform2D(IDENTITY);
final static AffineTransform2D IDENTITY_2D_FLIP = new AffineTransform2D(IDENTITY_FLIP);
static URL checkSource(Object source) throws MalformedURLException, DataSourceException {
URL sourceURL = null;
// /////////////////////////////////////////////////////////////////////
//
// Check source
//
// /////////////////////////////////////////////////////////////////////
// if it is a URL or a String let's try to see if we can get a file to
// check if we have to build the index
if (source instanceof URL) {
sourceURL = ((URL) source);
source = DataUtilities.urlToFile(sourceURL);
} else if (source instanceof String) {
// is it a File?
final String tempSource = (String) source;
File tempFile = new File(tempSource);
if (!tempFile.exists()) {
// is it a URL
try {
sourceURL = new URL(tempSource);
source = DataUtilities.urlToFile(sourceURL);
} catch (MalformedURLException e) {
sourceURL = null;
source = null;
}
} else {
sourceURL = tempFile.toURI().toURL();
source = tempFile;
}
}
// at this point we have tried to convert the thing to a File as hard as
// we could, let's see what we can do
if (source instanceof File) {
final File sourceFile = (File) source;
if (sourceFile.isDirectory())
sourceURL = ((File) source).toURI().toURL();
} else
sourceURL = null;
return sourceURL;
}
/**
* Look for an {@link ImageReader} instance that is able to read the
* provided {@link ImageInputStream}, which must be non null.
*
* <p>
* In case no reader is found, <code>null</code> is returned.
*
* @param inStream
* an instance of {@link ImageInputStream} for which we need to
* find a suitable {@link ImageReader}.
* @return a suitable instance of {@link ImageReader} or <code>null</code>
* if one cannot be found.
*/
static ImageReader getReader(final ImageInputStream inStream) {
Utilities.ensureNonNull("inStream", inStream);
// get a reader
inStream.mark();
final Iterator<ImageReader> readersIt = ImageIO.getImageReaders(inStream);
if (!readersIt.hasNext()) {
return null;
}
return readersIt.next();
}
/**
* Retrieves an {@link ImageInputStream} for the provided input {@link File}
* .
*
* @param file
* @return
* @throws IOException
*/
static ImageInputStream getInputStream(final File file) throws IOException {
final ImageInputStream inStream = ImageIO.createImageInputStream(file);
if (inStream == null)
return null;
return inStream;
}
/**
* Checks that the provided <code>dimensions</code> when intersected with
* the source region used by the provided {@link ImageReadParam} instance
* does not result in an empty {@link Rectangle}.
*
* <p>
* Input parameters cannot be null.
*
* @param readParameters
* an instance of {@link ImageReadParam} for which we want to
* check the source region element.
* @param dimensions
* an instance of {@link Rectangle} to use for the check.
* @return <code>true</code> if the intersection is not empty,
* <code>false</code> otherwise.
*/
static boolean checkEmptySourceRegion(final ImageReadParam readParameters,
final Rectangle dimensions) {
Utilities.ensureNonNull("readDimension", dimensions);
Utilities.ensureNonNull("readP", readParameters);
final Rectangle sourceRegion = readParameters.getSourceRegion();
Rectangle.intersect(sourceRegion, dimensions, sourceRegion);
if (sourceRegion.isEmpty())
return true;
readParameters.setSourceRegion(sourceRegion);
return false;
}
/**
* Checks that a {@link File} is a real file, exists and is readable.
*
* @param file
* the {@link File} instance to check. Must not be null.
*
* @return <code>true</code> in case the file is a real file, exists and is
* readable; <code>false </code> otherwise.
*/
static boolean checkFileReadable(final File file) {
if (LOGGER.isLoggable(Level.FINE)) {
final StringBuilder builder = new StringBuilder();
builder.append("Checking file:")
.append(FilenameUtils.getFullPath(file.getAbsolutePath()))
.append("\n");
builder.append("canRead:").append(file.canRead()).append("\n");
builder.append("isHidden:").append(file.isHidden()).append("\n");
builder.append("isFile").append(file.isFile()).append("\n");
builder.append("canWrite").append(file.canWrite()).append("\n");
LOGGER.fine(builder.toString());
}
if (!file.exists() || !file.canRead() || !file.isFile())
return false;
return true;
}
/** Logger for the {@link ImageCollectionReader} class. */
private final static Logger LOGGER = org.geotools.util.logging.Logging
.getLogger(ImageCollectionReader.class.toString());
/** Move to base utils */
static float rationalTolerance = 0.000001F;
final static String PATH_KEY = "PATH";
ReadType DEFAULT_READ_TYPE = AbstractGridFormat.USE_JAI_IMAGEREAD
.getDefaultValue() ? ReadType.JAI_IMAGEREAD : ReadType.DIRECT_READ;
}