/*
* 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.coverageio.jp2k;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import javax.media.jai.ImageLayout;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import org.geotools.resources.i18n.ErrorKeys;
import org.geotools.resources.i18n.Errors;
/**
* This enum can be used to distinguish between different read methods, namely,
* JAI ImageRead based and Java2D direct read via ImageReader.
*
* @author Simone Giannecchini, GeoSolutions SAS
*
*/
enum ReadType {
DIRECT_READ {
RenderedImage read(
final ImageReadParam readP,
final int imageIndex,
final File rasterFile,
final Rectangle readDimension,
final Dimension tileDimension, // we just ignore in this case
final ImageReaderSpi spi) throws IOException {
//
// Using ImageReader to load the data directly
//
ImageInputStream inStream = null;
ImageReader reader = null;
try {
inStream = Utils.getInputStream(rasterFile);
if (inStream == null) {
return null;
}
reader = spi.createReaderInstance();
if (reader == null) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("Unable to get reader for file " + rasterFile.getAbsolutePath());
}
return null;
}
inStream.reset();
reader.setInput(inStream);
// check source regione
if (Utils.checkEmptySourceRegion(readP, readDimension)) {
return null;
}
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "reading file: " + rasterFile.getAbsolutePath());
}
// read data
return reader.read(imageIndex, readP);
} catch (IOException e) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Unable to compute source area for file " + rasterFile.getAbsolutePath(), e);
}
return null;
} finally {
// close everything
try {
// reader
if (reader != null) {
reader.dispose();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
try {
// instream
if (inStream != null) {
inStream.close();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
}
}
},
JAI_IMAGEREAD {
@Override
RenderedImage read(
final ImageReadParam readP,
final int imageIndex,
final File rasterFile,
final Rectangle readDimension,
final Dimension tileDimension,
final ImageReaderSpi spi)
throws IOException {
// /
// Using ImageReader to load the data directly
//
ImageInputStream inStream = null;
ImageReader reader = null;
try {
// get stream
inStream = Utils.getInputStream(rasterFile);
if (inStream == null) {
return null;
}
// get a reader
reader = spi.createReaderInstance();
if (reader == null) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("Unable to get reader for file " + rasterFile.getAbsolutePath());
}
return null;
}
inStream.reset();
reader.setInput(inStream);
// check source region
if (Utils.checkEmptySourceRegion(readP, readDimension)) {
return null;
}
} catch (IOException e) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Unable to compute source area for file " + rasterFile.getAbsolutePath(), e);
}
return null;
} finally {
// close everything
try {
// reader
if (reader != null) {
reader.dispose();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
try {
// instream
if (inStream != null) {
inStream.close();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
}
// read data
final ParameterBlock pbjImageRead = new ParameterBlock();
pbjImageRead.add(rasterFile);
pbjImageRead.add(imageIndex);
pbjImageRead.add(false);
pbjImageRead.add(false);
pbjImageRead.add(false);
pbjImageRead.add(null);
pbjImageRead.add(null);
pbjImageRead.add(readP);
pbjImageRead.add(spi.createReaderInstance());
final RenderedOp raster;
if (tileDimension != null) {
// build a proper layout
final ImageLayout layout = new ImageLayout();
layout.setTileWidth(tileDimension.width).setTileHeight(tileDimension.height);
raster = JAI.create("ImageRead", pbjImageRead, new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));
} else {
raster = JAI.create("ImageRead", pbjImageRead);
}
// force rendering (a-la JAI)
if (raster != null) {
raster.getWidth();
}
return raster;
}
},
JAI_IMAGEREAD_MT {
@Override
RenderedImage read(
final ImageReadParam readP,
final int imageIndex,
final File rasterFile,
final Rectangle readDimension,
final Dimension tileDimension,
final ImageReaderSpi spi)
throws IOException {
// /
// Using ImageReader to load the data directly
//
ImageInputStream inStream = null;
ImageReader reader = null;
try {
// get stream
inStream = Utils.getInputStream(rasterFile);
if (inStream == null) {
return null;
}
// get a reader
reader = spi.createReaderInstance();
if (reader == null) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.warning("Unable to get reader for file " + rasterFile.getAbsolutePath());
}
return null;
}
inStream.reset();
reader.setInput(inStream);
// check source region
if (Utils.checkEmptySourceRegion(readP, readDimension)) {
return null;
}
} catch (IOException e) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, "Unable to compute source area for file " + rasterFile.getAbsolutePath(), e);
}
return null;
} finally {
// close everything
try {
// reader
if (reader != null) {
reader.dispose();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
try {
// instream
if (inStream != null) {
inStream.close();
}
} catch (Throwable t) {
// swallow the exception, we are just trying to close as much stuff as possible
}
}
// read data
final ParameterBlock pbjImageRead = new ParameterBlock();
pbjImageRead.add(rasterFile);
pbjImageRead.add(imageIndex);
pbjImageRead.add(false);
pbjImageRead.add(false);
pbjImageRead.add(false);
pbjImageRead.add(null);
pbjImageRead.add(null);
pbjImageRead.add(readP);
pbjImageRead.add(spi.createReaderInstance());
final RenderedOp raster;
if (tileDimension != null) {
// build a proper layout
final ImageLayout layout = new ImageLayout();
layout.setTileWidth(tileDimension.width).setTileHeight(tileDimension.height);
raster = JAI.create("ImageReadMT", pbjImageRead, new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));
} else {
raster = JAI.create("ImageReadMT", pbjImageRead);
}
// force rendering (a-la JAI)
if (raster != null) {
raster.getWidth();
}
return raster;
}
},
UNSPECIFIED {
@Override
RenderedImage read(
final ImageReadParam readP,
final int imageIndex,
final File rasterFile,
final Rectangle readDimension,
final Dimension tileDimension,
final ImageReaderSpi spi)
throws IOException {
throw new UnsupportedOperationException(Errors.format(ErrorKeys.UNSUPPORTED_OPERATION_$1, "read"));
}
};
/** Logger. */
private final static Logger LOGGER = org.geotools.util.logging.Logging.getLogger(ReadType.class);
/**
* Default {@link ReadType} enumeration.
*
* <p>
* We use the JAI ImageRead as the default type so that we can be sure that
* we can read very large images with deferred loading.
*
* @return the default {@link ReadType}.
*/
static ReadType getDefault() {
return JAI_IMAGEREAD;
}
/**
* Load the raster data from the underlying source with the specified read type.
*
* @param readParameters
* @param imageIndex
* @param rasterFile
* @param readDimension
* @param tileDimension
* a {@link Dimension} object that can be used to suggest
* specific tile dimension for the raster to load. It can be
* <code>null</code>.
*
* @return a {@link RenderedImage} instance that matches the provided
* request parameters as close as possible.
*
* @throws IOException
* in case something bad occurs during the decoding process.
*/
abstract RenderedImage read(
final ImageReadParam readParameters,
final int imageIndex,
final File rasterFile,
final Rectangle readDimension,
final Dimension tileDimension,
final ImageReaderSpi spi) throws IOException;
};