PdfCopyTest.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.io.source.ByteArrayOutputStream;
import com.itextpdf.io.source.ByteUtils;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
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.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
@Tag("IntegrationTest")
public class PdfCopyTest extends ExtendedITextTest {
public static final String destinationFolder = TestUtil.getOutputPath() + "/kernel/pdf/PdfCopyTest/";
public static final String sourceFolder = "./src/test/resources/com/itextpdf/kernel/pdf/PdfCopyTest/";
@BeforeAll
public static void beforeClass() {
createOrClearDestinationFolder(destinationFolder);
}
@AfterAll
public static void afterClass() {
CompareTool.cleanup(destinationFolder);
}
@Test
@LogMessages(messages = {
@LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY),
@LogMessage(messageTemplate = IoLogMessageConstant.MAKE_COPY_OF_CATALOG_DICTIONARY_IS_FORBIDDEN)
})
public void copySignedDocuments() throws IOException {
PdfDocument pdfDoc1 = new PdfDocument(new PdfReader(sourceFolder + "hello_signed.pdf"));
PdfDocument pdfDoc2 = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copySignedDocuments.pdf"));
pdfDoc1.copyPagesTo(1, 1, pdfDoc2);
pdfDoc2.close();
pdfDoc1.close();
PdfDocument pdfDocument = new PdfDocument(CompareTool.createOutputReader(destinationFolder + "copySignedDocuments.pdf"));
PdfDictionary sig = (PdfDictionary) pdfDocument.getPdfObject(13);
PdfDictionary sigRef = sig.getAsArray(PdfName.Reference).getAsDictionary(0);
Assertions.assertTrue(PdfName.SigRef.equals(sigRef.getAsName(PdfName.Type)));
Assertions.assertTrue(sigRef.get(PdfName.Data).isNull());
}
@Test
public void copying1() throws IOException {
PdfDocument pdfDoc1 = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copying1_1.pdf"));
pdfDoc1.getDocumentInfo().setAuthor("Alexander Chingarev").
setCreator("iText 6").
setTitle("Empty iText 6 Document");
pdfDoc1.getCatalog().put(new PdfName("a"), new PdfName("b").makeIndirect(pdfDoc1));
PdfPage page1 = pdfDoc1.addNewPage();
page1.flush();
pdfDoc1.close();
pdfDoc1 = new PdfDocument(CompareTool.createOutputReader(destinationFolder + "copying1_1.pdf"));
PdfDocument pdfDoc2 = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copying1_2.pdf"));
pdfDoc2.addNewPage();
pdfDoc2.getDocumentInfo().getPdfObject()
.put(new PdfName("a"), pdfDoc1.getCatalog().getPdfObject().get(new PdfName("a")).copyTo(pdfDoc2));
pdfDoc2.close();
pdfDoc1.close();
PdfReader reader = CompareTool.createOutputReader(destinationFolder + "copying1_2.pdf");
PdfDocument pdfDocument = new PdfDocument(reader);
assertFalse(reader.hasRebuiltXref(), "Rebuilt");
PdfDictionary trailer = pdfDocument.getTrailer();
PdfDictionary info = trailer.getAsDictionary(PdfName.Info);
PdfName b = info.getAsName(new PdfName("a"));
assertEquals("/b", b.toString());
pdfDocument.close();
}
@Test
public void copying2() throws IOException {
PdfDocument pdfDoc1 = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copying2_1.pdf"));
for (int i = 0; i < 10; i++) {
PdfPage page1 = pdfDoc1.addNewPage();
page1.getContentStream(0).getOutputStream()
.write(ByteUtils.getIsoBytes("%page " + String.valueOf(i + 1) + "\n"));
page1.flush();
}
pdfDoc1.close();
pdfDoc1 = new PdfDocument(CompareTool.createOutputReader(destinationFolder + "copying2_1.pdf"));
PdfDocument pdfDoc2 = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copying2_2.pdf"));
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
pdfDoc2.addPage(pdfDoc1.getPage(i + 1).copyTo(pdfDoc2));
}
}
pdfDoc2.close();
pdfDoc1.close();
PdfReader reader = CompareTool.createOutputReader(destinationFolder + "copying2_2.pdf");
PdfDocument pdfDocument = new PdfDocument(reader);
assertFalse(reader.hasRebuiltXref(), "Rebuilt");
for (int i = 0; i < 5; i++) {
byte[] bytes = pdfDocument.getPage(i + 1).getContentBytes();
assertEquals("%page " + String.valueOf(i * 2 + 1) + "\n", new String(bytes));
}
pdfDocument.close();
}
@Test
public void copying3() throws IOException {
PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copying3_1.pdf"));
PdfDictionary helloWorld = (PdfDictionary) new PdfDictionary().makeIndirect(pdfDoc);
PdfDictionary helloWorld1 = (PdfDictionary) new PdfDictionary().makeIndirect(pdfDoc);
helloWorld.put(new PdfName("Hello"), new PdfString("World"));
helloWorld.put(new PdfName("HelloWrld"), helloWorld);
helloWorld.put(new PdfName("HelloWrld1"), helloWorld1);
PdfPage page = pdfDoc.addNewPage();
page.getPdfObject().put(new PdfName("HelloWorld"), helloWorld);
page.getPdfObject().put(new PdfName("HelloWorldClone"), (PdfObject) helloWorld.clone());
pdfDoc.close();
PdfReader reader = CompareTool.createOutputReader(destinationFolder + "copying3_1.pdf");
pdfDoc = new PdfDocument(reader);
assertFalse(reader.hasRebuiltXref(), "Rebuilt");
PdfDictionary dic0 = pdfDoc.getPage(1).getPdfObject().getAsDictionary(new PdfName("HelloWorld"));
assertEquals(4, dic0.getIndirectReference().getObjNumber());
assertEquals(0, dic0.getIndirectReference().getGenNumber());
PdfDictionary dic1 = pdfDoc.getPage(1).getPdfObject().getAsDictionary(new PdfName("HelloWorldClone"));
assertEquals(8, dic1.getIndirectReference().getObjNumber());
assertEquals(0, dic1.getIndirectReference().getGenNumber());
PdfString str0 = dic0.getAsString(new PdfName("Hello"));
PdfString str1 = dic1.getAsString(new PdfName("Hello"));
assertEquals(str0.getValue(), str1.getValue());
assertEquals(str0.getValue(), "World");
PdfDictionary dic01 = dic0.getAsDictionary(new PdfName("HelloWrld"));
PdfDictionary dic11 = dic1.getAsDictionary(new PdfName("HelloWrld"));
assertEquals(dic01.getIndirectReference().getObjNumber(), dic11.getIndirectReference().getObjNumber());
assertEquals(dic01.getIndirectReference().getGenNumber(), dic11.getIndirectReference().getGenNumber());
assertEquals(dic01.getIndirectReference().getObjNumber(), 4);
assertEquals(dic01.getIndirectReference().getGenNumber(), 0);
PdfDictionary dic02 = dic0.getAsDictionary(new PdfName("HelloWrld1"));
PdfDictionary dic12 = dic1.getAsDictionary(new PdfName("HelloWrld1"));
assertEquals(dic02.getIndirectReference().getObjNumber(), dic12.getIndirectReference().getObjNumber());
assertEquals(dic02.getIndirectReference().getGenNumber(), dic12.getIndirectReference().getGenNumber());
assertEquals(dic12.getIndirectReference().getObjNumber(), 5);
assertEquals(dic12.getIndirectReference().getGenNumber(), 0);
pdfDoc.close();
}
@Test
@LogMessages(messages = {
@LogMessage(messageTemplate = IoLogMessageConstant.SOURCE_DOCUMENT_HAS_ACROFORM_DICTIONARY)
})
public void copyDocumentsWithFormFieldsTest() throws IOException, InterruptedException {
String filename = sourceFolder + "fieldsOn2-sPage.pdf";
PdfDocument sourceDoc = new PdfDocument(new PdfReader(filename));
PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copyDocumentsWithFormFields.pdf"));
sourceDoc.initializeOutlines();
sourceDoc.copyPagesTo(1, sourceDoc.getNumberOfPages(), pdfDoc);
sourceDoc.close();
pdfDoc.close();
assertNull(new CompareTool().compareByContent(destinationFolder + "copyDocumentsWithFormFields.pdf",
sourceFolder + "cmp_copyDocumentsWithFormFields.pdf", destinationFolder, "diff_"));
}
@Test
public void copySamePageWithAnnotationsSeveralTimes() throws IOException, InterruptedException {
String filename = sourceFolder + "rotated_annotation.pdf";
PdfDocument sourceDoc = new PdfDocument(new PdfReader(filename));
PdfDocument pdfDoc = new PdfDocument(
CompareTool.createTestPdfWriter(destinationFolder + "copySamePageWithAnnotationsSeveralTimes.pdf"));
sourceDoc.initializeOutlines();
sourceDoc.copyPagesTo(Arrays.asList(1, 1, 1), pdfDoc);
sourceDoc.close();
pdfDoc.close();
assertNull(new CompareTool().compareByContent(destinationFolder + "copySamePageWithAnnotationsSeveralTimes.pdf",
sourceFolder + "cmp_copySamePageWithAnnotationsSeveralTimes.pdf", destinationFolder, "diff_"));
}
@Test
public void copyIndirectInheritablePageEntriesTest01() throws IOException, InterruptedException {
String src = sourceFolder + "indirectPageProps.pdf";
String filename = "copyIndirectInheritablePageEntriesTest01.pdf";
String dest = destinationFolder + filename;
String cmp = sourceFolder + "cmp_" + filename;
PdfDocument outputDoc = new PdfDocument(CompareTool.createTestPdfWriter(dest));
PdfDocument sourceDoc = new PdfDocument(new PdfReader(src));
sourceDoc.copyPagesTo(1, 1, outputDoc);
sourceDoc.close();
outputDoc.close();
assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder, "diff_"));
}
@Test
public void copyPageNoRotationToDocWithRotationInKidsPageTest() throws IOException, InterruptedException {
String src = sourceFolder + "srcFileWithSetRotation.pdf";
String dest = destinationFolder + "copyPageNoRotationToDocWithRotationInKidsPage.pdf";
String cmp = sourceFolder + "cmp_copyPageNoRotationToDocWithRotationInKidsPage.pdf";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), CompareTool.createTestPdfWriter(dest));
PdfDocument sourceDoc = new PdfDocument(new PdfReader(sourceFolder + "noRotationProp.pdf"));
sourceDoc.copyPagesTo(1, sourceDoc.getNumberOfPages(), pdfDoc);
sourceDoc.close();
pdfDoc.close();
assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder));
}
@Test
//TODO: update cmp-files when DEVSIX-3635 will be fixed
public void copyPageNoRotationToDocWithRotationInPagesDictTest() throws IOException, InterruptedException {
String src = sourceFolder + "indirectPageProps.pdf";
String dest = destinationFolder + "copyPageNoRotationToDocWithRotationInPagesDict.pdf";
String cmp = sourceFolder + "cmp_copyPageNoRotationToDocWithRotationInPagesDict.pdf";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), CompareTool.createTestPdfWriter(dest));
PdfDocument sourceDoc = new PdfDocument(new PdfReader(sourceFolder + "noRotationProp.pdf"));
sourceDoc.copyPagesTo(1, sourceDoc.getNumberOfPages(), pdfDoc);
sourceDoc.close();
pdfDoc.close();
assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder));
}
@Test
public void copyPageWithRotationInPageToDocWithRotationInPagesDictTest() throws IOException, InterruptedException {
String src = sourceFolder + "indirectPageProps.pdf";
String dest = destinationFolder + "copyPageWithRotationInPageToDocWithRotationInPagesDict.pdf";
String cmp = sourceFolder + "cmp_copyPageWithRotationInPageToDocWithRotationInPagesDict.pdf";
PdfDocument pdfDoc = new PdfDocument(new PdfReader(src), CompareTool.createTestPdfWriter(dest));
PdfDocument sourceDoc = new PdfDocument(
new PdfReader(sourceFolder + "srcFileCopyPageWithSetRotationValueInKids.pdf"));
sourceDoc.copyPagesTo(1, sourceDoc.getNumberOfPages(), pdfDoc);
sourceDoc.close();
pdfDoc.close();
assertNull(new CompareTool().compareByContent(dest, cmp, destinationFolder));
}
@Test
public void copySelfContainedObject() throws IOException {
ByteArrayOutputStream inputBytes = new ByteArrayOutputStream();
PdfDocument prepInputDoc = new PdfDocument(new PdfWriter(inputBytes));
PdfDictionary selfContainedDict = new PdfDictionary();
PdfName randDictName = PdfName.Sound;
PdfName randEntry1 = PdfName.R;
PdfName randEntry2 = PdfName.S;
selfContainedDict.put(randEntry1, selfContainedDict);
selfContainedDict.put(randEntry2, selfContainedDict);
prepInputDoc.addNewPage().put(randDictName, selfContainedDict.makeIndirect(prepInputDoc));
prepInputDoc.close();
PdfDocument srcDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(inputBytes.toByteArray())));
PdfDocument destDoc = new PdfDocument(CompareTool.createTestPdfWriter(destinationFolder + "copySelfContainedObject.pdf"));
srcDoc.copyPagesTo(1, 1, destDoc);
PdfDictionary destPageObj = destDoc.getFirstPage().getPdfObject();
PdfDictionary destSelfContainedDict = destPageObj.getAsDictionary(randDictName);
PdfDictionary destSelfContainedDictR = destSelfContainedDict.getAsDictionary(randEntry1);
PdfDictionary destSelfContainedDictS = destSelfContainedDict.getAsDictionary(randEntry2);
Assertions.assertEquals(destSelfContainedDict.getIndirectReference(),
destSelfContainedDictR.getIndirectReference());
Assertions.assertEquals(destSelfContainedDict.getIndirectReference(),
destSelfContainedDictS.getIndirectReference());
destDoc.close();
srcDoc.close();
}
@Test
public void copyDifferentRangesOfPagesWithBookmarksTest() throws IOException, InterruptedException {
String outFileName = destinationFolder + "copyDifferentRangesOfPagesWithBookmarksTest.pdf";
String cmpFileName = sourceFolder + "cmp_copyDifferentRangesOfPagesWithBookmarksTest.pdf";
PdfDocument targetPdf = new PdfDocument(CompareTool.createTestPdfWriter(outFileName));
targetPdf.initializeOutlines();
PdfDocument sourcePdf = new PdfDocument(new PdfReader(sourceFolder + "sameDocWithBookmarksPdf.pdf"));
sourcePdf.initializeOutlines();
int sourcePdfLength = sourcePdf.getNumberOfPages();
int sourcePdfOutlines = sourcePdf.getOutlines(false).getAllChildren().size();
sourcePdf.copyPagesTo(3, sourcePdfLength, targetPdf);
sourcePdf.copyPagesTo(1, 2, targetPdf);
int targetOutlines = targetPdf.getOutlines(false).getAllChildren().size();
Assertions.assertEquals(sourcePdfOutlines, targetOutlines);
sourcePdf.close();
targetPdf.close();
Assertions.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder));
}
@Test
// TODO DEVSIX-577. Update cmp
public void copyPagesLinkAnnotationTest() throws IOException, InterruptedException {
String outFileName = destinationFolder + "copyPagesLinkAnnotationTest.pdf";
String cmpFileName = sourceFolder + "cmp_copyPagesLinkAnnotationTest.pdf";
PdfDocument targetPdf = new PdfDocument(CompareTool.createTestPdfWriter(outFileName));
PdfDocument linkAnotPdf = new PdfDocument(new PdfReader(sourceFolder + "pdfLinkAnnotationTest.pdf"));
int linkPdfLength = linkAnotPdf.getNumberOfPages();
linkAnotPdf.copyPagesTo(3, linkPdfLength, targetPdf);
linkAnotPdf.copyPagesTo(1, 2, targetPdf);
List<PdfAnnotation> annotations = getPdfAnnotations(targetPdf);
Assertions.assertEquals(0, annotations.size(), "The number of merged annotations are not the same.");
linkAnotPdf.close();
targetPdf.close();
Assertions.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder));
}
@Test
public void objRefAsStreamCopyTest() throws IOException, InterruptedException {
String pdf = sourceFolder + "objRefAsStream.pdf";
String outPdf = destinationFolder + "objRefAsStreamCopy.pdf";
String cmpPdf = sourceFolder + "cmp_objRefAsStreamCopy.pdf";
PdfDocument pdfFile = new PdfDocument(new PdfReader(pdf));
PdfDocument copiedFile = new PdfDocument(CompareTool.createTestPdfWriter(outPdf));
copiedFile.setTagged();
pdfFile.copyPagesTo(1, 1, copiedFile);
pdfFile.close();
copiedFile.close();
Assertions.assertNull(new CompareTool().compareByContent(outPdf, cmpPdf, destinationFolder, "diff"));
}
@Test
public void copyDocWithFullDDictionary() throws IOException, InterruptedException {
String outFileName = destinationFolder + "copyDocWithDDictionary.pdf";
String cmpFileName = sourceFolder + "cmp_copyDocWithDDictionary.pdf";
PdfDocument inPdf = new PdfDocument(new PdfReader(sourceFolder + "DocWithDDictionary.pdf"));
PdfDocument outPdf = new PdfDocument(new PdfWriter(outFileName));
inPdf.copyPagesTo(1, 1, outPdf);
inPdf.close();
outPdf.close();
Assertions.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder));
}
private List<PdfAnnotation> getPdfAnnotations(PdfDocument pdfDoc) {
int number = pdfDoc.getNumberOfPages();
ArrayList<PdfAnnotation> annotations = new ArrayList<>();
for(int i = 1; i <= number; i++){
annotations.addAll(pdfDoc.getPage(i).getAnnotations());
}
return annotations;
}
}