/*
* Copyright 2006-2017 ICEsoft Technologies Canada Corp.
*
* 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 org.icepdf.core.pobjects.functions;
import org.icepdf.core.pobjects.Dictionary;
import org.icepdf.core.pobjects.Name;
import org.icepdf.core.pobjects.Reference;
import org.icepdf.core.util.Library;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;
/**
* <p>The class <code>Function</code> is factory responsible for creating the correct
* function type for the given "FunctionType" dictionary entry.</p>
* <br>
* <p>Functions in PDF represent static, self-contained numerical transformations.
* In general, a function can take any number (m) of input values and produce any
* number (n) of output values:
* <ul>
* <li>f(x<sub>0</sub>,..., x<sub>m-1</sub>) = y<sub>0</sub>, ... , y<sub>n-1</sub></li>
* </ul>
* <p>In PDF functions, all the input values and all the output values are numbers.
* Each function definition includes a <code>domain</code>, the set of legal
* values for the input. Some functions also define a <code>range</code>, the
* set of legal values for the output. Input and output values are clipped to
* the respective <code>domain</code> and <code>range</code>.
* </p>
* <br>
* <p>This function factory currently support the following function types:</p>
* <ul>
* <li><b>type 0</b> - sampled function, uses a table of sample values to define the function.
* various techniques are used to interpolate values between the sampled values.
* </li>
* <li><b>type 2</b> - exponential interpolation, defines a set of
* coefficients for an exponential function.
* </li>
* <li><b>type 3</b> - stitching function, a combination of
* other functions, partitioned across a domain.
* </li>
* <li><b>type 4</b> - calculator function, uses operators from
* the PostScript language do describe an arithmetic expression.
* </li>
* </ul>
*
* @since 1.0
*/
public abstract class Function {
private static final Logger logger =
Logger.getLogger(Function.class.toString());
public static final Name FUNCTIONTYPE_NAME = new Name("FunctionType");
public static final Name DOMAIN_NAME = new Name("Domain");
public static final Name RANGE_NAME = new Name("Range");
/**
* An array of 2 x m numbers, where m is the number of input values. Input
* values outside the declared domain are clipped to the nearest boundary value.
*/
protected float[] domain;
/**
* An array of 2 x n numbers, where n is the number of output values. Output
* values outside the declared range are clipped to the nearest boundary value.
* If this entry is absent, no clipping is done.
*/
protected float[] range;
/**
* Function type associated with this function.
*/
protected int functionType;
/**
* <p>Creates a new instance of a Function object. Possible function types
* are:</p>
* <ul>
* <li>0 - sampled funciton.</li>
* <li>2 - exponential interpolation funciton.</li>
* </ul>
*
* @param l document library.
* @param o dictionary or Hashmap containing Function type entries.
* @return Function object for the specified function type, null if the
* function type is not available or not defined.
*/
public static Function getFunction(Library l, Object o) {
Dictionary d = null;
if (o instanceof Reference) {
o = l.getObject((Reference) o);
}
// create a dictionary out of the object if possible
if (o instanceof Dictionary) {
d = (Dictionary) o;
} else if (o instanceof HashMap) {
d = new Dictionary(l, (HashMap) o);
}
if (d != null) {
// find out what time of function type and create the appropriate
// function object.
int fType = d.getInt(FUNCTIONTYPE_NAME);
switch (fType) {
// sampled function
case 0:
return new Function_0(d);
// exponential interpolation
case 2:
return new Function_2(d);
// stitching function
case 3:
return new Function_3(d);
// PostScript calculator
case 4:
return new Function_4(d);
}
}
return null;
}
/**
* Creates a new instance of <code>Function</code> object.
*
* @param d dictionary containing a vaild function dictionary.
*/
protected Function(Dictionary d) {
List dom = (List) d.getObject(DOMAIN_NAME);
domain = new float[dom.size()];
for (int i = 0; i < dom.size(); i++) {
domain[i] = ((Number) dom.get(i)).floatValue();
}
List r = (List) d.getObject(RANGE_NAME);
if (r != null) {
range = new float[r.size()];
for (int i = 0; i < r.size(); i++) {
range[i] = ((Number) r.get(i)).floatValue();
}
}
}
/**
* <p>Gets the function type number.
* <ul>
* <li><b>type 0</b> - sampled function, uses a table of sample values to define the function.
* various techniques are used to interpolate values between the sampled values.
* </li>
* <li><b>type 2</b> - exponential interpolation, defines a set of
* coeffiecients for an exponential function.
* </li>
* <li><b>type 3</b> - stitching function, a combination of
* other functions, partitioned across a domain.
* </li>
* <li><b>type 4</b> - calculator function, uses operators from
* the PostScript language do describe an arithmetic expression.
* </li>
* </ul>
*/
public int getFunctionType() {
return functionType;
}
/**
* <p>Interpolation function. For the given value of x, the interpolate
* calculates the y value on the line defined by the two points
* (x<sub>min</sub>, y<sub>min</sub>) and (x<sub>max</sub>, y<sub>max</sub>).
*
* @param x value we want to find a y value for.
* @param xmin point 1, x value.
* @param xmax point 2, x value.
* @param ymin point 1, y value.
* @param ymax oint 2, y value.
* @return y value for the given x value on the point define by
* (x<sub>min</sub>, y<sub>min</sub>) and (x<sub>max</sub>, y<sub>max</sub>).
*/
public static float interpolate(float x, float xmin, float xmax, float ymin, float ymax) {
return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin;
}
/**
* <p>Evaluates the input values specified by <code>m</code>. In general, a
* function can take any number (m) of input values and produce any
* number (n) of output values:
* <ul>
* <li>f(x<sub>0</sub>,..., x<sub>m-1</sub>) = y<sub>0</sub>, ... , y<sub>n-1</sub></li>
* </ul>
*
* @param m input values to put through function.
* @return n output values.
*/
public abstract float[] calculate(float[] m);
public float[] getDomain() {
return domain;
}
public float[] getRange() {
return range;
}
}