OcgPropertiesCopierTest.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.font.PdfEncodings;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.io.source.ByteArrayOutputStream;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextAnnotation;
import com.itextpdf.kernel.pdf.layer.PdfLayer;
import com.itextpdf.kernel.pdf.layer.PdfLayerMembership;
import com.itextpdf.kernel.pdf.layer.PdfOCProperties;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.kernel.pdf.xobject.PdfImageXObject;
import com.itextpdf.test.ExtendedITextTest;
import com.itextpdf.test.LogLevelConstants;
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.HashSet;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Tag;
@Tag("UnitTest")
public class OcgPropertiesCopierTest extends ExtendedITextTest {
private static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/pdf/OcgPropertiesCopierTest/";
@Test
public void copySamePageTwiceTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(new PdfLayer("name", fromDocument).getPdfObject());
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name");
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
fromDocument.copyPagesTo(1, 1, toDocument);
fromDocument.copyPagesTo(1, 1, toDocument);
OcgPropertiesCopierTest.checkLayersNameInToDocument(toDocument, names);
}
}
}
@Test
@LogMessages(
messages = @LogMessage(messageTemplate = IoLogMessageConstant.OCG_COPYING_ERROR, logLevel = LogLevelConstants.ERROR)
)
public void attemptToCopyInvalidOCGTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
PdfDictionary layer = new PdfLayer("name1", fromDocument).getPdfObject();
layer.remove(PdfName.Name);
pdfResource.addProperties(layer);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyDifferentPageWithSameOcgTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfDictionary layer = new PdfLayer("name", fromDocument).getPdfObject();
for (int i = 0; i < 5; i++) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(layer);
pdfResource.makeIndirect(fromDocument);
}
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name");
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
fromDocument.copyPagesTo(1, 2, toDocument);
fromDocument.copyPagesTo(3, 5, toDocument);
// The test verifies that identical layers on different pages are copied exactly once
OcgPropertiesCopierTest.checkLayersNameInToDocument(toDocument, names);
}
}
}
@Test
public void copyOcgOnlyFromCopiedPagesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(new PdfLayer("name1", fromDocument).getPdfObject());
pdfResource.makeIndirect(fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(new PdfLayer("name2", fromDocument).getPdfObject());
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name1");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcgWithEmptyOCGsInOCPropertiesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
PdfDictionary ocg = new PdfDictionary();
ocg.put(PdfName.Type, PdfName.OCG);
ocg.put(PdfName.Name, new PdfString("name"));
ocg.makeIndirect(fromDocument);
pdfResource.addProperties(ocg);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name");
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
// This test verifies that if the PDF is invalid, i.e. if OCProperties.OCGs is empty in the document,
// but there are OCGs that are used on the page, then OCGs will be copied
Assertions.assertTrue(fromDocument.getCatalog().getPdfObject().getAsDictionary(PdfName.OCProperties).getAsArray(PdfName.OCGs).isEmpty());
fromDocument.copyPagesTo(1, 1, toDocument);
OcgPropertiesCopierTest.checkLayersNameInToDocument(toDocument, names);
}
}
}
@Test
public void notCopyConfigsTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(new PdfLayer("name1", fromDocument).getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfObject ocg = new PdfLayer("name2", fromDocument).getPdfObject();
fromDocument.getCatalog().getOCProperties(true);
PdfDictionary ocProperties = fromDocument.getCatalog().getOCProperties(false).getPdfObject();
PdfDictionary config = new PdfDictionary();
config.put(PdfName.Name, new PdfString("configName", PdfEncodings.UNICODE_BIG));
PdfArray ocgs = new PdfArray();
ocgs.add(ocg);
config.put(PdfName.OCGs, ocgs);
ocProperties.put(PdfName.Configs, new PdfArray(config));
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name1");
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
fromDocument.copyPagesTo(1, 1, toDocument);
OcgPropertiesCopierTest.checkLayersNameInToDocument(toDocument, names);
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
// Check that the Configs field has not been copied
Assertions.assertFalse(ocProperties.getPdfObject().containsKey(PdfName.Configs));
}
}
}
@Test
@LogMessages(
messages = @LogMessage(messageTemplate = IoLogMessageConstant.DOCUMENT_HAS_CONFLICTING_OCG_NAMES)
)
public void copyOCGsWithConflictNamesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
PdfLayer layer1 = new PdfLayer("Layer1", fromDocument);
pdfResource.addProperties(layer1.getPdfObject());
PdfLayer layer2 = new PdfLayer("Layer1_2", fromDocument);
pdfResource.addProperties(layer2.getPdfObject());
new PdfLayer("Layer1_3", fromDocument);
}
fromDocBytes = outputStream.toByteArray();
}
byte[] toDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(outputStream))) {
toDocument.addNewPage();
new PdfLayer("Layer1", toDocument);
new PdfLayer("Layer1_0", toDocument);
new PdfLayer("Layer1_1", toDocument);
}
toDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("Layer1");
names.add("Layer1_0");
names.add("Layer1_1");
names.add("Layer1_2");
// NOTE: Two layers with the same name in the output document after the merge, due
// to the fact that we do not check names for conflicts in the original documents
names.add("Layer1_2");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes, toDocBytes);
}
// Copying different fields from the dictionary D test block
@Test
public void copySameRBGroupFromDifferentPages() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfLayer radio1 = new PdfLayer("Radio1", fromDocument);
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(radio1.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer radio2 = new PdfLayer("Radio2", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(radio2.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer radio3 = new PdfLayer("Radio3", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(radio3.getPdfObject());
pdfResource.makeIndirect(fromDocument);
// Should be removed
PdfLayer radio4 = new PdfLayer("Radio4", fromDocument);
List<PdfLayer> options = new ArrayList<>();
options.add(radio1);
options.add(radio2);
options.add(radio3);
options.add(radio4);
PdfLayer.addOCGRadioGroup(fromDocument, options);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(radio3.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer radio5 = new PdfLayer("Radio5", fromDocument);
options = new ArrayList<>();
options.add(radio3);
options.add(radio4);
options.add(radio5);
PdfLayer.addOCGRadioGroup(fromDocument, options);
}
fromDocBytes = outputStream.toByteArray();
}
Set<String> namesOrTitles = new HashSet<>();
namesOrTitles.add("Radio1");
namesOrTitles.add("Radio2");
namesOrTitles.add("Radio3");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfDocument toDocument = new PdfDocument(new PdfWriter(outputStream));
PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)));
fromDocument.copyPagesTo(1, 1, toDocument);
fromDocument.copyPagesTo(2, 2, toDocument);
fromDocument.copyPagesTo(3, 3, toDocument);
OcgPropertiesCopierTest.checkLayersOrTitleNameInToDocument(toDocument, namesOrTitles);
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
ocProperties.fillDictionary();
toDocument.close();
byte[] toDocOutputBytes = outputStream.toByteArray();
outputStream.close();
PdfDocument pdfDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(toDocOutputBytes)), new PdfWriter(new ByteArrayOutputStream()));
ocProperties = pdfDoc.getCatalog().getOCProperties(true);
PdfDictionary dDict = ocProperties.getPdfObject().getAsDictionary(PdfName.D);
PdfArray rbGroups = dDict.getAsArray(PdfName.RBGroups);
Assertions.assertEquals(2, rbGroups.size());
Assertions.assertEquals(3, rbGroups.getAsArray(0).size());
Assertions.assertEquals("Radio1", rbGroups.getAsArray(0).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Radio2", rbGroups.getAsArray(0).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Radio3", rbGroups.getAsArray(0).getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, rbGroups.getAsArray(1).size());
Assertions.assertEquals("Radio3", rbGroups.getAsArray(1).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
}
@Test
public void copySameOrderGroupFromDifferentPages() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfLayer parent1 = new PdfLayer("parent1", fromDocument);
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(parent1.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer child1 = new PdfLayer("child1", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(child1.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer child2 = new PdfLayer("child2", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(child2.getPdfObject());
pdfResource.makeIndirect(fromDocument);
// Should be removed
PdfLayer child3 = new PdfLayer("child3", fromDocument);
parent1.addChild(child1);
parent1.addChild(child2);
parent1.addChild(child3);
// Parent used
PdfLayer parent2 = new PdfLayer("parent2", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(parent2.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer child4 = new PdfLayer("child4", fromDocument);
parent2.addChild(child4);
// Child used
PdfLayer child5 = new PdfLayer("child5", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(child5.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer parent3 = new PdfLayer("parent3", fromDocument);
parent3.addChild(child5);
PdfLayer parent4 = PdfLayer.createTitle("parent4", fromDocument);
PdfLayer child6 = new PdfLayer("child6", fromDocument);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(child6.getPdfObject());
pdfResource.makeIndirect(fromDocument);
parent4.addChild(child6);
PdfLayer parent5 = PdfLayer.createTitle("parent5", fromDocument);
PdfLayer child7 = new PdfLayer("child7", fromDocument);
parent5.addChild(child7);
// Child used
PdfLayer grandpa1 = new PdfLayer("grandpa1", fromDocument);
PdfLayer parent6 = new PdfLayer("parent6", fromDocument);
grandpa1.addChild(parent6);
PdfLayer child8 = new PdfLayer("child8", fromDocument);
parent6.addChild(child8);
page = fromDocument.addNewPage();
pdfResource = page.getResources();
pdfResource.addProperties(child8.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfLayer child9 = new PdfLayer("child9", fromDocument);
parent6.addChild(child9);
grandpa1.addChild(new PdfLayer("parent7", fromDocument));
}
fromDocBytes = outputStream.toByteArray();
}
Set<String> namesOrTitles = new HashSet<>();
namesOrTitles.add("parent1");
namesOrTitles.add("child1");
namesOrTitles.add("child2");
namesOrTitles.add("parent2");
namesOrTitles.add("parent3");
namesOrTitles.add("child5");
namesOrTitles.add("parent4");
namesOrTitles.add("child6");
namesOrTitles.add("grandpa1");
namesOrTitles.add("parent6");
namesOrTitles.add("child8");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfDocument toDocument = new PdfDocument(new PdfWriter(outputStream));
PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)));
for (int i = 1; i <= fromDocument.getNumberOfPages(); i++) {
fromDocument.copyPagesTo(i, i, toDocument);
}
OcgPropertiesCopierTest.checkLayersOrTitleNameInToDocument(toDocument, namesOrTitles);
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
ocProperties.fillDictionary();
toDocument.close();
byte[] toDocOutputBytes = outputStream.toByteArray();
outputStream.close();
PdfDocument pdfDoc = new PdfDocument(new PdfReader(new ByteArrayInputStream(toDocOutputBytes)), new PdfWriter(new ByteArrayOutputStream()));
ocProperties = pdfDoc.getCatalog().getOCProperties(true);
PdfDictionary dDict = ocProperties.getPdfObject().getAsDictionary(PdfName.D);
PdfArray order = dDict.getAsArray(PdfName.Order);
Assertions.assertEquals(8, order.size());
Assertions.assertEquals("parent1", order.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(2, order.getAsArray(1).size());
Assertions.assertEquals("child1", order.getAsArray(1).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("child2", order.getAsArray(1).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("parent2", order.getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("parent3", order.getAsDictionary(3).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, order.getAsArray(4).size());
Assertions.assertEquals("child5", order.getAsArray(4).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(2, order.getAsArray(5).size());
Assertions.assertEquals("parent4", order.getAsArray(5).getAsString(0).toUnicodeString());
Assertions.assertEquals("child6", order.getAsArray(5).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("grandpa1", order.getAsDictionary(6).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(2, order.getAsArray(7).size());
Assertions.assertEquals("parent6", order.getAsArray(7).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, order.getAsArray(7).getAsArray(1).size());
Assertions.assertEquals("child8", order.getAsArray(7).getAsArray(1).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
}
@Test
public void copyOrderToEmptyDocumentTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
// One layer which used in resources
PdfLayer layer1 = new PdfLayer("Layer1", fromDocument);
pdfResource.addProperties(layer1.getPdfObject());
// One layer which not used in resources (will be ignored)
new PdfLayer("Layer2", fromDocument);
// Unused title with used children (level 1 in layers hierarchy)
PdfLayer grandpa1 = PdfLayer.createTitle("Grandpa1", fromDocument);
// Unused title with used children (level 2 in layers hierarchy)
PdfLayer parent1 = PdfLayer.createTitle("Parent1", fromDocument);
parent1.addChild(new PdfLayer("Child1", fromDocument));
PdfLayer child2 = new PdfLayer("Child2", fromDocument);
pdfResource.addProperties(child2.getPdfObject());
parent1.addChild(child2);
grandpa1.addChild(parent1);
grandpa1.addChild(new PdfLayer("Child3", fromDocument));
PdfLayer child4 = new PdfLayer("Child4", fromDocument);
pdfResource.addProperties(child4.getPdfObject());
grandpa1.addChild(child4);
// Unused layer with used children
PdfLayer parent2 = new PdfLayer("Parent2", fromDocument);
PdfLayer child5 = new PdfLayer("Child5", fromDocument);
parent2.addChild(child5);
pdfResource.addProperties(child5.getPdfObject());
parent2.addChild(new PdfLayer("Child6", fromDocument));
// Unused title with unused children (will be ignored)
PdfLayer parent3 = PdfLayer.createTitle("Parent3", fromDocument);
parent3.addChild(new PdfLayer("Child7", fromDocument));
parent3.addChild(new PdfLayer("Child8", fromDocument));
// Unused layer with unused children (will be ignored)
PdfLayer parent4 = new PdfLayer("Parent4", fromDocument);
parent4.addChild(new PdfLayer("Child9", fromDocument));
parent4.addChild(new PdfLayer("Child10", fromDocument));
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
Set<String> namesOrTitles = new HashSet<>();
namesOrTitles.add("Layer1");
namesOrTitles.add("Grandpa1");
namesOrTitles.add("Parent1");
namesOrTitles.add("Child2");
namesOrTitles.add("Child4");
namesOrTitles.add("Parent2");
namesOrTitles.add("Child5");
PdfArray order = OcgPropertiesCopierTest.copyPagesAndAssertLayersNameAndGetDDict(namesOrTitles, fromDocBytes, null).getAsArray(PdfName.Order);
Assertions.assertEquals(4, order.size());
Assertions.assertEquals("Layer1", order.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
PdfArray subArray = order.getAsArray(1);
Assertions.assertEquals(3, subArray.size());
Assertions.assertEquals("Grandpa1", subArray.getAsString(0).toUnicodeString());
Assertions.assertEquals(2, subArray.getAsArray(1).size());
Assertions.assertEquals("Parent1", subArray.getAsArray(1).getAsString(0).toUnicodeString());
Assertions.assertEquals("Child2", subArray.getAsArray(1).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Child4", subArray.getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Parent2", order.getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, order.getAsArray(3).size());
Assertions.assertEquals("Child5", order.getAsArray(3).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
}
@Test
public void copyDFieldsToEmptyDocumentTest() throws IOException {
byte[] fromDocBytes = OcgPropertiesCopierTest.getDocumentWithAllDFields();
Set<String> namesOrTitles = new HashSet<>();
namesOrTitles.add("Parent1");
namesOrTitles.add("Child1");
namesOrTitles.add("Locked1");
namesOrTitles.add("Radio1");
namesOrTitles.add("Radio3");
namesOrTitles.add("Radio4");
namesOrTitles.add("On1");
namesOrTitles.add("Off1");
namesOrTitles.add("noPrint1");
PdfDictionary dDict = OcgPropertiesCopierTest.copyPagesAndAssertLayersNameAndGetDDict(namesOrTitles, fromDocBytes, null);
PdfArray locked = dDict.getAsArray(PdfName.Locked);
Assertions.assertEquals(1, locked.size());
Assertions.assertEquals("Locked1", locked.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
PdfArray rbGroups = dDict.getAsArray(PdfName.RBGroups);
Assertions.assertEquals(2, rbGroups.size());
Assertions.assertEquals(2, rbGroups.getAsArray(0).size());
Assertions.assertEquals("Radio1", rbGroups.getAsArray(0).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Radio3", rbGroups.getAsArray(0).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, rbGroups.getAsArray(1).size());
Assertions.assertEquals("Radio4", rbGroups.getAsArray(1).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertNull(dDict.getAsArray(PdfName.ON));
PdfArray off = dDict.getAsArray(PdfName.OFF);
Assertions.assertEquals(1, off.size());
Assertions.assertEquals("Off1", off.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertNull(dDict.getAsArray(PdfName.Creator));
Assertions.assertEquals("Name", dDict.getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(PdfName.ON, dDict.getAsName(PdfName.BaseState));
PdfArray asArray = dDict.getAsArray(PdfName.AS);
Assertions.assertEquals(1, asArray.size());
Assertions.assertEquals(1, asArray.getAsDictionary(0).getAsArray(PdfName.Category).size());
Assertions.assertEquals(PdfName.Print, asArray.getAsDictionary(0).getAsArray(PdfName.Category).getAsName(0));
Assertions.assertEquals("noPrint1", asArray.getAsDictionary(0).getAsArray(PdfName.OCGs).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(PdfName.View, dDict.getAsName(PdfName.Intent));
Assertions.assertEquals(PdfName.VisiblePages, dDict.getAsName(PdfName.ListMode));
}
@Test
public void copyDFieldsToDocumentWithDDictTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
// Order
PdfLayer parent1 = new PdfLayer("from_Parent1", fromDocument);
PdfLayer child1 = new PdfLayer("from_Child1", fromDocument);
pdfResource.addProperties(child1.getPdfObject());
parent1.addChild(child1);
// Locked
PdfLayer locked1 = new PdfLayer("from_Locked1", fromDocument);
locked1.setLocked(true);
pdfResource.addProperties(locked1.getPdfObject());
// RBGroups
PdfLayer radio1 = new PdfLayer("from_Radio1", fromDocument);
pdfResource.addProperties(radio1.getPdfObject());
List<PdfLayer> options = new ArrayList<>();
options.add(radio1);
PdfLayer.addOCGRadioGroup(fromDocument, options);
// ON
PdfLayer on1 = new PdfLayer("from_On1", fromDocument);
on1.setOn(true);
pdfResource.addProperties(on1.getPdfObject());
// OFF
PdfLayer off1 = new PdfLayer("from_Off1", fromDocument);
off1.setOn(false);
pdfResource.addProperties(off1.getPdfObject());
pdfResource.makeIndirect(fromDocument);
PdfOCProperties ocProperties = fromDocument.getCatalog().getOCProperties(true);
// Creator (will be deleted and not copied)
ocProperties.getPdfObject().put(PdfName.Creator, new PdfString("from_CreatorName", PdfEncodings.UNICODE_BIG));
// Name (will be automatically changed)
ocProperties.getPdfObject().put(PdfName.Name, new PdfString("from_Name", PdfEncodings.UNICODE_BIG));
// BaseState (will be not copied)
ocProperties.getPdfObject().put(PdfName.BaseState, new PdfName("Unchanged"));
// AS (will be automatically changed)
ocProperties.getPdfObject().put(PdfName.AS, new PdfArray());
PdfLayer noPrint1 = new PdfLayer("from_noPrint1", fromDocument);
pdfResource.addProperties(noPrint1.getPdfObject());
noPrint1.setPrint("Print", false);
// Intent (will be not copied)
ocProperties.getPdfObject().put(PdfName.Intent, PdfName.View);
// ListMode (will be not copied)
ocProperties.getPdfObject().put(PdfName.ListMode, new PdfName("AllPages"));
}
fromDocBytes = outputStream.toByteArray();
}
byte[] toDocBytes = OcgPropertiesCopierTest.getDocumentWithAllDFields();
Set<String> namesOrTitles = new HashSet<>();
namesOrTitles.add("Parent1");
namesOrTitles.add("Child1");
namesOrTitles.add("Locked1");
namesOrTitles.add("Locked2");
namesOrTitles.add("Radio1");
namesOrTitles.add("Radio2");
namesOrTitles.add("Radio3");
namesOrTitles.add("Radio4");
namesOrTitles.add("On1");
namesOrTitles.add("On2");
namesOrTitles.add("Off1");
namesOrTitles.add("Off2");
namesOrTitles.add("noPrint1");
namesOrTitles.add("from_Parent1");
namesOrTitles.add("from_Child1");
namesOrTitles.add("from_Locked1");
namesOrTitles.add("from_Radio1");
namesOrTitles.add("from_On1");
namesOrTitles.add("from_Off1");
namesOrTitles.add("from_noPrint1");
PdfDictionary dDict = OcgPropertiesCopierTest.copyPagesAndAssertLayersNameAndGetDDict(namesOrTitles, fromDocBytes, toDocBytes);
PdfArray locked = dDict.getAsArray(PdfName.Locked);
Assertions.assertEquals(3, locked.size());
Assertions.assertEquals("Locked1", locked.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Locked2", locked.getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("from_Locked1", locked.getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
PdfArray rbGroups = dDict.getAsArray(PdfName.RBGroups);
Assertions.assertEquals(3, rbGroups.size());
Assertions.assertEquals(3, rbGroups.getAsArray(0).size());
Assertions.assertEquals("Radio1", rbGroups.getAsArray(0).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Radio2", rbGroups.getAsArray(0).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Radio3", rbGroups.getAsArray(0).getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, rbGroups.getAsArray(1).size());
Assertions.assertEquals("Radio4", rbGroups.getAsArray(1).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(1, rbGroups.getAsArray(2).size());
Assertions.assertEquals("from_Radio1", rbGroups.getAsArray(2).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertNull(dDict.getAsArray(PdfName.ON));
PdfArray off = dDict.getAsArray(PdfName.OFF);
Assertions.assertEquals(3, off.size());
Assertions.assertEquals("Off1", off.getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("Off2", off.getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("from_Off1", off.getAsDictionary(2).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertNull(dDict.getAsArray(PdfName.Creator));
Assertions.assertEquals("Name", dDict.getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(PdfName.ON, dDict.getAsName(PdfName.BaseState));
PdfArray asArray = dDict.getAsArray(PdfName.AS);
Assertions.assertEquals(1, asArray.size());
Assertions.assertEquals(1, asArray.getAsDictionary(0).getAsArray(PdfName.Category).size());
Assertions.assertEquals(PdfName.Print, asArray.getAsDictionary(0).getAsArray(PdfName.Category).getAsName(0));
Assertions.assertEquals(2, asArray.getAsDictionary(0).getAsArray(PdfName.OCGs).size());
Assertions.assertEquals("noPrint1", asArray.getAsDictionary(0).getAsArray(PdfName.OCGs).getAsDictionary(0).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals("from_noPrint1", asArray.getAsDictionary(0).getAsArray(PdfName.OCGs).getAsDictionary(1).getAsString(PdfName.Name).toUnicodeString());
Assertions.assertEquals(PdfName.View, dDict.getAsName(PdfName.Intent));
Assertions.assertEquals(PdfName.VisiblePages, dDict.getAsName(PdfName.ListMode));
}
// Copy OCGs from different locations (OCMDs, annotations, content streams, xObjects) test block
@Test
public void copyOcgFromStreamPropertiesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(new PdfLayer("name", fromDocument).getPdfObject());
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcgFromAnnotationTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10));
annotation.setLayer(new PdfLayer("someName", fromDocument));
page.addAnnotation(annotation);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcgFromApAnnotationTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10));
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(50, 10));
formXObject.setLayer(new PdfLayer("someName1", fromDocument));
formXObject.makeIndirect(fromDocument);
PdfDictionary nDict = new PdfDictionary();
nDict.put(PdfName.ON, formXObject.getPdfObject());
annotation.setAppearance(PdfName.N, nDict);
formXObject = new PdfFormXObject(new Rectangle(50, 10));
formXObject.setLayer(new PdfLayer("someName2", fromDocument));
PdfResources formResources = formXObject.getResources();
formResources.addProperties(new PdfLayer("someName3", fromDocument).getPdfObject());
formXObject.makeIndirect(fromDocument);
PdfDictionary rDict = new PdfDictionary();
rDict.put(PdfName.OFF, formXObject.getPdfObject());
annotation.setAppearance(PdfName.R, rDict);
formXObject = new PdfFormXObject(new Rectangle(50, 10));
formXObject.setLayer(new PdfLayer("someName4", fromDocument));
formXObject.makeIndirect(fromDocument);
annotation.setAppearance(PdfName.D, formXObject.getPdfObject());
page.addAnnotation(annotation);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName1");
names.add("someName2");
names.add("someName3");
names.add("someName4");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcgFromImageXObjectTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
ImageData imageData = ImageDataFactory.create(SOURCE_FOLDER + "smallImage.png");
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
imageXObject.setLayer(new PdfLayer("someName", fromDocument));
imageXObject.makeIndirect(fromDocument);
pdfResource.addImage(imageXObject);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcgsFromFormXObjectRecursivelyTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(50, 10));
formXObject.setLayer(new PdfLayer("someName1", fromDocument));
PdfResources formResources = formXObject.getResources();
formResources.addProperties(new PdfLayer("someName2", fromDocument).getPdfObject());
ImageData imageData = ImageDataFactory.create(SOURCE_FOLDER + "smallImage.png");
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
imageXObject.setLayer(new PdfLayer("someName3", fromDocument));
imageXObject.makeIndirect(fromDocument);
formResources.addImage(imageXObject);
formResources.makeIndirect(fromDocument);
formXObject.makeIndirect(fromDocument);
pdfResource.addForm(formXObject);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName1");
names.add("someName2");
names.add("someName3");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcmdByDictionaryFromStreamPropertiesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
// Pass one name to the createOcmdDict method, so the OCMD.OCGs field will be a dictionary, not an array
pdfResource.addProperties(OcgPropertiesCopierTest.createOcmdDict(new String[] {"name1"}, fromDocument));
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name1");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcmdByArrayFromStreamPropertiesTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
pdfResource.addProperties(OcgPropertiesCopierTest.createOcmdDict(new String[] {"name1", "name2"}, fromDocument));
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("name1");
names.add("name2");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcmdFromAnnotationTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfAnnotation annotation = new PdfTextAnnotation(new Rectangle(50, 10));
annotation.setLayer(new PdfLayerMembership(OcgPropertiesCopierTest.createOcmdDict(new String[] {"someName1", "someName2"}, fromDocument)));
page.addAnnotation(annotation);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName1");
names.add("someName2");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcmdFromImageXObjectTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
ImageData imageData = ImageDataFactory.create(SOURCE_FOLDER + "smallImage.png");
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
imageXObject.setLayer(new PdfLayerMembership(OcgPropertiesCopierTest.createOcmdDict(new String[] {"someName1", "someName2"}, fromDocument)));
imageXObject.makeIndirect(fromDocument);
pdfResource.addImage(imageXObject);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName1");
names.add("someName2");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyOcmdsFromFormXObjectRecursivelyTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
PdfFormXObject formXObject = new PdfFormXObject(new Rectangle(50, 10));
formXObject.setLayer(new PdfLayerMembership(OcgPropertiesCopierTest.createOcmdDict(new String[] {"someName1", "someName2"}, fromDocument)));
PdfResources formResources = formXObject.getResources();
formResources.addProperties(OcgPropertiesCopierTest.createOcmdDict(new String[] {"someName3", "someName4"}, fromDocument));
ImageData imageData = ImageDataFactory.create(SOURCE_FOLDER + "smallImage.png");
PdfImageXObject imageXObject = new PdfImageXObject(imageData);
imageXObject.setLayer(new PdfLayerMembership(OcgPropertiesCopierTest.createOcmdDict(new String[] {"someName5", "someName6"}, fromDocument)));
imageXObject.makeIndirect(fromDocument);
formResources.addImage(imageXObject);
formResources.makeIndirect(fromDocument);
formXObject.makeIndirect(fromDocument);
pdfResource.addForm(formXObject);
pdfResource.makeIndirect(fromDocument);
fromDocument.getCatalog().getOCProperties(true);
}
fromDocBytes = outputStream.toByteArray();
}
List<String> names = new ArrayList<>();
names.add("someName1");
names.add("someName2");
names.add("someName3");
names.add("someName4");
names.add("someName5");
names.add("someName6");
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes);
}
@Test
public void copyEmptyOcgTest() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfDictionary DDic = new PdfDictionary();
DDic.put(PdfName.ON, new PdfArray());
DDic.put(PdfName.Order, new PdfArray());
DDic.put(PdfName.RBGroups, new PdfArray());
PdfDictionary OcDic = new PdfDictionary();
OcDic.put(PdfName.D, DDic);
OcDic.put(PdfName.OCGs, new PdfArray());
fromDocument.getCatalog().put(PdfName.OCProperties,OcDic);
}
fromDocBytes = outputStream.toByteArray();
}
try (PdfDocument toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
fromDocument.copyPagesTo(1, 1, toDocument);
Assertions.assertNull(toDocument.getCatalog().getOCProperties(false));
}
}
}
private static byte[] getDocumentWithAllDFields() throws IOException {
byte[] fromDocBytes;
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
try (PdfDocument fromDocument = new PdfDocument(new PdfWriter(outputStream))) {
PdfPage page = fromDocument.addNewPage();
PdfResources pdfResource = page.getResources();
// Order
PdfLayer parent1 = new PdfLayer("Parent1", fromDocument);
PdfLayer child1 = new PdfLayer("Child1", fromDocument);
pdfResource.addProperties(child1.getPdfObject());
parent1.addChild(child1);
// Locked
PdfLayer locked1 = new PdfLayer("Locked1", fromDocument);
locked1.setLocked(true);
pdfResource.addProperties(locked1.getPdfObject());
PdfLayer locked2 = new PdfLayer("Locked2", fromDocument);
locked2.setLocked(true);
// RBGroups
PdfLayer radio1 = new PdfLayer("Radio1", fromDocument);
pdfResource.addProperties(radio1.getPdfObject());
PdfLayer radio2 = new PdfLayer("Radio2", fromDocument);
PdfLayer radio3 = new PdfLayer("Radio3", fromDocument);
pdfResource.addProperties(radio3.getPdfObject());
List<PdfLayer> options = new ArrayList<>();
options.add(radio1);
options.add(radio2);
options.add(radio3);
PdfLayer.addOCGRadioGroup(fromDocument, options);
options = new ArrayList<>();
PdfLayer radio4 = new PdfLayer("Radio4", fromDocument);
options.add(radio4);
pdfResource.addProperties(radio4.getPdfObject());
PdfLayer.addOCGRadioGroup(fromDocument, options);
// ON
PdfLayer on1 = new PdfLayer("On1", fromDocument);
on1.setOn(true);
pdfResource.addProperties(on1.getPdfObject());
PdfLayer on2 = new PdfLayer("On2", fromDocument);
on2.setOn(true);
// OFF
PdfLayer off1 = new PdfLayer("Off1", fromDocument);
off1.setOn(false);
pdfResource.addProperties(off1.getPdfObject());
PdfLayer off2 = new PdfLayer("Off2", fromDocument);
off2.setOn(false);
pdfResource.makeIndirect(fromDocument);
PdfOCProperties ocProperties = fromDocument.getCatalog().getOCProperties(true);
PdfDictionary dDictionary = ocProperties.getPdfObject().getAsDictionary(PdfName.D);
// Creator (will be not copied)
dDictionary.put(PdfName.Creator, new PdfString("CreatorName", PdfEncodings.UNICODE_BIG));
// Name (will be automatically changed)
dDictionary.put(PdfName.Name, new PdfString("Name", PdfEncodings.UNICODE_BIG));
// BaseState (will be not copied)
dDictionary.put(PdfName.BaseState, PdfName.ON);
// AS (will be automatically changed)
PdfArray asArray = new PdfArray();
PdfDictionary dict = new PdfDictionary();
dict.put(PdfName.Event, PdfName.View);
PdfArray categoryArray = new PdfArray();
categoryArray.add(PdfName.Zoom);
dict.put(PdfName.Category, categoryArray);
PdfArray ocgs = new PdfArray();
ocgs.add(locked1.getPdfObject());
dict.put(PdfName.OCGs, ocgs);
asArray.add(dict);
dDictionary.put(PdfName.AS, asArray);
PdfLayer noPrint1 = new PdfLayer("noPrint1", fromDocument);
pdfResource.addProperties(noPrint1.getPdfObject());
noPrint1.setPrint("Print", false);
// Intent (will be not copied)
dDictionary.put(PdfName.Intent, PdfName.View);
// ListMode (will be not copied)
dDictionary.put(PdfName.ListMode, PdfName.VisiblePages);
}
fromDocBytes = outputStream.toByteArray();
}
return fromDocBytes;
}
private static PdfDictionary createOcmdDict(String[] names, PdfDocument document) {
PdfDictionary ocmd = new PdfDictionary();
ocmd.put(PdfName.Type, PdfName.OCMD);
if (names.length > 1) {
PdfArray ocgs = new PdfArray();
for (String name : names) {
ocgs.add(new PdfLayer(name, document).getPdfObject());
}
ocmd.put(PdfName.OCGs, ocgs);
} else {
ocmd.put(PdfName.OCGs, new PdfLayer(names[0], document).getPdfObject());
}
ocmd.makeIndirect(document);
return ocmd;
}
private static PdfDictionary copyPagesAndAssertLayersNameAndGetDDict(Set<String> namesOrTitles, byte[] fromDocBytes, byte[] toDocBytes) throws IOException {
PdfDocument toDocument;
if (toDocBytes == null) {
toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
} else {
toDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(toDocBytes)), new PdfWriter(new ByteArrayOutputStream()));
}
PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)));
fromDocument.copyPagesTo(1, 1, toDocument);
OcgPropertiesCopierTest.checkLayersOrTitleNameInToDocument(toDocument, namesOrTitles);
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
return ocProperties.getPdfObject().getAsDictionary(PdfName.D);
}
private static void copyPagesAndAssertLayersName(List<String> names, byte[] fromDocBytes, byte[] toDocBytes) throws IOException {
PdfDocument toDocument;
if (toDocBytes == null) {
toDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()));
} else {
toDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(toDocBytes)), new PdfWriter(new ByteArrayOutputStream()));
}
try (PdfDocument fromDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(fromDocBytes)))) {
fromDocument.copyPagesTo(1, 1, toDocument);
OcgPropertiesCopierTest.checkLayersNameInToDocument(toDocument, names);
}
toDocument.close();
}
private static void checkLayersOrTitleNameInToDocument(PdfDocument toDocument, Set<String> namesOrTitles) {
Assertions.assertNotNull(toDocument.getCatalog());
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
ocProperties.fillDictionary();
Assertions.assertNotNull(ocProperties);
Assertions.assertEquals(namesOrTitles.size(), ocProperties.getLayers().size());
for (PdfLayer layer : ocProperties.getLayers()) {
Assertions.assertNotNull(layer);
String layerTitle = layer.getTitle();
if (namesOrTitles.contains(layerTitle)) {
Assertions.assertTrue(namesOrTitles.remove(layerTitle));
} else {
PdfDictionary layerDictionary = layer.getPdfObject();
Assertions.assertNotNull(layerDictionary.get(PdfName.Name));
String layerName = layerDictionary.get(PdfName.Name).toString();
Assertions.assertTrue(namesOrTitles.remove(layerName));
}
}
}
private static void checkLayersNameInToDocument(PdfDocument toDocument, List<String> names) {
Assertions.assertNotNull(toDocument.getCatalog());
PdfOCProperties ocProperties = toDocument.getCatalog().getOCProperties(false);
Assertions.assertNotNull(ocProperties);
Assertions.assertEquals(names.size(), ocProperties.getLayers().size());
for (PdfLayer layer : ocProperties.getLayers()) {
Assertions.assertNotNull(layer);
PdfDictionary layerDictionary = layer.getPdfObject();
Assertions.assertNotNull(layerDictionary.get(PdfName.Name));
String layerNameString = layerDictionary.get(PdfName.Name).toString();
Assertions.assertTrue(names.contains(layerNameString));
names.remove(layerNameString);
}
}
private static void copyPagesAndAssertLayersName(List<String> names, byte[] fromDocBytes) throws IOException {
OcgPropertiesCopierTest.copyPagesAndAssertLayersName(names, fromDocBytes, null);
}
}