All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jpedal.function.PDFSampled Maven / Gradle / Ivy

/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/support/
 *
 * (C) Copyright 1997-2017 IDRsolutions and Contributors.
 *
 * This file is part of JPedal/JPDF2HTML5
 *
 @LICENSE@
 *
 * ---------------
 * PDFSampled.java
 * ---------------
 */
package org.jpedal.function;

/**
 * Class to handle Type 0 shading (Sampled) from a Pdf
 */
public class PDFSampled extends PDFGenericFunction implements PDFFunction {

    private final int[] size;
    private final int m;
    private final int n;
    private final float outputs[];
    private final double[] sampleArray;
    private float[] prevInputs;
    private final double[] cubeN;
    private final int[] cubeVertex;
    private final int cubeVertices;

    public PDFSampled(final byte[] stream, final int bits, final float[] domain, final float[] range,
                      final float[] encode, final float[] decode, final int[] size) {
        super(domain, range);
        this.size = size;
        this.m = domain.length / 2;
        this.n = range.length / 2;

        int sampleLen = 1;

        for (int i = 0; i < size.length; i++) {
            sampleLen *= size[i];
        }
        sampleLen *= (range.length / 2);

        sampleArray = new double[sampleLen];
        int pos = 0;
        int buffer = 0;

        final double sampleMul = 1.0 / (Math.pow(2, bits) - 1);

        int index = 0;
        for (int i = 0; i < sampleLen; i++) {
            while (pos < bits) {
                buffer <<= 8;
                buffer |= (stream[index++] & 0xff);
                pos += 8;
            }
            pos -= bits;
            sampleArray[i] = (buffer >> pos) * sampleMul;
            buffer &= (1L << pos) - 1;
        }

        if (encode != null) {
            this.encode = encode;
        } else {
            final int defaultSize = size.length;
            this.encode = new float[defaultSize * 2];
            for (int ii = 0; ii < defaultSize; ii++) {
                this.encode[(ii * 2) + 1] = size[ii] - 1;
            }
        }

        if (decode != null) {
            this.decode = decode;
        } else {
            final int defaultSize = range.length;
            this.decode = new float[defaultSize];
            System.arraycopy(range, 0, this.decode, 0, defaultSize);
        }

        outputs = new float[n];
        prevInputs = new float[m];
        for (int i = 0; i < m; i++) {
            prevInputs[i] = Float.MAX_VALUE;
        }
        cubeVertices = 1 << m;
        cubeN = new double[cubeVertices];
        cubeVertex = new int[cubeVertices];
    }

    /**
     * Calculate the output values for this point in the shading object. (Only
     * used by Stitching)
     *
     * @param subinput : Shading input values
     * @return returns the shading values for this point
     */
    @Override
    public float[] computeStitch(final float[] subinput) {
        return compute(subinput);
    }

    private static boolean isSame(final float[] arr0, final float[] arr1) {
        for (int i = 0; i < arr0.length; i++) {
            if (arr0[i] != arr1[i]) {
                return false;
            }
        }
        return true;
    }

    @Override
    public float[] compute(final float[] input) {
        if (isSame(input, prevInputs)) {
            return outputs;
        }

        prevInputs = input.clone();

        for (int i = 0; i < cubeVertices; i++) {
            cubeN[i] = 1;
            cubeVertex[i] = 0;
        }

        int k = n, pos = 1;
        for (int i = 0; i < m; ++i) {
            final int first = 2 * i;
            final int next = first + 1;

            final double xi = Math.min(Math.max(input[i], domain[first]), domain[next]);
            double e = interpolateDouble(xi, domain[first], domain[next], encode[first], encode[next]);

            final int cur = size[i];
            e = Math.min(Math.max(e, 0), cur - 1);

            final double e0 = e < cur - 1 ? ((int) e) : (e - 1.0);
            final double n0 = e0 + 1 - e;
            final double n1 = e - e0;
            final double offset0 = e0 * k;
            final double offset1 = offset0 + k;
            for (int j = 0; j < cubeVertices; j++) {
                if ((j & pos) != 0) {
                    cubeN[j] *= n1;
                    cubeVertex[j] += offset1;
                } else {
                    cubeN[j] *= n0;
                    cubeVertex[j] += offset0;
                }
            }

            k *= cur;
            pos <<= 1;
        }

        int kk, ff, nn;
        double pp;
        for (int i = 0; i < n; i++) {
            ff = i << 1;
            nn = ff + 1;
            pp = 0;
            for (int j = 0; j < cubeVertices; j++) {
                kk = cubeVertex[j] + 1;
                if (kk > -1) {
                    pp += sampleArray[cubeVertex[j] + i] * cubeN[j];
                }
            }
            pp = interpolateDouble(pp, 0, 1, decode[ff], decode[nn]);
            outputs[i] = (float) Math.min(Math.max(pp, range[ff]), range[nn]);
        }
        return outputs;

    }

    private static double interpolateDouble(final double x, final double xmin, final double xmax, final double ymin, final double ymax) {
        return ((x - xmin) * (ymax - ymin) / (xmax - xmin)) + ymin;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy