Author: lehmi Date: Thu Feb 6 07:07:12 2025 New Revision: 1923600 URL: http://svn.apache.org/viewvc?rev=1923600&view=rev Log: PDFBOX-5945: fix SIZE entry in trailer dictionary, add test provided by Lahcen FTIH
Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java?rev=1923600&r1=1923599&r2=1923600&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java (original) +++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdfwriter/COSWriter.java Thu Feb 6 07:07:12 2025 @@ -684,18 +684,19 @@ public class COSWriter implements ICOSVi getStandardOutput().writeEOL(); COSDictionary trailer = doc.getTrailer(); - //sort xref, needed only if object keys not regenerated - Collections.sort(getXRefEntries()); - XReferenceEntry lastEntry = getXRefEntries().get(getXRefEntries().size() - 1); - trailer.setLong(COSName.SIZE, lastEntry.getReferencedKey().getNumber() + 1); // Only need to stay, if an incremental update will be performed - if (!incrementalUpdate) + if (!incrementalUpdate) { - trailer.removeItem( COSName.PREV ); + // sort xref, needed only if object keys not regenerated + Collections.sort(getXRefEntries()); + XReferenceEntry lastEntry = getXRefEntries().get(getXRefEntries().size() - 1); + trailer.setLong(COSName.SIZE, lastEntry.getReferencedKey().getNumber() + 1); + trailer.removeItem(COSName.PREV); } if (!doc.isXRefStream()) { - trailer.removeItem( COSName.XREF_STM ); + trailer.setLong(COSName.SIZE, number + 1); + trailer.removeItem(COSName.XREF_STM); } // Remove a checksum if present trailer.removeItem( COSName.DOC_CHECKSUM ); Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java?rev=1923600&r1=1923599&r2=1923600&view=diff ============================================================================== --- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java (original) +++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdfwriter/COSWriterTest.java Thu Feb 6 07:07:12 2025 @@ -16,6 +16,9 @@ */ package org.apache.pdfbox.pdfwriter; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -23,9 +26,21 @@ import java.io.IOException; import java.nio.file.Paths; import org.apache.pdfbox.Loader; +import org.apache.pdfbox.cos.COSDocument; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObjectKey; import org.apache.pdfbox.multipdf.PageExtractor; +import org.apache.pdfbox.pdfwriter.compress.CompressParameters; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.PDResources; +import org.apache.pdfbox.pdmodel.common.PDRectangle; +import org.apache.pdfbox.pdmodel.font.PDFont; +import org.apache.pdfbox.pdmodel.font.PDType1Font; +import org.apache.pdfbox.pdmodel.font.Standard14Fonts; +import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationWidget; +import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm; +import org.apache.pdfbox.pdmodel.interactive.form.PDTextField; import org.junit.jupiter.api.Test; class COSWriterTest @@ -68,4 +83,69 @@ class COSWriterTest } } } + + @Test + void testPDFBox5945() throws Exception + { + byte[] input = create(); + checkTrailerSize(input); + + byte[] output = edit(input); + checkTrailerSize(output); + } + + private static void checkTrailerSize(byte[] docData) throws IOException + { + try (PDDocument pdDocument = Loader.loadPDF(docData)) + { + COSDocument cosDocument = pdDocument.getDocument(); + long maxObjNumber = cosDocument.getXrefTable().keySet().stream() // + .mapToLong(COSObjectKey::getNumber).max().getAsLong(); + long sizeFromTrailer = cosDocument.getTrailer().getLong(COSName.SIZE); + assertEquals(maxObjNumber + 1, sizeFromTrailer); + } + } + + private static byte[] create() throws IOException + { + try (PDDocument pdDocument = new PDDocument()) + { + PDAcroForm acroForm = new PDAcroForm(pdDocument); + pdDocument.getDocumentCatalog().setAcroForm(acroForm); + PDFont font1 = new PDType1Font(Standard14Fonts.FontName.HELVETICA); + PDFont font2 = new PDType1Font(Standard14Fonts.FontName.ZAPF_DINGBATS); + PDResources resources = new PDResources(); + resources.put(COSName.getPDFName("Helv"), font1); + resources.put(COSName.getPDFName("ZaDb"), font2); + acroForm.setDefaultResources(resources); + PDPage page = new PDPage(PDRectangle.A4); + pdDocument.addPage(page); + PDTextField textField = new PDTextField(acroForm); + textField.setPartialName("textFieldName"); + acroForm.getFields().add(textField); + PDAnnotationWidget widget = textField.getWidgets().get(0); + widget.setPage(page); + page.getAnnotations().add(widget); + PDRectangle rectangle = new PDRectangle(10, 200, 200, 15); + widget.setRectangle(rectangle); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + pdDocument.save(out, CompressParameters.NO_COMPRESSION); + return out.toByteArray(); + } + } + + private static byte[] edit(byte[] input) throws IOException + { + try (PDDocument pdDocument = Loader.loadPDF(input)) + { + PDTextField textField = (PDTextField) pdDocument.getDocumentCatalog().getAcroForm() + .getField("textFieldName"); + assertNotNull(textField); + textField.setMultiline(true); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + pdDocument.saveIncremental(out); + return out.toByteArray(); + } + } + }