/*
* 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.ComponentColorModel;
import java.awt.image.RenderedImage;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
import javax.media.jai.ImageLayout;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RenderedOp;
import javax.media.jai.operator.BandMergeDescriptor;
import javax.media.jai.operator.FormatDescriptor;
import org.geotools.coverage.GridSampleDimension;
import org.geotools.coverage.TypeMap;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridGeometry2D;
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.util.SimpleInternationalString;
import org.opengis.coverage.grid.GridCoverage;
import org.opengis.util.InternationalString;
/**
* This {@link BandMergeNode} wraps a {@link JAI} {@link BandMergeDescriptor}
* operation for usage withing SLD 1.0 processing.
*
* @author Simone Giannecchini, GeoSolutions.
* TODO we should preserve properties
*
*/
class BandMergeNode extends BaseCoverageProcessingNode implements
CoverageProcessingNode {
/*
* (non-Javadoc)
* @see CoverageProcessingNode#getName()
*/
public InternationalString getName() {
return Vocabulary.formatInternational(VocabularyKeys.BAND_MERGE);
}
/*
* (non-Javadoc)
* @see org.geotools.renderer.lite.gridcoverage2d.BaseCoverageProcessingNode#dispose(boolean)
*/
public synchronized void dispose(boolean force) {
///////////////////////////////////////////////////////////////////////
//
// Dispose local intermediate operations
//
///////////////////////////////////////////////////////////////////////
final Iterator<RenderedImage> it=intermediateOps.iterator();
while(it.hasNext())
{
final PlanarImage image= PlanarImage.wrapRenderedImage((RenderedImage)it.next());
image.dispose();
}
super.dispose(force);
}
/**
* Holds the intermediate {@link RenderedOp} we create along the path for
* this {@link CoverageProcessingNode} in order to be able to dispose them
* later on.
*/
private Stack<RenderedImage> intermediateOps = new Stack<RenderedImage>();
/**
* Default constructor for the {@link BandMergeNode} which merge multiple
* single bands into s single coverage.
*
* @param hints
* {@link Hints} to control this node behavior.
*/
public BandMergeNode(Hints hints) {
// we use at most 3 bands for a band merge node according to the specs
super(
3,
hints,
SimpleInternationalString.wrap("BandMergeNode"),
SimpleInternationalString
.wrap("Node which applies a BandMergeNode following SLD 1.0 spec."));
}
protected GridCoverage execute() {
assert Thread.holdsLock(this);
assert getSources().size() <= 3;
// /////////////////////////////////////////////////////////////////////
//
// 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()) {
// //
//
// only one source, let's forward it, nothing to do.
//
// //
final int size = sources.size();
if (size == 1) {
return getSource(0).getOutput();
}
// //
//
// We can accept only 3 sources at this step
//
// //
if (size != 3) {
throw new IllegalArgumentException(Errors.format(
ErrorKeys.INVALID_NUMBER_OF_SOURCES_$1, Integer.valueOf(size)));
}
// /////////////////////////////////////////////////////////////////////
//
// we have at least two sources, let's merge them
//
// /////////////////////////////////////////////////////////////////////
final Iterator<CoverageProcessingNode> it = sources.iterator();
RenderedImage op = null;
GridGeometry2D gridGeometry = null;
ImageLayout layout = null;
final Hints hints = getHints();
final List<GridCoverage2D> sourceGridCoverages= new ArrayList<GridCoverage2D>();
do {
// //
//
// Get the source image and do the merge
//
// //
final CoverageProcessingNode currentSourceNode = (CoverageProcessingNode) it.next();
final GridCoverage2D currentSourceCoverage = (GridCoverage2D) currentSourceNode.getOutput();
sourceGridCoverages.add(currentSourceCoverage);
final GridGeometry2D gg = (GridGeometry2D) currentSourceCoverage.getGridGeometry();
if (gridGeometry == null) {
// get the envelope for the first source.
gridGeometry = gg;
// color model
final ComponentColorModel cm = new ComponentColorModel(
ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB),
false, false, Transparency.OPAQUE,
currentSourceCoverage.getRenderedImage()
.getSampleModel().getDataType());
layout = new ImageLayout();
layout.setColorModel(cm);
} else if (!gg.equals(gridGeometry))
throw new IllegalArgumentException(Errors.format(
ErrorKeys.MUST_SHARE_GRIDGEOMETRY_$1, "BandMerge"));
// //
//
// Merge the current source with the results of the others
// merges
//
// //
if (op == null)
op = currentSourceCoverage.getRenderedImage();
else {
op = BandMergeDescriptor.create(op, currentSourceCoverage.getRenderedImage(), hints);
// //
//
// Save the intermediate image
//
// //
intermediateOps.add(op);
}
} while (it.hasNext());
// /////////////////////////////////////////////////////////////////////
//
// let's now create the output coverage and
//
// /////////////////////////////////////////////////////////////////////
if (layout != null)
hints.add(new RenderingHints(JAI.KEY_IMAGE_LAYOUT, layout));
op = FormatDescriptor.create(op, Integer.valueOf(op.getSampleModel().getDataType()), hints);
final GridSampleDimension [] sd= new GridSampleDimension[op.getSampleModel().getNumBands()];
for(int i=0;i<sd.length;i++)
sd[i]= new GridSampleDimension(TypeMap.getColorInterpretation(op.getColorModel(), i).name());
return getCoverageFactory().create(
"BandMerge",
op,
gridGeometry,
null,
sourceGridCoverages.toArray(new GridCoverage[sourceGridCoverages.size()]),
null);
}
throw new IllegalStateException(Errors.format(
ErrorKeys.SOURCE_CANT_BE_NULL_$1, "BandMergeNode"));
}
}