/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package de.cismet.cismap.commons.rasterservice;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.geom.util.AffineTransformation;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFImage;
import org.apache.log4j.Logger;
import org.deegree.io.geotiff.GeoTiffReader;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;
import de.cismet.cismap.commons.CrsTransformer;
import de.cismet.cismap.commons.interaction.CismapBroker;
import de.cismet.cismap.commons.rasterservice.georeferencing.PointCoordinatePair;
/**
* DOCUMENT ME!
*
* @author jruiz
* @version $Revision$, $Date$
*/
public class ImageFileUtils {
//~ Static fields/initializers ---------------------------------------------
private static final Logger LOG = Logger.getLogger(ImageFileUtils.class);
private static final Map<String, String> WORLD_FILE_ENDINGS = new HashMap<String, String>();
static {
WORLD_FILE_ENDINGS.put("jpg", "jgw");
WORLD_FILE_ENDINGS.put("jpeg", "jgw");
WORLD_FILE_ENDINGS.put("png", "pgw");
WORLD_FILE_ENDINGS.put("gif", "gfw");
WORLD_FILE_ENDINGS.put("tif", "tfw");
WORLD_FILE_ENDINGS.put("tiff", "tfw");
}
public static final String[] SUPPORTED_IMAGE_FORMATS = { "png", "jpg", "jpeg", "tif", "tiff", "gif" };
//~ Enums ------------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public enum Mode {
//~ Enum constants -----------------------------------------------------
WORLDFILE, TIFF, GEO_REFERENCED
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @param imageFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static File getWorldFile(final File imageFile) {
final File worldFile = getWorldFileWithoutCheck(imageFile);
if (worldFile.exists()) {
return worldFile;
} else {
return null;
}
}
/**
* DOCUMENT ME!
*
* @param imageFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static File getWorldFileWithoutCheck(final File imageFile) {
final String name = imageFile.getAbsolutePath();
final String ending = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
final String wfEnding = WORLD_FILE_ENDINGS.get(ending);
if (wfEnding != null) {
final String worldFileName = name.substring(0, name.lastIndexOf(".") + 1) + wfEnding;
final File worldFile = new File(worldFileName);
return worldFile;
} else {
return null;
}
}
/**
* DOCUMENT ME!
*
* @param imageFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws Exception DOCUMENT ME!
*/
public static ImageFileMetaData getTiffMetaData(final File imageFile) throws Exception {
GeoTiffReader r = new GeoTiffReader(imageFile);
final org.deegree.model.spatialschema.Envelope e = r.getBoundingBox();
final Envelope en = new Envelope(e.getMin().getX(), e.getMax().getX(), e.getMin().getY(), e.getMax().getY());
final TIFFImage tiffImage = r.getTIFFImage();
final Rectangle rec = tiffImage.getBounds();
r = null;
System.gc();
return new ImageFileMetaData(rec, en, null, null);
}
/**
* DOCUMENT ME!
*
* @param fileName DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static boolean isImageFileEnding(final String fileName) {
for (final String ending : SUPPORTED_IMAGE_FORMATS) {
if (fileName.endsWith(ending)) {
return true;
}
}
return false;
}
/**
* DOCUMENT ME!
*
* @param imageFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static Mode determineMode(final File imageFile) {
ImageFileMetaData md = null;
final File worldFile = ImageFileUtils.getWorldFile(imageFile);
if (worldFile != null) {
md = getWorldFileMetaData(imageFile, worldFile);
if (md != null) {
return md.isRasterGeoRef() ? Mode.GEO_REFERENCED : Mode.WORLDFILE;
}
}
if (imageFile.getName().toLowerCase().endsWith("tif")) {
try {
return Mode.TIFF;
} catch (final Exception ex) {
}
}
return (md != null) ? Mode.TIFF : Mode.GEO_REFERENCED;
}
/**
* DOCUMENT ME!
*
* @param worldFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static boolean checkIfRasterGeoRef(final File worldFile) {
if (worldFile != null) {
try {
final BufferedReader br = new BufferedReader(new FileReader(worldFile));
String line;
while (((line = br.readLine()) != null)) {
if (line.startsWith("#cidsgeoref;")) {
return true;
}
}
br.close();
} catch (Exception e) {
LOG.error("Cannot parse the world file", e);
}
}
return false;
}
/**
* Determines the meta information about the image file. It will be assumed, that a world file for the image file
* exists. The world file must have the file ending .jgw, .pgw, .gfw or .tfw depending on the image format.
*
* @param imageFile DOCUMENT ME!
* @param worldFile DOCUMENT ME!
*
* @return the meta information about the image file
*/
public static ImageFileMetaData getWorldFileMetaData(final File imageFile, final File worldFile) {
try {
final BufferedReader br = new BufferedReader(new FileReader(worldFile));
final double[] matrix = new double[6];
final List<PointCoordinatePair> pairs = new ArrayList<>();
boolean isRasterGeoReof = false;
// read parameter from world file
int index = 0;
String line;
while (((line = br.readLine()) != null)) {
if (line.startsWith("#cidsgeoref;")) {
isRasterGeoReof = true;
continue;
}
if (isRasterGeoReof) {
if (line.startsWith("#")) {
final String[] parts = line.substring(1).split(";|,");
if (parts.length == 4) {
final Point point = new Point(Integer.parseInt(parts[0]), Integer.parseInt(parts[1]));
final Coordinate coordinate = new Coordinate(Double.parseDouble(parts[2]),
Double.parseDouble(parts[3]));
pairs.add(new PointCoordinatePair(point, coordinate));
}
}
} else {
if (line.trim().isEmpty() || line.startsWith("#")) {
continue;
}
if (line.contains(",")) {
line = line.replaceAll(",", ".");
}
matrix[index++] = Double.parseDouble(line);
}
}
br.close();
if (index == matrix.length) {
final AffineTransformation transform = new AffineTransformation(
matrix[0],
matrix[2],
matrix[4],
matrix[1],
matrix[3],
matrix[5]);
final Dimension imageDimension = ImageFileUtils.getImageDimension(imageFile);
final double imageWidth = imageDimension.getWidth();
final double imageHeight = imageDimension.getHeight();
final Rectangle imageBounds = new Rectangle(0, 0, (int)imageWidth, (int)imageHeight);
final GeometryFactory factory = new GeometryFactory(
new PrecisionModel(),
CrsTransformer.extractSridFromCrs(CismapBroker.getInstance().getSrs().getCode()));
final LinearRing linear = factory.createLinearRing(
new Coordinate[] {
new Coordinate(0, 0),
new Coordinate(imageWidth, 0),
new Coordinate(imageWidth, imageHeight),
new Coordinate(0, imageHeight),
new Coordinate(0, 0)
});
final Envelope imageEnvelope = transform.transform(factory.createPolygon(linear, null))
.getEnvelopeInternal();
final ImageFileMetaData metaData = new ImageFileMetaData(
imageBounds,
imageEnvelope,
transform,
(isRasterGeoReof) ? pairs.toArray(new PointCoordinatePair[0]) : null);
return metaData;
}
} catch (Exception e) {
LOG.error("Cannot parse the world file", e);
}
return null;
}
/**
* Determines the width and height of the given iamge file. This method does not completely read the image.
*
* @param imgFile DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws IOException DOCUMENT ME!
*/
public static Dimension getImageDimension(final File imgFile) throws IOException {
final int pos = imgFile.getName().lastIndexOf(".");
if (pos == -1) {
throw new IOException("The file " + imgFile.getAbsolutePath()
+ " has not extension, so no reader can be found.");
}
final String fileSuffix = imgFile.getName().substring(pos + 1);
final Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix(fileSuffix);
if (iter.hasNext()) {
final ImageReader reader = iter.next();
try {
final ImageInputStream stream = new FileImageInputStream(imgFile);
reader.setInput(stream);
final int width = reader.getWidth(reader.getMinIndex());
final int height = reader.getHeight(reader.getMinIndex());
return new Dimension(width, height);
} catch (IOException e) {
LOG.warn("Error reading: " + imgFile.getAbsolutePath(), e);
} finally {
reader.dispose();
}
}
throw new IOException("No suitable reader found for file format: " + fileSuffix);
}
}