/* JAI-Ext - OpenSource Java Advanced Image Extensions Library
* http://www.geo-solutions.it/
* Copyright 2014 GeoSolutions
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package it.geosolutions.jaiext.rlookup;
import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptorImpl;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.ROI;
import javax.media.jai.RenderedOp;
import javax.media.jai.registry.RenderedRegistryMode;
/**
* Describes the "RangeLookup" operation.
* <p>
* This is a variation on the JAI Lookup operation. It works with a {@linkplain RangeLookupTable} object in which each entry maps a source image value
* range to a destination image value.
*
* <p>
* Users may also define a {@link ROI} object to use for masking image areas.
*
* <p>
* In the example below, double data values from a source image are mapped to integer values in a destination image.
*
* <pre>
* <code>
* RenderedImage srcImage = ...
*
* // RangeLookupTable is an immutable class. Use the associated Builder class
* // to construct a new table. The type parameters define source data type
* // and destination type respectively
* RangeLookupTable.Builder<Double, Integer> builder =
* new RangeLookupTable.Builder<Double, Integer>();
*
* // Map all source values less than zero to -1
* Range<Double> r = Range.create(Double.NEGATIVE_INFINITY, false, 0.0, false);
* builder.add(r, -1);
*
* // Map all source values from 0.0 (inclusive) to 1.0 (exclusive) to 1
* r = Range.create(0.0, true, 1.0, false);
* builder.add(r, 1);
*
* // Map all source values from 1.0 (inclusive) to 2.0 (exclusive) to 2
* r = Range.create(1.0, true, 2.0, false);
* builder.add(r, 2);
*
* // Map all source values greater than or equal to 2.0 to 3
* r = Range.create(2.0, true, Double.POSITIVE_INFINITY, false);
* builder.add(r, 3);
*
* // Create the lookup table and the JAI operation
* RangeLookupTable<Double, Integer> table = builder.build();
*
* ParameterBlockJAI pb = new ParameterBlockJAI("rangelookup");
* pb.setSource("source0", srcImage);
* pb.setParameter("table", table);
* RenderedImage destImage = JAI.create("rangelookup", pb);
* </code>
* </pre>
*
* The example above uses a table with complete coverage of all source image values. It is also allowed to have a table that only covers parts of the
* source domain. In this case, a default destination value can be specified via the "default" parameter to RangeLookup, and this will be returned for
* all unmatched source values. If the "default" parameter is null (which is its default setting) unmatched source values will be passed through to
* the destination image. Note that this may produce surprising results when converting a float or double source image to an integral destination
* image due to value truncation and overflow.
*
* <p>
* <b>Parameters</b>
* <table border="1">
* <tr>
* <th>Name</th>
* <th>Type</th>
* <th>Description</th>
* <th>Default value</th>
* </tr>
* <tr>
* <td>table</td>
* <td>RangeLookupTable</td>
* <td>Table mapping source value ranges to destination values</td>
* <td>NO DEFAULT</td>
* </tr>
* <tr>
* <td>default</td>
* <td>Number</td>
* <td>Specifies the value to return for source values that do not map to any ranges in the lookup table. If null, unmatched source values will be
* passed through to the destination image.</td>
* <td>null (pass-through)</td>
* </tr>
* <tr>
* <td>roi</td>
* <td>javax.media.jai.ROI</td>
* <td>Specifies a ROI to use for reducing computation area</td>
* <td>null</td>
* </tr>
* </table>
*
*
* @author Michael Bedward
* @author Simone Giannecchini, GeoSolutions
*/
public class RangeLookupDescriptor extends OperationDescriptorImpl {
/** serialVersionUID */
private static final long serialVersionUID = 6435703646431578734L;
static final int TABLE_ARG = 0;
static final int DEFAULT_ARG = 1;
static final int ROI_ARG = 2;
private static final String[] paramNames = { "table", "default", "roi" };
private static final Class<?>[] paramClasses = { RangeLookupTable.class, Number.class,
javax.media.jai.ROI.class };
private static final Object[] paramDefaults = { NO_PARAMETER_DEFAULT, (Number) null, null };
/** Constructor. */
public RangeLookupDescriptor() {
super(new String[][] {
{ "GlobalName", "RLookup" },
{ "LocalName", "RLookup" },
{ "Vendor", "it.geosolutions.jaiext" },
{ "Description", "Maps source image value ranges to destination image values" },
{ "DocURL", "" },
{ "Version", "1.0" },
{
"arg0Desc",
String.format("%s - table holding source value ranges mapped to "
+ "destination values", paramNames[TABLE_ARG]) },
{
"arg1Desc",
String.format("%s - value to use for unmatched source values "
+ "(default: null to pass through source values)",
paramNames[DEFAULT_ARG]) },
{
"arg2Desc",
String.format("%s - ROI used for reducing the image computations "
+ "(default: all the image is valid)", paramNames[ROI_ARG]) }, },
new String[] { RenderedRegistryMode.MODE_NAME }, // supported modes
1, // number of sources
paramNames, paramClasses, paramDefaults,
null // valid values (none defined)
);
}
/**
* Creates a new {@link RenderedOp} with the RLookup operation applied.
*
* @param table input {@link RangeLookupTable}
* @param defaultValue Value to set for pixels outside ROI or outside of the Table Range
* @param roi Input {@link ROI} to use in computation
* @param hints Configuration hints
*/
public static RenderedOp create(RenderedImage source, RangeLookupTable table,
Number defaultValue, ROI roi, RenderingHints hints) {
// Definition of the ParameterBlock
ParameterBlockJAI pb = new ParameterBlockJAI("RLookup");
// Setting the source
pb.setSource(source, 0);
// Setting the parameters
pb.setParameter("table", table);
pb.setParameter("default", defaultValue);
pb.setParameter("roi", roi);
// Calling the operation
return JAI.create("RLookup", pb, hints);
}
}