/* 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.imagefunction; import it.geosolutions.jaiext.range.Range; import java.awt.RenderingHints; import java.awt.image.renderable.ParameterBlock; import javax.media.jai.ImageFunction; import javax.media.jai.JAI; import javax.media.jai.OperationDescriptorImpl; import javax.media.jai.ParameterBlockJAI; import javax.media.jai.PropertyGenerator; import javax.media.jai.ROI; import javax.media.jai.RenderableOp; import javax.media.jai.RenderedOp; import javax.media.jai.registry.RenderedRegistryMode; import com.sun.media.jai.util.PropertyGeneratorImpl; /** * This property generator computes the properties for the operation "ImageFunction" dynamically. */ class ImageFunctionPropertyGenerator extends PropertyGeneratorImpl { /** Constructor. */ public ImageFunctionPropertyGenerator() { super(new String[] { "COMPLEX" }, new Class[] { Boolean.class }, new Class[] { RenderedOp.class, RenderableOp.class }); } /** * Returns the specified property. * * @param name Property name. * @param opNode Operation node. */ public Object getProperty(String name, Object opNode) { validate(name, opNode); if (name.equalsIgnoreCase("complex")) { if (opNode instanceof RenderedOp) { RenderedOp op = (RenderedOp) opNode; ParameterBlock pb = op.getParameterBlock(); ImageFunction imFunc = (ImageFunction) pb.getObjectParameter(0); return imFunc.isComplex() ? Boolean.TRUE : Boolean.FALSE; } else if (opNode instanceof RenderableOp) { RenderableOp op = (RenderableOp) opNode; ParameterBlock pb = op.getParameterBlock(); ImageFunction imFunc = (ImageFunction) pb.getObjectParameter(0); return imFunc.isComplex() ? Boolean.TRUE : Boolean.FALSE; } } return java.awt.Image.UndefinedProperty; } } /** * An <code>OperationDescriptor</code> describing the "ImageFunction" operation. * * <p> * The "ImageFunction" operation generates an image on the basis of a functional description provided by an object which is an instance of a class * which implements the <code>ImageFunction</code> interface. The <i>(x,y)</i> coordinates passed to the <code>getElements()</code> methods of the * <code>ImageFunction</code> object are derived by applying an optional translation and scaling to the X- and Y-coordinates of the image. The image * X- and Y-coordinates as usual depend on the values of the minimum X- and Y- coordinates of the image which need not be zero. Specifically, the * function coordinates passed to <code>getElements()</code> are calculated from the image coordinates as: * * <pre> * functionX = xScale * (imageX - xTrans); * functionY = yScale * (imageY - yTrans); * </pre> * * This implies that the pixel at coordinates <i>(xTrans,yTrans)</i> will be assigned the value of the function at <i>(0,0)</i>. * * <p> * The number of bands in the destination image must be equal to the value returned by the <code>getNumElements()</code> method of the * <code>ImageFunction</code> unless the <code>isComplex()</code> method of the <code>ImageFunction</code> returns <code>true</code> in which case it * will be twice that. The data type of the destination image is determined by the <code>SampleModel</code> specified by an <code>ImageLayout</code> * object provided via a hint. If no layout hint is provided, the data type will default to single-precision floating point. The double precision * floating point form of the <code>getElements()</code> method of the <code>ImageFunction</code> will be invoked if and only if the data type is * specified to be <code>double</code>. For all other data types the single precision form of <code>getElements()</code> will be invoked and the * destination sample values will be clamped to the data type of the image. * * <p> * The width and height of the image are provided explicitely as parameters. These values override the width and height specified via an * <code>ImageLayout</code> if such is provided. * * <p> * "ImageFunction" defines a PropertyGenerator that sets the "COMPLEX" property of the image to <code>java.lang.Boolean.TRUE</code> or * <code>java.lang.Boolean.FALSE</code> depending on whether the <code>isComplex()</code> method of the <code>ImageFunction</code> parameter returns * <code>true</code> or <code>false</code>, respectively. This property may be retrieved by calling the <code>getProperty()</code> method with * "COMPLEX" as the property name. * * <p> * It should be pointed out that users can define a valid area using an input {@link ROI} object, and also can define NoData values by using an input * NoData {@link Range}. * * <p> * <table border=1> * <caption>Resource List</caption> * <tr> * <th>Name</th> * <th>Value</th> * </tr> * <tr> * <td>GlobalName</td> * <td>ImageFunction</td> * </tr> * <tr> * <td>LocalName</td> * <td>ImageFunction</td> * </tr> * <tr> * <td>Vendor</td> * <td>it.geosolutions.jaiext</td> * </tr> * <tr> * <td>Description</td> * <td>Generates an image from a functional description.</td> * </tr> * <tr> * <td>DocURL</td> * <td></td> * </tr> * <tr> * <td>Version</td> * <td>1.0</td> * </tr> * <tr> * <td>arg0Desc</td> * <td>The function object.</td> * </tr> * <tr> * <td>arg1Desc</td> * <td>The image width.</td> * </tr> * <tr> * <td>arg2Desc</td> * <td>The image height.</td> * </tr> * <tr> * <td>arg3Desc</td> * <td>The X scale factor.</td> * </tr> * <tr> * <td>arg4Desc</td> * <td>The Y scale factor.</td> * </tr> * <tr> * <td>arg5Desc</td> * <td>The X translation.</td> * </tr> * <tr> * <td>arg6Desc</td> * <td>The Y translation.</td> * </tr> * <tr> * <td>arg7Desc</td> * <td>The ROI object.</td> * </tr> * <tr> * <td>arg8Desc</td> * <td>The NoData range object.</td> * </tr> * <tr> * <td>arg9Desc</td> * <td>The value for destination NoData.</td> * </tr> * </table> * </p> * * <p> * <table border=1> * <caption>Parameter List</caption> * <tr> * <th>Name</th> * <th>Class Type</th> * <th>Default Value</th> * </tr> * <tr> * <td>function</td> * <td>javax.media.jai.ImageFunction</td> * <td>NO_PARAMETER_DEFAULT</td> * <tr> * <td>width</td> * <td>java.lang.Integer</td> * <td>NO_PARAMETER_DEFAULT</td> * <tr> * <td>height</td> * <td>java.lang.Integer</td> * <td>NO_PARAMETER_DEFAULT</td> * <tr> * <td>xScale</td> * <td>java.lang.Float</td> * <td>1.0F</td> * <tr> * <td>yScale</td> * <td>java.lang.Float</td> * <td>1.0F</td> * <tr> * <td>xTrans</td> * <td>java.lang.Float</td> * <td>0.0F</td> * <tr> * <td>yTrans</td> * <td>java.lang.Float</td> * <td>0.0F</td> * <tr> * <td>roi</td> * <td>javax.media.jai.ROI</td> * <td>null</td> * <tr> * <td>nodata</td> * <td>it.geosolutions.jaiext.range.Range</td> * <td>null</td> * <tr> * <td>destNoData</td> * <td>java.lang.Float</td> * <td>0.0F</td> * </table> * </p> * */ public class ImageFunctionDescriptor extends OperationDescriptorImpl { /** Constructor. */ public ImageFunctionDescriptor() { super(new String[][] { { "GlobalName", "ImageFunction" }, { "LocalName", "ImageFunction" }, { "Vendor", "it.geosolutions.jaiext" }, { "Description", JaiI18N.getString("ImageFunctionDescriptor0") }, { "DocURL", "" }, { "Version", JaiI18N.getString("DescriptorVersion") }, { "arg0Desc", JaiI18N.getString("ImageFunctionDescriptor1") }, { "arg1Desc", JaiI18N.getString("ImageFunctionDescriptor2") }, { "arg2Desc", JaiI18N.getString("ImageFunctionDescriptor3") }, { "arg3Desc", JaiI18N.getString("ImageFunctionDescriptor4") }, { "arg4Desc", JaiI18N.getString("ImageFunctionDescriptor5") }, { "arg5Desc", JaiI18N.getString("ImageFunctionDescriptor6") }, { "arg6Desc", JaiI18N.getString("ImageFunctionDescriptor7") }, { "arg6Desc", JaiI18N.getString("ImageFunctionDescriptor8") }, { "arg6Desc", JaiI18N.getString("ImageFunctionDescriptor9") }, { "arg6Desc", JaiI18N.getString("ImageFunctionDescriptor10") } }, 0, new Class[] { javax.media.jai.ImageFunction.class, java.lang.Integer.class, java.lang.Integer.class, java.lang.Float.class, java.lang.Float.class, java.lang.Float.class, java.lang.Float.class, javax.media.jai.ROI.class, it.geosolutions.jaiext.range.Range.class, java.lang.Float.class }, new String[] { "function", "width", "height", "xScale", "yScale", "xTrans", "yTrans", "roi", "nodata", "destNoData" }, new Object[] { NO_PARAMETER_DEFAULT, NO_PARAMETER_DEFAULT, NO_PARAMETER_DEFAULT, new Float(1.0F), new Float(1.0F), // unity scale new Float(0.0F), new Float(0.0F), // zero translation null, null, new Float(0.0F) }); } /** * Returns an array of <code>PropertyGenerators</code> implementing property inheritance for the "ImageFunction" operation. * * @return An array of property generators. */ public PropertyGenerator[] getPropertyGenerators() { PropertyGenerator[] pg = new PropertyGenerator[1]; pg[0] = new ImageFunctionPropertyGenerator(); return pg; } /** * Generates an image from a functional description. * * <p> * Creates a <code>ParameterBlockJAI</code> from all supplied arguments except <code>hints</code> and invokes * {@link JAI#create(String,ParameterBlock,RenderingHints)}. * * @see JAI * @see ParameterBlockJAI * @see RenderedOp * * @param function The functional description. * @param width The image width. * @param height The image height. * @param xScale The X scale factor. May be <code>null</code>. * @param yScale The Y scale factor. May be <code>null</code>. * @param xTrans The X translation. May be <code>null</code>. * @param yTrans The Y translation. May be <code>null</code>. * @param roi The optional ROI . May be <code>null</code>. * @param nodata The optional NoData Range used for checking invalid values May be <code>null</code>. * @param destNoData The Y translation. * @param hints The <code>RenderingHints</code> to use. May be <code>null</code>. * @return The <code>RenderedOp</code> destination. * @throws IllegalArgumentException if <code>function</code> is <code>null</code>. * @throws IllegalArgumentException if <code>width</code> is <code>null</code>. * @throws IllegalArgumentException if <code>height</code> is <code>null</code>. */ public static RenderedOp create(ImageFunction function, Integer width, Integer height, Float xScale, Float yScale, Float xTrans, Float yTrans, ROI roi, Range nodata, float destNoData, RenderingHints hints) { // Creating the parameter block ParameterBlockJAI pb = new ParameterBlockJAI("ImageFunction", RenderedRegistryMode.MODE_NAME); // Setting the parameters (No Source is needed) pb.setParameter("function", function); pb.setParameter("width", width); pb.setParameter("height", height); pb.setParameter("xScale", xScale); pb.setParameter("yScale", yScale); pb.setParameter("xTrans", xTrans); pb.setParameter("yTrans", yTrans); pb.setParameter("roi", roi); pb.setParameter("nodata", nodata); pb.setParameter("destNoData", destNoData); return JAI.create("ImageFunction", pb, hints); } }