/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2001-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.coverage; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.image.RasterFormatException; import java.awt.image.RenderedImage; import java.awt.image.WritableRaster; import java.awt.image.renderable.ParameterBlock; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.LogRecord; import javax.media.jai.CRIFImpl; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import javax.media.jai.OperationDescriptorImpl; import javax.media.jai.OperationRegistry; import javax.media.jai.PlanarImage; import javax.media.jai.PointOpImage; import javax.media.jai.iterator.RectIterFactory; import javax.media.jai.iterator.WritableRectIter; import javax.media.jai.registry.RenderedRegistryMode; import org.geotools.coverage.grid.AbstractGridCoverage; import org.geotools.resources.i18n.Errors; import org.geotools.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Loggings; import org.geotools.resources.i18n.LoggingKeys; import org.geotools.util.logging.Logging; import org.geotools.image.TransfertRectIter; /** * An image that contains transformed samples. It may be sample values after their * transformation to geophyics values, or the converse. Images are created using the * {@code SampleTranscoder.CRIF} inner class, where "CRIF" stands for * {@link java.awt.image.renderable.ContextualRenderedImageFactory}. The image * operation name is {@code "org.geotools.SampleTranscode"}. * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux (IRD) * * @since 2.1 */ final class SampleTranscoder extends PointOpImage { /** * The operation name. * NOTE: Class {@link org.geotools.coverage.grid.GridCoverage2D} * uses this name, but can't refer to this constant since it is in an other package. */ public static final String OPERATION_NAME = "org.geotools.SampleTranscode"; /** * Category lists for each bands. * The array length must matches the number of bands in source image. */ private final CategoryList[] categories; /** * Constructs a new {@code SampleTranscoder}. * * @param image The source image. * @param categories The category lists, one for each image's band. * @param hints The rendering hints. */ private SampleTranscoder(final RenderedImage image, final CategoryList[] categories, final RenderingHints hints) { super(image, (ImageLayout)hints.get(JAI.KEY_IMAGE_LAYOUT), hints, false); this.categories = categories; if (categories.length != image.getSampleModel().getNumBands()) { // Should not happen, since SampleDimension$Descriptor has already checked it. throw new RasterFormatException(String.valueOf(categories.length)); } permitInPlaceOperation(); } /** * Computes one of the destination image tile. * * @todo There is two optimisations we could do here: *
{@link GridSampleDimension#geophysics geophysics}(!isGeophysics)
,
*
* where {@code isGeophysics} is the previous state of the sample dimension.
*/
private static final class Descriptor extends OperationDescriptorImpl {
/**
* For cross-version serialization.
*/
private static final long serialVersionUID = -4204913600785080791L;
/**
* Construct the descriptor.
*/
public Descriptor() {
super(new String[][]{{"GlobalName", OPERATION_NAME},
{"LocalName", OPERATION_NAME},
{"Vendor", "Geotools 2"},
{"Description", "Transformation from sample to geophysics values"},
{"DocURL", "http://www.geotools.org/"},
{"Version", "1.0"}},
new String[] {RenderedRegistryMode.MODE_NAME}, 1,
new String[] {"sampleDimensions"}, // Argument names
new Class [] {GridSampleDimension[].class}, // Argument classes
new Object[] {NO_PARAMETER_DEFAULT}, // Default values for parameters,
null // No restriction on valid parameter values.
);
}
/**
* Returns {@code true} if the parameters are valids. This implementation check
* that the number of bands in the source image is equals to the number of supplied
* sample dimensions, and that all sample dimensions has categories.
*
* @param modeName The mode name (usually "Rendered").
* @param param The parameter block for the operation to performs.
* @param message A buffer for formatting an error message if any.
*/
@Override
protected boolean validateParameters(final String modeName,
final ParameterBlock param,
final StringBuffer message)
{
if (!super.validateParameters(modeName, param, message)) {
return false;
}
final RenderedImage source = (RenderedImage) param.getSource(0);
final GridSampleDimension[] bands = (GridSampleDimension[]) param.getObjectParameter(0);
final int numBands = source.getSampleModel().getNumBands();
if (numBands != bands.length) {
message.append(Errors.format(ErrorKeys.NUMBER_OF_BANDS_MISMATCH_$3,
numBands, bands.length, "SampleDimension"));
return false;
}
for (int i=0; i