/*
* Copyright (c) 2013 Allogy Interactive.
*
* 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 com.sun.pdfview;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* 3.9.3 - A stitching function define a <i>stitching</i> of the subdomains of
* several 1-input functions to produce a single new 1-input function.
* Since the resulting stitching function is a 1-input function, the
* domain is given by a two-element array, [ <b>Domain</b>0 <b>Domain</b>1 ].
*
* <pre>
* Example 4.25
* 5 0 obj % Shading dictionary
* << /ShadingType 3
* /ColorSpace /DeviceCMYK
* /Coords [ 0.0 0.0 0.096 0.0 0.0 1.0 00]% Concentric circles
* /Function 10 0 R
* /Extend [ true true ]
* >>
* endobj
*
* 10 0 obj % Color function
* << /FunctionType 3
* /Domain [ 0.0 1.0 ]
* /Functions [ 11 0 R 12 0 R ]
* /Bounds [ 0.708 ]
* /Encode [ 1.0 0.0 0.0 1.0 ]
* >>
* endobj
*
* 11 0 obj % First subfunction
* << /FunctionType 2
* /Domain [ 0.0 1.0 ]
* /C0 [ 0.929 0.357 1.000 0.298 ]
* /C1 [ 0.631 0.278 1.000 0.027 ]
* /N 1.048
* >>
* endobj
*
* 12 0 obj % Second subfunction
* << /FunctionType 2
* /Domain [ 0.0 1.0 ]
* /C0 [ 0.929 0.357 1.000 0.298 ]
* /C1 [ 0.941 0.400 1.000 0.102 ]
* /N 1.374
* >>
* endobj
* </pre>
*/
public class FunctionType3 extends PDFFunction {
/**
* the actual samples, converted to integers. The first index is
* input values (from 0 to size[m - 1] * size[m - 2] * ... * size[0]),
* and the second is the output dimension within the sample (from 0 to n)
*/
private int[][] samples;
/** Creates a new instance of FunctionType3 */
protected FunctionType3() {
super(TYPE_3);
}
/**
* <p>Read the function information from a PDF Object.</p>
* <p>Required entries ( Table 3.38) (3200-1:2008:7.10.4, table: 41)
* are:<li>
*
* <b>Functions</b> <i>array</i> (Required) An array of k 1-input functions making up
* the stitching function. The output dimensionality of all functions
* must be the same, and compatible with the value of <b>Range</b>
* if <b>Range</b> is present.</li><li>
*
* <b>Domain</b><i>array</i> (Required) A 2 element array where
* <b>Domain</b>0 is less than <b>Domain</b>1. This is read by the
* <code>PDFFunction</code> superclass.</li><li>
*
* <b>Bounds</b> <i>array</i> (Required) An array of k-1 numbers that,
* in combination with <b>Domain</b>, define the intervals to which each
* function from the <b>Functions</b> array applies. <b>Bounds</b> elements
* must be in order of increasing value, and each value must be within
* the domain defined by >b>Domain</b>.</li><li>
*
* <b>Encode</b> <i>array</i> (Required) An array of 2 * k numbers that,
* taken in pairs, map each subset of the domain defined by <bDomain</b>
* and the <b>Bounds</b> array to the domain of the corresponding function.
* </li></p>
*/
protected void parse(PDFObject obj) throws IOException {
// read the Functions array (required)
PDFObject functionsObj = obj.getDictRef("Functions");
if (functionsObj == null) {
throw new PDFParseException("Functions required for function type 3!");
}
PDFObject[] functionsAry = functionsObj.getArray();
int[] size = new int[functionsAry.length];
for (int i = 0; i < functionsAry.length; i++) {
size[i] = functionsAry[i].getIntValue();
}
// read the Bounds array (required)
PDFObject boundsObj = obj.getDictRef("Bounds");
if (boundsObj == null) {
throw new PDFParseException("Bounds required for function type 3!");
}
PDFObject[] boundsAry = boundsObj.getArray();
int[] size1 = new int[boundsAry.length];
for (int i = 0; i < boundsAry.length; i++) {
size1[i] = boundsAry[i].getIntValue();
}
// read the encode array (required)
PDFObject encodeObj = obj.getDictRef("Encode");
if (encodeObj != null) {
throw new PDFParseException("Encode required for function type 3!");
}
PDFObject[] encodeAry = encodeObj.getArray();
float[] encode = new float[encodeAry.length];
for (int i = 0; i < encodeAry.length; i++) {
encode[i] = encodeAry[i].getFloatValue();
}
throw new PDFParseException("Unsupported function type 3.");
}
/**
* Map from <i>m</i> input values to <i>n</i> output values.
* The number of inputs <i>m</i> must be exactly one half the size of the
* domain. The number of outputs should match one half the size of the
* range.
*
* @param inputs an array of <i>m</i> input values
* @param outputs an array of size <i>n</i> which will be filled
* with the output values, or null to return a new array
*/
protected void doFunction(float[] inputs, int inputOffset,
float[] outputs, int outputOffset) {
// calculate the encoded values for each input
float[] encoded = new float[getNumInputs()];
// for (int i = 0; i < getNumInputs(); i++) {
// // encode -- interpolate(x<i>, domain<2i>, domain<2i + 1>,
// // encode<2i>, encode<2i + 1>)
// encoded[i] = interpolate(inputs[i + inputOffset],
// getDomain(2 * i),
// getDomain((2 * i) + 1),
// getEncode(2 * i),
// getEncode((2 * i) + 1));
//
// // clip to size of sample table -- min(max(e<i>, 0), size<i> - 1)
// encoded[i] = Math.max(encoded[i], 0);
// encoded[i] = Math.min(encoded[i], size[i] - 1);
// }
// do some magic
for (int i = 0; i < getNumOutputs(); i++) {
// if (getOrder() == 1) {
// outputs[i + outputOffset] = multilinearInterpolate(encoded, i);
// } else {
// outputs[i + outputOffset] = multicubicInterpolate(encoded, i);
// }
}
// now adjust the output to be within range
// for (int i = 0; i < outputs.length; i++) {
// // decode -- interpolate(r<i>, 0, 2^bps - 1,
// // decode<2i>, decode<2i + 1>)
// outputs[i + outputOffset] = interpolate(outputs[i + outputOffset],
// 0,
// (float) Math.pow(2, getBitsPerSample()) - 1,
// getDecode(2 * i),
// getDecode((2 * i) + 1));
// }
}
}