PdfAnnotationFlattenerTest.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.utils;
import com.itextpdf.commons.utils.PlaceHolderTextUtil;
import com.itextpdf.commons.utils.PlaceHolderTextUtil.PlaceHolderTextBy;
import com.itextpdf.io.font.constants.StandardFonts;
import com.itextpdf.io.source.ByteArrayOutputStream;
import com.itextpdf.kernel.colors.Color;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.exceptions.PdfException;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.logs.KernelLogMessageConstant;
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.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfString;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.action.PdfAction;
import com.itextpdf.kernel.pdf.annot.PdfAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfCircleAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfLinkAnnotation;
import com.itextpdf.kernel.pdf.annot.PdfTextMarkupAnnotation;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.kernel.utils.annotationsflattening.DefaultAnnotationFlattener;
import com.itextpdf.kernel.utils.annotationsflattening.IAnnotationFlattener;
import com.itextpdf.kernel.utils.annotationsflattening.PdfAnnotationFlattenFactory;
import com.itextpdf.kernel.utils.annotationsflattening.RemoveWithoutDrawingFlattener;
import com.itextpdf.kernel.utils.annotationsflattening.WarnFormfieldFlattener;
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.IOException;
import java.util.ArrayList;
import java.util.Collections;
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;
@Tag("IntegrationTest")
public class PdfAnnotationFlattenerTest extends ExtendedITextTest {
public static final String SOURCE_FOLDER = "./src/test/resources/com/itextpdf/kernel/utils/flatteningTest/";
public static final String DESTINATION_FOLDER = TestUtil.getOutputPath() + "/kernel/utils/flatteningTest/";
@BeforeAll
public static void beforeClass() {
createDestinationFolder(DESTINATION_FOLDER);
}
@AfterAll
public static void afterClass() {
CompareTool.cleanup(DESTINATION_FOLDER);
}
@Test
public void testNullAnnotations() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
List<PdfAnnotation> annotations = null;
Assertions.assertThrows(PdfException.class, () -> {
flattener.flatten(annotations);
});
}
}
@Test
public void testNullDocument() {
PdfDocument pdfDoc = null;
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
Assertions.assertThrows(PdfException.class, () -> {
flattener.flatten(pdfDoc);
});
}
@Test
public void testNullPageDrawAppearanceWorker() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
IAnnotationFlattener flattener = new DefaultAnnotationFlattener();
PdfPage page = pdfDoc.getFirstPage();
Assertions.assertThrows(PdfException.class, () -> {
flattener.flatten(null, page);
});
}
}
@Test
public void testNullAnnotationDrawAppearanceWorker() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
IAnnotationFlattener flattener = new DefaultAnnotationFlattener();
Assertions.assertThrows(PdfException.class, () -> {
flattener.flatten(new PdfLinkAnnotation(new Rectangle(20, 20)), null);
});
}
}
@Test
public void testEmptyAnnotations() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(new ArrayList<>());
Assertions.assertEquals(0, pdfDoc.getFirstPage().getAnnotsSize());
}
}
@Test
public void defaultAppearanceGetsRendered() throws IOException, InterruptedException {
String resultFile = DESTINATION_FOLDER + "default_annotations_app.pdf";
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(resultFile))) {
PdfFormXObject formN = new PdfFormXObject(new Rectangle(179, 530, 122, 21));
PdfCanvas canvasN = new PdfCanvas(formN, pdfDoc);
PdfAnnotation annotation = new PdfLinkAnnotation(new Rectangle(100, 540, 300, 50)).
setAction(PdfAction.createURI("http://itextpdf.com/node"));
canvasN
.saveState()
.setColor(ColorConstants.RED, true)
.setLineWidth(1.5f)
.rectangle(180, 531, 120, 48)
.fill()
.restoreState();
canvasN.saveState()
.beginText()
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 12)
.setColor(ColorConstants.YELLOW, true)
.moveText(180, 531)
.showText("Hello appearance")
.endText()
.restoreState();
;
annotation.setNormalAppearance(formN.getPdfObject());
pdfDoc.addNewPage();
pdfDoc.getFirstPage().addAnnotation(annotation);
DefaultAnnotationFlattener worker =
new DefaultAnnotationFlattener();
worker.flatten(annotation, pdfDoc.getFirstPage());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile,
SOURCE_FOLDER + "cmp_default_annotations_app.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = KernelLogMessageConstant.FLATTENING_IS_NOT_YET_SUPPORTED)})
public void unknownAnnotationsDefaultImplementation() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
PdfDictionary unknownAnnot = new PdfDictionary();
unknownAnnot.put(PdfName.Subtype, new PdfName("Unknown"));
unknownAnnot.put(PdfName.Rect, new PdfArray(new int[] {100, 100, 200, 200}));
PdfAnnotation unknownAnnotation = PdfAnnotation.makeAnnotation(unknownAnnot);
pdfDoc.addNewPage();
pdfDoc.getFirstPage().addAnnotation(unknownAnnotation);
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(Collections.singletonList(unknownAnnotation));
//Annotation is not removed in default implementation
Assertions.assertEquals(1, pdfDoc.getFirstPage().getAnnotsSize());
}
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = KernelLogMessageConstant.FLATTENING_IS_NOT_YET_SUPPORTED)})
public void nullTypeAnnotationsDefaultImplementation() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
PdfDictionary unknownAnnot = new PdfDictionary();
unknownAnnot.put(PdfName.Rect, new PdfArray(new int[] {100, 100, 200, 200}));
PdfAnnotation unknownAnnotation = PdfAnnotation.makeAnnotation(unknownAnnot);
pdfDoc.addNewPage();
pdfDoc.getFirstPage().addAnnotation(unknownAnnotation);
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(Collections.singletonList(unknownAnnotation));
//Annotation is not removed in default implementation
Assertions.assertEquals(1, pdfDoc.getFirstPage().getAnnotsSize());
}
}
@Test
public void overwriteDefaultImplementation() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
int[] borders = {0, 0, 1};
pdfDoc.addNewPage();
pdfDoc.getFirstPage().addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 540, 300, 25)).
setAction(PdfAction.createURI("http://itextpdf.com/node")).
setBorder(new PdfArray(borders)));
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener(new CustomPdfAnnotationFlattenFactory());
flattener.flatten(pdfDoc.getFirstPage().getAnnotations());
Assertions.assertEquals(0, pdfDoc.getFirstPage().getAnnotsSize());
}
}
@Test
public void removeQuadPoints() throws IOException, InterruptedException {
String fileToFlatten = DESTINATION_FOLDER + "file_to_quadpoints.pdf";
String resultFile = DESTINATION_FOLDER + "flattened_quadpoints.pdf";
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(fileToFlatten))) {
PdfPage page = pdfDoc.addNewPage();
PdfCanvas canvas = new PdfCanvas(page);
float x = 50;
float y = 750;
float textLength = 350;
float[] points = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
PdfAnnotation annot = createTextAnnotation(canvas, x, y, points, PdfName.StrikeOut, ColorConstants.RED);
annot.getPdfObject().remove(PdfName.QuadPoints);
page.addAnnotation(annot);
}
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createOutputReader(fileToFlatten), CompareTool.createTestPdfWriter(resultFile))) {
new PdfAnnotationFlattener()
.flatten(pdfDoc.getFirstPage().getAnnotations());
}
//it is expected that the line is the middle of the page because the annotation whole rectangle is the
// size of the page, it's also expected that underline will not show up as it is at the bottom of the page
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_text_quadpoints.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void invalidQuadPoints() throws IOException, InterruptedException {
String fileToFlatten = DESTINATION_FOLDER + "file_to_invalid_quadpoints.pdf";
String resultFile = DESTINATION_FOLDER + "flattened_invalid_quadpoints.pdf";
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(fileToFlatten))) {
PdfPage page = pdfDoc.addNewPage();
PdfCanvas canvas = new PdfCanvas(page);
float x = 50;
float y = 750;
float textLength = 350;
float[] points = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
PdfAnnotation annot = createTextAnnotation(canvas, x, y, points, PdfName.StrikeOut, ColorConstants.RED);
annot.getPdfObject().put(PdfName.QuadPoints, new PdfArray(new float[] {0, 0, 0, 0, 0, 0}));
page.addAnnotation(annot);
}
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createOutputReader(fileToFlatten), CompareTool.createTestPdfWriter(resultFile))) {
new PdfAnnotationFlattener()
.flatten(pdfDoc.getFirstPage().getAnnotations());
}
//it is expected that the line is the middle of the page because the annotation whole rectangle is the
// size of the page, it's also expected that underline will not show up as it is at the bottom of the page
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_invalid_quadpoints.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void testEmptyParamListDoesntDeleteAnyAnnots() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
int[] borders = {0, 0, 1};
pdfDoc.getFirstPage().addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 540, 300, 25)).
setAction(PdfAction.createURI("http://itextpdf.com/node")).
setBorder(new PdfArray(borders)));
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(new ArrayList<>());
Assertions.assertEquals(1, pdfDoc.getFirstPage().getAnnotsSize());
}
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = KernelLogMessageConstant.FLATTENING_IS_NOT_YET_SUPPORTED)})
public void testListFromDifferentPageDoesntDeleteAnyAnnotsButWarnsUser() {
try (PdfDocument pdfDoc = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
pdfDoc.addNewPage();
pdfDoc.addNewPage();
int[] borders = {0, 0, 1};
pdfDoc.getPage(1).addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 540, 300, 25)).
setAction(PdfAction.createURI("http://itextpdf.com/node")).
setBorder(new PdfArray(borders)));
pdfDoc.getPage(2).addAnnotation(new PdfLinkAnnotation(new Rectangle(100, 540, 300, 25)).
setAction(PdfAction.createURI("http://itextpdf.com/node")).
setBorder(new PdfArray(borders)));
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(pdfDoc.getPage(2).getAnnotations());
Assertions.assertEquals(1, pdfDoc.getFirstPage().getAnnotsSize());
Assertions.assertEquals(1, pdfDoc.getPage(2).getAnnotsSize());
}
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = KernelLogMessageConstant.FLATTENING_IS_NOT_YET_SUPPORTED)})
public void flattenPdfLink() throws IOException, InterruptedException {
String resultFile = DESTINATION_FOLDER + "flattened_pdf_link.pdf";
try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(SOURCE_FOLDER + "simple_link_annotation.pdf"),
CompareTool.createTestPdfWriter(resultFile))) {
new PdfAnnotationFlattener().flatten(pdfDoc);
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattened_pdf_link.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenPdfLinkWithDefaultAppearance() throws IOException, InterruptedException {
String resultFile = DESTINATION_FOLDER + "flattened_DA_pdf_link.pdf";
try (PdfDocument pdfDoc = new PdfDocument(new PdfReader(SOURCE_FOLDER + "simple_link_annotation.pdf"),
CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotation annot = pdfDoc.getFirstPage().getAnnotations().get(0);
annot.setNormalAppearance(new PdfDictionary());
PdfFormXObject formN = new PdfFormXObject(new Rectangle(179, 530, 122, 21));
PdfCanvas canvasN = new PdfCanvas(formN, pdfDoc);
canvasN
.saveState()
.setColor(ColorConstants.RED, true)
.setLineWidth(1.5f)
.rectangle(180, 531, 120, 48)
.fill()
.restoreState();
annot.setNormalAppearance(formN.getPdfObject());
new PdfAnnotationFlattener().flatten(pdfDoc);
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattened_DA_pdf_link.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenTextMarkupAnnotations()
throws IOException, InterruptedException {
String fileToFlatten = DESTINATION_FOLDER + "file_to_flatten_markup_text.pdf";
String resultFile = DESTINATION_FOLDER + "flattened_markup_text.pdf";
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createTestPdfWriter(fileToFlatten))) {
PdfPage page = pdfDoc.addNewPage();
PdfCanvas canvas = new PdfCanvas(page);
float x = 50;
float y = 750;
float textLength = 350;
float[] points = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
page.addAnnotation(createTextAnnotation(canvas, x, y, points, PdfName.Underline, ColorConstants.RED));
y -= 50;
float[] points2 = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
page.addAnnotation(createTextAnnotation(canvas, x, y, points2, PdfName.StrikeOut, ColorConstants.BLUE));
y -= 50;
float[] points3 = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
page.addAnnotation(createTextAnnotation(canvas, x, y, points3, PdfName.Squiggly, ColorConstants.RED));
y -= 50;
float[] points4 = {x, y + 15, x + textLength, y + 15, x, y - 4, x + textLength, y - 4};
page.addAnnotation(createTextAnnotation(canvas, x, y, points4, PdfName.Highlight, ColorConstants.YELLOW));
}
try (PdfDocument pdfDoc = new PdfDocument(CompareTool.createOutputReader(fileToFlatten), CompareTool.createTestPdfWriter(resultFile))) {
new PdfAnnotationFlattener()
.flatten(pdfDoc.getFirstPage().getAnnotations());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_text_markup_flatten.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
@LogMessages(messages = {@LogMessage(messageTemplate = KernelLogMessageConstant.FLATTENING_IS_NOT_YET_SUPPORTED)})
public void flattenLinkAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenLinkAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenLinkAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(1, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenLinkAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
@LogMessages(messages = {
@LogMessage(messageTemplate = KernelLogMessageConstant.FORMFIELD_ANNOTATION_WILL_NOT_BE_FLATTENED)})
public void flattenWidgetAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenWidgetAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenWidgetAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
List<PdfAnnotation> annot = flattener.flatten(document);
Assertions.assertEquals(1, annot.size());
Assertions.assertEquals(1, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenWidgetAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenScreenAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenScreenAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenScreenAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenScreenAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flatten3DAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flatten3DAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flatten3DAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flatten3DAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenHighlightAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenHighlightAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenHighlightAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenHighlightAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenUnderlineAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenUnderlineAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenUnderlineAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenUnderlineAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenSquigglyAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenSquigglyAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenSquigglyAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenSquigglyAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenStrikeOutAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenStrikeOutAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenStrikeOutAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenStrikeOutAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenCaretAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenCaretAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenCaretAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenCaretAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenTextAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenTextAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenTextAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenTextAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenSoundAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenSoundAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenSoundAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenSoundAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenStampAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenStampAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenStampAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
Assertions.assertEquals(0, flattener.flatten(document).size());
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenStampAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenFileAttachmentAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenFileAttachmentAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenFileAttachmentAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile,
SOURCE_FOLDER + "cmp_flattenFileAttachmentAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenInkAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenInkAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenInkAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenInkAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenPrinterMarkAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenPrinterMarkAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenPrinterMarkAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile,
SOURCE_FOLDER + "cmp_flattenPrinterMarkAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenTrapNetAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenTrapNetAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenTrapNetAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenTrapNetAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void testWarnAnnotationFlattenerAnnotNull() {
WarnFormfieldFlattener warnFormfieldFlattener = new WarnFormfieldFlattener();
PdfPage page = null;
Assertions.assertThrows(PdfException.class, () -> {
warnFormfieldFlattener.flatten(null, page);
});
}
@Test
public void testWarnAnnotationFlattenerPageNull() {
WarnFormfieldFlattener warnFormfieldFlattener = new WarnFormfieldFlattener();
PdfAnnotation annot = new PdfCircleAnnotation(new Rectangle(100, 100, 100, 100));
Assertions.assertThrows(PdfException.class, () -> {
warnFormfieldFlattener.flatten(annot, null);
});
}
@Test
public void removeWithoutDrawingFormfieldFlattenerNull() {
RemoveWithoutDrawingFlattener flattener = new RemoveWithoutDrawingFlattener();
PdfPage page = null;
Assertions.assertThrows(PdfException.class, () -> {
flattener.flatten(null, page);
});
}
@Test
public void removeWithoutDrawingAnnotationFlattenerPageNull() {
RemoveWithoutDrawingFlattener warnFormfieldFlattener = new RemoveWithoutDrawingFlattener();
PdfAnnotation annot = new PdfCircleAnnotation(new Rectangle(100, 100, 100, 100));
Assertions.assertThrows(PdfException.class, () -> {
warnFormfieldFlattener.flatten(annot, null);
});
}
@Test
public void flattenFreeTextAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenFreeTextAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenFreeTextAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenFreeTextAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenSquareAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenSquareAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenSquareAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenSquareAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenCircleAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenCircleAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenCircleAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenCircleAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flatteningOfAnnotationListWithNullAnnotationContinues() {
try (PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
document.addNewPage();
ArrayList<PdfAnnotation> annots = new ArrayList<>();
annots.add(null);
flattener.flatten(annots);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
}
@Test
public void flatteningOfAnnotationListWithNoPageAttachedAnnotationContinues() {
try (PdfDocument document = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
document.addNewPage();
ArrayList<PdfAnnotation> annots = new ArrayList<>();
annots.add(new PdfCircleAnnotation(new Rectangle(100, 100, 100, 100)));
flattener.flatten(annots);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
}
@Test
public void flattenLineAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenLineAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenLineAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenLineAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenPolygonAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenPolygonAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenPolygonAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenPolygonAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenPolyLineAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenPolyLineAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenPolyLineAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenPolyLineAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenRedactAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenRedactAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenRedactAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenRedactAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
@Test
public void flattenWatermarkAnnotationTest() throws IOException, InterruptedException {
String sourceFile = SOURCE_FOLDER + "flattenWatermarkAnnotationTest.pdf";
String resultFile = DESTINATION_FOLDER + "flattenWatermarkAnnotationTest.pdf";
try (PdfDocument document = new PdfDocument(new PdfReader(sourceFile), CompareTool.createTestPdfWriter(resultFile))) {
PdfAnnotationFlattener flattener = new PdfAnnotationFlattener();
flattener.flatten(document);
Assertions.assertEquals(0, document.getFirstPage().getAnnotations().size());
}
Assertions.assertNull(
new CompareTool().compareByContent(resultFile, SOURCE_FOLDER + "cmp_flattenWatermarkAnnotationTest.pdf",
DESTINATION_FOLDER, "diff_"));
}
private PdfTextMarkupAnnotation createTextAnnotation(PdfCanvas canvas, float x, float y, float[] quadPoints,
PdfName type,
Color color)
throws IOException {
canvas
.saveState()
.beginText()
.moveText(x, y)
.setFontAndSize(PdfFontFactory.createFont(StandardFonts.HELVETICA), 16)
.showText(PlaceHolderTextUtil.getPlaceHolderText(PlaceHolderTextBy.WORDS, 5))
.endText()
.restoreState();
PdfTextMarkupAnnotation markup = null;
if (PdfName.Underline.equals(type)) {
markup = PdfTextMarkupAnnotation.createUnderline(PageSize.A4, quadPoints);
}
if (PdfName.StrikeOut.equals(type)) {
markup = PdfTextMarkupAnnotation.createStrikeout(PageSize.A4, quadPoints);
}
if (PdfName.Highlight.equals(type)) {
markup = PdfTextMarkupAnnotation.createHighLight(PageSize.A4, quadPoints);
}
if (PdfName.Squiggly.equals(type)) {
markup = PdfTextMarkupAnnotation.createSquiggly(PageSize.A4, quadPoints);
}
if (markup == null) {
throw new IllegalArgumentException();
}
markup.setContents(new PdfString("TextMarkup"));
markup.setColor(color.getColorValue());
return markup;
}
static class CustomPdfAnnotationFlattenFactory extends PdfAnnotationFlattenFactory {
@Override
public IAnnotationFlattener getAnnotationFlattenWorker(PdfName name) {
if (PdfName.Link.equals(name)) {
return new IAnnotationFlattener() {
@Override
public boolean flatten(PdfAnnotation annotation, PdfPage page) {
page.removeAnnotation(annotation);
return true;
}
};
}
return super.getAnnotationFlattenWorker(name);
}
}
}