diff options
Diffstat (limited to 'pdf-as-pdfbox-2/src')
10 files changed, 219 insertions, 90 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 7cff90d6..0b148551 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 @@ -52,9 +52,11 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map.Entry; +import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.Vector; @@ -69,6 +71,8 @@ import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.graphics.PDXObject; import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDPropBuild; +import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDPropBuildDataDict; import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature; import org.apache.pdfbox.util.Matrix; @@ -101,6 +105,9 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SignaturePlaceholderExtractor extends PDFStreamEngine implements PlaceholderExtractorConstants { + public static final String PREFIX = "PDF-AS_"; + + private final Set<String> placeholderNames = new HashSet<>(); private final List<SignaturePlaceholderData> placeholders = new ArrayList<>(); private int currentPage = 0; @@ -137,51 +144,36 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl */ public SignaturePlaceholderData extract(PDDocument doc, String placeholderId, int matchMode) throws PdfAsException { - List<String> extistingSignatureNames = existingExistingSignatureNames(doc); - - - int pageNr = 0; - for (final PDPage page : doc.getPages()) { - pageNr++; + log.debug("Initial found #{} already used placeholders", extistingSignatureNames.size()); - try { - this.currentPage = pageNr; - if (page.getContents() != null && page.getResources() != null && page.getContentStreams() != null) { - processPage(page); // TODO: pdfbox2 - right? - - } - - final SignaturePlaceholderData ret = matchPlaceholderPage( - removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), placeholderId, matchMode); - if (ret != null) { - return ret; - - } - - } catch (final IOException e1) { - throw new PDFIOException("error.pdf.io.04", e1); - - } catch (final Throwable e) { - throw new PDFIOException("error.pdf.io.04", e); - - } - } + SignaturePlaceholderData foundOnSinglePage = + parseDocumentAndSearchOnSiglePages(doc, extistingSignatureNames, placeholderId, matchMode); - if (placeholders.size() > 0) { - final SignaturePlaceholderData ret = matchPlaceholderDocument( - removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), placeholderId, matchMode); - return ret; - - } - // no placeholders found, apply strict mode if set - if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { - throw new PlaceholderExtractionException("error.pdf.stamp.09"); + if (foundOnSinglePage != null) { + return foundOnSinglePage; + } else { + return searchOnAnyPage(extistingSignatureNames, matchMode); + } - return null; } + /** + * Set a placeholderId into signature directory. + * + * @param signature Signature + * @param placeholderId placeholderId + */ + public static void setPlaceholderId(PDSignature signature, String placeholderId) { + PDPropBuild sigProps = getOrNew(signature); + PDPropBuildDataDict appProps = getOrNew(sigProps); + appProps.setName(PREFIX + placeholderId); + sigProps.setPDPropBuildApp(appProps); + signature.setPropBuild(sigProps); + + } + @Override protected void processOperator(Operator operator, List<COSBase> arguments) throws IOException { @@ -235,12 +227,14 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl final String posString = "p:" + currentPage + ";x:" + Math.floor(x) + ";y:" + Math.ceil(y) + ";w:" + Math.ceil(w); - - log.debug("Found Placeholder at: {}", posString); + try { data.setTablePos(new TablePos(posString)); - data.setPlaceholderName(objectName.getName()); + + data.setPlaceholderName(buildUniqueObjectName(objectName)); + log.debug("Found Placeholder at: {}", data.toString()); placeholders.add(data); + placeholderNames.add(data.getPlaceholderName()); } catch (final PdfAsException e) { throw new IOException(); @@ -255,8 +249,78 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl super.processOperator(operator, arguments); } } + + private SignaturePlaceholderData searchOnAnyPage(List<String> extistingSignatureNames, int matchMode) throws PlaceholderExtractionException { + if (placeholders.size() > 0) { + final SignaturePlaceholderData ret = matchPlaceholderDocument( + removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), matchMode); + return ret; + + } + // no placeholders found, apply strict mode if set + if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { + throw new PlaceholderExtractionException("error.pdf.stamp.09"); + + } + + return null; + + } + + private SignaturePlaceholderData parseDocumentAndSearchOnSiglePages(PDDocument doc, List<String> extistingSignatureNames, + String placeholderId, int matchMode) throws PDFIOException { + int pageNr = 0; + for (final PDPage page : doc.getPages()) { + pageNr++; + + SignaturePlaceholderData ret = processSinglePage(page, pageNr, extistingSignatureNames, placeholderId, matchMode); + if (ret != null) { + log.debug("Found placeholder to use on page: {}. Stopping further search ... ", this.currentPage); + return ret; + + } + } + + return null; + + } + + private SignaturePlaceholderData processSinglePage(PDPage page, int pageNr, List<String> extistingSignatureNames, + String placeholderId, int matchMode) throws PDFIOException { + try { + this.currentPage = pageNr; + if (page.getContents() != null && page.getResources() != null && page.getContentStreams() != null) { + processPage(page); // TODO: pdfbox2 - right? + + } + + return matchPlaceholderOnSinglePage( + removeAlreadyUsePlaceholders(placeholders, extistingSignatureNames), placeholderId, matchMode); + + } catch (final Throwable e) { + throw new PDFIOException("error.pdf.io.04", e); + + } + } + + + /** + * Builds unique placeholderId from PDF element. + * + * @param name PDF element name + * @return unique identifier + */ + private String buildUniqueObjectName(COSName name) { + final String baseName = name.getName(); + int i = 0; + String candidate = baseName; + while (placeholderNames.contains(candidate)) { + candidate = baseName + "_" + (++i); + } + return candidate; + } - private SignaturePlaceholderData matchPlaceholderPage( + private SignaturePlaceholderData matchPlaceholderOnSinglePage( List<SignaturePlaceholderData> placeholders, String placeholderId, int matchMode) { log.debug("Searching requested placeholder:{} with matchMode:{} in single page ... ", placeholderId, matchMode); @@ -264,15 +328,22 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl return null; } - - // check if find a placeholder with that ID + for (final SignaturePlaceholderData data : placeholders) { + + /* + * If specific placeholderId is requested and placeholder as an Id, check if it already matches + */ if (placeholderId != null && data.getId() != null && matchPlaceHolderId(placeholderId, data.getId())) { return data; } + /* + * If mode is not sorted and there is no specific placeholderId requested + * and placeholder contains no Id use the first one found + */ if (matchMode != PLACEHOLDER_MATCH_MODE_SORTED && placeholderId == null && data.getId() == null) { return data; @@ -284,10 +355,9 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl } private SignaturePlaceholderData matchPlaceholderDocument( - List<SignaturePlaceholderData> placeholders, String placeholderId, - int matchMode) throws PlaceholderExtractionException { + List<SignaturePlaceholderData> placeholders, int matchMode) throws PlaceholderExtractionException { - log.debug("Searching requested placeholder:{} with matchMode:{} on any page ... ", placeholderId, matchMode); + log.debug("Searching requested placeholder with matchMode:{} on any page ... ", matchMode); if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) { throw new PlaceholderExtractionException("error.pdf.stamp.09"); @@ -382,19 +452,20 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl } } + private List<String> existingExistingSignatureNames(PDDocument doc) { - final List<String> existingLocations = new ArrayList<>(); try { - final List<PDSignature> pdSignatureList = doc.getSignatureDictionaries(); - if (pdSignatureList.size() != 0) { - for (final PDSignature sig : pdSignatureList) { - existingLocations.add(sig.getLocation()); - } - } + final List<PDSignature> pdSignatureList = doc.getSignatureDictionaries(); + return pdSignatureList.stream() + .map(el -> readPlaceHolderId(el)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } catch (final IOException e) { - e.printStackTrace(); + log.warn("Can not parse signature dictionaries", e); + return Collections.emptyList(); + } - return existingLocations; } private List<SignaturePlaceholderData> removeAlreadyUsePlaceholders( @@ -403,7 +474,7 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl List<SignaturePlaceholderData> result = placeholders.stream() .filter(el -> !existingPlaceholders.contains(el.getPlaceholderName())) .collect(Collectors.toList()); - log.debug("Initial found #{} placeholders, but #{} removed because already used.", + log.trace("Initial found #{} placeholders, but #{} removed because already used.", placeholders.size(), placeholders.size() - result.size()); return result; @@ -511,4 +582,33 @@ public class SignaturePlaceholderExtractor extends PDFStreamEngine implements Pl } return null; } + + /** + * Read placeholderId from signature. + * + * @param signature Signature + * @return placeholderId or <code>null</code> if there is no placeholderId. + */ + private static String readPlaceHolderId(PDSignature signature) { + PDPropBuild sigProps = getOrNew(signature); + PDPropBuildDataDict appProps = getOrNew(sigProps); + String newHolderId = appProps.getName() != null && appProps.getName().startsWith(PREFIX) + ? appProps.getName().substring(PREFIX.length()) + : appProps.getName(); + + // read placeHolderId from old location element as backup + return newHolderId != null ? newHolderId : signature.getLocation(); + + } + + private static final PDPropBuildDataDict getOrNew(PDPropBuild sigProps) { + PDPropBuildDataDict props = sigProps.getApp(); + return props != null ? props : new PDPropBuildDataDict(); + } + + private static final PDPropBuild getOrNew(PDSignature signature) { + PDPropBuild sigProps = signature.getPropBuild(); + return sigProps != null ? sigProps : new PDPropBuild(); + + } } diff --git a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java index 37ceee97..d8a25a9a 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java +++ b/pdf-as-pdfbox-2/src/main/java/at/gv/egiz/pdfas/lib/impl/signing/pdfbox2/PADESPDFBOXSigner.java @@ -85,6 +85,7 @@ import at.gv.egiz.pdfas.lib.impl.ErrorExtractor; import at.gv.egiz.pdfas.lib.impl.SignaturePositionImpl; import at.gv.egiz.pdfas.lib.impl.configuration.SignatureProfileConfiguration; import at.gv.egiz.pdfas.lib.impl.pdfbox2.PDFBOXObject; +import at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder.SignaturePlaceholderExtractor; import at.gv.egiz.pdfas.lib.impl.pdfbox2.positioning.Positioning; import at.gv.egiz.pdfas.lib.impl.pdfbox2.utils.PdfBoxUtils; import at.gv.egiz.pdfas.lib.impl.placeholder.PlaceholderFilter; @@ -163,9 +164,9 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { pdfObject.getStatus().getSignParamter().getPlaceHolderId()); if (nextPlaceholderData != null) { - log.info("Placeholder data found."); - signature.setLocation(nextPlaceholderData.getPlaceholderName()); - + log.info("Placeholder data found. Injection placeholderId ..."); + SignaturePlaceholderExtractor.setPlaceholderId(signature, nextPlaceholderData.getPlaceholderName()); + if (nextPlaceholderData.getProfile() != null) { if (pdfObject.getStatus().getSettings().isValue(IConfigurationConstants.PLACEHOLDER_PROFILE_OVERWRITE, true)) { log.debug("Placeholder Profile set to: {}", nextPlaceholderData.getProfile()); @@ -613,24 +614,24 @@ public class PADESPDFBOXSigner implements IPdfSigner, IConfigurationConstants { return tablePos; } else { - TablePos signaturePos = null; - final String signaturePosString = signatureProfileConfiguration.getDefaultPositioning(); + TablePos defaultSignaturePos = null; + final String defaultPosString = signatureProfileConfiguration.getDefaultPositioning(); - if (signaturePosString != null) { - log.debug("using signature Positioning: " + signaturePosString); - signaturePos = new TablePos(signaturePosString); + + if (defaultPosString != null) { + log.debug("Default signature positioning is: {}", defaultPosString); + defaultSignaturePos = new TablePos(defaultPosString); } - log.debug("using Positioning: " + profilePosParam); - if (profilePosParam != null) { + log.debug("Find positioning parameter: {} Merge it with default ...", profilePosParam); // Merge Signature Position - return new TablePos(profilePosParam, signaturePos); + return new TablePos(profilePosParam, defaultSignaturePos); - } else if (signaturePos != null){ + } else if (defaultSignaturePos != null){ // Fallback to signature Position! - return signaturePos; + return defaultSignaturePos; } else { return new TablePos(); diff --git a/pdf-as-pdfbox-2/src/main/java/at/knowcenter/wag/egov/egiz/pdfbox2/pdf/PDFUtilities.java b/pdf-as-pdfbox-2/src/main/java/at/knowcenter/wag/egov/egiz/pdfbox2/pdf/PDFUtilities.java index 995b4e10..741860e2 100644 --- a/pdf-as-pdfbox-2/src/main/java/at/knowcenter/wag/egov/egiz/pdfbox2/pdf/PDFUtilities.java +++ b/pdf-as-pdfbox-2/src/main/java/at/knowcenter/wag/egov/egiz/pdfbox2/pdf/PDFUtilities.java @@ -68,33 +68,37 @@ public abstract class PDFUtilities implements IConfigurationConstants{ public static float getMaxYPosition( PDDocument pdfDataSource, int page, IPDFVisualObject pdfTable, float signatureMarginVertical, float footer_line, ISettings settings) throws IOException { - - PositioningRenderer renderer = new PositioningRenderer(pdfDataSource); - //BufferedImage bim = renderer.renderImage(page); - - int width = (int) pdfDataSource.getPage(page).getCropBox().getWidth(); - int height = (int) pdfDataSource.getPage(page).getCropBox().getHeight(); - BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + int width = (int) pdfDataSource.getPage(page).getCropBox().getWidth(); + int height = (int) pdfDataSource.getPage(page).getCropBox().getHeight(); + + // flip image in case of page rotation is 90 or 270 + BufferedImage bim = (pdfDataSource.getPage(page).getRotation() % 180 == 0) + ? new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB) + : new BufferedImage(height, width, BufferedImage.TYPE_INT_ARGB); + Graphics2D graphics = bim.createGraphics(); graphics.setBackground(MAGIC_COLOR); - + + PositioningRenderer renderer = new PositioningRenderer(pdfDataSource); renderer.renderPageToGraphics(page, graphics); - Color bgColor = MAGIC_COLOR; - - if("true".equals(settings.getValue(BG_COLOR_DETECTION))){ //only used if background color should be determined automatically - bgColor = determineBackgroundColor(bim); - } - + /* + * Only used if background color should be determined automatically. + * That can be necessary of PDF contains page-size images. + */ + Color bgColor = "true".equals(settings.getValue(BG_COLOR_DETECTION)) + ? determineBackgroundColor(bim) + : MAGIC_COLOR; + int yCoord = bim.getHeight() - 1 - (int)footer_line; for(int row = yCoord; row >= 0; row--) { - if (row == 0) - yCoord = row; - else - { + if (row == 0) { + yCoord = row; + + } else { for(int col = 0; col < bim.getWidth(); col++){ int val = bim.getRGB(col, row); if(val != bgColor.getRGB()){ @@ -105,11 +109,14 @@ public abstract class PDFUtilities implements IConfigurationConstants{ } } } + String outFile = settings.getValue(SIG_PLACEMENT_DEBUG_OUTPUT); - if(outFile!=null){ + if(outFile != null){ ImageIOUtil.writeImage(bim, outFile, 72); } + return yCoord; + } public static Color determineBackgroundColor(BufferedImage bim){ 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 fbe3cdea..8bd733c3 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 @@ -2,11 +2,13 @@ package at.gv.egiz.pdfas.lib.testpdfbox; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.List; import org.apache.pdfbox.pdmodel.PDDocument; +import org.junit.Ignore; import org.junit.Test; import at.gv.egiz.pdfas.lib.impl.pdfbox2.placeholder.SignatureFieldsAndPlaceHolderExtractor; @@ -20,7 +22,6 @@ public class PDFBoxPlaceholderExtractorTest { public void nextPlaceholder() { SignaturePlaceholderData result = getNextSignaturePlaceHolder("/data/platzhalter_en_de_test.pdf"); assertEquals("Im48", result.getPlaceholderName()); - } @Test @@ -28,9 +29,29 @@ public class PDFBoxPlaceholderExtractorTest { public void allPlaceHolders() { List<String> listOfPlaceHolders = getPlaceHolders("/data/platzhalter_en_de_test.pdf"); assertNotNull(listOfPlaceHolders); + assertTrue(listOfPlaceHolders.isEmpty()); } + @Test + @SneakyThrows + public void nextPlaceholderDuplicateElements() { + assertEquals("Im0_1", getNextSignaturePlaceHolder("/data/Testdoc_Signatur.pdf").getPlaceholderName()); + assertEquals("Im0_2", getNextSignaturePlaceHolder("/data/own_Testdoc+Signatur-sign-sign.pdf").getPlaceholderName()); + assertEquals("Im0_2", getNextSignaturePlaceHolder("/data/own_Testdoc+Signatur-sign-sign-4_sign.pdf").getPlaceholderName()); + assertEquals("Im0", getNextSignaturePlaceHolder("/data/own_Testdoc+Signatur-sign-sign-4_sign-sign.pdf").getPlaceholderName()); + + } + + @Test + @Ignore + @SneakyThrows + public void placeHolderInAnnotation() { + SignaturePlaceholderData listOfPlaceHolders = getNextSignaturePlaceHolder("/data/Test-sign.pdf"); + assertNotNull(listOfPlaceHolders); + + } + private static List<String> getPlaceHolders(String filePath) throws IOException { final PDDocument doc = PDDocument.load(PDFBoxPlaceholderExtractorTest.class.getResourceAsStream( filePath)); diff --git a/pdf-as-pdfbox-2/src/test/resources/data/Test-sign.pdf b/pdf-as-pdfbox-2/src/test/resources/data/Test-sign.pdf Binary files differnew file mode 100644 index 00000000..7395663e --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/Test-sign.pdf diff --git a/pdf-as-pdfbox-2/src/test/resources/data/Testdoc_Signatur.pdf b/pdf-as-pdfbox-2/src/test/resources/data/Testdoc_Signatur.pdf Binary files differnew file mode 100644 index 00000000..81af9006 --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/Testdoc_Signatur.pdf diff --git a/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign-sign.pdf b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign-sign.pdf Binary files differnew file mode 100644 index 00000000..d1623f5e --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign-sign.pdf diff --git a/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign.pdf b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign.pdf Binary files differnew file mode 100644 index 00000000..72d6007f --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign-4_sign.pdf diff --git a/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign.pdf b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign.pdf Binary files differnew file mode 100644 index 00000000..5c472d46 --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign-sign.pdf diff --git a/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign.pdf b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign.pdf Binary files differnew file mode 100644 index 00000000..1bda36c6 --- /dev/null +++ b/pdf-as-pdfbox-2/src/test/resources/data/own_Testdoc+Signatur-sign.pdf |
