diff -Nru libsejda-java-3.2.56/debian/changelog libsejda-java-3.2.66/debian/changelog --- libsejda-java-3.2.56/debian/changelog 2018-10-12 11:11:13.000000000 +0000 +++ libsejda-java-3.2.66/debian/changelog 2019-02-27 12:51:08.000000000 +0000 @@ -1,3 +1,15 @@ +libsejda-java (3.2.66-1~18.04) bionic; urgency=medium + + * Backport for OpenJDK 11 (dependency of pdfsam). LP: #1814133. + + -- Matthias Klose Wed, 27 Feb 2019 13:51:08 +0100 + +libsejda-java (3.2.66-1) unstable; urgency=medium + + * New upstream version 3.2.66. + + -- Markus Koschany Sat, 22 Dec 2018 12:32:07 +0100 + libsejda-java (3.2.56-1) unstable; urgency=medium * New upstream version 3.2.56. diff -Nru libsejda-java-3.2.56/pom.xml libsejda-java-3.2.66/pom.xml --- libsejda-java-3.2.56/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -6,7 +6,7 @@ sejda-parent pom sejda - 3.2.56 + 3.2.66 An extendible and configurable PDF manipulation layer library. A ready to use java library to perform PDF documents manipulation without having to deal with the low level API. Sejda offers many "ready to go" manipulations implemented using the SAMBox but it can be extended to use other implementations. @@ -32,7 +32,7 @@ scm:git:git@github.com:torakiki/sejda.git scm:git:git@github.com:torakiki/sejda.git scm:git:git@github.com:torakiki/sejda.git - v3.2.56 + v3.2.66 @@ -338,7 +338,7 @@ 2.9.1 4.2.0.Final 1.3 - 1.1.41 + 1.1.46 1.56 3.3.1 3.15 diff -Nru libsejda-java-3.2.56/sejda-console/.classpath libsejda-java-3.2.66/sejda-console/.classpath --- libsejda-java-3.2.56/sejda-console/.classpath 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-console/.classpath 2018-12-03 16:42:31.000000000 +0000 @@ -15,11 +15,13 @@ + + diff -Nru libsejda-java-3.2.56/sejda-console/pom.xml libsejda-java-3.2.66/sejda-console/pom.xml --- libsejda-java-3.2.56/sejda-console/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-console/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -10,7 +10,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -183,6 +183,13 @@ + + + + org.sejda.cli + + + diff -Nru libsejda-java-3.2.56/sejda-console/src/test/java/org/sejda/cli/CommandLineTestBuilder.java libsejda-java-3.2.66/sejda-console/src/test/java/org/sejda/cli/CommandLineTestBuilder.java --- libsejda-java-3.2.56/sejda-console/src/test/java/org/sejda/cli/CommandLineTestBuilder.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-console/src/test/java/org/sejda/cli/CommandLineTestBuilder.java 2018-12-03 16:42:31.000000000 +0000 @@ -191,7 +191,7 @@ } public T invokeSejdaConsole() { - return (T) new CommandLineExecuteTestHelper(true) + return new CommandLineExecuteTestHelper(true) .invokeConsoleAndReturnTaskParameters(this.toCommandLineString()); } } diff -Nru libsejda-java-3.2.56/sejda-conversion/pom.xml libsejda-java-3.2.66/sejda-conversion/pom.xml --- libsejda-java-3.2.56/sejda-conversion/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-conversion/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -10,10 +10,26 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml - + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.conversion + + + + + + + org.sejda diff -Nru libsejda-java-3.2.56/sejda-conversion/src/main/java/org/sejda/conversion/PdfFileSourceListAdapter.java libsejda-java-3.2.66/sejda-conversion/src/main/java/org/sejda/conversion/PdfFileSourceListAdapter.java --- libsejda-java-3.2.56/sejda-conversion/src/main/java/org/sejda/conversion/PdfFileSourceListAdapter.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-conversion/src/main/java/org/sejda/conversion/PdfFileSourceListAdapter.java 2018-12-03 16:42:31.000000000 +0000 @@ -43,6 +43,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; +import org.sejda.common.XMLUtils; import org.sejda.conversion.exception.ConversionException; import org.sejda.model.exception.SejdaRuntimeException; import org.sejda.model.input.PdfFileSource; @@ -245,9 +246,11 @@ protected List doParseFileNames(File file) throws IOException, SAXException, ParserConfigurationException, XPathException { - DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilderFactory domFactory = XMLUtils.getDocumentBuilderFactory(); domFactory.setNamespaceAware(true); + DocumentBuilder builder = domFactory.newDocumentBuilder(); + builder.setErrorHandler(XMLUtils.ERROR_HANDLER); Document doc = builder.parse(file); List result = new ArrayList<>(); diff -Nru libsejda-java-3.2.56/sejda-core/pom.xml libsejda-java-3.2.66/sejda-core/pom.xml --- libsejda-java-3.2.56/sejda-core/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-core/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -5,7 +5,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -41,6 +41,13 @@ + + + + org.sejda.core + + + diff -Nru libsejda-java-3.2.56/sejda-core/src/main/java/org/sejda/core/context/XmlConfigurationStrategy.java libsejda-java-3.2.66/sejda-core/src/main/java/org/sejda/core/context/XmlConfigurationStrategy.java --- libsejda-java-3.2.56/sejda-core/src/main/java/org/sejda/core/context/XmlConfigurationStrategy.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-core/src/main/java/org/sejda/core/context/XmlConfigurationStrategy.java 2018-12-03 16:42:31.000000000 +0000 @@ -41,6 +41,7 @@ import javax.xml.xpath.XPathFactory; import org.apache.commons.io.IOUtils; +import org.sejda.common.XMLUtils; import org.sejda.core.Sejda; import org.sejda.core.notification.strategy.AsyncNotificationStrategy; import org.sejda.core.notification.strategy.NotificationStrategy; @@ -92,10 +93,12 @@ } private void initializeFromInputStream(InputStream input) throws ConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { + DocumentBuilderFactory factory = XMLUtils.getDocumentBuilderFactory(); initializeSchemaValidation(factory); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setErrorHandler(XMLUtils.ERROR_HANDLER); Document document = builder.parse(input); notificationStrategy = getNotificationStrategy(document); diff -Nru libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/BaseTaskTest.java libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/BaseTaskTest.java --- libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/BaseTaskTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/BaseTaskTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -196,6 +196,11 @@ org.sejda.core.service.TestUtils.assertPageText(page, text); } + public void assertPageTextExactLines(PDPage page, String text) { + org.sejda.core.service.TestUtils.assertPageTextExactLines(page, text); + } + + public void assertPageTextContains(PDPage page, String text) { org.sejda.core.service.TestUtils.assertPageTextContains(page, text); } diff -Nru libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/PdfToExcelTaskTest.java libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/PdfToExcelTaskTest.java --- libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/PdfToExcelTaskTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/PdfToExcelTaskTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -21,7 +21,12 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -105,7 +110,7 @@ List row = new ArrayList<>(); for(String s: record){ row.add(s); - }; + } results.add(row); } diff -Nru libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/TestUtils.java libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/TestUtils.java --- libsejda-java-3.2.56/sejda-core/src/test/java/org/sejda/core/service/TestUtils.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-core/src/test/java/org/sejda/core/service/TestUtils.java 2018-12-03 16:42:31.000000000 +0000 @@ -23,7 +23,7 @@ import org.sejda.sambox.pdmodel.common.PDPageLabels; import org.sejda.sambox.pdmodel.common.PDRectangle; import org.sejda.sambox.pdmodel.interactive.annotation.PDAnnotationLink; -import org.sejda.sambox.pdmodel.interactive.documentnavigation.destination.PDPageFitWidthDestination; +import org.sejda.sambox.pdmodel.interactive.documentnavigation.destination.PDPageDestination; import org.sejda.sambox.text.PDFTextStripperByArea; import java.awt.*; @@ -120,7 +120,7 @@ } public static void assertPageDestination(PDAnnotationLink link, PDPage expectedPage) throws IOException { - PDPage actualPage = ((PDPageFitWidthDestination)link.getDestination()).getPage(); + PDPage actualPage = ((PDPageDestination)link.getDestination()).getPage(); assertEquals(expectedPage, actualPage); } Binary files /tmp/tmpdydrno/C1JeVewHtQ/libsejda-java-3.2.56/sejda-core/src/test/resources/pdf/2-up_fonts.pdf and /tmp/tmpdydrno/EFOcJMcr5c/libsejda-java-3.2.66/sejda-core/src/test/resources/pdf/2-up_fonts.pdf differ diff -Nru libsejda-java-3.2.56/sejda-distribution/pom.xml libsejda-java-3.2.66/sejda-distribution/pom.xml --- libsejda-java-3.2.56/sejda-distribution/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-distribution/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -10,7 +10,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml diff -Nru libsejda-java-3.2.56/sejda-docs/pom.xml libsejda-java-3.2.66/sejda-docs/pom.xml --- libsejda-java-3.2.56/sejda-docs/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-docs/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -5,7 +5,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml Binary files /tmp/tmpdydrno/C1JeVewHtQ/libsejda-java-3.2.56/sejda-fonts/fonts/sans/NotoKufiArabic-Regular.ttf and /tmp/tmpdydrno/EFOcJMcr5c/libsejda-java-3.2.66/sejda-fonts/fonts/sans/NotoKufiArabic-Regular.ttf differ diff -Nru libsejda-java-3.2.56/sejda-fonts/fonts/sans/README.txt libsejda-java-3.2.66/sejda-fonts/fonts/sans/README.txt --- libsejda-java-3.2.56/sejda-fonts/fonts/sans/README.txt 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-fonts/fonts/sans/README.txt 2018-12-03 16:42:31.000000000 +0000 @@ -12,7 +12,6 @@ # list to maximize the amount of meta data retained in the final merged font. 'NotoSans-Regular.ttf', 'NotoSansBengali-Regular.ttf', - 'NotoKufiArabic-Regular.ttf', 'NotoNaskhArabic-Regular.ttf', 'NotoSansBengali-Regular.ttf', 'NotoSansDevanagari-Regular.ttf', diff -Nru libsejda-java-3.2.56/sejda-fonts/pom.xml libsejda-java-3.2.66/sejda-fonts/pom.xml --- libsejda-java-3.2.56/sejda-fonts/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-fonts/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -10,10 +10,26 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml - + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.fonts + + + + + + + org.sejda Binary files /tmp/tmpdydrno/C1JeVewHtQ/libsejda-java-3.2.56/sejda-fonts/src/main/resources/fonts/sans/NotoSansMerged-Regular.ttf and /tmp/tmpdydrno/EFOcJMcr5c/libsejda-java-3.2.66/sejda-fonts/src/main/resources/fonts/sans/NotoSansMerged-Regular.ttf differ diff -Nru libsejda-java-3.2.56/sejda-image-writers/pom.xml libsejda-java-3.2.66/sejda-image-writers/pom.xml --- libsejda-java-3.2.56/sejda-image-writers/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-image-writers/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -6,7 +6,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -14,7 +14,23 @@ jar sejda image writers - + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.core.writer + + + + + + + org.sejda diff -Nru libsejda-java-3.2.56/sejda-model/pom.xml libsejda-java-3.2.66/sejda-model/pom.xml --- libsejda-java-3.2.56/sejda-model/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-model/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -6,7 +6,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -26,6 +26,13 @@ + + + + org.sejda.model + + + diff -Nru libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/common/XMLUtils.java libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/common/XMLUtils.java --- libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/common/XMLUtils.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/common/XMLUtils.java 2018-12-03 16:42:31.000000000 +0000 @@ -20,7 +20,15 @@ package org.sejda.common; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Node; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; /** * Provides some utility methods to deal with xml. @@ -29,6 +37,9 @@ * */ public final class XMLUtils { + + private static final Logger LOG = LoggerFactory.getLogger(XMLUtils.class); + private XMLUtils() { // hide } @@ -70,4 +81,31 @@ } return defaultValue; } + + public static final DocumentBuilderFactory getDocumentBuilderFactory() throws ParserConfigurationException { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + + factory.setValidating(true); + factory.setFeature("http://xml.org/sax/features/validation", true); + + return factory; + } + + public static final ErrorHandler ERROR_HANDLER = new ErrorHandler() { + + @Override + public void warning(SAXParseException e) throws SAXException { + // noop + } + + @Override + public void error(SAXParseException e) throws SAXException { + LOG.debug(e.getMessage()); + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + }; } diff -Nru libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/model/parameter/MergeParameters.java libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/model/parameter/MergeParameters.java --- libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/model/parameter/MergeParameters.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/model/parameter/MergeParameters.java 2018-12-03 16:42:31.000000000 +0000 @@ -70,6 +70,7 @@ private boolean filenameFooter = false; /* Makes all pages same width as the first page */ private boolean normalizePageSizes = false; + private boolean firstInputCoverTitle = false; @Override public SingleTaskOutput getOutput() { @@ -179,11 +180,20 @@ this.catalogPageLabelsPolicy = catalogPageLabelsPolicy; } + public boolean isFirstInputCoverTitle() { + return firstInputCoverTitle; + } + + public void setFirstInputCoverTitle(boolean firstInputCoverTitle) { + this.firstInputCoverTitle = firstInputCoverTitle; + } + @Override public int hashCode() { return new HashCodeBuilder().appendSuper(super.hashCode()).append(inputList).append(acroFormPolicy) .append(blankPageIfOdd).append(outlinePolicy).append(tocPolicy).append(output).append(filenameFooter) - .append(normalizePageSizes).append(catalogPageLabelsPolicy).toHashCode(); + .append(normalizePageSizes).append(catalogPageLabelsPolicy).append(firstInputCoverTitle) + .toHashCode(); } @Override @@ -201,6 +211,7 @@ .append(output, params.getOutput()).append(filenameFooter, params.isFilenameFooter()) .append(normalizePageSizes, params.isNormalizePageSizes()) .append(catalogPageLabelsPolicy, params.catalogPageLabelsPolicy) + .append(firstInputCoverTitle, params.firstInputCoverTitle) .isEquals(); } } diff -Nru libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/model/parameter/PageSize.java libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/model/parameter/PageSize.java --- libsejda-java-3.2.56/sejda-model/src/main/java/org/sejda/model/parameter/PageSize.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-model/src/main/java/org/sejda/model/parameter/PageSize.java 2018-12-03 16:42:31.000000000 +0000 @@ -34,11 +34,16 @@ private static final float POINTS_PER_MM = 1 / (10 * 2.54f) * POINTS_PER_INCH; /** A rectangle the size of U.S. Letter, 8.5" x 11". */ - public static final PageSize LETTER = new PageSize(8.5f * POINTS_PER_INCH, - 11f * POINTS_PER_INCH, "Letter"); + public static final PageSize LETTER = new PageSize(8.5f * POINTS_PER_INCH, 11f * POINTS_PER_INCH, "Letter"); /** A rectangle the size of U.S. Legal, 8.5" x 14". */ - public static final PageSize LEGAL = new PageSize(8.5f * POINTS_PER_INCH, - 14f * POINTS_PER_INCH, "Legal"); + public static final PageSize LEGAL = new PageSize(8.5f * POINTS_PER_INCH, 14f * POINTS_PER_INCH, "Legal"); + /** A rectangle the size of U.S. Ledger, 11" x 17". */ + public static final PageSize LEDGER = new PageSize(11f * POINTS_PER_INCH,17f * POINTS_PER_INCH, "Ledger"); + /** A rectangle the size of U.S. Tabloid, 17" x 11". */ + public static final PageSize TABLOID = new PageSize(17f * POINTS_PER_INCH,11f * POINTS_PER_INCH, "Tabloid"); + /** A rectangle the size of U.S. Executive, 7.25" x 10.55". */ + public static final PageSize EXECUTIVE = new PageSize(7.25f * POINTS_PER_INCH,10.55f * POINTS_PER_INCH, "Executive"); + /** A rectangle the size of A0 Paper. */ public static final PageSize A0 = new PageSize(841 * POINTS_PER_MM, 1189 * POINTS_PER_MM, "A0"); diff -Nru libsejda-java-3.2.56/sejda-ocr/pom.xml libsejda-java-3.2.66/sejda-ocr/pom.xml --- libsejda-java-3.2.56/sejda-ocr/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-ocr/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -6,7 +6,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -15,6 +15,22 @@ sejda ocr + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.impl.sambox.ocr + + + + + + + org.sejda @@ -35,7 +51,7 @@ org.sejda sambox ${sambox.version} - + com.twelvemonkeys.imageio imageio-core diff -Nru libsejda-java-3.2.56/sejda-optional-fonts/pom.xml libsejda-java-3.2.66/sejda-optional-fonts/pom.xml --- libsejda-java-3.2.56/sejda-optional-fonts/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-optional-fonts/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -10,10 +10,26 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.fonts.optional + + + + + + + org.sejda diff -Nru libsejda-java-3.2.56/sejda-sambox/pom.xml libsejda-java-3.2.66/sejda-sambox/pom.xml --- libsejda-java-3.2.56/sejda-sambox/pom.xml 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/pom.xml 2018-12-03 16:42:31.000000000 +0000 @@ -6,7 +6,7 @@ org.sejda sejda-parent - 3.2.56 + 3.2.66 ../pom.xml @@ -15,6 +15,22 @@ sejda sambox + + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.sejda.impl.sambox + + + + + + + org.sejda diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/CombineReorderTask.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/CombineReorderTask.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/CombineReorderTask.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/CombineReorderTask.java 2018-12-03 16:42:31.000000000 +0000 @@ -64,7 +64,7 @@ private List documents = new ArrayList<>(); private Map documentNames = new HashMap<>(); private AcroFormsMerger acroFormsMerger; - private LookupTable pagesLookup = new LookupTable<>(); + private Map> pagesLookup = new HashMap<>(); private OutlineMerger outlineMerger; @Override @@ -95,6 +95,7 @@ PDDocumentHandler sourceDocumentHandler = input.open(sourceOpener); documents.add(sourceDocumentHandler); documentNames.put(sourceDocumentHandler, input.getName()); + pagesLookup.put(sourceDocumentHandler, new LookupTable<>()); } int currentStep = 0; @@ -117,10 +118,11 @@ destinationDocument.addBlankPage(mediaBox); } else { try { - PDPage page = documents.get(filePage.getFileIndex()).getPage(pageNum); + PDDocumentHandler documentHandler = documents.get(filePage.getFileIndex()); + PDPage page = documentHandler.getPage(pageNum); PDPage newPage = destinationDocument.importPage(page); lastPage = newPage; - pagesLookup.addLookupEntry(page, newPage); + pagesLookup.get(documentHandler).addLookupEntry(page, newPage); rotator.rotate(i + 1, filePage.getRotation()); } catch (PageNotFoundException e) { executionContext().assertTaskIsLenient(e); @@ -133,10 +135,11 @@ } for (PDDocumentHandler document : documents) { - outlineMerger.updateOutline(document.getUnderlyingPDDocument(), documentNames.get(document), pagesLookup); + LookupTable lookupTable = pagesLookup.get(document); + outlineMerger.updateOutline(document.getUnderlyingPDDocument(), documentNames.get(document), lookupTable); LookupTable annotationsLookup = new AnnotationsDistiller(document.getUnderlyingPDDocument()) - .retainRelevantAnnotations(pagesLookup); + .retainRelevantAnnotations(lookupTable); clipSignatures(annotationsLookup.values()); acroFormsMerger.mergeForm(document.getUnderlyingPDDocument().getDocumentCatalog().getAcroForm(), diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/AnnotationsDistiller.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/AnnotationsDistiller.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/AnnotationsDistiller.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/AnnotationsDistiller.java 2018-12-03 16:42:31.000000000 +0000 @@ -79,7 +79,10 @@ try { Set keptAnnotations = new LinkedHashSet<>(); for (PDAnnotation annotation : page.getAnnotations()) { - if (!annotationsLookup.hasLookupFor(annotation)) { + PDAnnotation mapped = annotationsLookup.lookup(annotation); + if (nonNull(mapped)) { + keptAnnotations.add(mapped); + } else { if (annotation instanceof PDAnnotationLink) { processLinkAnnotation(relevantPages, keptAnnotations, (PDAnnotationLink) annotation); } else { diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/CatalogPageLabelsMerger.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/CatalogPageLabelsMerger.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/CatalogPageLabelsMerger.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/CatalogPageLabelsMerger.java 2018-12-03 16:42:31.000000000 +0000 @@ -19,6 +19,11 @@ package org.sejda.impl.sambox.component; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.sejda.impl.sambox.util.PageLabelUtils; import org.sejda.model.outline.CatalogPageLabelsPolicy; import org.sejda.sambox.pdmodel.PDDocument; @@ -27,9 +32,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.*; - /** * Merges multiple /Catalog /PageLabels definitions, from multiple docs, into one. */ @@ -44,30 +46,30 @@ public CatalogPageLabelsMerger(CatalogPageLabelsPolicy policy) { this.policy = policy; - if(policy == CatalogPageLabelsPolicy.DISCARD) { + if (policy == CatalogPageLabelsPolicy.DISCARD) { mergedPageLabels = null; } } public void add(PDDocument doc, Set pagesToImport) { - if(policy == CatalogPageLabelsPolicy.DISCARD) { + if (policy == CatalogPageLabelsPolicy.DISCARD) { return; } try { PDPageLabels docLabels = doc.getDocumentCatalog().getPageLabels(); - if(docLabels == null) { + if (docLabels == null) { docLabels = new PDPageLabels(); } - if(pagesToImport.size() < doc.getNumberOfPages()) { + if (pagesToImport.size() < doc.getNumberOfPages()) { // not all pages are being imported // first update doc's page labels and remove pages not being imported List pagesToRemove = computePagesToRemove(doc, pagesToImport); docLabels = PageLabelUtils.removePages(docLabels, pagesToRemove, doc.getNumberOfPages()); } - for(Map.Entry entry: docLabels.getLabels().entrySet()){ + for (Map.Entry entry : docLabels.getLabels().entrySet()) { PDPageLabelRange range = entry.getValue(); // the page index in the original doc @@ -79,13 +81,13 @@ // but might be right for Chapter 1 (arabic) + Chapter 2 (arabic) // not sure what to do, defer for later // if(range.hasStart()) { - // range.setStart(range.getStart() + totalPages); - //} + // range.setStart(range.getStart() + totalPages); + // } mergedPageLabels.setLabelItem(newPageIndex, range); } - } catch (IOException ex) { + } catch (Exception ex) { LOG.warn("An error occurred retrieving /PageLabels of document {}, will not be merged", doc); } finally { // always advance the total number of pages @@ -94,13 +96,13 @@ } private static List computePagesToRemove(PDDocument doc, Set pagesToImport) { - if(doc.getNumberOfPages() == pagesToImport.size()) { + if (doc.getNumberOfPages() == pagesToImport.size()) { return new ArrayList<>(); } List pagesToRemove = new ArrayList<>(); - for(int i = 1; i <= doc.getNumberOfPages(); i++) { - if(!pagesToImport.contains(i)) { + for (int i = 1; i <= doc.getNumberOfPages(); i++) { + if (!pagesToImport.contains(i)) { pagesToRemove.add(i); } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/FilenameFooterWriter.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/FilenameFooterWriter.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/FilenameFooterWriter.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/FilenameFooterWriter.java 2018-12-03 16:42:31.000000000 +0000 @@ -44,12 +44,14 @@ private boolean addFooter = false; private PageTextWriter writer; + private PDDocument document; private static PDFont FONT = PDType1Font.HELVETICA; private static double FONT_SIZE = 10; public FilenameFooterWriter(boolean addFooter, PDDocument document) { this.writer = new PageTextWriter(document); + this.document = document; this.addFooter = addFooter; } @@ -76,7 +78,11 @@ return writer.getStringWidth(text, FONT, (float) FONT_SIZE); } - private String truncateIfRequired(String text, double maxWidth) throws TaskIOException { + private String truncateIfRequired(String original, double maxWidth) throws TaskIOException { + // check if all characters are supported by the fonts available + // replace any bad characters with # + String text = FontUtils.replaceUnsupportedCharacters(original, document, "#"); + if (stringWidth(text) <= maxWidth) { return text; } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/image/ExifHelper.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/image/ExifHelper.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/image/ExifHelper.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/image/ExifHelper.java 2018-12-03 16:42:31.000000000 +0000 @@ -18,19 +18,19 @@ */ package org.sejda.impl.sambox.component.image; +import java.io.IOException; + +import org.sejda.model.input.FileSource; +import org.sejda.model.input.Source; +import org.sejda.model.input.SourceDispatcher; +import org.sejda.model.input.StreamSource; + import com.drew.imaging.ImageMetadataReader; import com.drew.imaging.ImageProcessingException; import com.drew.metadata.Directory; import com.drew.metadata.Metadata; import com.drew.metadata.MetadataException; import com.drew.metadata.exif.ExifIFD0Directory; -import org.sejda.model.exception.TaskIOException; -import org.sejda.model.input.FileSource; -import org.sejda.model.input.Source; -import org.sejda.model.input.SourceDispatcher; -import org.sejda.model.input.StreamSource; - -import java.io.IOException; /** * Reads exif orientation of an image and determines if the image should be rotated or not. @@ -42,7 +42,7 @@ try { return imageSource.dispatch(new SourceDispatcher() { @Override - public Integer dispatch(FileSource source) throws TaskIOException { + public Integer dispatch(FileSource source) { try { int orientation = readExifOrientation(ImageMetadataReader.readMetadata(source.getSource())); return getRotation(orientation); @@ -52,7 +52,7 @@ } @Override - public Integer dispatch(StreamSource source) throws TaskIOException { + public Integer dispatch(StreamSource source) { try { int orientation = readExifOrientation(ImageMetadataReader.readMetadata(source.getSource())); return getRotation(orientation); diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PageTextWriter.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PageTextWriter.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PageTextWriter.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PageTextWriter.java 2018-12-03 16:42:31.000000000 +0000 @@ -253,4 +253,9 @@ transform.scale(1, -1); return transform.transform(position, null); } + + public static void writeHeader(PDDocument doc, PDPage page, String text) throws TaskIOException { + PageTextWriter writer = new PageTextWriter(doc); + writer.write(page, HorizontalAlign.CENTER, VerticalAlign.TOP, text, FontUtils.HELVETICA, 10d, Color.black); + } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PDDocumentHandler.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PDDocumentHandler.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PDDocumentHandler.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/PDDocumentHandler.java 2018-12-03 16:42:31.000000000 +0000 @@ -39,6 +39,9 @@ import org.sejda.model.exception.TaskException; import org.sejda.model.exception.TaskIOException; import org.sejda.model.image.ImageColorType; +import org.sejda.sambox.contentstream.PDContentStream; +import org.sejda.sambox.pdmodel.*; +import org.sejda.sambox.pdmodel.graphics.PDXObject; import org.sejda.sambox.rendering.ImageType; import org.sejda.model.pdf.PdfVersion; import org.sejda.model.pdf.label.PdfPageLabel; @@ -48,13 +51,6 @@ import org.sejda.sambox.cos.COSName; import org.sejda.sambox.encryption.StandardSecurity; import org.sejda.sambox.output.WriteOption; -import org.sejda.sambox.pdmodel.PDDocument; -import org.sejda.sambox.pdmodel.PDDocumentCatalog; -import org.sejda.sambox.pdmodel.PDDocumentInformation; -import org.sejda.sambox.pdmodel.PDPage; -import org.sejda.sambox.pdmodel.PDPageTree; -import org.sejda.sambox.pdmodel.PageLayout; -import org.sejda.sambox.pdmodel.PageMode; import org.sejda.sambox.pdmodel.common.PDRectangle; import org.sejda.sambox.pdmodel.font.PDFont; import org.sejda.sambox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline; @@ -424,17 +420,46 @@ return result; } - public PDFont findFont(String searchedName) { - for (PDPage page : document.getPages()) { - for (COSName fontName : page.getResources().getFontNames()) { - try { - PDFont font = page.getResources().getFont(fontName); - if (font != null && font.getName() != null && searchedName.equalsIgnoreCase(font.getName())) { + private PDFont findFont(PDResources resources, String searchedName, int level) { + // prevent stackoverflow by limiting how deep we go searching + if(level > 15) { + return null; + } + + for (COSName fontName : resources.getFontNames()) { + try { + PDFont font = resources.getFont(fontName); + if (font != null && font.getName() != null && searchedName.equalsIgnoreCase(font.getName())) { + return font; + } + } catch (Exception e) { + LOG.warn("Failure while searching font in resources", e); + } + } + + for (COSName objectName: resources.getXObjectNames()) { + try { + PDXObject pdxObject = resources.getXObject(objectName); + if(pdxObject instanceof PDContentStream) { + PDResources res = ((PDContentStream)pdxObject).getResources(); + PDFont font = findFont(res, searchedName, level + 1); + if(font != null) { return font; } - } catch (IOException e) { - LOG.warn("Failed to load font from resources: {}", fontName); } + } catch (Exception e) { + LOG.warn("Failure while searching font in XObject", e); + } + } + + return null; + } + + public PDFont findFont(String searchedName) { + for (PDPage page : document.getPages()) { + PDFont font = findFont(page.getResources(), searchedName, 1); + if(font != null) { + return font; } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/TableOfContentsCreator.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/TableOfContentsCreator.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/TableOfContentsCreator.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/component/TableOfContentsCreator.java 2018-12-03 16:42:31.000000000 +0000 @@ -45,7 +45,7 @@ import org.sejda.sambox.pdmodel.font.PDType1Font; import org.sejda.sambox.pdmodel.interactive.annotation.PDAnnotation; import org.sejda.sambox.pdmodel.interactive.annotation.PDAnnotationLink; -import org.sejda.sambox.pdmodel.interactive.documentnavigation.destination.PDPageFitWidthDestination; +import org.sejda.sambox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,7 +101,7 @@ } private PDAnnotationLink linkAnnotationFor(PDPage importedPage) { - PDPageFitWidthDestination pageDest = new PDPageFitWidthDestination(); + PDPageXYZDestination pageDest = new PDPageXYZDestination(); pageDest.setPage(importedPage); PDAnnotationLink link = new PDAnnotationLink(); link.setDestination(pageDest); @@ -113,19 +113,26 @@ * Generates a ToC and prepend it to the given document */ public void addToC() throws TaskException { + addToC(0); + } + + /** + * Generates a ToC and inserts it in the doc at before the given page number + */ + public void addToC(int beforePageNumber) throws TaskException { try { PDPageTree pagesTree = document.getPages(); ofNullable(generateToC()).filter(l -> !l.isEmpty()).ifPresent(t -> { int toCPagesCount = t.size(); t.descendingIterator().forEachRemaining(p -> { if (pagesTree.getCount() > 0) { - pagesTree.insertBefore(p, pagesTree.get(0)); + pagesTree.insertBefore(p, pagesTree.get(beforePageNumber)); } else { pagesTree.add(p); } }); if (params.isBlankPageIfOdd() && toCPagesCount % 2 == 1) { - PDPage lastTocPage = pagesTree.get(toCPagesCount - 1); + PDPage lastTocPage = pagesTree.get(beforePageNumber + toCPagesCount - 1); PDPage blankPage = new PDPage(lastTocPage.getMediaBox()); pagesTree.insertAfter(blankPage, lastTocPage); } @@ -181,8 +188,9 @@ } } - String pageString = SEPARATOR + Long.toString(i.page + tocNumberOfPages); - float x2 = getPageNumberX(separatorWidth, i.page + tocNumberOfPages); + long pageNumber = i.page + tocNumberOfPages; + String pageString = SEPARATOR + Long.toString(pageNumber); + float x2 = getPageNumberX(separatorWidth, pageNumber); writeText(page, pageString, x2, y); // make the item clickable and link to the page number diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/MergeTask.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/MergeTask.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/MergeTask.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/MergeTask.java 2018-12-03 16:42:31.000000000 +0000 @@ -72,6 +72,8 @@ private FilenameFooterWriter footerWriter; private PDRectangle currentPageSize = PDRectangle.A4; private long pagesCounter = 0; + private long inputsCounter = 0; + private int firstInputNumberOfPages = 0; @Override public void before(MergeParameters parameters, TaskExecutionContext executionContext) throws TaskException { @@ -103,18 +105,23 @@ convertImageMergeInputToPdf(parameters); for (PdfMergeInput input : parameters.getPdfInputList()) { + inputsCounter++; LOG.debug("Opening {}", input.getSource()); PDDocumentHandler sourceDocumentHandler = input.getSource().open(sourceOpener); toClose.add(sourceDocumentHandler); + if(inputsCounter == 1) { + firstInputNumberOfPages = sourceDocumentHandler.getNumberOfPages(); + } + LOG.debug("Adding pages"); LookupTable pagesLookup = new LookupTable<>(); - long relativeCounter = 0; + long relativePagesCounter = 0; Set pagesToImport = input.getPages(sourceDocumentHandler.getNumberOfPages()); for (Integer currentPage : pagesToImport) { executionContext().assertTaskNotCancelled(); pagesCounter++; - relativeCounter++; + relativePagesCounter++; try { PDPage page = sourceDocumentHandler.getPage(currentPage); // we keep rotation into account @@ -125,20 +132,29 @@ pagesLookup.addLookupEntry(page, importedPage); String sourceBaseName = FilenameUtils.getBaseName(input.getSource().getName()); + // processing the first page of the source - if (tocCreator.shouldGenerateToC() && relativeCounter == 1) { - tocCreator.pageSizeIfNotSet(currentPageSize); - if (ToCPolicy.DOC_TITLES == parameters.getTableOfContentsPolicy()) { - sourceBaseName = ofNullable( - sourceDocumentHandler.getUnderlyingPDDocument().getDocumentInformation()) - .map(i -> i.getTitle()).filter(StringUtils::isNotBlank) - .orElse(sourceBaseName); + if (tocCreator.shouldGenerateToC() && relativePagesCounter == 1) { + if(parameters.isFirstInputCoverTitle() && inputsCounter == 1) { + // skip the cover/title document, don't add it to the ToC + } else { + tocCreator.pageSizeIfNotSet(currentPageSize); + if (ToCPolicy.DOC_TITLES == parameters.getTableOfContentsPolicy()) { + sourceBaseName = ofNullable( + sourceDocumentHandler.getUnderlyingPDDocument().getDocumentInformation()) + .map(i -> i.getTitle()).filter(StringUtils::isNotBlank) + .orElse(sourceBaseName); + } + tocCreator.appendItem(sourceBaseName, pagesCounter, importedPage); } - tocCreator.appendItem(sourceBaseName, pagesCounter, importedPage); } - this.footerWriter.addFooter(importedPage, sourceBaseName, - pagesCounter + tocCreator.tocNumberOfPages()); + long currentPageNumber = pagesCounter + tocCreator.tocNumberOfPages(); + if(parameters.isFirstInputCoverTitle() && inputsCounter == 1) { + // the toc will be added after the cover/title pages + currentPageNumber = pagesCounter; + } + this.footerWriter.addFooter(importedPage, sourceBaseName, currentPageNumber); LOG.trace("Added imported page"); } catch (PageNotFoundException e) { executionContext().assertTaskIsLenient(e); @@ -146,7 +162,7 @@ .taskWarning(String.format("Page %d was skipped, could not be processed", currentPage), e); } } - relativeCounter = 0; + relativePagesCounter = 0; outlineMerger.updateOutline(sourceDocumentHandler.getUnderlyingPDDocument(), input.getSource().getName(), pagesLookup); @@ -186,7 +202,12 @@ if (tocCreator.hasToc()) { LOG.debug("Adding generated ToC"); - tocCreator.addToC(); + int beforePageNumber = 0; + if(parameters.isFirstInputCoverTitle()) { + // add ToC after the cover/title pages + beforePageNumber = firstInputNumberOfPages; + } + tocCreator.addToC(beforePageNumber); } if(catalogPageLabelsMerger.hasPageLabels()) { diff -Nru libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/util/FontUtils.java libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/util/FontUtils.java --- libsejda-java-3.2.56/sejda-sambox/src/main/java/org/sejda/impl/sambox/util/FontUtils.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/main/java/org/sejda/impl/sambox/util/FontUtils.java 2018-12-03 16:42:31.000000000 +0000 @@ -27,7 +27,15 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; @@ -108,7 +116,8 @@ if (!canDisplay(text, font)) { PDFont fallback = findFontFor(document, text); String fallbackName = fallback == null ? null : fallback.getName(); - LOG.debug("Text '{}' cannot be written with font {}, using fallback {}", text, font.getName(), fallbackName); + LOG.debug("Text '{}' cannot be written with font {}, using fallback {}", text, font.getName(), + fallbackName); return fallback; } return font; @@ -396,10 +405,11 @@ } /** - * Wraps the given text on multiple lines, if it does not fit within the given maxWidth - * It will try to determine if all text can be written with given font and find a fallback for parts that are not supported. + * Wraps the given text on multiple lines, if it does not fit within the given maxWidth It will try to determine if all text can be written with given font and find a fallback + * for parts that are not supported. */ - public static List wrapLines(String rawLabel, PDFont font, float fontSize, double maxWidth, PDDocument document) throws TaskIOException { + public static List wrapLines(String rawLabel, PDFont font, float fontSize, double maxWidth, + PDDocument document) throws TaskIOException { List lines = new ArrayList<>(); String label = org.sejda.core.support.util.StringUtils.normalizeWhitespace(rawLabel); @@ -415,7 +425,7 @@ String resolvedLabel = stringAndFont.getText(); String[] words = visualToLogical(resolvedLabel).split("(?<=\\b)"); - for(String word: words) { + for (String word : words) { double textWidth = getSimpleStringWidth(word, resolvedFont, fontSize); if (textWidth > maxWidth || word.length() > 10) { @@ -456,7 +466,7 @@ } } - if(!currentString.toString().isEmpty()) { + if (!currentString.toString().isEmpty()) { lines.add(currentString.toString().trim()); } @@ -464,8 +474,7 @@ } /** - * Calculates the width of the string using the given font. - * Does not try to find out if the text can actually be written with the given font and find fallback + * Calculates the width of the string using the given font. Does not try to find out if the text can actually be written with the given font and find fallback */ public static double getSimpleStringWidth(String text, PDFont font, double fontSize) throws IOException { double textWidth = font.getStringWidth(text) / 1000 * fontSize; @@ -483,8 +492,7 @@ /** * Supports writing labels which require multiple fonts (eg: mixing thai and english words) Returns a list of text with associated font. */ - public static List resolveFonts(String label, PDFont font, PDDocument document) - throws TaskIOException { + public static List resolveFonts(String label, PDFont font, PDDocument document) { PDFont currentFont = font; StringBuilder currentString = new StringBuilder(); @@ -508,7 +516,7 @@ f = FontUtils.getStandardType1Font(StandardType1Font.HELVETICA); } - if(f != currentFont) { + if (f != currentFont) { // end current string, before space if (currentString.length() > 0) { result.add(new TextWithFont(currentString.toString(), currentFont)); @@ -542,7 +550,11 @@ return result; } - public static String removeUnsupportedCharacters(String text, PDDocument doc) throws TaskIOException { + public static String removeUnsupportedCharacters(String text, PDDocument doc) { + return replaceUnsupportedCharacters(text, doc, ""); + } + + public static String replaceUnsupportedCharacters(String text, PDDocument doc, String replacement) { List resolved = resolveFonts(text, HELVETICA, doc); Set unsupported = new HashSet<>(); resolved.forEach(tf -> { @@ -553,7 +565,7 @@ String result = text; for (String s : unsupported) { - result = result.replaceAll(Pattern.quote(s), ""); + result = result.replaceAll(Pattern.quote(s), replacement); } return result; diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/AnnotationsDistillerTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/AnnotationsDistillerTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/AnnotationsDistillerTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/AnnotationsDistillerTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -104,8 +104,7 @@ assertEquals(6, annots.size()); assertThat(annots.stream().map(PDAnnotation::getAnnotationName).collect(Collectors.toList()), Matchers.contains(annotations.stream().map(PDAnnotation::getAnnotationName) - .map(d -> Matchers.equalTo(d)) - .collect(Collectors.toList()))); + .map(d -> Matchers.equalTo(d)).collect(Collectors.toList()))); } @Test @@ -377,6 +376,26 @@ assertEquals(1, parent.size()); assertTrue(annotations.contains(parent.get(0))); } + } + @Test + public void pagesHaveTheSameAnnotations() { + PDAnnotationLink annotation = new PDAnnotationLink(); + PDPageDestination dest = new PDPageFitDestination(); + dest.setPage(oldPage); + annotation.setDestination(dest); + + PDPage secondOld = new PDPage(); + PDPage secondNew = new PDPage(); + lookup.addLookupEntry(secondOld, secondNew); + List annotations = Arrays.asList(annotation, new PDAnnotationText()); + oldPage.setAnnotations(annotations); + secondOld.setAnnotations(annotations); + PDDocument doc = new PDDocument(); + doc.addPage(oldPage); + doc.addPage(secondOld); + new AnnotationsDistiller(doc).retainRelevantAnnotations(lookup); + assertEquals(oldPage.getAnnotations().size(), newPage.getAnnotations().size()); + assertEquals(secondOld.getAnnotations().size(), secondNew.getAnnotations().size()); } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/FilenameFooterWriterTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/FilenameFooterWriterTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/FilenameFooterWriterTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/FilenameFooterWriterTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -24,6 +24,7 @@ import org.junit.Test; import org.sejda.model.exception.TaskException; +import org.sejda.model.exception.TaskIOException; import org.sejda.sambox.pdmodel.PDDocument; import org.sejda.sambox.pdmodel.PDPage; @@ -50,7 +51,7 @@ PDPage page = new PDPage(); doc.addPage(page); new FilenameFooterWriter(true, doc).addFooter(page, "My very long title that will not fit on the page and needs to be truncated so that it will not overflow and cover the page number and generally look not so nice", 20); - assertThat(new PdfTextExtractorByArea().extractFooterText(page).trim(), is("My very long title that will not fit on the page and needs to be truncated so that it will not overflow and cover the page num 20")); + assertPageFooterText(page,"My very long title that will not fit on the page and needs to be truncated so that it will not overflow and cover the page num 20"); } @Test @@ -61,4 +62,20 @@ new FilenameFooterWriter(false, doc).addFooter(page, "My Footer", 20); assertThat(new PdfTextExtractorByArea().extractFooterText(page).trim(), isEmptyOrNullString()); } + + @Test + public void write_filename_contains_bad_characters() throws TaskException { + PDDocument doc = new PDDocument(); + PDPage page = new PDPage(); + doc.addPage(page); + String withBadCharacter = "This is a bad \uF021character"; + FilenameFooterWriter writer = new FilenameFooterWriter(true, doc); + writer.addFooter(page, withBadCharacter, 1); + + assertPageFooterText(page, "This is a bad #character 1"); + } + + private void assertPageFooterText(PDPage page, String expectedText) throws TaskIOException { + assertThat(new PdfTextExtractorByArea().extractFooterText(page).trim(), is(expectedText)); + } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/PDDocumentHandlerTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/PDDocumentHandlerTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/PDDocumentHandlerTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/PDDocumentHandlerTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -30,6 +30,7 @@ import org.sejda.sambox.pdmodel.PageLayout; import org.sejda.sambox.pdmodel.PageMode; import org.sejda.sambox.pdmodel.common.PDRectangle; +import org.sejda.sambox.pdmodel.font.PDFont; import org.sejda.sambox.pdmodel.interactive.pagenavigation.PDThreadBead; import static org.junit.Assert.*; @@ -107,6 +108,13 @@ } } + @Test + public void findFont_xform_resources() throws IOException { + PDDocument doc = testDoc("pdf/2-up_fonts.pdf"); + PDFont font = new PDDocumentHandler(doc).findFont("arialmt"); + assertNotNull(font); + } + private PDDocument testDoc(String resourceName) throws IOException { return PDFParser.parse(SeekableSources .inMemorySeekableSourceFrom(getClass().getClassLoader().getResourceAsStream(resourceName))); diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/TableOfContentsCreatorTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/TableOfContentsCreatorTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/TableOfContentsCreatorTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/component/TableOfContentsCreatorTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -19,6 +19,7 @@ package org.sejda.impl.sambox.component; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; @@ -380,7 +381,37 @@ victim.pageSizeIfNotSet(PDRectangle.A4); victim.addToC(); - // the junk letters are because of 'No Unicode mapping for CID+64 (64) in font NotoSansArmenian-Regular' - TestUtils.assertPageTextExactLines(doc.getPage(0), "Item multiple fonts @1E5P7F 10\n"); + TestUtils.assertPageTextExactLines(doc.getPage(0), "Item multiple fonts հայերէն 10\n"); + } + + @Test + public void test_Toc_Add_At_Specific_Page() throws TaskException { + MergeParameters params = new MergeParameters(); + params.setTableOfContentsPolicy(ToCPolicy.FILE_NAMES); + params.setBlankPageIfOdd(true); + + PDDocument doc = new PDDocument(); + PDPage pageA = new PDPage(), pageB = new PDPage(); + doc.addPage(pageA); doc.addPage(pageB); + + PageTextWriter.writeHeader(doc, pageA, "PageA"); + PageTextWriter.writeHeader(doc, pageB, "PageB"); + + TableOfContentsCreator victim = new TableOfContentsCreator(params, doc); + victim.appendItem("This is an item", 2, pageB); + victim.pageSizeIfNotSet(PDRectangle.A4); + + victim.addToC(1); + + assertThat(doc.getNumberOfPages(), is(4)); // one extra for blank page if odd + + // blank page pageA + TestUtils.assertPageTextExactLines(doc.getPage(0), "PageA\n"); + // toc + TestUtils.assertPageTextExactLines(doc.getPage(1), "This is an item 2\n"); + // extra blank page if odd + TestUtils.assertPageTextExactLines(doc.getPage(2), ""); + // blank page pageB + TestUtils.assertPageTextExactLines(doc.getPage(3), "PageB\n"); } } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/MergeSamboxTaskTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/MergeSamboxTaskTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/MergeSamboxTaskTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/MergeSamboxTaskTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -632,6 +632,42 @@ }); } + @Test + public void withCoverPage() throws IOException { + List inputs = new ArrayList(); + inputs.add(new PdfMergeInput(shortInput())); // 4 pages, cover/title doc + inputs.add(new PdfMergeInput(regularInput())); // 11 pages + inputs.add(new PdfMergeInput(customInput("pdf/attachments_as_annots.pdf", "attachments_as_annots.pdf"))); // 3 pages + + MergeParameters parameters = setUpParameters(inputs); + parameters.setTableOfContentsPolicy(ToCPolicy.FILE_NAMES); + parameters.setFilenameFooter(true); + parameters.setFirstInputCoverTitle(true); + + testContext.pdfOutputTo(parameters); + + execute(parameters); + + testContext.assertTaskCompleted(); + testContext.assertPages(19).forEachPdfOutput(d -> { + // first 4 pages are the cover/title doc - short input + assertFooterHasText(d.getPage(0), "short-test-file 1"); + assertFooterHasText(d.getPage(3), "short-test-file 4"); + + // the TOC + assertFooterHasText(d.getPage(4), ""); + assertPageTextExactLines(d.getPage(4), "test-file 6\nattachments_as_annots 17\n"); + + // next 11 pages are the regular input + assertFooterHasText(d.getPage(5), "test-file 6"); + assertFooterHasText(d.getPage(15), "test-file 16"); + + // next 3 pages are attachments_as_annots doc + assertFooterHasText(d.getPage(16), "attachments_as_annots 17"); + assertFooterHasText(d.getPage(18), "attachments_as_annots 19"); + }); + } + private float widthOfCropBox(PDPage page) { return page.getCropBox().rotate(page.getRotation()).getWidth(); } diff -Nru libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/util/FontUtilsTest.java libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/util/FontUtilsTest.java --- libsejda-java-3.2.56/sejda-sambox/src/test/java/org/sejda/impl/sambox/util/FontUtilsTest.java 2018-07-27 15:14:06.000000000 +0000 +++ libsejda-java-3.2.66/sejda-sambox/src/test/java/org/sejda/impl/sambox/util/FontUtilsTest.java 2018-12-03 16:42:31.000000000 +0000 @@ -303,7 +303,7 @@ } @Test - public void wrapping_Lines() throws TaskIOException, IOException { + public void wrapping_Lines() throws TaskIOException { PDDocument doc = new PDDocument(); List lines = FontUtils.wrapLines("This is a long line that cannot fit on a single line and could be wrapped", HELVETICA, 10, 191, doc); assertThat(lines, is(Arrays.asList( @@ -313,7 +313,7 @@ } @Test - public void wrapping_Lines_Without_Word_Break() throws TaskIOException, IOException { + public void wrapping_Lines_Without_Word_Break() throws TaskIOException { PDDocument doc = new PDDocument(); List lines = FontUtils.wrapLines("This_is_a_long_line_that_cannot_fit_on_a_single_line_and_could_be_wrapped", HELVETICA, 10, 191, doc); assertThat(lines, is(Arrays.asList( @@ -323,7 +323,7 @@ } @Test - public void wrapping_Lines_Without_Word_Break_Or_Other_Delimiters() throws TaskIOException, IOException { + public void wrapping_Lines_Without_Word_Break_Or_Other_Delimiters() throws TaskIOException { PDDocument doc = new PDDocument(); List lines = FontUtils.wrapLines("Thisisalonglinethatcannotfitonasinglelineandcouldbewrapped", HELVETICA, 10, 191, doc); assertThat(lines, is(Arrays.asList( @@ -333,7 +333,7 @@ } @Test - public void wrapping_Lines_Words_Mixed_With_Super_Long_Words() throws TaskIOException, IOException { + public void wrapping_Lines_Words_Mixed_With_Super_Long_Words() throws TaskIOException { PDDocument doc = new PDDocument(); List lines = FontUtils.wrapLines("This is a long linethatcannotfitonasinglelineandcouldbe wrapped", HELVETICA, 10, 191, doc); assertThat(lines, is(Arrays.asList(