/*
* ImageImporter.java
*
* Created on August 15, 2006, 8:29 PM
*
*/
package ika.geoimport;
import ika.geo.*;
import ika.gui.ProgressIndicator;
import java.io.*;
import java.awt.image.*;
import ika.utils.*;
import java.awt.Dimension;
import java.net.*;
import javax.imageio.*;
import javax.imageio.stream.*;
/**
* An importer for raster images that can be georeferenced by a world file.
* Uses java.io to read various formats (GIF, JPEG). If JAI is installed,
* additional files can be read (TIFF, Targa and others).
* @author Bernhard Jenny, Institute of Cartography, ETH Zurich
*/
public class ImageImporter extends GeoImporter {
/**
* Use the DPI information optionally stored in the image file header to
* determine the size of the image if there is no world file associated with
* the image file.
* The default setting is false, i.e. the DPI information is not per default
* extracted from the file header to avoid parsing the image if not required.
*/
private boolean readDPI = false;
/**
* If true, the read image is optimized for fast display on the current
* main monitor. If this is not wanted, use setOptimizeForDisplay(false)
* before the image is imported.
*/
private boolean optimizeForDisplay = true;
/**
* True if the imported image is georeferenced, i.e. an associated world
* file has been found. use isGeoreferenced() to access this flag.
*/
private boolean georeferenced = false;
/** Creates a new instance of ImageImporter */
public ImageImporter() {
}
/**
* Returns the width and height of an image without reading the image pixels.
* @param url The image
* @return The dimensions of the image
* @throws IOException
*/
public static Dimension getDimensions(java.net.URL url) throws IOException {
ImageReader reader = null;
ImageInputStream iis = null;
try {
reader = ika.utils.ImageUtils.findImageReader(url);
if (reader == null) {
throw new java.io.IOException("The image is not readable.");
}
iis = ImageIO.createImageInputStream(url.openStream());
reader.setInput(iis);
return new Dimension(reader.getWidth(0), reader.getHeight(0));
} finally {
if (reader != null) {
reader.dispose();
try {
// reader.dispose() does not close the ImageInputStream!
// so do this here.
if (iis != null) {
iis.close();
}
} catch (Exception exc) {
// do not throw an exception if an error occurs on closing.
}
}
}
}
protected GeoImage importData(java.net.URL url) throws IOException {
// read the image into a BufferedImage
MetaBufferedImage metaBufferedImage = this.readImage(url);
if (metaBufferedImage == null) // if the user cancels, null is returned
{
return null;
}
// the following cannot be cancelled, so disable the cancel button.
if (this.getProgressIndicator() != null) {
this.getProgressIndicator().disableCancel();
}
// optimize the image for fast display
BufferedImage bufferedImage;
if (optimizeForDisplay) {
bufferedImage =
ImageUtils.optimizeForGraphicsHardware(metaBufferedImage.image);
} else {
bufferedImage = metaBufferedImage.image;
}
// create the GeoImage
GeoImage geoImage = new GeoImage/*Pyramid*/(bufferedImage, url);
geoImage.setName(ika.utils.FileUtils.getFileNameWithoutExtension(url.getPath()));
// search and read an associated world file containing georeferencing
// information. If there is a World file we are done.
URL worldFileURL = WorldFileImporter.searchWorldFile(url);
this.georeferenced = worldFileURL != null;
if (worldFileURL != null) {
WorldFileImporter.readWorldFile(geoImage, worldFileURL);
} else if (this.readDPI) {
// No world file found. Use the possibly available dpi information.
float[] pixelSizeMM =
ika.utils.ImageUtils.getPixelSizeMillimeterFromMetadata(
metaBufferedImage.meta);
if (pixelSizeMM != null) {
geoImage.setCellSize(pixelSizeMM[0] / 1000.);
geoImage.setNorth(bufferedImage.getHeight() * pixelSizeMM[1] / 1000.);
}
}
// Enable the cancel button again. Maybe the progress indicator will be
// reused.
if (this.getProgressIndicator() != null) {
this.getProgressIndicator().enableCancel();
}
return geoImage;
}
public String getImporterName() {
return "Image Importer";
}
/**
* Reads an image from a URL and returns the image.
* Updates the ProgressIndicator.
*/
private MetaBufferedImage readImage(java.net.URL url) throws IOException {
ImageReader reader = null;
ImageInputStream iis = null;
try {
reader = ika.utils.ImageUtils.findImageReader(url);
if (reader == null) {
throw new java.io.IOException("The image is not readable.");
}
// setup input stream
iis = ImageIO.createImageInputStream(url.openStream());
reader.setInput(iis);
// setup progress indicator
ProgressIndicator progIndicator = this.getProgressIndicator();
if (progIndicator != null) {
ImageImporterProgressAdaptor progressAdaptor =
new ImageImporterProgressAdaptor(progIndicator);
reader.addIIOReadProgressListener(progressAdaptor);
try {
if (url.getProtocol().equals("file")) {
if (new java.io.File(url.toURI()).length() > 1024 * 1024 * 2) {
progressAdaptor.showDialog();
}
}
} catch (Exception exc) {
}
}
// find the image to read and read it
final int imageIndex = reader.getMinIndex();
BufferedImage bufferedImage = reader.read(imageIndex);
// if the user cancels the import, the image is not null,
// but contains black areas.
if (this.getProgressIndicator() != null && getProgressIndicator().isAborted()) {
return null;
}
// read the metadata
javax.imageio.metadata.IIOMetadata meta = null;
try {
if (this.readDPI) {
meta = reader.getImageMetadata(imageIndex);
}
} catch (Exception exc) {
}
return new MetaBufferedImage(bufferedImage, meta);
} finally {
if (reader != null) {
reader.dispose();
try {
// reader.dispose() does not close the ImageInputStream!
// so do this here.
if (iis != null) {
iis.close();
}
} catch (Exception exc) {
// do not throw an exception if an error occurs on closing.
}
}
}
}
/**
* Searches a URL referencing a data source for an image. This verifies
* whether the passed URL contains an image that can be read.
* @param url The URL to verify.
* @return The passed URL or null if it does not contain a readable image.
*/
protected java.net.URL findDataURL(java.net.URL url) {
if (url == null) {
return null;
}
if (ika.utils.ImageUtils.findImageReader(url) != null) {
return url;
}
return null;
}
/**
* MetaBufferedImage is a helper class that groups a BufferedImage with
* its associated metadata.
*/
private class MetaBufferedImage {
public BufferedImage image;
public javax.imageio.metadata.IIOMetadata meta;
public MetaBufferedImage(BufferedImage image,
javax.imageio.metadata.IIOMetadata meta) {
this.image = image;
this.meta = meta;
}
}
/**
* Returns true if the DPI information should be read if there is no world
* file associated with this image file.
*/
public boolean isReadDPI() {
return readDPI;
}
/**
* Set whether the DPI information should be read if there is no world file
* associated with this image file.
*/
public void setReadDPI(boolean readDPI) {
this.readDPI = readDPI;
}
public boolean isOptimizeForDisplay() {
return optimizeForDisplay;
}
public void setOptimizeForDisplay(boolean optimizeForDisplay) {
this.optimizeForDisplay = optimizeForDisplay;
}
public boolean isGeoreferenced() {
return georeferenced;
}
}