PdfType2FunctionTest.java
/*
This file is part of the iText (R) project.
Copyright (c) 1998-2025 Apryse Group NV
Authors: Apryse Software.
This program is offered under a commercial and under the AGPL license.
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
AGPL licensing:
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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 <https://www.gnu.org/licenses/>.
*/
package com.itextpdf.kernel.pdf.function;
import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
import com.itextpdf.kernel.exceptions.PdfException;
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.PdfString;
import com.itextpdf.test.ExtendedITextTest;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
@Tag("UnitTest")
public class PdfType2FunctionTest extends ExtendedITextTest {
private final static double EPSILON = 10e-6;
@Test
public void constructorInvalidObjWithoutNTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.remove(PdfName.N);
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_N, ex.getMessage());
}
@Test
public void constructorInvalidObjNNotNumberTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.N, new PdfString("some text"));
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_N, ex.getMessage());
}
@Test
public void constructorInvalidObjWithNonIntegerNTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.N, new PdfNumber(2.3));
final PdfArray domain = type2Func.getAsArray(PdfName.Domain);
domain.add(0, new PdfNumber(-1));
domain.remove(2);
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_N_NOT_INTEGER, ex.getMessage());
}
@Test
public void constructorInvalidObjWithNegativeNTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.N, new PdfNumber(-2));
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_N_NEGATIVE, ex.getMessage());
}
@Test
public void constructorInvalidDomainTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.Domain, new PdfArray(new double[] {1}));
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_DOMAIN, ex.getMessage());
}
@Test
public void constructorCorrectDomainTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.Domain, new PdfArray(new double[] {1, 2, 3, 4}));
PdfType2Function type2Function = new PdfType2Function(type2Func);
Assertions.assertEquals(2, type2Function.getInputSize());
}
@Test
public void constructorInvalidCDifferentSizeTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.C0, new PdfArray(new int[]{1, 2}));
type2Func.put(PdfName.C1, new PdfArray(new int[]{3}));
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_OUTPUT_SIZE, ex.getMessage());
}
@Test
public void constructorInvalidCAndRangeDifferentSizeTest() {
PdfDictionary type2Func = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2Func.put(PdfName.C0, new PdfArray(new int[]{1, 2}));
type2Func.put(PdfName.Range, new PdfArray(new int[] {1, 3}));
Exception ex = Assertions.assertThrows(PdfException.class, () -> new PdfType2Function(type2Func));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_TYPE_2_FUNCTION_OUTPUT_SIZE, ex.getMessage());
}
@Test
public void constructorWithRangeTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.Range, new PdfArray(new int[] {1, 2, 3, 4, 5, 6}));
PdfType2Function type2Func = new PdfType2Function(type2FuncDict);
Assertions.assertArrayEquals(new double[] {0, 0, 0}, type2Func.getC0(), EPSILON);
Assertions.assertArrayEquals(new double[] {1, 1, 1}, type2Func.getC1(), EPSILON);
Assertions.assertEquals(2, type2Func.getN(), EPSILON);
}
@Test
public void constructorMinimalTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
PdfType2Function type2Func = new PdfType2Function(type2FuncDict);
Assertions.assertArrayEquals(new double[] {0}, type2Func.getC0(), EPSILON);
Assertions.assertArrayEquals(new double[] {1}, type2Func.getC1(), EPSILON);
Assertions.assertEquals(2, type2Func.getN(), EPSILON);
}
@Test
public void constructorFullTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.C0, new PdfArray(new int[] {0, 1}));
type2FuncDict.put(PdfName.C1, new PdfArray(new int[] {1, 2}));
PdfType2Function type2Func = new PdfType2Function(type2FuncDict);
Assertions.assertEquals(2, type2Func.getN(), EPSILON);
Assertions.assertArrayEquals(new double[] {0, 1}, type2Func.getC0(), EPSILON);
Assertions.assertArrayEquals(new double[] {1, 2}, type2Func.getC1(), EPSILON);
}
@Test
public void calculateInvalid2NumberInputTest() {
PdfType2Function type2Func = new PdfType2Function(PdfFunctionUtil.createMinimalPdfType2FunctionDict());
Exception ex = Assertions.assertThrows(PdfException.class, () -> type2Func.calculate(new double[] {0, 1}));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_INPUT_FOR_TYPE_2_FUNCTION, ex.getMessage());
}
@Test
public void calculateInvalidNullInputTest() {
PdfType2Function type2Func = new PdfType2Function(PdfFunctionUtil.createMinimalPdfType2FunctionDict());
Exception ex = Assertions.assertThrows(PdfException.class, () -> type2Func.calculate(null));
Assertions.assertEquals(KernelExceptionMessageConstant.INVALID_INPUT_FOR_TYPE_2_FUNCTION, ex.getMessage());
}
@Test
public void calculateInputClipTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.Domain, new PdfArray(new int[] {1, 3}));
PdfType2Function type2Function = new PdfType2Function(type2FuncDict);
double[] output = type2Function.calculate(new double[] {8});
// input value was clipped to 3 from 8
Assertions.assertArrayEquals(new double[] {9}, output, EPSILON);
}
@Test
public void calculateTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.Domain, new PdfArray(new int[] {1, 3}));
type2FuncDict.put(PdfName.C0, new PdfArray(new int[] {0, 1}));
type2FuncDict.put(PdfName.C1, new PdfArray(new int[] {0, -3}));
PdfType2Function type2Function = new PdfType2Function(type2FuncDict);
double[] output = type2Function.calculate(new double[] {2});
Assertions.assertArrayEquals(new double[] {0, -15}, output, EPSILON);
}
@Test
public void calculateWithoutC0Test() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.Domain, new PdfArray(new int[] {1, 3}));
type2FuncDict.put(PdfName.C1, new PdfArray(new int[] {0, -3}));
PdfType2Function type2Function = new PdfType2Function(type2FuncDict);
double[] output = type2Function.calculate(new double[] {2});
Assertions.assertArrayEquals(new double[] {0, -12}, output, EPSILON);
}
@Test
public void calculateClipOutputTest() {
PdfDictionary type2FuncDict = PdfFunctionUtil.createMinimalPdfType2FunctionDict();
type2FuncDict.put(PdfName.Domain, new PdfArray(new int[] {1, 3}));
type2FuncDict.put(PdfName.Range, new PdfArray(new int[] {-4, -2}));
PdfType2Function type2Function = new PdfType2Function(type2FuncDict);
double[] output = type2Function.calculate(new double[] {2});
// output value was clipped to -2 from 4
Assertions.assertArrayEquals(new double[] {-2}, output, EPSILON);
}
}