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

com.itextpdf.kernel.pdf.function.AbstractPdfFunction Maven / Gradle / Ivy

There is a newer version: 8.0.5
Show newest version
/*

    This file is part of the iText (R) project.
    Copyright (c) 1998-2023 iText Group NV
    Authors: Bruno Lowagie, Paulo Soares, et al.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License version 3
    as published by the Free Software Foundation with the addition of the
    following permission added to Section 15 as permitted in Section 7(a):
    FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
    ITEXT GROUP. ITEXT GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT
    OF THIRD PARTY RIGHTS

    This program is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU Affero General Public License for more details.
    You should have received a copy of the GNU Affero General Public License
    along with this program; if not, see http://www.gnu.org/licenses or write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA, 02110-1301 USA, or download the license from the following URL:
    http://itextpdf.com/terms-of-use/

    The interactive user interfaces in modified source and object code versions
    of this program must display Appropriate Legal Notices, as required under
    Section 5 of the GNU Affero General Public License.

    In accordance with Section 7(b) of the GNU Affero General Public License,
    a covered work must retain the producer line in every PDF that is created
    or manipulated using iText.

    You can be released from the requirements of the license by purchasing
    a commercial license. Buying such a license is mandatory as soon as you
    develop commercial activities involving the iText software without
    disclosing the source code of your own applications.
    These activities include: offering paid services to customers as an ASP,
    serving PDFs on the fly in a web application, shipping iText with a closed
    source product.

    For more information, please contact iText Software Corp. at this
    address: [email protected]
 */
package com.itextpdf.kernel.pdf.function;

import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfNumber;
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfObjectWrapper;
import com.itextpdf.kernel.pdf.PdfStream;
import com.itextpdf.kernel.pdf.colorspace.PdfColorSpace;
import com.itextpdf.kernel.pdf.function.BaseInputOutPutConvertors.IInputConversionFunction;
import com.itextpdf.kernel.pdf.function.BaseInputOutPutConvertors.IOutputConversionFunction;

import java.io.IOException;
import java.util.Arrays;

/**
 * The abstract PdfFunction class that represents the Function Dictionary or Stream PDF object.
 * Holds common properties and methods and a factory method. (see ISO-320001 Chapter 7.10)
 *
 * @param  Either a {@link PdfDictionary} or a {@link PdfStream}
 */
public abstract class AbstractPdfFunction extends PdfObjectWrapper implements IPdfFunction {

    private final int functionType;
    private double[] domain;
    private double[] range;

    /**
     * Constructs a PdfFunction from a new PdfObject.
     *
     * @param pdfObject    The new, empty, object, created in a concrete implementation
     * @param functionType The function type, can be 0, 2, 3 or 4
     * @param domain       the valid input domain, input will be clipped to this domain
     *                     contains a min max pair per input component
     * @param range        the valid output range, oputput will be clipped to this range
     *                     contains a min max pair per output component
     */
    protected AbstractPdfFunction(T pdfObject, int functionType, double[] domain, double[] range) {
        super(pdfObject);
        this.functionType = functionType;
        if (domain != null) {
            this.domain = Arrays.copyOf(domain, domain.length);
            pdfObject.put(PdfName.Domain,new PdfArray(domain));
        }
        if (range != null) {
            this.range = Arrays.copyOf(range, range.length);
            pdfObject.put(PdfName.Range,new PdfArray(range));
        }
        pdfObject.put(PdfName.FunctionType,new PdfNumber(functionType));
    }


    /**
     * Constructs a PdfFunction from an existing PdfObject.
     *
     * @param pdfObject Either a {@link PdfDictionary} or a {@link PdfStream}
     */
    protected AbstractPdfFunction(T pdfObject) {
        super(pdfObject);
        final PdfNumber functionTypeObj = pdfObject.getAsNumber(PdfName.FunctionType);
        functionType = functionTypeObj == null ? -1 : functionTypeObj.intValue();
        final PdfArray domainObj = pdfObject.getAsArray(PdfName.Domain);
        domain = domainObj == null ? null : domainObj.toDoubleArray();
        final PdfArray rangeObj = pdfObject.getAsArray(PdfName.Range);
        range = rangeObj == null ? null : rangeObj.toDoubleArray();
    }

    /**
     * The function type, (see ISO-320001 Table 38).
     *
     * @return The function type, either 0, 2, 3 or 4
     */
    @Override
    public int getFunctionType() {
        return functionType;
    }

    /**
     * Chacks wether the output of the function matches in components with the passed by color space.
     *
     * @param alternateSpace The color space to verify against
     *
     * @return True when compatible
     */
    @Override
    public boolean checkCompatibilityWithColorSpace(PdfColorSpace alternateSpace) {
        return getOutputSize() == alternateSpace.getNumberOfComponents();
    }

    /**
     * The number of input components.
     *
     * @return The number of input components
     */
    @Override
    public int getInputSize() {
        return getPdfObject().getAsArray(PdfName.Domain).size() / 2;
    }

    /**
     * The number of output components.
     *
     * @return The number of output components
     */
    @Override
    public int getOutputSize() {
        return range == null ? 0 : (range.length / 2);
    }

    /**
     * The valid input domain, input will be clipped to this domain contains a min max pair per input component.
     *
     * 

* (see ISO-320001 Table 38) * * @return the input domain */ @Override public double[] getDomain() { if (domain == null) { return null; } return Arrays.copyOf(domain, domain.length); } /** * The valid input domain, input will be clipped to this domain contains a min max pair per input component. * *

* (see ISO-320001 Table 38) * * @param value the new set of limits */ @Override public void setDomain(double[] value) { domain = Arrays.copyOf(value, value.length); getPdfObject().put(PdfName.Domain, new PdfArray(domain)); } /** * the valid output range, output will be clipped to this range contains a min max pair per output component. * *

* (see ISO-320001 Table 38) * * @return the output range */ @Override public double[] getRange() { if (range != null) { return Arrays.copyOf(range, range.length); } return null; } /** * the valid output range, output will be clipped to this range contains a min max pair per output component. * *

* (see ISO-320001 Table 38) * * @param value the new set of limts */ @Override public void setRange(double[] value) { if (value == null) { getPdfObject().remove(PdfName.Range); return; } range = Arrays.copyOf(value, value.length); getPdfObject().put(PdfName.Range, new PdfArray(range)); } /** * Performs the calculation in bulk on a set of raw data and returns a new set of raw data. * * @param bytes The uninterpreted set of data to be transformed * @param offset Where to start converting the data * @param length How many of the input bytes should be converted * @param wordSizeInputLength How many bytes represents one input value * @param wordSizeOutputLength How many bytes represents one output value * * @return the transformed result as a raw byte array * * @throws IOException on data reading errors */ @Override public byte[] calculateFromByteArray(byte[] bytes, int offset, int length, int wordSizeInputLength, int wordSizeOutputLength) throws IOException { return calculateFromByteArray(bytes, offset, length, wordSizeInputLength, wordSizeOutputLength, null, null); } /** * Performs the calculation in bulk on a set of raw data and returns a new set of raw data. * * @param bytes The uninterpreted set of data to be transformed * @param offset Where to start converting the data * @param length How many of the input bytes should be converted * @param wordSizeInputLength How many bytes represents one input value * @param wordSizeOutputLength How many bytes represents one output value * @param inputConvertor a custom input convertor * @param outputConvertor a custom output convertor * * @return the transformed result as a raw byte array * * @throws IOException on data reading errors */ @Override public byte[] calculateFromByteArray(byte[] bytes, int offset, int length, int wordSizeInputLength, int wordSizeOutputLength, IInputConversionFunction inputConvertor, IOutputConversionFunction outputConvertor) throws IOException { final int bytesPerInputWord = (int) Math.ceil(wordSizeInputLength / 8.0); final int bytesPerOutputWord = (int) Math.ceil(wordSizeOutputLength / 8.0); final int inputSize = getInputSize(); final int outputSize = getOutputSize(); IInputConversionFunction actualInputConvertor = inputConvertor; if (actualInputConvertor == null) { actualInputConvertor = BaseInputOutPutConvertors.getInputConvertor(bytesPerInputWord, 1); } IOutputConversionFunction actualOutputConvertor = outputConvertor; if (actualOutputConvertor == null) { actualOutputConvertor = BaseInputOutPutConvertors.getOutputConvertor(bytesPerOutputWord, 1.0); } final double[] inValues = actualInputConvertor.convert(bytes, offset, length); final double[] outValues = new double[inValues.length / inputSize * outputSize]; int outIndex = 0; for (int i = 0; i < inValues.length; i += inputSize) { final double[] singleRes = calculate(Arrays.copyOfRange(inValues, i, i + inputSize)); System.arraycopy(singleRes, 0, outValues, outIndex, singleRes.length); outIndex+= singleRes.length; } return actualOutputConvertor.convert(outValues); } /** * Clip input values to the allowed domain. * *

* (see ISO-320001 Table 38) * * @param input the input values to be clipped * * @return the values clipped between the boundaries defined in the domain */ @Override public double[] clipInput(double[] input) { if (input.length * 2 != domain.length) { throw new IllegalArgumentException(KernelExceptionMessageConstant.INPUT_NOT_MULTIPLE_OF_DOMAIN_SIZE); } return clip(input, domain); } /** * Clip output values to the allowed range, if there is a range. * *

* (see ISO-320001 Table 38) * * @param input the output values to be clipped * * @return the values clipped between the boundaries defined in the range */ @Override public double[] clipOutput(double[] input) { if (range == null) { return input; } if (input.length * 2 != range.length) { throw new IllegalArgumentException(KernelExceptionMessageConstant.INPUT_NOT_MULTIPLE_OF_RANGE_SIZE); } return clip(input, range); } @Override public PdfObject getAsPdfObject() { return super.getPdfObject(); } protected static double[] clip(double[] values, double[] limits) { assert (values.length * 2 == limits.length); double[] result = new double[values.length]; int j = 0; for (int i = 0; i < values.length; ++i) { final double lowerBound = limits[j++]; final double upperBound = limits[j++]; result[i] = Math.min(Math.max(lowerBound, values[i]), upperBound); } return result; } protected static double[] normalize(double[] values, double[] limits) { assert (values.length * 2 == limits.length); double[] normal = new double[values.length]; int j = 0; for (int i = 0; i < values.length; ++i) { final double lowerBound = limits[j++]; final double upperBound = Math.max(lowerBound + Double.MIN_VALUE, limits[j++]); normal[i] = Math.min(Math.max(0, (values[i] - lowerBound) / (upperBound - lowerBound)), 1); } return normal; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy