CreateShadingTest.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.colorspace;
import com.itextpdf.kernel.pdf.PdfArray;
import com.itextpdf.kernel.pdf.PdfDictionary;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfName;
import com.itextpdf.kernel.pdf.PdfObject;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfResources;
import com.itextpdf.kernel.pdf.StampingProperties;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.colorspace.PdfDeviceCs.Cmyk;
import com.itextpdf.kernel.pdf.colorspace.PdfDeviceCs.Gray;
import com.itextpdf.kernel.pdf.colorspace.shading.PdfAxialShading;
import com.itextpdf.kernel.pdf.colorspace.shading.AbstractPdfShading;
import com.itextpdf.kernel.pdf.colorspace.shading.PdfRadialShading;
import com.itextpdf.kernel.pdf.colorspace.shading.ShadingType;
import com.itextpdf.kernel.pdf.function.AbstractPdfFunction;
import com.itextpdf.kernel.pdf.function.PdfType2Function;
import com.itextpdf.kernel.pdf.function.PdfType3Function;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.kernel.utils.CompareTool.CompareResult;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.TestUtil;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
@Tag("IntegrationTest")
public class CreateShadingTest extends ExtendedITextTest {
public static final String destinationFolder = TestUtil.getOutputPath() + "/kernel/pdf/colorspace/CreateShadingTest/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/colorspace/CreateShadingTest/";
@BeforeAll
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
@AfterAll
public static void afterClass() {
CompareTool.cleanup(destinationFolder);
}
@Test
public void createAxialShadingWithStitchingFunctionTest() throws IOException {
String testName = "createAxialShadingWithStitchingFunctionTest";
String outName = destinationFolder + testName + ".pdf";
String cmpName = sourceFolder + "cmp_" + testName + ".pdf";
PdfDocument pdfDocument = new PdfDocument(CompareTool.createTestPdfWriter(outName));
PdfCanvas pdfCanvas = new PdfCanvas(pdfDocument.addNewPage());
int x0 = 40;
int y0 = 500;
int x1 = 80;
int y1 = 400;
PdfArray shadingVector = new PdfArray(new int[] {x0, y0, x1, y1});
PdfType3Function stitchingFunction = createStitchingCmykShadingFunction();
PdfAxialShading axialShading = new PdfAxialShading(new Cmyk(), shadingVector, stitchingFunction);
pdfCanvas.paintShading(axialShading);
pdfDocument.close();
assertShadingDictionaryResult(outName, cmpName, "Sh1");
}
@Test
public void modifyAxialShadingTest() throws IOException {
String testName = "modifyAxialShadingTest";
String outName = destinationFolder + testName + ".pdf";
String cmpName = sourceFolder + "cmp_" + testName + ".pdf";
String input = sourceFolder + "axialShading.pdf";
PdfDocument pdfDocument = new PdfDocument(
new PdfReader(input), CompareTool.createTestPdfWriter(outName),
new StampingProperties().useAppendMode());
PdfResources resources = pdfDocument.getPage(1).getResources();
for (PdfName resName : resources.getResourceNames()) {
AbstractPdfShading shading = resources.getShading(resName);
if (shading != null && shading.getShadingType() == ShadingType.AXIAL) {
PdfAxialShading axialShading = (PdfAxialShading) shading;
// "cut" shading and extend colors
axialShading.setDomain(0.1f, 0.8f);
axialShading.setExtend(true, true);
}
}
pdfDocument.close();
assertShadingDictionaryResult(outName, cmpName, "Sh1");
}
@Test
public void createSimpleRadialShadingTest() throws IOException {
String testName = "createSimpleRadialShadingTest";
String outName = destinationFolder + testName + ".pdf";
String cmpName = sourceFolder + "cmp_" + testName + ".pdf";
PdfDocument pdfDocument = new PdfDocument(CompareTool.createTestPdfWriter(outName));
PdfCanvas pdfCanvas = new PdfCanvas(pdfDocument.addNewPage());
int x0 = 100;
int y0 = 500;
int r0 = 25;
int x1 = x0;
int y1 = y0;
int r1 = 50;
PdfRadialShading radialShading = new PdfRadialShading(
new Gray(),
x0, y0, r0, new float[] {0.9f},
x1, y1, r1, new float[] {0.2f},
new boolean[]{false, false}
);
pdfCanvas.paintShading(radialShading);
pdfDocument.close();
assertShadingDictionaryResult(outName, cmpName, "Sh1");
}
@Test
public void createRadialShadingWithStitchingFunctionTest() throws IOException {
String testName = "createRadialShadingWithStitchingFunctionTest";
String outName = destinationFolder + testName + ".pdf";
String cmpName = sourceFolder + "cmp_" + testName + ".pdf";
PdfDocument pdfDocument = new PdfDocument(CompareTool.createTestPdfWriter(outName));
PdfCanvas pdfCanvas = new PdfCanvas(pdfDocument.addNewPage());
int x0 = 40;
int y0 = 500;
int r0 = 25;
int x1 = 380;
int y1 = 400;
int r1 = 50;
PdfArray shadingVector = new PdfArray(new int[] {x0, y0, r0, x1, y1, r1});
PdfType3Function stitchingFunction = createStitchingCmykShadingFunction();
PdfRadialShading radialShading = new PdfRadialShading(new Cmyk(), shadingVector, stitchingFunction);
pdfCanvas.paintShading(radialShading);
pdfDocument.close();
assertShadingDictionaryResult(outName, cmpName, "Sh1");
}
@Test
public void modifyRadialShadingTest() throws IOException {
String testName = "modifyRadialAxialShadingTest";
String outName = destinationFolder + testName + ".pdf";
String cmpName = sourceFolder + "cmp_" + testName + ".pdf";
String input = sourceFolder + "radialShading.pdf";
PdfDocument pdfDocument = new PdfDocument(
new PdfReader(input), CompareTool.createTestPdfWriter(outName),
new StampingProperties().useAppendMode());
PdfResources resources = pdfDocument.getPage(1).getResources();
for (PdfName resName : resources.getResourceNames()) {
AbstractPdfShading shading = resources.getShading(resName);
if (shading != null && shading.getShadingType() == ShadingType.RADIAL) {
PdfRadialShading radialShading = (PdfRadialShading) shading;
// "cut" shading and extend colors
radialShading.setDomain(0.1f, 0.8f);
radialShading.setExtend(true, true);
}
}
pdfDocument.close();
assertShadingDictionaryResult(outName, cmpName, "Sh1");
}
private static PdfType3Function createStitchingCmykShadingFunction() {
float[] domain0to1 = new float[] {0, 1};
float[] range0to1For4n = new float[] {0, 1, 0, 1, 0, 1, 0, 1};
float[] cmykColor0 = {0.2f, 0.4f, 0f, 0f};
float[] cmykColor1 = {0.2f, 1f, 0f, 0f};
PdfType2Function function0 = new PdfType2Function(domain0to1, null, cmykColor0, cmykColor1, 1);
PdfType2Function function1 = new PdfType2Function(domain0to1, null, cmykColor1, cmykColor0, 1);
float[] boundForTwoFunctionsSubdomains = new float[] {0.5f};
float[] encodeStitchingSubdomainToNthFunctionDomain = new float[] {0, 1, 0, 1};
return new PdfType3Function(domain0to1, range0to1For4n,
new ArrayList<AbstractPdfFunction<? extends PdfDictionary>>(Arrays.asList(function0, function1)),
boundForTwoFunctionsSubdomains, encodeStitchingSubdomainToNthFunctionDomain);
}
private static void assertShadingDictionaryResult(String outName, String cmpName, String shadingResourceName) throws IOException {
printOutCmpPdfNameAndDir(outName, cmpName);
PdfDocument outPdf = new PdfDocument(CompareTool.createOutputReader(outName));
PdfDocument cmpPdf = new PdfDocument(CompareTool.createOutputReader(cmpName));
PdfName resName = new PdfName(shadingResourceName);
PdfObject outShDictionary = outPdf.getPage(1).getResources().getResourceObject(PdfName.Shading, resName);
PdfObject cmpShDictionary = cmpPdf.getPage(1).getResources().getResourceObject(PdfName.Shading, resName);
Assertions.assertTrue(outShDictionary.isDictionary());
CompareResult compareResult = new CompareTool()
.compareDictionariesStructure((PdfDictionary) outShDictionary, (PdfDictionary) cmpShDictionary);
Assertions.assertNull(compareResult);
outPdf.close();
cmpPdf.close();
}
}