PdfDestinationTest.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;
import com.itextpdf.io.logs.IoLogMessageConstant;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
import com.itextpdf.kernel.pdf.filespec.PdfStringFS;
import com.itextpdf.kernel.pdf.navigation.PdfDestination;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitDestination;
import com.itextpdf.kernel.pdf.navigation.PdfExplicitRemoteGoToDestination;
import com.itextpdf.kernel.pdf.navigation.PdfStringDestination;
import com.itextpdf.kernel.pdf.navigation.PdfStructureDestination;
import com.itextpdf.kernel.pdf.tagging.PdfStructElem;
import com.itextpdf.kernel.utils.CompareTool;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.TestUtil;
import com.itextpdf.test.annotations.LogMessage;
import com.itextpdf.test.annotations.LogMessages;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNull;
@Tag("IntegrationTest")
public class PdfDestinationTest extends ExtendedITextTest {
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfDestinationTest/";
public static final String destinationFolder = TestUtil.getOutputPath() + "/kernel/pdf/PdfDestinationTest/";
@BeforeAll
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
@AfterAll
public static void afterClass() {
CompareTool.cleanup(destinationFolder);
}
@Test
public void destTest01() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleNoLinks.pdf";
String outFile = destinationFolder + "destTest01.pdf";
String cmpFile = sourceFolder + "cmp_destTest01.pdf";
PdfDocument document = new PdfDocument(new PdfReader(srcFile), CompareTool.createTestPdfWriter(outFile));
PdfPage firstPage = document.getPage(1);
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
linkExplicitDest.setAction(PdfAction.createGoTo(PdfExplicitDestination.createFit(document.getPage(2))));
firstPage.addAnnotation(linkExplicitDest);
PdfLinkAnnotation linkStringDest = new PdfLinkAnnotation(new Rectangle(35, 760, 160, 15));
PdfExplicitDestination destToPage3 = PdfExplicitDestination.createFit(document.getPage(3));
String stringDest = "thirdPageDest";
document.addNamedDestination(stringDest, destToPage3.getPdfObject());
linkStringDest.setAction(PdfAction.createGoTo(new PdfStringDestination(stringDest)));
firstPage.addAnnotation(linkStringDest);
document.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest01() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleWithLinks.pdf";
String outFile = destinationFolder + "destCopyingTest01.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest01.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 2, 3), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest02() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleWithLinks.pdf";
String outFile = destinationFolder + "destCopyingTest02.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest02.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Collections.singletonList(1), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest03() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleWithLinks.pdf";
String outFile = destinationFolder + "destCopyingTest03.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest03.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 2), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest04() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleWithLinks.pdf";
String outFile = destinationFolder + "destCopyingTest04.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest04.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 3), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest05() throws IOException, InterruptedException {
String srcFile = sourceFolder + "simpleWithLinks.pdf";
String outFile = destinationFolder + "destCopyingTest05.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest05.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 2, 3, 1), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest06() throws IOException, InterruptedException {
String srcFile = sourceFolder + "sourceWithNamedDestination.pdf";
String outFile = destinationFolder + "destCopyingTest06.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest06.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 2, 1), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void destCopyingTest07() throws IOException, InterruptedException {
String srcFile = sourceFolder + "sourceStringDestWithPageNumber.pdf";
String outFile = destinationFolder + "destCopyingTest07.pdf";
String cmpFile = sourceFolder + "cmp_destCopyingTest07.pdf";
PdfDocument srcDoc = new PdfDocument(new PdfReader(srcFile));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
srcDoc.copyPagesTo(Arrays.asList(1, 2, 1), destDoc);
destDoc.close();
srcDoc.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void structureDestinationWithoutRemoteIdTest() throws IOException {
String srcFile = sourceFolder + "customRolesMappingPdf2.pdf";
PdfDocument document = new PdfDocument(new PdfReader(srcFile), new PdfWriter(new ByteArrayOutputStream()));
PdfStructElem imgElement = new PdfStructElem((PdfDictionary) document.getPdfObject(13));
try {
PdfAction.createGoToR(new PdfStringFS("Some fake destination"),
PdfStructureDestination.createFit(imgElement));
Assertions.fail("Exception not thrown");
} catch (IllegalArgumentException e) {
Assertions.assertEquals("Structure destinations shall specify structure element ID in remote go-to actions. Structure element that has no ID is specified instead", e.getMessage());
}
document.close();
}
@Test
public void structureDestination01Test() throws IOException, InterruptedException {
String srcFile = sourceFolder + "customRolesMappingPdf2.pdf";
String outFile = destinationFolder + "structureDestination01Test.pdf";
String cmpFile = sourceFolder + "cmp_structureDestination01Test.pdf";
PdfDocument document = new PdfDocument(new PdfReader(srcFile), CompareTool.createTestPdfWriter(outFile));
PdfStructElem imgElement = new PdfStructElem((PdfDictionary) document.getPdfObject(13));
PdfStructureDestination dest = PdfStructureDestination.createFit(imgElement);
PdfPage secondPage = document.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
linkExplicitDest.setAction(PdfAction.createGoTo(dest));
secondPage.addAnnotation(linkExplicitDest);
document.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void structureDestination02Test() throws IOException, InterruptedException {
String srcFile = sourceFolder + "customRolesMappingPdf2.pdf";
String outFile = destinationFolder + "structureDestination02Test.pdf";
String cmpFile = sourceFolder + "cmp_structureDestination02Test.pdf";
PdfDocument document = new PdfDocument(new PdfReader(srcFile), CompareTool.createTestPdfWriter(outFile));
PdfStructElem imgElement = new PdfStructElem((PdfDictionary) document.getPdfObject(13));
PdfStructureDestination dest = PdfStructureDestination.createFit(imgElement);
PdfPage secondPage = document.addNewPage();
PdfPage thirdPage = document.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
PdfAction gotoStructAction = PdfAction.createGoTo(PdfExplicitDestination.createFit(thirdPage));
gotoStructAction.put(PdfName.SD, dest.getPdfObject());
linkExplicitDest.setAction(gotoStructAction);
secondPage.addAnnotation(linkExplicitDest);
document.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void makeDestination01Test() throws IOException {
String srcFile = sourceFolder + "cmp_structureDestination01Test.pdf";
PdfDocument pdfDocument = new PdfDocument(new PdfReader(srcFile));
PdfObject destObj = ((PdfLinkAnnotation) pdfDocument.getPage(2).getAnnotations().get(0)).getAction().get(PdfName.D);
PdfDestination destWrapper = PdfDestination.makeDestination(destObj);
Assertions.assertEquals(PdfStructureDestination.class, destWrapper.getClass());
}
@Test
public void remoteGoToDestinationTest01() throws IOException, InterruptedException {
String cmpFile = sourceFolder + "cmp_remoteGoToDestinationTest01.pdf";
String outFile = destinationFolder + "remoteGoToDestinationTest01.pdf";
PdfDocument out = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
out.addNewPage();
List<PdfDestination> destinations = new ArrayList<>(7);
destinations.add(PdfExplicitRemoteGoToDestination.createFit(1));
destinations.add(PdfExplicitRemoteGoToDestination.createFitH(1, 10));
destinations.add(PdfExplicitRemoteGoToDestination.createFitV(1, 10));
destinations.add(PdfExplicitRemoteGoToDestination.createFitR(1, 10, 10, 10, 10));
destinations.add(PdfExplicitRemoteGoToDestination.createFitB(1));
destinations.add(PdfExplicitRemoteGoToDestination.createFitBH(1, 10));
destinations.add(PdfExplicitRemoteGoToDestination.createFitBV(1, 10));
int y = 785;
for (PdfDestination destination : destinations) {
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, y, 160, 15));
PdfAction action = PdfAction.createGoToR(new PdfStringFS("Some fake destination"), destination);
linkExplicitDest.setAction(action);
out.getFirstPage().addAnnotation(linkExplicitDest);
y -= 20;
}
out.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void remoteGoToDestinationTest02() throws IOException, InterruptedException {
String cmpFile = sourceFolder + "cmp_remoteGoToDestinationTest02.pdf";
String outFile = destinationFolder + "remoteGoToDestinationTest02.pdf";
PdfDocument out = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
out.addNewPage();
out.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
PdfAction action = PdfAction.createGoToR(new PdfStringFS("Some fake destination"),
PdfExplicitRemoteGoToDestination.createFitR(2, 10, 10, 10, 10), true);
linkExplicitDest.setAction(action);
out.getFirstPage().addAnnotation(linkExplicitDest);
out.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void remoteGoToRIllegalDestinationTest() throws IOException {
String outFile = destinationFolder + "remoteGoToDestinationTest01.pdf";
PdfDocument document = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
document.addNewPage();
document.addNewPage();
try {
PdfAction.createGoToR(new PdfStringFS("Some fake destination"),
PdfExplicitDestination.createFitB(document.getPage(1)));
Assertions.fail("Exception not thrown");
} catch (IllegalArgumentException e) {
Assertions.assertEquals("Explicit destinations shall specify page number in remote go-to actions instead of page dictionary", e.getMessage());
}
document.close();
}
@Test
public void remoteGoToRByIntDestinationTest() throws IOException, InterruptedException {
String cmpFile = sourceFolder + "cmp_remoteGoToRByIntDestinationTest.pdf";
String outFile = destinationFolder + "remoteGoToRByIntDestinationTest.pdf";
PdfDocument out = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
out.addNewPage();
out.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
PdfAction action = PdfAction.createGoToR("Some fake destination", 2);
linkExplicitDest.setAction(action);
out.getFirstPage().addAnnotation(linkExplicitDest);
out.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void remoteGoToRByStringDestinationTest() throws IOException, InterruptedException {
String cmpFile = sourceFolder + "cmp_remoteGoToRByStringDestinationTest.pdf";
String outFile = destinationFolder + "remoteGoToRByStringDestinationTest.pdf";
PdfDocument out = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
out.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
PdfAction action = PdfAction.createGoToR("Some fake destination", "1");
linkExplicitDest.setAction(action);
out.getFirstPage().addAnnotation(linkExplicitDest);
out.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = IoLogMessageConstant.INVALID_DESTINATION_TYPE)})
public void remoteGoToNotValidExplicitDestinationTest() throws IOException, InterruptedException {
String cmpFile = sourceFolder + "cmp_remoteGoToNotValidExplicitDestinationTest.pdf";
String outFile = destinationFolder + "remoteGoToNotValidExplicitDestinationTest.pdf";
PdfDocument document = new PdfDocument(CompareTool.createTestPdfWriter(outFile));
document.addNewPage();
PdfLinkAnnotation linkExplicitDest = new PdfLinkAnnotation(new Rectangle(35, 785, 160, 15));
linkExplicitDest.setAction(PdfAction.createGoTo(PdfExplicitRemoteGoToDestination.createFit(1)));
document.getFirstPage().addAnnotation(linkExplicitDest);
document.close();
assertNull(new CompareTool().compareByContent(outFile, cmpFile, destinationFolder, "diff_"));
}
@Test
public void copyNullDestination() throws IOException {
try (
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) {
pdfDocument.addNewPage();
PdfDestination copiedDestination = pdfDocument.getCatalog()
.copyDestination(null, new HashMap<PdfPage, PdfPage>(), pdfDocument);
// We expect null to be returned if the destination to be copied is null
Assertions.assertNull(copiedDestination);
}
}
}