| /* |
| * 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.fop.render.gradient; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.apache.fop.render.gradient.GradientMaker.DoubleFormatter; |
| |
| public class Function { |
| |
| public interface SubFunctionRenderer { |
| |
| void outputFunction(StringBuilder out, int functionIndex); |
| } |
| |
| /** |
| * Required: The Type of function (0,2,3,4) default is 0. |
| */ |
| private int functionType; |
| |
| /** |
| * Required: 2 * m Array of Double numbers which are possible inputs to the function |
| */ |
| private List<Double> domain; |
| |
| /** |
| * Required: 2 * n Array of Double numbers which are possible outputs to the function |
| */ |
| private List<Double> range; |
| |
| /** |
| * Required for Type 0: Number of Bits used to represent each sample value. |
| * Limited to 1,2,4,8,12,16,24, or 32 |
| */ |
| private int bitsPerSample = 1; |
| |
| /** |
| * Optional for Type 0: order of interpolation between samples. |
| * Limited to linear (1) or cubic (3). Default is 1 |
| */ |
| private int order = 1; |
| |
| /** |
| * Optional for Type 0: A 2 * m array of Doubles which provides a |
| * linear mapping of input values to the domain. |
| * |
| * Required for Type 3: A 2 * k array of Doubles that, taken |
| * in pairs, map each subset of the domain defined by Domain |
| * and the Bounds array to the domain of the corresponding function. |
| * Should be two values per function, usually (0,1), |
| * as in [0 1 0 1] for 2 functions. |
| */ |
| private List<Double> encode; |
| |
| /* *************************TYPE 2************************** */ |
| |
| /** |
| * Required For Type 2: An Array of n Doubles defining |
| * the function result when x=0. Default is [0]. |
| */ |
| private float[] cZero; |
| |
| /** |
| * Required For Type 2: An Array of n Doubles defining |
| * the function result when x=1. Default is [1]. |
| */ |
| private float[] cOne; |
| |
| /** |
| * Required for Type 2: The interpolation exponent. |
| * Each value x will return n results. |
| * Must be greater than 0. |
| */ |
| private double interpolationExponentN = 1; |
| |
| /* *************************TYPE 3************************** */ |
| |
| /** |
| * Required for Type 3: An vector of PDFFunctions which |
| * form an array of k single input functions making up |
| * the stitching function. |
| */ |
| private List<Function> functions; |
| |
| /** |
| * Optional for Type 3: An array of (k-1) Doubles that, |
| * in combination with Domain, define the intervals to which |
| * each function from the Functions array apply. Bounds |
| * elements must be in order of increasing magnitude, |
| * and each value must be within the value of Domain. |
| * k is the number of functions. |
| * If you pass null, it will output (1/k) in an array of k-1 elements. |
| * This makes each function responsible for an equal amount of the stitching function. |
| * It makes the gradient even. |
| */ |
| private List<Float> bounds; |
| |
| /** |
| * create an complete Function object of Type 2, an Exponential Interpolation function. |
| * |
| * Use null for an optional object parameter if you choose not to use it. |
| * For optional int parameters, pass the default. |
| * @param domain List objects of Double objects. |
| * This is the domain of the function. |
| * See page 264 of the PDF 1.3 Spec. |
| * @param range List of Doubles that is the Range of the function. |
| * See page 264 of the PDF 1.3 Spec. |
| * @param cZero This is a vector of Double objects which defines the function result |
| * when x=0. |
| * |
| * This attribute is optional. |
| * It's described on page 268 of the PDF 1.3 spec. |
| * @param cOne This is a vector of Double objects which defines the function result |
| * when x=1. |
| * |
| * This attribute is optional. |
| * It's described on page 268 of the PDF 1.3 spec. |
| * @param interpolationExponentN This is the inerpolation exponent. |
| * |
| * This attribute is required. |
| * PDF Spec page 268 |
| */ |
| public Function(List<Double> domain, List<Double> range, float[] cZero, float[] cOne, |
| double interpolationExponentN) { |
| this(2, domain, range); |
| this.cZero = cZero; |
| this.cOne = cOne; |
| this.interpolationExponentN = interpolationExponentN; |
| } |
| |
| /** |
| * create an complete Function object of Type 3, a Stitching function. |
| * |
| * Use null for an optional object parameter if you choose not to use it. |
| * For optional int parameters, pass the default. |
| * @param domain List objects of Double objects. |
| * This is the domain of the function. |
| * See page 264 of the PDF 1.3 Spec. |
| * @param range List objects of Double objects. |
| * This is the Range of the function. |
| * See page 264 of the PDF 1.3 Spec. |
| * @param functions A List of the PDFFunction objects that the stitching function stitches. |
| * |
| * This attributed is required. |
| * It is described on page 269 of the PDF spec. |
| * @param bounds This is a vector of Doubles representing the numbers that, |
| * in conjunction with Domain define the intervals to which each function from |
| * the 'functions' object applies. It must be in order of increasing magnitude, |
| * and each must be within Domain. |
| * |
| * It basically sets how much of the gradient each function handles. |
| * |
| * This attributed is required. |
| * It's described on page 269 of the PDF 1.3 spec. |
| * @param encode List objects of Double objects. |
| * This is the linear mapping of input values intop the domain |
| * of the function's sample table. Default is hard to represent in |
| * ascii, but basically [0 (Size0 1) 0 (Size1 1)...]. |
| * This attribute is required. |
| * |
| * See page 270 in the PDF 1.3 spec. |
| */ |
| public Function(List<Double> domain, List<Double> range, List<Function> functions, |
| List<Float> bounds, List<Double> encode) { |
| this(3, domain, range); |
| this.functions = functions; |
| this.bounds = bounds; |
| this.encode = makeEncode(encode); |
| } |
| |
| private List<Double> makeEncode(List<Double> encode) { |
| if (encode != null) { |
| return encode; |
| } else { |
| encode = new ArrayList<Double>(functions.size() * 2); |
| for (int i = 0; i < functions.size(); i++) { |
| encode.add(0.0); |
| encode.add(1.0); |
| } |
| return encode; |
| } |
| } |
| |
| private Function(int functionType, List<Double> domain, List<Double> range) { |
| this.functionType = functionType; |
| this.domain = (domain == null) ? Arrays.asList(0.0, 1.0) : domain; |
| this.range = range; |
| } |
| |
| /** |
| * Gets the function type |
| */ |
| public int getFunctionType() { |
| return functionType; |
| } |
| |
| /** |
| * Gets the function bounds |
| */ |
| public List<Float> getBounds() { |
| return bounds; |
| } |
| |
| /** |
| * The function domain |
| */ |
| public List<Double> getDomain() { |
| return domain; |
| } |
| |
| /** |
| * Gets the function encoding |
| */ |
| public List<Double> getEncode() { |
| return encode; |
| } |
| |
| /** |
| * Gets the sub-functions |
| */ |
| public List<Function> getFunctions() { |
| if (functions == null) { |
| return Collections.emptyList(); |
| } else { |
| return functions; |
| } |
| } |
| |
| /** |
| * Gets the bits per sample of the function |
| */ |
| public int getBitsPerSample() { |
| return bitsPerSample; |
| } |
| |
| /** |
| * Gets the interpolation exponent of the function |
| */ |
| public double getInterpolationExponentN() { |
| return interpolationExponentN; |
| } |
| |
| /** |
| * Gets the function order |
| */ |
| public int getOrder() { |
| return order; |
| } |
| |
| /** |
| * Gets the function range |
| */ |
| public List<Double> getRange() { |
| return range; |
| } |
| |
| /** |
| * Gets the function C0 value (color for gradient) |
| */ |
| public float[] getCZero() { |
| return cZero; |
| } |
| |
| /** |
| * Gets the function C1 value (color for gradient) |
| */ |
| public float[] getCOne() { |
| return cOne; |
| } |
| |
| public String output(StringBuilder out, DoubleFormatter doubleFormatter, |
| SubFunctionRenderer subFunctionRenderer) { |
| out.append("<<\n/FunctionType " + functionType + "\n"); |
| outputDomain(out, doubleFormatter); |
| if (this.functionType == 0) { |
| outputEncode(out, doubleFormatter); |
| outputBitsPerSample(out); |
| outputOrder(out); |
| outputRange(out, doubleFormatter); |
| out.append(">>"); |
| } else if (functionType == 2) { |
| outputRange(out, doubleFormatter); |
| outputCZero(out, doubleFormatter); |
| outputCOne(out, doubleFormatter); |
| outputInterpolationExponentN(out, doubleFormatter); |
| out.append(">>"); |
| } else if (functionType == 3) { |
| outputRange(out, doubleFormatter); |
| if (!functions.isEmpty()) { |
| out.append("/Functions [ "); |
| for (int i = 0; i < functions.size(); i++) { |
| subFunctionRenderer.outputFunction(out, i); |
| out.append(' '); |
| } |
| out.append("]\n"); |
| } |
| outputEncode(out, doubleFormatter); |
| out.append("/Bounds "); |
| if (bounds != null) { |
| GradientMaker.outputDoubles(out, doubleFormatter, bounds); |
| } else if (!functions.isEmpty()) { |
| // if there are n functions, |
| // there must be n-1 bounds. |
| // so let each function handle an equal portion |
| // of the whole. e.g. if there are 4, then [ 0.25 0.25 0.25 ] |
| int numberOfFunctions = functions.size(); |
| String functionsFraction = doubleFormatter.formatDouble(1.0 / numberOfFunctions); |
| out.append("[ "); |
| for (int i = 0; i + 1 < numberOfFunctions; i++) { |
| out.append(functionsFraction); |
| out.append(" "); |
| } |
| out.append("]"); |
| } |
| out.append("\n>>"); |
| } else if (functionType == 4) { |
| outputRange(out, doubleFormatter); |
| out.append(">>"); |
| } |
| return out.toString(); |
| } |
| |
| private void outputDomain(StringBuilder p, DoubleFormatter doubleFormatter) { |
| p.append("/Domain "); |
| GradientMaker.outputDoubles(p, doubleFormatter, domain); |
| p.append("\n"); |
| } |
| |
| private void outputBitsPerSample(StringBuilder out) { |
| out.append("/BitsPerSample " + bitsPerSample + "\n"); |
| } |
| |
| private void outputOrder(StringBuilder out) { |
| if (order == 1 || order == 3) { |
| out.append("\n/Order " + order + "\n"); |
| } |
| } |
| |
| private void outputRange(StringBuilder out, DoubleFormatter doubleFormatter) { |
| if (range != null) { |
| out.append("/Range "); |
| GradientMaker.outputDoubles(out, doubleFormatter, range); |
| out.append("\n"); |
| } |
| } |
| |
| private void outputEncode(StringBuilder out, DoubleFormatter doubleFormatter) { |
| out.append("/Encode "); |
| GradientMaker.outputDoubles(out, doubleFormatter, encode); |
| out.append("\n"); |
| } |
| |
| private void outputCZero(StringBuilder out, DoubleFormatter doubleFormatter) { |
| if (cZero != null) { |
| out.append("/C0 [ "); |
| for (float c : cZero) { |
| out.append(doubleFormatter.formatDouble(c)); |
| out.append(" "); |
| } |
| out.append("]\n"); |
| } |
| } |
| |
| private void outputCOne(StringBuilder out, DoubleFormatter doubleFormatter) { |
| if (cOne != null) { |
| out.append("/C1 [ "); |
| for (float c : cOne) { |
| out.append(doubleFormatter.formatDouble(c)); |
| out.append(" "); |
| } |
| out.append("]\n"); |
| } |
| } |
| |
| private void outputInterpolationExponentN(StringBuilder out, DoubleFormatter doubleFormatter) { |
| out.append("/N "); |
| out.append(doubleFormatter.formatDouble(interpolationExponentN)); |
| out.append("\n"); |
| } |
| |
| } |