
org.sejda.sambox.pdmodel.common.function.PDFunction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sambox Show documentation
Show all versions of sambox Show documentation
An Apache PDFBox fork intended to be used as PDF processor for Sejda and PDFsam
related projects
/*
* 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.sejda.sambox.pdmodel.common.function;
import java.io.IOException;
import org.sejda.sambox.cos.COSArray;
import org.sejda.sambox.cos.COSBase;
import org.sejda.sambox.cos.COSDictionary;
import org.sejda.sambox.cos.COSName;
import org.sejda.sambox.cos.COSObjectable;
import org.sejda.sambox.cos.COSStream;
import org.sejda.sambox.pdmodel.common.PDRange;
import org.sejda.sambox.pdmodel.common.PDStream;
/**
* This class represents a function in a PDF document.
*
* @author Ben Litchfield
*
*/
public abstract class PDFunction implements COSObjectable
{
private PDStream functionStream = null;
private COSDictionary functionDictionary = null;
private COSArray domain = null;
private COSArray range = null;
private int numberOfInputValues = -1;
private int numberOfOutputValues = -1;
/**
* Constructor.
*
* @param function The function stream.
*
*/
public PDFunction(COSBase function)
{
if (function instanceof COSStream)
{
functionStream = new PDStream((COSStream) function);
functionStream.getCOSObject().setItem(COSName.TYPE, COSName.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 stream.
*
* @return The stream for this object.
*/
@Override
public COSDictionary getCOSObject()
{
if (functionStream != null)
{
return functionStream.getCOSObject();
}
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
{
if (function == COSName.IDENTITY)
{
return new PDFunctionTypeIdentity(null);
}
COSBase base = function.getCOSObject();
if (!(base instanceof COSDictionary))
{
throw new IOException("Expected dictionary but found " + base.getClass().getSimpleName()
+ " for Function");
}
COSDictionary functionDictionary = (COSDictionary) base;
int functionType = functionDictionary.getInt(COSName.FUNCTION_TYPE);
switch (functionType)
{
case 0:
return new PDFunctionType0(functionDictionary);
case 2:
return new PDFunctionType2(functionDictionary);
case 3:
return new PDFunctionType3(functionDictionary);
case 4:
return new PDFunctionType4(functionDictionary);
default:
throw new IOException("Error: Unknown function type " + functionType);
}
}
/**
* 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 range specified.
*
* @return The number of output parameters that have a range specified.
*/
public int getNumberOfOutputParameters()
{
if (numberOfOutputValues == -1)
{
COSArray rangeValues = getRangeValues();
numberOfOutputValues = rangeValues.size() / 2;
}
return numberOfOutputValues;
}
/**
* 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;
getCOSObject().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()
{
if (numberOfInputValues == -1)
{
COSArray array = getDomainValues();
numberOfInputValues = array.size() / 2;
}
return numberOfInputValues;
}
/**
* 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;
getCOSObject().setItem(COSName.DOMAIN, domainValues);
}
/**
* @deprecated Replaced by {@link #eval(float[] input)}
*/
@Deprecated
public COSArray eval(COSArray input) throws IOException
{
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) getCOSObject().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) getCOSObject().getDictionaryObject(COSName.DOMAIN);
}
return domain;
}
/**
* Clip the given input values to the ranges.
*
* @param inputValues the input values
* @return the clipped values
*/
protected float[] clipToRange(float[] inputValues)
{
COSArray rangesArray = getRangeValues();
float[] result;
if (rangesArray != null)
{
float[] rangeValues = rangesArray.toFloatArray();
int numberOfRanges = rangeValues.length / 2;
result = new float[numberOfRanges];
for (int i = 0; i < numberOfRanges; i++)
{
int index = i << 1;
result[i] = clipToRange(inputValues[i], rangeValues[index], rangeValues[index + 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)
{
if (x < rangeMin)
{
return rangeMin;
}
else if (x > rangeMax)
{
return rangeMax;
}
return x;
}
/**
* 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));
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "FunctionType" + getFunctionType();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy