/* * Geotools 2 - OpenSource mapping toolkit * (C) 2003, Geotools Project Management Committee (PMC) * (C) 2001, Institut de Recherche pour le Développement * * 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; either * version 2.1 of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * This package contains documentation from OpenGIS specifications. * OpenGIS consortium's work is fully acknowledged here. */ package org.geotools.cv; // J2SE dependencies 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.awt.image.renderable.RenderedImageFactory; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; 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.resources.i18n.ErrorKeys; import org.geotools.resources.i18n.Errors; import org.geotools.resources.image.DualRectIter; /** * 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 * SampleTranscoder.CRIF inner class, where "CRIF" stands for * {@link java.awt.image.renderable.ContextualRenderedImageFactory}. The image * operation name is "org.geotools.legacy.SampleTranscode". * * @source $URL$ * @version $Id$ * @author Martin Desruisseaux * * @deprecated Replaced by {@link org.geotools.coverage.SampleTranscoder} * in the org.geotools.coverage package. */ final class SampleTranscoder extends PointOpImage { /** * The operation name. NOTE: Class {@link org.geotools.gc.GridCoverage} * 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.legacy.SampleTranscode"; /** * Ensemble des catégories qui donnent une signification aux pixels de l'image. La * longueur de ce tableau doit correspondre au nombre de bandes de l'image source. */ private final CategoryList[] categories; /** * Construct a new 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(); } /** * Compute one of the destination image tile. * * @task TODO: There is two optimisations we could do here: * * 1) If source and destination are the same raster, then a single * {@link WritableRectIter} object would be more efficient (the * hard work is to detect if source and destination are the same). * 2) If the destination image is a single-banded, non-interleaved * sample model, we could apply the transform directly in the * {@link java.awt.image.DataBuffer}. We can even avoid to copy * sample value if source and destination raster are the same. * * @param sources An array of length 1 with source image. * @param dest The destination tile. * @param destRect the rectangle within the destination to be written. */ protected void computeRect(final PlanarImage[] sources, final WritableRaster dest, final Rectangle destRect) { final PlanarImage source = sources[0]; WritableRectIter iterator = RectIterFactory.createWritable(dest, destRect); if (true) { // TODO: Detect if source and destination rasters are the same. If they are // the same, we should skip this block. Iteration will then be faster. iterator = DualRectIter.create(RectIterFactory.create(source, destRect), iterator); } int band=0; if (!iterator.finishedBands()) do { categories[band].transform(iterator); band++; } while (!iterator.nextBandDone()); assert(band == categories.length) : band; } ///////////////////////////////////////////////////////////////////////////////// //////// //////// //////// REGISTRATION OF "SampleTranscode" IMAGE OPERATION //////// //////// //////// ///////////////////////////////////////////////////////////////////////////////// /** * The operation descriptor for the "SampleTranscode" operation. This operation can * apply the {@link SampleDimension#getSampleToGeophysics sampleToGeophysics} transform * on all pixels in all bands of an image. The transformations are supplied as a list of * {@link SampleDimension}s, one for each band. The supplied SampleDimensions * objects describe the categories in the source image. The target image * will matches sample dimension * * {@link SampleDimension#geophysics geophysics}(!isGeophysics), * * where isGeophysics is the previous state of the sample dimension. */ private static final class Descriptor extends OperationDescriptorImpl { /** * 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://modules.geotools.org/gcs-coverage"}, {"Version", "1.0"}}, new String[] {RenderedRegistryMode.MODE_NAME}, 1, new String[] {"sampleDimensions"}, // Argument names new Class [] {SampleDimension[].class}, // Argument classes new Object[] {NO_PARAMETER_DEFAULT}, // Default values for parameters, null // No restriction on valid parameter values. ); } /** * Returns 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. */ 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 SampleDimension[] bands = (SampleDimension[]) param.getObjectParameter(0); final int numBands = source.getSampleModel().getNumBands(); if (numBands != bands.length) { message.append(Errors.format(ErrorKeys.NUMBER_OF_BANDS_MISMATCH_$3, new Integer(numBands), new Integer(bands.length), "SampleDimension")); return false; } for (int i=0; icategories1 are * equals to the inverse of categories2. */ private static boolean isInverse(final CategoryList[] categories1, final CategoryList[] categories2) { if (categories1.length != categories2.length) { return false; } for (int i=0; i