From 485e89f588a61b30f2aa2cb1d4e3406fce8d2bb8 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 13 Jan 2026 13:20:06 +0100 Subject: fix(placeholder): generate placeholderId using name and object reference Reason: according to the PDF specification, a name only needs to be unique within a specific resource list, and multiple resource lists may exist within a document --- .../placeholder/SignaturePlaceholderExtractor.java | 28 ++++++++++++++++++++- .../testpdfbox/PDFBoxPlaceholderExtractorTest.java | 2 +- ...SignatureFieldsAndPlaceHolderExtractorTest.java | 20 +++++++-------- .../src/test/resources/new_qr_2_signed.pdf | Bin 225097 -> 267402 bytes .../src/test/resources/new_qr_2_signed_signed.pdf | Bin 267093 -> 352501 bytes .../resources/new_qr_2_signed_signed_signed.pdf | Bin 310607 -> 437946 bytes 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java index 011eac89..8716603b 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/pdfbox2/placeholder/SignaturePlaceholderExtractor.java @@ -65,7 +65,9 @@ import org.apache.pdfbox.contentstream.PDFStreamEngine; import org.apache.pdfbox.contentstream.operator.Operator; import org.apache.pdfbox.contentstream.operator.OperatorProcessor; import org.apache.pdfbox.cos.COSBase; +import org.apache.pdfbox.cos.COSDictionary; import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSObject; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.graphics.PDXObject; @@ -243,7 +245,7 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl try { data.setTablePos(new TablePos(posString)); - data.setPlaceholderName(objectName.getName()); + data.setPlaceholderName(buildUniqueObjectName(objectName)); log.debug("Found Placeholder at: {}", data.toString()); placeholders.add(data); @@ -291,7 +293,31 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl } + /** + * Builds unique placeholderId from PDF element. + * + * @param name PDF element name + * @return unique identifier + */ + private String buildUniqueObjectName(COSName name) + { + COSDictionary dict = getResources().getCOSObject().getCOSDictionary(COSName.XOBJECT); + if (dict == null) + { + return name.getName(); + + } + + COSBase base = dict.getItem(name); + if (base instanceof COSObject) + { + return name.getName() + "_" + String.valueOf(((COSObject) base).getObjectNumber()); + + } + return name.getName(); + + } private SignaturePlaceholderData matchPlaceholderPage( List placeholders, String placeholderId, int matchMode) { diff --git a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java index 80e3eb4d..d0c215ae 100644 --- a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java +++ b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/PDFBoxPlaceholderExtractorTest.java @@ -21,7 +21,7 @@ public class PDFBoxPlaceholderExtractorTest { @SneakyThrows public void nextPlaceholder() { SignaturePlaceholderData result = getNextSignaturePlaceHolder("/data/platzhalter_en_de_test.pdf"); - assertEquals("Im48", result.getPlaceholderName()); + assertEquals("Im48_48", result.getPlaceholderName()); } diff --git a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java index 0ed05eb5..2e5e475c 100644 --- a/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java +++ b/pdf-as-pdfbox-2/src/test/java/at/gv/egiz/pdfas/lib/testpdfbox/SignatureFieldsAndPlaceHolderExtractorTest.java @@ -29,12 +29,12 @@ public class SignatureFieldsAndPlaceHolderExtractorTest { @Test public void notSigned(){ SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); } @Test public void signedOnce(){ SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed.pdf")); - Assert.assertEquals("Image8",result.getPlaceholderName()); + Assert.assertEquals("Image8_8",result.getPlaceholderName()); } @Test public void signedTwice(){ @@ -56,7 +56,7 @@ public class SignatureFieldsAndPlaceHolderExtractorTest { @Test public void firstQrCodeOnUnsignedDoc() { SignaturePlaceholderData result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); } @@ -66,28 +66,28 @@ public class SignatureFieldsAndPlaceHolderExtractorTest { Assert.assertEquals(null,result); result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed.pdf")); - Assert.assertEquals("Image8",result.getPlaceholderName()); + Assert.assertEquals("Image8_8",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed.pdf")); - Assert.assertEquals("Image8",result.getPlaceholderName()); + Assert.assertEquals("Image8_8",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed_signed_signed.pdf")); Assert.assertEquals(null,result); result = getNextSignaturePlaceHolder(getPath("new_qr_2-2.pdf")); - Assert.assertEquals("Image5",result.getPlaceholderName()); + Assert.assertEquals("Image5_5",result.getPlaceholderName()); result = getNextSignaturePlaceHolder(getPath("new_qr_2_signed.pdf")); - Assert.assertEquals("Image8",result.getPlaceholderName()); + Assert.assertEquals("Image8_8",result.getPlaceholderName()); } @Test public void notSignedAndNoFields(){ diff --git a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed.pdf b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed.pdf index be6fdddb..c3a53b23 100644 Binary files a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed.pdf and b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed.pdf differ diff --git a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed.pdf b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed.pdf index ee0f140f..1b831a73 100644 Binary files a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed.pdf and b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed.pdf differ diff --git a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed_signed.pdf b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed_signed.pdf index 34769dd0..6468ada7 100644 Binary files a/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed_signed.pdf and b/pdf-as-pdfbox-2/src/test/resources/new_qr_2_signed_signed_signed.pdf differ -- cgit v1.2.3