aboutsummaryrefslogtreecommitdiff
path: root/pdf-as-lib
diff options
context:
space:
mode:
authorAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2013-11-27 10:05:35 +0100
committerAndreas Fitzek <andreas.fitzek@iaik.tugraz.at>2013-11-27 10:05:35 +0100
commit29ec10fb663523c4a18904c332199ce6e974dd2f (patch)
tree3d68c52ca1fd5e2cb2f90c1890db22e4fd943dcb /pdf-as-lib
parentf3476576c50efd922593c82656efda7aec5ae97f (diff)
downloadpdf-as-4-29ec10fb663523c4a18904c332199ce6e974dd2f.tar.gz
pdf-as-4-29ec10fb663523c4a18904c332199ce6e974dd2f.tar.bz2
pdf-as-4-29ec10fb663523c4a18904c332199ce6e974dd2f.zip
Support for QR Placeholders in PAdES
Diffstat (limited to 'pdf-as-lib')
-rw-r--r--pdf-as-lib/bin/placeholder/empty.jpgbin0 -> 631 bytes
-rw-r--r--pdf-as-lib/bin/placeholder/pdfbox-reader.properties23
-rw-r--r--pdf-as-lib/build.gradle2
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/PdfAsFactory.java4
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java87
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderContext.java72
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderData.java152
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java351
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/package-info.java8
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java2
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/RequestedSignature.java4
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java2
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/sl/util/BKUSLConnector.java2
-rw-r--r--pdf-as-lib/src/main/java/at/gv/egiz/sl/util/ISignatureConnectorSLWrapper.java2
-rw-r--r--pdf-as-lib/src/main/resources/placeholder/empty.jpgbin0 -> 631 bytes
-rw-r--r--pdf-as-lib/src/main/resources/placeholder/pdfbox-reader.properties23
16 files changed, 722 insertions, 12 deletions
diff --git a/pdf-as-lib/bin/placeholder/empty.jpg b/pdf-as-lib/bin/placeholder/empty.jpg
new file mode 100644
index 00000000..7913177d
--- /dev/null
+++ b/pdf-as-lib/bin/placeholder/empty.jpg
Binary files differ
diff --git a/pdf-as-lib/bin/placeholder/pdfbox-reader.properties b/pdf-as-lib/bin/placeholder/pdfbox-reader.properties
new file mode 100644
index 00000000..a3decc96
--- /dev/null
+++ b/pdf-as-lib/bin/placeholder/pdfbox-reader.properties
@@ -0,0 +1,23 @@
+BT = org.apache.pdfbox.util.operator.BeginText
+cm = org.apache.pdfbox.util.operator.Concatenate
+Do = org.apache.pdfbox.util.operator.Invoke
+ET = org.apache.pdfbox.util.operator.EndText
+gs = org.apache.pdfbox.util.operator.SetGraphicsStateParameters
+q = org.apache.pdfbox.util.operator.GSave
+Q = org.apache.pdfbox.util.operator.GRestore
+T* = org.apache.pdfbox.util.operator.NextLine
+Tc = org.apache.pdfbox.util.operator.SetCharSpacing
+Td = org.apache.pdfbox.util.operator.MoveText
+TD = org.apache.pdfbox.util.operator.MoveTextSetLeading
+Tf = org.apache.pdfbox.util.operator.SetTextFont
+Tj = org.apache.pdfbox.util.operator.ShowText
+TJ = org.apache.pdfbox.util.operator.ShowTextGlyph
+TL = org.apache.pdfbox.util.operator.SetTextLeading
+Tm = org.apache.pdfbox.util.operator.SetMatrix
+Tr = org.apache.pdfbox.util.operator.SetTextRenderingMode
+Ts = org.apache.pdfbox.util.operator.SetTextRise
+Tw = org.apache.pdfbox.util.operator.SetWordSpacing
+Tz = org.apache.pdfbox.util.operator.SetHorizontalTextScaling
+w = org.apache.pdfbox.util.operator.SetLineWidth
+\' = org.apache.pdfbox.util.operator.MoveAndShow
+\" = org.apache.pdfbox.util.operator.SetMoveAndShow \ No newline at end of file
diff --git a/pdf-as-lib/build.gradle b/pdf-as-lib/build.gradle
index 68d65d99..683df99c 100644
--- a/pdf-as-lib/build.gradle
+++ b/pdf-as-lib/build.gradle
@@ -67,6 +67,8 @@ dependencies {
compile group: 'eu.europa.ec.joinup.egovlabs.pdf-as.iaik', name: 'iaik_ecc_eval_signed', version: '2.19'
compile group: 'log4j', name: 'log4j', version: '1.2.17'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.5'
+ compile group: 'com.google.zxing', name: 'core', version: '2.2'
+ compile group: 'com.google.zxing', name: 'javase', version: '2.2'
//compile group: 'org.slf4j', name: 'slf4j-log4j12', version: '1.7.5'
testCompile group: 'junit', name: 'junit', version: '4.+'
/*generateJavaFromWsdlDeps('org.apache.axis:axis:1.4')
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/PdfAsFactory.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/PdfAsFactory.java
index 10391ecc..e26e3fdb 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/PdfAsFactory.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/api/PdfAsFactory.java
@@ -14,8 +14,8 @@ import at.gv.egiz.pdfas.lib.impl.VerifyParameterImpl;
public class PdfAsFactory {
static {
- //PropertyConfigurator.configure(ClassLoader.getSystemResourceAsStream("resources/log4j.properties"));
- BasicConfigurator.configure();
+ PropertyConfigurator.configure(ClassLoader.getSystemResourceAsStream("resources/log4j.properties"));
+ //BasicConfigurator.configure();
}
public static PdfAs createPdfAs(File configuration) {
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java
index 4a8e41c3..2f2d47c8 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/PdfAsImpl.java
@@ -3,6 +3,7 @@ package at.gv.egiz.pdfas.lib.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
@@ -35,6 +36,8 @@ import at.gv.egiz.pdfas.lib.api.verify.VerifyResult;
import at.gv.egiz.pdfas.lib.impl.configuration.ConfigurationImpl;
import at.gv.egiz.pdfas.lib.impl.configuration.PlaceholderConfiguration;
import at.gv.egiz.pdfas.lib.impl.configuration.SignatureProfileConfiguration;
+import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderData;
+import at.gv.egiz.pdfas.lib.impl.placeholder.SignaturePlaceholderExtractor;
import at.gv.egiz.pdfas.lib.impl.positioning.Positioning;
import at.gv.egiz.pdfas.lib.impl.signing.IPdfSigner;
import at.gv.egiz.pdfas.lib.impl.signing.PdfSignerFactory;
@@ -105,13 +108,12 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants {
status.getPdfObject().setOriginalDocument(
parameter.getDataSource().getByteData());
- // Placeholder search?
- if (placeholderConfiguration.isGlobalPlaceholderEnabled()) {
- // TODO: Do placeholder search
- }
-
this.stampPdf(status);
+ FileOutputStream fos = new FileOutputStream("/home/afitzek/qr_2_stamped.pdf");
+ fos.write(status.getPdfObject().getStampedDocument());
+ fos.close();
+
/*
* if (requestedSignature.isVisual()) {
* logger.info("Creating visual siganture block"); //
@@ -259,7 +261,7 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants {
if (verifyFilter != null) {
List<VerifyResult> results = verifyFilter.verify(
contentData.toByteArray(), content.getBytes());
- if(results != null && !results.isEmpty()) {
+ if (results != null && !results.isEmpty()) {
result.addAll(results);
}
}
@@ -421,6 +423,72 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants {
}
}
+ private boolean checkPlaceholderSignature(OperationStatus status)
+ throws PdfAsException, IOException {
+ if (status.getPlaceholderConfiguration().isGlobalPlaceholderEnabled()) {
+ SignaturePlaceholderData signaturePlaceholderData = SignaturePlaceholderExtractor
+ .extract(new ByteArrayInputStream(status.getPdfObject()
+ .getOriginalDocument()), null, 1);
+
+ if (signaturePlaceholderData != null) {
+ RequestedSignature requestedSignature = status
+ .getRequestedSignature();
+
+ if (signaturePlaceholderData.getProfile() != null) {
+ requestedSignature
+ .setSignatureProfileID(signaturePlaceholderData
+ .getProfile());
+ }
+
+ String signatureProfileID = requestedSignature
+ .getSignatureProfileID();
+
+ TablePos tablePos = signaturePlaceholderData.getTablePos();
+
+ SignatureProfileSettings signatureProfileSettings = TableFactory
+ .createProfile(signatureProfileID, settings);
+
+ Table main = TableFactory.createSigTable(
+ signatureProfileSettings, MAIN, settings,
+ requestedSignature);
+
+ IPDFStamper stamper = StamperFactory
+ .createDefaultStamper(settings);
+ IPDFVisualObject visualObject = stamper.createVisualPDFObject(
+ status.getPdfObject(), main);
+
+ PDDocument originalDocument = PDDocument
+ .load(new ByteArrayInputStream(status.getPdfObject()
+ .getOriginalDocument()));
+
+ PositioningInstruction positioningInstruction = Positioning
+ .determineTablePositioning(tablePos, "", originalDocument,
+ visualObject);
+
+ // ================================================================
+ // StampingStage (visual) -> stamp logical signature block to
+ // location (itext)
+
+ byte[] incrementalUpdate = stamper.writeVisualObject(visualObject,
+ positioningInstruction, status.getPdfObject()
+ .getOriginalDocument(), signaturePlaceholderData.getPlaceholderName());
+
+ SignaturePositionImpl position = new SignaturePositionImpl();
+ position.setX(positioningInstruction.getX());
+ position.setY(positioningInstruction.getY());
+ position.setPage(positioningInstruction.getPage());
+ position.setHeight(visualObject.getHeight());
+ position.setWidth(visualObject.getWidth());
+
+ requestedSignature.setSignaturePosition(position);
+
+ status.getPdfObject().setStampedDocument(incrementalUpdate);
+ return true;
+ }
+ }
+ return false;
+ }
+
private void stampPdf(OperationStatus status) throws PdfAsException,
IOException {
@@ -429,6 +497,11 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants {
SignatureProfileConfiguration signatureProfileConfiguration = status
.getSignatureProfileConfiguration(signatureProfileID);
+ if (checkPlaceholderSignature(status)) {
+ logger.info("Placeholder found for Signature");
+ return;
+ }
+
if (requestedSignature.isVisual()) {
logger.info("Creating visual siganture block");
// ================================================================
@@ -477,7 +550,7 @@ public class PdfAsImpl implements PdfAs, IConfigurationConstants {
byte[] incrementalUpdate = stamper.writeVisualObject(visualObject,
positioningInstruction, status.getPdfObject()
- .getOriginalDocument());
+ .getOriginalDocument(), null);
SignaturePositionImpl position = new SignaturePositionImpl();
position.setX(positioningInstruction.getX());
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderContext.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderContext.java
new file mode 100644
index 00000000..28a34f6a
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderContext.java
@@ -0,0 +1,72 @@
+/**
+ * <copyright> Copyright 2006 by Know-Center, Graz, Austria </copyright>
+ * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
+ * joint initiative of the Federal Chancellery Austria and Graz University of
+ * Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.pdfas.lib.impl.placeholder;
+
+/**
+ * Store and retrieve {@link SignaturePlaceholderData} in/from a thread local context.
+ *
+ * @author exthex
+ *
+ */
+public class SignaturePlaceholderContext {
+
+ private ThreadLocal sigHolder = new ThreadLocal();
+
+ private static SignaturePlaceholderContext instance = new SignaturePlaceholderContext();
+
+ /**
+ * Constructor. Private because this is a singleton.
+ */
+ private SignaturePlaceholderContext() {
+
+ }
+
+ /**
+ * Get the {@link SignaturePlaceholderData} which is currently bound to this thread.
+ * Might be null.
+ *
+ * @return
+ */
+ public static SignaturePlaceholderData getSignaturePlaceholderData(){
+ return (SignaturePlaceholderData)instance.sigHolder.get();
+ }
+
+ /**
+ *
+ * @return true if there is currently a {@link SignaturePlaceholderData} bound to this thread, false otherwise.
+ */
+ public static boolean isSignaturePlaceholderDataSet() {
+ return instance.sigHolder.get() != null;
+ }
+
+ /**
+ * Bind a {@link SignaturePlaceholderData} to this thread.
+ * If the given data is null, the context will be cleared.
+ *
+ * @param data if null, clears the ThreadLocal, else binds the data to the current thread.
+ */
+ public static void setSignaturePlaceholderData(SignaturePlaceholderData data) {
+ instance.sigHolder.set(data);
+ }
+}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderData.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderData.java
new file mode 100644
index 00000000..d068104a
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderData.java
@@ -0,0 +1,152 @@
+/**
+ * <copyright> Copyright 2006 by Know-Center, Graz, Austria </copyright>
+ * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
+ * joint initiative of the Federal Chancellery Austria and Graz University of
+ * Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.pdfas.lib.impl.placeholder;
+
+import at.knowcenter.wag.egov.egiz.pdf.TablePos;
+
+/**
+ * This class represents all the data which can be extracted from a placeholder image.
+ *
+ * @author exthex
+ *
+ */
+public class SignaturePlaceholderData {
+
+ public static final String ID_KEY = "id";
+
+ public static final String PROFILE_KEY = "profile";
+
+ public static final String TYPE_KEY = "type";
+
+ public static final String SIG_KEY_KEY = "key";
+
+ private String profile;
+
+ private String type;
+
+ private String key;
+
+ private String id;
+
+ private TablePos tablePos;
+
+ private String placeholderName;
+
+ /**
+ *
+ * @param profile
+ * @param type
+ * @param sigKey
+ * @param id
+ */
+ public SignaturePlaceholderData(String profile, String type, String sigKey, String id) {
+ this.profile = profile;
+ this.type = type;
+ this.key = sigKey;
+ this.id = id;
+ }
+
+ /**
+ * Get the table position for the signature block.<br/>
+ * The table position is created from the page number, the upper left corner and the width of the placeholder image.
+ *
+ * @return
+ */
+ public TablePos getTablePos() {
+ return tablePos;
+ }
+
+ void setTablePos(TablePos tablePos) {
+ this.tablePos = tablePos;
+ }
+
+ /**
+ * The profile name. Might be null if not included in the qr-code.
+ *
+ * @return
+ */
+ public String getProfile() {
+ return profile;
+ }
+
+ void setProfile(String profile) {
+ this.profile = profile;
+ }
+
+ /**
+ * The signature type: "textual" or "binary". Might be null if not included in the qr-code.
+ * @return
+ */
+ public String getType() {
+ return type;
+ }
+
+ void setType(String type) {
+ this.type = type;
+ }
+
+ /**
+ * The key identifier for MOA signature. Might be null if not included in the qr-code.
+ *
+ * @return
+ */
+ public String getKey() {
+ return key;
+ }
+
+ void setKey(String key) {
+ this.key = key;
+ }
+
+ public String toString() {
+ return getClass().toString() + ": profile=" + profile + "; type=" + type + "; sigKey=" + key + "; table pos=" + tablePos;
+ }
+
+ void setPlaceholderName(String name) {
+ this.placeholderName = name;
+ }
+
+ /**
+ * The name of the placeholder image.
+ *
+ * @return
+ */
+ public String getPlaceholderName() {
+ return placeholderName;
+ }
+
+ /**
+ * The id associated with this placeholder.
+ *
+ * @return
+ */
+ public String getId() {
+ return id;
+ }
+
+ void setId(String id) {
+ this.id = id;
+ }
+
+}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java
new file mode 100644
index 00000000..eabc27e2
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/SignaturePlaceholderExtractor.java
@@ -0,0 +1,351 @@
+/**
+ * <copyright> Copyright 2006 by Know-Center, Graz, Austria </copyright>
+ * PDF-AS has been contracted by the E-Government Innovation Center EGIZ, a
+ * joint initiative of the Federal Chancellery Austria and Graz University of
+ * Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by
+ * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * You may not use this work except in compliance with the Licence.
+ * You may obtain a copy of the Licence at:
+ * http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the Licence is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the Licence for the specific language governing permissions and
+ * limitations under the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text
+ * file for details on the various modules and licenses.
+ * The "NOTICE" text file is part of the distribution. Any derivative works
+ * that you distribute must include a readable copy of the "NOTICE" text file.
+ */
+package at.gv.egiz.pdfas.lib.impl.placeholder;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.exceptions.WrappedIOException;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
+import org.apache.pdfbox.util.Matrix;
+import org.apache.pdfbox.util.PDFOperator;
+import org.apache.pdfbox.util.PDFStreamEngine;
+import org.apache.pdfbox.util.ResourceLoader;
+
+import at.gv.egiz.pdfas.common.exceptions.PDFIOException;
+import at.gv.egiz.pdfas.common.exceptions.PdfAsException;
+import at.gv.egiz.pdfas.common.exceptions.PlaceholderExtractionException;
+import at.knowcenter.wag.egov.egiz.pdf.TablePos;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.BinaryBitmap;
+import com.google.zxing.DecodeHintType;
+import com.google.zxing.LuminanceSource;
+import com.google.zxing.MultiFormatReader;
+import com.google.zxing.NotFoundException;
+import com.google.zxing.ReaderException;
+import com.google.zxing.Result;
+import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
+import com.google.zxing.common.HybridBinarizer;
+
+//////
+
+
+
+/**
+ * Extract all relevant information from a placeholder image.
+ *
+ * @author exthex
+ *
+ */
+public class SignaturePlaceholderExtractor extends PDFStreamEngine {
+ /**
+ * The log.
+ */
+ private static Log log = LogFactory.getLog(SignaturePlaceholderExtractor.class);
+
+ public static final String QR_PLACEHOLDER_IDENTIFIER = "PDF-AS-POS";
+ public static final int PLACEHOLDER_MATCH_MODE_STRICT = 0;
+ public static final int PLACEHOLDER_MATCH_MODE_MODERATE = 1;
+ public static final int PLACEHOLDER_MATCH_MODE_LENIENT = 2;
+
+ private List placeholders = new Vector();
+ private int currentPage = 0;
+
+ private SignaturePlaceholderExtractor(String placeholderId, int placeholderMatchMode) throws IOException {
+ super(ResourceLoader.loadProperties("placeholder/pdfbox-reader.properties",
+ true));
+ }
+
+ /**
+ * Search the document for placeholder images and possibly included
+ * additional info.<br/>
+ * Searches only for the first placeholder page after page from top.
+ *
+ * @param inputStream
+ * @return all available info from the first found placeholder.
+ * @throws PDFDocumentException if the document could not be read.
+ * @throws PlaceholderExtractionException if STRICT matching mode was requested and no suitable placeholder could be found.
+ */
+ public static SignaturePlaceholderData extract(InputStream inputStream, String placeholderId, int matchMode)
+ throws PdfAsException {
+ SignaturePlaceholderContext.setSignaturePlaceholderData(null);
+ PDDocument doc = null;
+ try
+ {
+ try {
+ doc = PDDocument.load(inputStream);
+ } catch (IOException e) {
+ throw new PDFIOException("failed to read document", e);
+ }
+ SignaturePlaceholderExtractor extractor;
+ try
+ {
+ extractor = new SignaturePlaceholderExtractor(placeholderId, matchMode);
+ } catch (IOException e2) {
+ throw new PDFIOException("failed to read document", e2);
+ }
+ List pages = doc.getDocumentCatalog().getAllPages();
+ Iterator iter = pages.iterator();
+ int pageNr = 0;
+ while (iter.hasNext()) {
+ pageNr++;
+ PDPage page = (PDPage) iter.next();
+ try {
+ extractor.setCurrentPage(pageNr);
+ extractor.processStream( page, page.findResources(), page.getContents().getStream() );
+ SignaturePlaceholderData ret = matchPlaceholderPage(extractor.placeholders, placeholderId, matchMode);
+ if (ret != null){
+ SignaturePlaceholderContext.setSignaturePlaceholderData(ret);
+ return ret;
+ }
+ } catch (IOException e1) {
+ throw new PDFIOException("failed to read document", e1);
+ }
+
+ }
+ if (extractor.placeholders.size() > 0){
+ SignaturePlaceholderData ret = matchPlaceholderDocument(extractor.placeholders, placeholderId, matchMode);
+ SignaturePlaceholderContext.setSignaturePlaceholderData(ret);
+ return ret;
+ }
+ // no placeholders found, apply strict mode if set
+ if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT) {
+ throw new PlaceholderExtractionException("no suitable placeholder found and STRICT matching mode requested.");
+ }
+
+ return null;
+ } finally {
+ if (doc != null)
+ try {
+ doc.close();
+ } catch (IOException e) {
+ log.debug("Could not close document.", e);
+ }
+ }
+
+ }
+
+ private static SignaturePlaceholderData matchPlaceholderDocument(
+ List placeholders, String placeholderId, int matchMode) throws PlaceholderExtractionException {
+
+ if (matchMode == PLACEHOLDER_MATCH_MODE_STRICT)
+ throw new PlaceholderExtractionException("no suitable placeholder found and STRICT matching mode requested.");
+
+ if (placeholders.size() == 0)
+ return null;
+
+ for (int i = 0; i < placeholders.size(); i++)
+ {
+ SignaturePlaceholderData spd = (SignaturePlaceholderData)placeholders.get(i);
+ if (spd.getId() == null)
+ return spd;
+ }
+
+ if (matchMode == PLACEHOLDER_MATCH_MODE_LENIENT)
+ return (SignaturePlaceholderData)placeholders.get(0);
+
+ return null;
+ }
+
+ private static SignaturePlaceholderData matchPlaceholderPage(List placeholders,
+ String placeholderId, int matchMode) {
+ if (placeholders.size() == 0)
+ return null;
+ for (int i = 0; i < placeholders.size(); i++)
+ {
+ SignaturePlaceholderData data = (SignaturePlaceholderData)placeholders.get(i);
+ if (placeholderId != null && placeholderId.equals(data.getId()))
+ return data;
+ if (placeholderId == null && data.getId() == null)
+ return data;
+ }
+ return null;
+ }
+
+ private void setCurrentPage(int pageNr) {
+ this.currentPage = pageNr;
+ }
+
+ protected void processOperator( PDFOperator operator, List arguments ) throws IOException
+ {
+ String operation = operator.getOperation();
+ if( operation.equals( "Do" ) )
+ {
+ COSName objectName = (COSName)arguments.get( 0 );
+ Map xobjects = getResources().getXObjects();
+ PDXObject xobject = (PDXObject)xobjects.get( objectName.getName() );
+ if( xobject instanceof PDXObjectImage )
+ {
+ try
+ {
+ PDXObjectImage image = (PDXObjectImage)xobject;
+ SignaturePlaceholderData data = checkImage(image);
+ if (data != null)
+ {
+ PDPage page = getCurrentPage();
+ Matrix ctm = getGraphicsState().getCurrentTransformationMatrix();
+ double rotationInRadians = (page.findRotation() * Math.PI)/180;
+
+ AffineTransform rotation = new AffineTransform();
+ rotation.setToRotation( rotationInRadians );
+ AffineTransform rotationInverse = rotation.createInverse();
+ Matrix rotationInverseMatrix = new Matrix();
+ rotationInverseMatrix.setFromAffineTransform( rotationInverse );
+ Matrix rotationMatrix = new Matrix();
+ rotationMatrix.setFromAffineTransform( rotation );
+
+ Matrix unrotatedCTM = ctm.multiply( rotationInverseMatrix );
+
+ float x = unrotatedCTM.getXPosition();
+ float y = unrotatedCTM.getYPosition() + unrotatedCTM.getYScale();
+ float w = unrotatedCTM.getXScale();
+
+ String posString = "p:" + currentPage + ";x:" + x + ";y:" + y + ";w:" + w;
+ try
+ {
+ data.setTablePos(new TablePos(posString));
+ data.setPlaceholderName(objectName.getName());
+ placeholders.add(data);
+ } catch (PdfAsException e) {
+ throw new WrappedIOException(e);
+ }
+ }
+ }
+ catch( NoninvertibleTransformException e )
+ {
+ throw new WrappedIOException( e );
+ }
+ }
+ }
+ else
+ {
+ super.processOperator( operator, arguments );
+ }
+ }
+
+ /**
+ * Checks an image if it is a placeholder for a signature.
+ *
+ * @param image
+ * @return
+ * @throws IOException
+ */
+ private SignaturePlaceholderData checkImage(PDXObjectImage image) throws IOException {
+ BufferedImage bimg = image.getRGBImage();
+ if (bimg == null) {
+ String type = image.getSuffix();
+ if (type != null) {
+ type = type.toUpperCase() + " images";
+ } else {
+ type = "Image type";
+ }
+ log.info("Unable to extract image for QRCode analysis. " + type + " not supported. Add additional JAI Image filters to your classpath. Refer to https://jai.dev.java.net. Skipping image.");
+ return null;
+ }
+ if(bimg.getHeight() < 10 || bimg.getWidth() < 10) {
+ log.debug("Image too small for QRCode. Skipping image.");
+ return null;
+ }
+
+ LuminanceSource source = new BufferedImageLuminanceSource(bimg);
+ BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
+ Result result;
+ long before = System.currentTimeMillis();
+ try {
+ Hashtable hints = new Hashtable();
+ Vector formats = new Vector();
+ formats.add(BarcodeFormat.QR_CODE);
+ hints.put(DecodeHintType.POSSIBLE_FORMATS, formats);
+ result = new MultiFormatReader().decode(bitmap, hints);
+
+ String text = result.getText();
+ String profile = null;
+ String type = null;
+ String sigKey = null;
+ String id = null;
+ if (text != null) {
+ if (text.startsWith(QR_PLACEHOLDER_IDENTIFIER)) {
+ String[] data = text.split(";");
+ if (data.length > 1) {
+ for (int i = 1; i < data.length; i++) {
+ String kvPair = data[i];
+ String[] kv = kvPair.split("=");
+ if (kv.length != 2) {
+ log.debug("Invalid parameter in placeholder data: " + kvPair);
+ } else {
+ if (kv[0].equalsIgnoreCase(SignaturePlaceholderData.ID_KEY)) {
+ id = kv[1];
+ } else if (kv[0].equalsIgnoreCase(SignaturePlaceholderData.PROFILE_KEY)) {
+ profile = kv[1];
+ } else if (kv[0]
+ .equalsIgnoreCase(SignaturePlaceholderData.SIG_KEY_KEY)) {
+ sigKey = kv[1];
+ } else if (kv[0]
+ .equalsIgnoreCase(SignaturePlaceholderData.TYPE_KEY)) {
+ type = kv[1];
+ }
+ }
+ }
+ }
+ return new SignaturePlaceholderData(profile, type, sigKey, id);
+ } else {
+ log.warn("QR-Code found but does not start with \"" + QR_PLACEHOLDER_IDENTIFIER + "\". Ignoring QR placeholder.");
+ }
+ }
+ } catch (ReaderException re) {
+ if (log.isDebugEnabled()) {
+ log.debug("Could not decode - not a placeholder. needed: "
+ + (System.currentTimeMillis() - before));
+ }
+ if (!(re instanceof NotFoundException)){
+ if (log.isInfoEnabled()) {
+ log.info("Failed to decode image", re);
+ }
+ }
+ } catch(ArrayIndexOutOfBoundsException e){
+ if (log.isInfoEnabled()) {
+ log.info("Failed to decode image. Probably a zxing bug", e);
+ }
+ }
+ return null;
+ }
+
+}
+
+
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/package-info.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/package-info.java
new file mode 100644
index 00000000..815565da
--- /dev/null
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/placeholder/package-info.java
@@ -0,0 +1,8 @@
+/**
+ *
+ */
+/**
+ * @author afitzek
+ *
+ */
+package at.gv.egiz.pdfas.lib.impl.placeholder; \ No newline at end of file
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java
index fce18ce7..5c84acfe 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/stamping/IPDFStamper.java
@@ -9,7 +9,7 @@ import at.knowcenter.wag.egov.egiz.table.Table;
public interface IPDFStamper {
public IPDFVisualObject createVisualPDFObject(PDFObject pdf, Table table);
public byte[] writeVisualObject(IPDFVisualObject visualObject, PositioningInstruction positioningInstruction,
- byte[] pdfData) throws PdfAsException;
+ byte[] pdfData, String placeholderName) throws PdfAsException;
public void setSettings(ISettings settings);
}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/RequestedSignature.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/RequestedSignature.java
index 8bf56259..8ae8e377 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/RequestedSignature.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/status/RequestedSignature.java
@@ -50,6 +50,10 @@ public class RequestedSignature {
return this.signatureProfile;
}
+ public void setSignatureProfileID(String signatureProfile) {
+ this.signatureProfile = signatureProfile;
+ }
+
public X509Certificate getCertificate() {
return this.certificate;
}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java
index 7aca582b..53c2e342 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/pdfas/lib/impl/verify/IVerifyFilter.java
@@ -3,9 +3,11 @@ package at.gv.egiz.pdfas.lib.impl.verify;
import java.util.List;
import at.gv.egiz.pdfas.common.exceptions.PdfAsException;
+import at.gv.egiz.pdfas.lib.api.Configuration;
import at.gv.egiz.pdfas.lib.api.verify.VerifyResult;
public interface IVerifyFilter {
+ public void setConfiguration(Configuration config);
public List<VerifyResult> verify(byte[] contentData, byte[] signatureContent) throws PdfAsException;
public List<FilterEntry> getFiters();
}
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/BKUSLConnector.java b/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/BKUSLConnector.java
index 3381dca5..deecae21 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/BKUSLConnector.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/BKUSLConnector.java
@@ -130,7 +130,7 @@ public class BKUSLConnector extends BaseSLConnector {
try {
slRequest = SLMarschaller.marshalToString(of
.createCreateCMSSignatureRequest(request));
- logger.trace(slRequest);
+ logger.debug(slRequest);
String slResponse = performHttpRequestToBKU(slRequest);
diff --git a/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/ISignatureConnectorSLWrapper.java b/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/ISignatureConnectorSLWrapper.java
index 491c465a..8a7950a4 100644
--- a/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/ISignatureConnectorSLWrapper.java
+++ b/pdf-as-lib/src/main/java/at/gv/egiz/sl/util/ISignatureConnectorSLWrapper.java
@@ -47,7 +47,7 @@ public class ISignatureConnectorSLWrapper implements ISignatureConnector {
}
public byte[] sign(byte[] input, int[] byteRange) throws PdfAsException {
- CreateCMSSignatureRequestType request = connector.createCMSRequest(input, byteRange);
+ CreateCMSSignatureRequestType request = connector.createCMSRequest(input, byteRange);
CreateCMSSignatureResponseType response = connector.sendCMSRequest(request);
return response.getCMSSignature();
diff --git a/pdf-as-lib/src/main/resources/placeholder/empty.jpg b/pdf-as-lib/src/main/resources/placeholder/empty.jpg
new file mode 100644
index 00000000..7913177d
--- /dev/null
+++ b/pdf-as-lib/src/main/resources/placeholder/empty.jpg
Binary files differ
diff --git a/pdf-as-lib/src/main/resources/placeholder/pdfbox-reader.properties b/pdf-as-lib/src/main/resources/placeholder/pdfbox-reader.properties
new file mode 100644
index 00000000..a3decc96
--- /dev/null
+++ b/pdf-as-lib/src/main/resources/placeholder/pdfbox-reader.properties
@@ -0,0 +1,23 @@
+BT = org.apache.pdfbox.util.operator.BeginText
+cm = org.apache.pdfbox.util.operator.Concatenate
+Do = org.apache.pdfbox.util.operator.Invoke
+ET = org.apache.pdfbox.util.operator.EndText
+gs = org.apache.pdfbox.util.operator.SetGraphicsStateParameters
+q = org.apache.pdfbox.util.operator.GSave
+Q = org.apache.pdfbox.util.operator.GRestore
+T* = org.apache.pdfbox.util.operator.NextLine
+Tc = org.apache.pdfbox.util.operator.SetCharSpacing
+Td = org.apache.pdfbox.util.operator.MoveText
+TD = org.apache.pdfbox.util.operator.MoveTextSetLeading
+Tf = org.apache.pdfbox.util.operator.SetTextFont
+Tj = org.apache.pdfbox.util.operator.ShowText
+TJ = org.apache.pdfbox.util.operator.ShowTextGlyph
+TL = org.apache.pdfbox.util.operator.SetTextLeading
+Tm = org.apache.pdfbox.util.operator.SetMatrix
+Tr = org.apache.pdfbox.util.operator.SetTextRenderingMode
+Ts = org.apache.pdfbox.util.operator.SetTextRise
+Tw = org.apache.pdfbox.util.operator.SetWordSpacing
+Tz = org.apache.pdfbox.util.operator.SetHorizontalTextScaling
+w = org.apache.pdfbox.util.operator.SetLineWidth
+\' = org.apache.pdfbox.util.operator.MoveAndShow
+\" = org.apache.pdfbox.util.operator.SetMoveAndShow \ No newline at end of file