/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-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.renderer.lite.gridcoverage2d; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.color.ColorSpace; import java.awt.image.ColorModel; import java.awt.image.ComponentColorModel; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.util.List; import javax.media.jai.ImageLayout; import javax.media.jai.JAI; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.processing.CoverageProcessor; import org.geotools.coverage.processing.operation.SelectSampleDimension; import org.geotools.factory.Hints; import org.geotools.renderer.i18n.ErrorKeys; import org.geotools.renderer.i18n.Errors; import org.geotools.renderer.i18n.Vocabulary; import org.geotools.renderer.i18n.VocabularyKeys; import org.geotools.styling.SelectedChannelType; import org.geotools.util.SimpleInternationalString; import org.opengis.parameter.ParameterValueGroup; import org.opengis.util.InternationalString; /** * This {@link CoverageProcessingNode} has been built for taking care of the band select operation within the context of applying SLD 1.0. * @author Simone Giannecchini, GeoSolutions. */ class BandSelectionNode extends StyleVisitorCoverageProcessingNodeAdapter implements CoverageProcessingNode { /* * (non-Javadoc) * @see CoverageProcessingNode#getName() */ public InternationalString getName() { return Vocabulary.formatInternational(VocabularyKeys.BAND_SELECTION); } /** * Index of the band we want to select. * @uml.property name="bandIndex" */ private int bandIndex = -1; /** * Default constructor. * * <p> * A band selection node can have at most one source node. */ public BandSelectionNode() { this(null); } /** * Default constructor. * * <p> * A band selection node can have at most one source node. * * @param hints * {@link Hints} to contro internal machinery for factories, */ public BandSelectionNode(Hints hints) { super( 1, hints, SimpleInternationalString.wrap("BandSelectionNode"), SimpleInternationalString .wrap("Node which applies a BandSelection following SLD 1.0 spec.")); } /* * (non-Javadoc) * * @see org.geotools.renderer.lite.gridcoverage2d.BaseCoverageProcessingNode#execute() */ protected GridCoverage2D execute() { // preconditions assert Thread.holdsLock(this); assert this.getSources().size() <= 1; // ///////////////////////////////////////////////////////////////////// // // Get the sources and see what we got to do. Note that if we have more // than once source we'll use only the first one but we'll // // ///////////////////////////////////////////////////////////////////// final List<CoverageProcessingNode> sources = this.getSources(); if (sources != null && !sources.isEmpty()) { final GridCoverage2D source = (GridCoverage2D) getSource(0).getOutput(); ensureSourceNotNull(source, this.getName().toString()); GridCoverage2D output = null; if (bandIndex != -1) { // ///////////////////////////////////////////////////////////////////// // // We have a valid band index, go ahead and to a band select // // ///////////////////////////////////////////////////////////////////// // // // // Is the index correct? // // // final int numSampleDimensions = source.getNumSampleDimensions(); if (bandIndex < 1 || bandIndex > numSampleDimensions) throw new IllegalArgumentException( Errors.format(ErrorKeys.BAD_BAND_NUMBER_$1,Integer.valueOf(bandIndex))); // // // // SHORTCUT // // Are we trying to do a band select on a single band coverage? // Note that we already checked that the index is valid. // // // if (bandIndex == 1 && numSampleDimensions == 1) { output = source; } else { // // // // Do the actual band selection. // // // final CoverageProcessor processor = new CoverageProcessor( this.getHints()); // get the source final ParameterValueGroup parameters = processor .getOperation("SelectSampleDimension") .getParameters(); parameters.parameter("SampleDimensions").setValue( new int[] { bandIndex - 1 }); parameters.parameter("Source").setValue(source); // // // // Save the output // // // final Hints hints = new Hints(getHints()); final ImageLayout layout = new ImageLayout(); final RenderedImage sourceRaster = source .getRenderedImage(); final SampleModel oldSM = sourceRaster.getSampleModel(); final ColorModel cm = new ComponentColorModel(ColorSpace .getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, oldSM.getDataType()); layout.setColorModel(cm); layout.setSampleModel(cm.createCompatibleSampleModel(oldSM .getWidth(), oldSM.getHeight())); hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout)); output = (GridCoverage2D) new SelectSampleDimension() .doOperation(parameters, hints); } // postcondition assert output.getNumSampleDimensions() == 1; } else // ///////////////////////////////////////////////////////////////////// // // We do not have a valid band index, let's try with a // conservative approach that is, let's forward the source // coverage intact. // TODO better throwing an error? // ///////////////////////////////////////////////////////////////////// output = source; return output; } throw new IllegalStateException("No source was set for this Node."); } public synchronized void visit(SelectedChannelType sct) { // ///////////////////////////////////////////////////////////////////// // // If a SelectedChannelType was provided, let's try to parse it. // // ///////////////////////////////////////////////////////////////////// if (sct != null) { final String name = sct.getChannelName(); try { bandIndex = Integer.parseInt(name); } catch (NumberFormatException e) { // something bad happened final IllegalArgumentException iee = new IllegalArgumentException( Errors.format(ErrorKeys.BAD_BAND_NUMBER_$1,Integer.valueOf(bandIndex))); iee.initCause(e); throw iee; } return; } // ///////////////////////////////////////////////////////////////////// // // If no SelectedChannelType was provided, let's just forward the // source. // // ///////////////////////////////////////////////////////////////////// // do nothing } /** * Retrieves the band index we use for this {@link BandSelectionNode} . <p> <code>-1</code> warns about a possible error. * @return the bandIndex * @uml.property name="bandIndex" */ public int getBandIndex() { return bandIndex; } }