Package org.apache.pdfbox.pdmodel.common.function

Source Code of org.apache.pdfbox.pdmodel.common.function.PDFunction

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.pdfbox.pdmodel.common.function;

import java.io.IOException;

import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.pdmodel.common.COSObjectable;
import org.apache.pdfbox.pdmodel.common.PDRange;
import org.apache.pdfbox.pdmodel.common.PDStream;

/**
* This class represents a function in a PDF document.
*
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
* @version $Revision: 1.3 $
*/
public abstract class PDFunction implements COSObjectable
{

    private PDStream functionStream = null;
    private COSDictionary functionDictionary = null;
    private COSArray domain = null;
    private COSArray range = null;

    /**
     * Constructor.
     *
     * @param function The function stream.
     *
     */
    public PDFunction( COSBase function )
    {
        if (function instanceof COSStream)
        {
            functionStream = new PDStream( (COSStream)function );
            functionStream.getStream().setName( COSName.TYPE, "Function" );
        }
        else if (function instanceof COSDictionary)
        {
            functionDictionary = (COSDictionary)function;
        }
    }

    /**
     * Returns the function type.
     *
     * Possible values are:
     *
     * 0 - Sampled function
     * 2 - Exponential interpolation function
     * 3 - Stitching function
     * 4 - PostScript calculator function
     *
     * @return the function type.
     */
    public abstract int getFunctionType();
   
    /**
     * Returns the COSObject.
     *
     * {@inheritDoc}
     */
    public COSBase getCOSObject()
    {
        if (functionStream != null)
        {
            return functionStream.getCOSObject();
        }
        else
        {
            return functionDictionary;
        }
    }

    /**
     * Returns the stream.
     * @return The stream for this object.
     */
    public COSDictionary getDictionary()
    {
        if (functionStream != null)
        {
            return functionStream.getStream();
        }
        else
        {
            return functionDictionary;
        }
    }

    /**
     * Returns the underlying PDStream.
     * @return The stream.
     */
    protected PDStream getPDStream()
    {
        return functionStream;
    }
    /**
     * Create the correct PD Model function based on the COS base function.
     *
     * @param function The COS function dictionary.
     *
     * @return The PDModel Function object.
     *
     * @throws IOException If we are unable to create the PDFunction object.
     */
    public static PDFunction create( COSBase function ) throws IOException
    {
        PDFunction retval = null;
        if( function instanceof COSObject )
        {
            function = ((COSObject)function).getObject();
        }
        COSDictionary functionDictionary = (COSDictionary)function;
        int functionType =  functionDictionary.getInt( COSName.FUNCTION_TYPE );
        if( functionType == 0 )
        {
            retval = new PDFunctionType0(functionDictionary);
        }
        else if( functionType == 2 )
        {
            retval = new PDFunctionType2(functionDictionary);
        }
        else if( functionType == 3 )
        {
            retval = new PDFunctionType3(functionDictionary);
        }
        else if( functionType == 4 )
        {
            retval = new PDFunctionType4(functionDictionary);
        }
        else
        {
            throw new IOException( "Error: Unknown function type " + functionType );
        }
        return retval;
    }

    /**
     * This will get the number of output parameters that
     * have a range specified.  A range for output parameters
     * is optional so this may return zero for a function
     * that does have output parameters, this will simply return the
     * number that have the rnage specified.
     *
     * @return The number of input parameters that have a range
     * specified.
     */
    public int getNumberOfOutputParameters()
    {
        COSArray rangeValues = getRangeValues();
        return rangeValues.size() / 2;
    }

    /**
     * This will get the range for a certain output parameters.  This is will never
     * return null.  If it is not present then the range 0 to 0 will
     * be returned.
     *
     * @param n The output parameter number to get the range for.
     *
     * @return The range for this component.
     */
    public PDRange getRangeForOutput(int n)
    {
        COSArray rangeValues = getRangeValues();
        return new PDRange( rangeValues, n );
    }

    /**
     * This will set the range values.
     *
     * @param rangeValues The new range values.
     */
    public void setRangeValues(COSArray rangeValues)
    {
        range = rangeValues;
        getDictionary().setItem(COSName.RANGE, rangeValues);
    }

    /**
     * This will get the number of input parameters that
     * have a domain specified.
     *
     * @return The number of input parameters that have a domain
     * specified.
     */
    public int getNumberOfInputParameters()
    {
        COSArray array = getDomainValues();
        return array.size() / 2;
    }

    /**
     * This will get the range for a certain input parameter.  This is will never
     * return null.  If it is not present then the range 0 to 0 will
     * be returned.
     *
     * @param n The parameter number to get the domain for.
     *
     * @return The domain range for this component.
     */
    public PDRange getDomainForInput(int n)
    {
        COSArray domainValues = getDomainValues();
        return new PDRange( domainValues, n );
    }

    /**
     * This will set the domain values.
     *
     * @param domainValues The new domain values.
     */
    public void setDomainValues(COSArray domainValues)
    {
        domain = domainValues;
        getDictionary().setItem(COSName.DOMAIN, domainValues);
    }


    /**
     * Evaluates the function at the given input.
     * ReturnValue = f(input)
     *
     * @param input The COSArray of input values for the function.
     * In many cases will be an array of a single value, but not always.
     *
     * @return The of outputs the function returns based on those inputs.
     * In many cases will be an COSArray of a single value, but not always.
     *
     * @throws IOException an IOExcpetion is thrown if something went wrong processing the function.
     *
     */
    public COSArray eval(COSArray input) throws IOException
    {
        // TODO should we mark this method as deprecated?
        float[] outputValues = eval(input.toFloatArray());
        COSArray array = new COSArray();
        array.setFloatArray(outputValues);
        return array;
    }

    /**
     * Evaluates the function at the given input.
     * ReturnValue = f(input)
     *
     * @param input The array of input values for the function.
     * In many cases will be an array of a single value, but not always.
     *
     * @return The of outputs the function returns based on those inputs.
     * In many cases will be an array of a single value, but not always.
     *
     * @throws IOException an IOExcpetion is thrown if something went wrong processing the function. 
     */
    public abstract float[] eval(float[] input) throws IOException;
   
    /**
     * Returns all ranges for the output values as COSArray .
     * Required for type 0 and type 4 functions
     * @return the ranges array.
     */
    protected COSArray getRangeValues()
    {
        if (range == null)
        {
            range = (COSArray)getDictionary().getDictionaryObject( COSName.RANGE );
        }
        return range;
    }

    /**
     * Returns all domains for the input values as COSArray.
     * Required for all function types.
     * @return the domains array.
     */
    private COSArray getDomainValues()
    {
        if (domain == null)
        {
            domain = (COSArray)getDictionary().getDictionaryObject( COSName.DOMAIN );
        }
        return domain;
    }

    /**
     * Clip the given input values to the ranges.
     *
     * @param inputArray the input values
     * @return the clipped values
     */
    protected float[] clipToRange(float[] inputValues)
    {
        COSArray rangesArray = getRangeValues();
        float[] result = null;
        if (rangesArray != null)
        {
            float[] rangeValues = rangesArray.toFloatArray();
            int numberOfRanges = rangeValues.length/2;
            result = new float[numberOfRanges];
            for (int i=0; i<numberOfRanges; i++)
            {
                result[i] = clipToRange(inputValues[i], rangeValues[2*i], rangeValues[2*i+1]);
            }
        }
        else
        {
            result = inputValues;
        }
        return result;
    }

    /**
     * Clip the given input value to the given range.
     *
     * @param x the input value
     * @param rangeMin the min value of the range
     * @param rangeMax the max value of the range

     * @return the clipped value
     */
    protected float clipToRange(float x, float rangeMin, float rangeMax)
    {
        return Math.min(Math.max(x, rangeMin), rangeMax);
    }

    /**
     * For a given value of x, interpolate calculates the y value
     * on the line defined by the two points (xRangeMin , xRangeMax )
     * and (yRangeMin , yRangeMax ).
     *
     * @param x the to be interpolated value.
     * @param xRangeMin the min value of the x range
     * @param xRangeMax the max value of the x range
     * @param yRangeMin the min value of the y range
     * @param yRangeMax the max value of the y range
     * @return the interpolated y value
     */
    protected float interpolate(float x, float xRangeMin, float xRangeMax, float yRangeMin, float yRangeMax)
    {
        return yRangeMin + ((x - xRangeMin) * (yRangeMax - yRangeMin)/(xRangeMax - xRangeMin));
    }

}
TOP

Related Classes of org.apache.pdfbox.pdmodel.common.function.PDFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.