diff options
author | afitzek <afitzek@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c> | 2012-01-09 11:23:48 +0000 |
---|---|---|
committer | afitzek <afitzek@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c> | 2012-01-09 11:23:48 +0000 |
commit | f41fb52ffdf58199de8b7c399fc97a96c961a25d (patch) | |
tree | 2a7ed3085a3cf7878b59a6de85b3ed38ff1cb316 /src | |
parent | 25d7ff77cb71f9fdf39cd872e3427fe58bc85c03 (diff) | |
download | pdf-as-3-f41fb52ffdf58199de8b7c399fc97a96c961a25d.tar.gz pdf-as-3-f41fb52ffdf58199de8b7c399fc97a96c961a25d.tar.bz2 pdf-as-3-f41fb52ffdf58199de8b7c399fc97a96c961a25d.zip |
Fixing Problem with multiple signatures in tagged PDFs
git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@893 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java | 205 |
1 files changed, 108 insertions, 97 deletions
diff --git a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java index f8cb09e..7ca5a0a 100644 --- a/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java @@ -53,23 +53,23 @@ import com.lowagie.text.pdfas.UrlInTextFinder; /**
* Helper class for writing the structure hierarchy of the signature elements.
* Everything is written with the PdfObject low level API because there is no better support.
- * The structured content is only written for structured (==tagged) input documents. The methods have to be called in the
+ * The structured content is only written for structured (==tagged) input documents. The methods have to be called in the
* defined order. The object cannot be reused for several signatures.<br>
* See pdf spec "Logical Structure" for details.<br>
* The struct writing could be a little more abstracted, but this would include quite some itext extension work. And like this it
* fits better to PDF-AS / wprinz coding style :-(
* @author exthex
- *
+ *
*/
public class StructContentHelper implements StructContentWriter {
private static final Logger logger = Logger.getLogger(StructContentHelper.class);
-
+
private static final String SIGBLOCK_STRUCT_TYPE = "P";
private static final PdfName PARENTTREENEXTKEY = new PdfName("ParentTreeNextKey");
- private static final String ALT_TEXT_DEFAULT = "Signaturbildmarke";
- private final static String ALT_TEXT_CONF_KEY = "sigLogoAltText";
-
-
+ private static final String ALT_TEXT_DEFAULT = "Signaturbildmarke";
+ private final static String ALT_TEXT_CONF_KEY = "sigLogoAltText";
+
+
private int nextMcid = 0;
/**
* MCID value used for the sigblock marked contend identifier
@@ -94,7 +94,7 @@ public class StructContentHelper implements StructContentWriter { private PdfDictionary page;
private PdfNumber parentTreeNextKey = null;
private PdfNumber annotationParentTreeKey = null;
-
+
/**
* Temporary save a pos
*/
@@ -103,21 +103,21 @@ public class StructContentHelper implements StructContentWriter { * Cell position of the signature verify link overlay
*/
private Rectangle verifyLinkCellPos = null;
-
+
/**
* Kids array (K) of the <code>StructTreeRoot</code>
*/
private PdfArray structTreeRootKids = null;
/**
- * Entry in the ParentTree.Nums array used for sigtable structs
+ * Entry in the ParentTree.Nums array used for sigtable structs
*/
private PdfArray mainParentTreeNumEntry;
/**
- * Create new helper for one signature, and bind it to {@link StructContentWriterHolder}
+ * Create new helper for one signature, and bind it to {@link StructContentWriterHolder}
* for thread local access from itext.
- *
+ *
* @param stamper
* @param content
* @param pageNr
@@ -136,44 +136,55 @@ public class StructContentHelper implements StructContentWriter { public void removeCurrent() {
StructContentWriterHolder.removeThreadLocalWriter();
}
-
+
/**
* Prepare structured content for signature block. This method initializes the whole StructTreeRoot stuff.
- * @param sigBlockObj
+ * @param sigBlockObj
* @throws PresentableException
*/
void prepareStructData(PdfTemplate sigBlockObj) throws PresentableException {
try {
- checkTagging();
+ checkTagging();
if (!isTagged) {
return;
}
-
+
doAnnoTabOrder();
PdfDictionary structTreeRoot = getStructTreeRoot();
stamperImp.markUsed(structTreeRoot);
- PdfArray parentTreeNums = getParentTreeNums();
-
+ PdfArray parentTreeNums = getParentTreeNums();
+
PdfNumber structParentsNr = page.getAsNumber(PdfName.STRUCTPARENTS); // read StructParents entry from current page
mainParentTreeNumEntry = obtainParentTreeEntry(structTreeRoot, parentTreeNums, structParentsNr, sigBlockObj);
-
+
nextMcid = mainParentTreeNumEntry.size();
sigBlockMcid = nextMcid;
nextMcid++;
this.structTreeRootKids = obtainStructTreeRootKids(structTreeRoot);
-
+
+ if(this.structTreeRootKids == null)
+ {
+ this.structTreeRootKids = this.createStructTreeRootKids(structTreeRoot);
+ }
+
} catch (Exception ex) {
logger.error("error", ex);
throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF,
"error writing structured signature content", ex);
}
}
-
+
+ PdfArray createStructTreeRootKids(PdfDictionary structTreeRoot) {
+ PdfArray tmp = new PdfArray();
+ structTreeRoot.put(PdfName.K, tmp);
+ return tmp;
+ }
+
/**
* Create struct data for main signature block
* @throws PresentableException
@@ -196,7 +207,7 @@ public class StructContentHelper implements StructContentWriter { "error writing structured signature content", ex);
}
}
-
+
/**
* Finish struct data for signblock and it's elements (NOT for the external link and annot!)
@@ -218,8 +229,8 @@ public class StructContentHelper implements StructContentWriter { }
/**
- * Build the structured content for the signature logo (bildmarke). {@link #beginFigureContent(PdfContentByte)} and
- * {@link #endFigureContent(PdfContentByte)} have to be called before this method to mark the logo in the stream. This
+ * Build the structured content for the signature logo (bildmarke). {@link #beginFigureContent(PdfContentByte)} and
+ * {@link #endFigureContent(PdfContentByte)} have to be called before this method to mark the logo in the stream. This
* is done implicitly in the modified itext source (see {@link StructContentWriterHolder}).
* @param so
* @param sigBlockObj
@@ -231,7 +242,7 @@ public class StructContentHelper implements StructContentWriter { PdfDictionary structTreeRoot = getStructTreeRoot();
PdfIndirectReference mcrRef = createMcrStructElem(this.figureMcid, sigBlockObj.getIndirectReference());
- PdfIndirectReference figureRef = createStructElem("Figure", mcrRef,
+ PdfIndirectReference figureRef = createStructElem("Figure", mcrRef,
getAltText(so.getSignatureTypeDefinition().getType()), structTreeRoot.getIndRef());
structTreeRootKids.add(figureRef);
@@ -250,42 +261,42 @@ public class StructContentHelper implements StructContentWriter { }
}
-
+
/**
* Build the link annotation for the signature verification link and the structured content accordingly.<br>
* The tagging does NOT work if the link is placed in a binary signature replace cell (phlengh for this cell)!!
* @param sigBlockObj
- * @param atp
- * @throws PresentableException
+ * @param atp
+ * @throws PresentableException
*/
void buildVerifyLinkStructData(PdfTemplate sigBlockObj, ActualTablePos atp) throws PresentableException {
- if (!this.isTagged || !this.isLinkMarked() || !isLinkFound()) return;
+ if (!this.isTagged || !this.isLinkMarked() || !isLinkFound()) return;
try {
PdfNumber parentTreeKey = getNewParentTreeKey();
-
- PdfArray annots = obrainAnnotsFromPage();
-
- PdfIndirectReference linkAnnotRef = createLinkAnnot(parentTreeKey, atp);
- annots.add(linkAnnotRef);
-
+
+ PdfArray annots = obrainAnnotsFromPage();
+
+ PdfIndirectReference linkAnnotRef = createLinkAnnot(parentTreeKey, atp);
+ annots.add(linkAnnotRef);
+
PdfIndirectReference objr = createObjrStructElem(linkAnnotRef);
- PdfIndirectReference mcr = createMcrStructElem(this.linkMcid, sigBlockObj.getIndirectReference());
-
+ PdfIndirectReference mcr = createMcrStructElem(this.linkMcid, sigBlockObj.getIndirectReference());
+
PdfDictionary structTreeRoot = getStructTreeRoot();
-
+
PdfArray linkKids = new PdfArray();
PdfIndirectReference linkKidsRef = stamper.getWriter().getPdfIndirectReference();
-
+
PdfIndirectReference linkRef = createStructElem("Link", linkKidsRef, structTreeRoot.getIndRef());
linkKids.add(objr);
-
- PdfIndirectReference span = createStructElem("Span", mcr, linkRef);
- linkKids.add(span);
-
+
+ PdfIndirectReference span = createStructElem("Span", mcr, linkRef);
+ linkKids.add(span);
+
stamper.getWriter().addToBody(linkKids, linkKidsRef);
structTreeRootKids.add(linkRef);
-
+
// create new entry in ParentTree
PdfArray parentTreeNums = getParentTreeNums();
parentTreeNums.add(parentTreeKey);
@@ -295,16 +306,16 @@ public class StructContentHelper implements StructContentWriter { stamperImp.markUsed(structTreeRoot.getAsDict(PdfName.PARENTTREE));
stamperImp.markUsed(structTreeRootKids);
stamperImp.markUsed(linkKids);
-
- stamperImp.markUsed(structTreeRoot);
-
+
+ stamperImp.markUsed(structTreeRoot);
+
} catch (IOException e) {
logger.error("error", e);
throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF,
"error writing structured signature content", e);
}
}
-
+
private boolean isLinkFound() {
return this.linkUrlString != null && this.verifyLinkCellPos != null && this.linkPosMap.size() > 0 && this.linkMcid >= 0;
}
@@ -320,11 +331,11 @@ public class StructContentHelper implements StructContentWriter { } else {
return null;
}
- }
+ }
/**
* Build and write structured content for adobe signature annotation
- *
+ *
* @param sigFormField
* @param title
* @throws PresentableException
@@ -378,7 +389,7 @@ public class StructContentHelper implements StructContentWriter { content.endMarkedContentSequence();
}
}
-
+
/**
* Writes start tag for signature logo marked content sequence.
*/
@@ -392,18 +403,18 @@ public class StructContentHelper implements StructContentWriter { }
}
}
-
+
/**
* Writes end tag for signature logo marked content sequence.
*/
public void endFigureContent(PdfContentByte localContent) {
if (isTagged && isFigureMarked()) {
- localContent.endMarkedContentSequence();
+ localContent.endMarkedContentSequence();
}
}
-
+
/**
- * Writes start tag for verify link marked content sequence.
+ * Writes start tag for verify link marked content sequence.
*/
public void beginLinkContent(PdfContentByte localContent, String urlString) {
// it's called from here com.lowagie.text.pdf.PdfContentByte.showText(String)
@@ -416,7 +427,7 @@ public class StructContentHelper implements StructContentWriter { } else {
logger.warn("cannot tag multiple verify links");
}
- }
+ }
}
/**
@@ -425,8 +436,8 @@ public class StructContentHelper implements StructContentWriter { public void endLinkContent(PdfContentByte localContent) {
if (isTagged && isLinkMarked()) {
localContent.endMarkedContentSequence();
- }
- }
+ }
+ }
/**
* Implements {@link StructContentWriter#markPos(Rectangle)}
@@ -436,22 +447,22 @@ public class StructContentHelper implements StructContentWriter { }
/**
- * Implements {@link StructContentWriter#storeCurrentPosAsLink()}
+ * Implements {@link StructContentWriter#storeCurrentPosAsLink()}
*/
public void storeCurrentPosAsLink() {
- this.verifyLinkCellPos = new Rectangle(this.tempMarkedPos);
+ this.verifyLinkCellPos = new Rectangle(this.tempMarkedPos);
}
-
+
public void putVal(String key, Object val) {
- tmpMap.put(key, val);
+ tmpMap.put(key, val);
}
public void storeVals() {
linkPosMap = new HashMap(tmpMap);
- }
-
+ }
+
/**
- * set explicit annotation tab order if missing
+ * set explicit annotation tab order if missing
*/
private void doAnnoTabOrder() {
if (page.getAsName(new PdfName("Tabs")) == null) {
@@ -470,31 +481,31 @@ public class StructContentHelper implements StructContentWriter { }
logger.debug("Input is tagged. Writing structure/WAI data.");
}
-
+
private PdfIndirectReference createLinkAnnot(PdfNumber structParentNr, ActualTablePos atp) throws IOException {
- PdfDictionary linkAnnot = new PdfDictionary();
-
- PdfDictionary a = new PdfDictionary();
+ PdfDictionary linkAnnot = new PdfDictionary();
+
+ PdfDictionary a = new PdfDictionary();
a.put(PdfName.S, new PdfName("URI"));
a.put(PdfName.TYPE, PdfName.ACTION);
a.put(PdfName.URI, new PdfString(this.linkUrlString));
linkAnnot.put(PdfName.A, a);
-
+
PdfDictionary bs = new PdfDictionary();
bs.put(PdfName.W, new PdfNumber(0));
linkAnnot.put(PdfName.BS, bs);
linkAnnot.put(PdfName.F, new PdfNumber(4));
-
+
// iText "converts" 0.0f to an integer, therefore we cannot use 0, not nice...
//linkAnnot.put(PdfName.RECT, new PdfArray(new float[] {0.01f, 0.01f, 0.01f, 0.01f}));
// take cell pos as link pos
linkAnnot.put(PdfName.RECT, new PdfArray(calcLinkPos(atp)));
-
+
linkAnnot.put(PdfName.STRUCTPARENT, structParentNr);
linkAnnot.put(PdfName.SUBTYPE, PdfName.LINK);
-
+
return stamper.getWriter().addToBody(linkAnnot).getIndirectReference();
}
@@ -525,10 +536,10 @@ public class StructContentHelper implements StructContentWriter { private float getPosMapVal(String key) {
return ((Float) this.linkPosMap.get(key)).floatValue();
}
-
+
protected static PdfArray createPdfArrayFromTablePos(ActualTablePos pos) {
return new PdfArray( new float[] {pos.x, pos.y, pos.x + pos.width, pos.y - pos.height});
- }
+ }
private PdfArray obrainAnnotsFromPage() throws IOException {
PdfArray annots = this.page.getAsArray(PdfName.ANNOTS);
@@ -551,7 +562,7 @@ public class StructContentHelper implements StructContentWriter { rk.add(root_k.getIndRef());
structTreeRoot.put(PdfName.K, structTreeRootKids);
- } else { // has to be array
+ } else if(root_k != null) { // has to be array
rk = (PdfArray) root_k;
}
return rk;
@@ -561,17 +572,17 @@ public class StructContentHelper implements StructContentWriter { PdfNumber structParentsNr, PdfTemplate sigBlockObj) {
int numsIdx = -1;
PdfArray parentTreeEntry = null;
-
+
if (structParentsNr == null) { // no StructParents entry yet, make new one and add new parenttree entry
PdfNumber parentTreeKey = null;
parentTreeNextKey = structTreeRoot.getAsNumber(PARENTTREENEXTKEY); // read next proposed key
if (parentTreeNextKey == null) { // this can be null if a non-perfect pdf creator was at work
// find the next key by counting
- int nextI = ((int) parentTreeNums.size() / 2); // know the "Number Trees" data structure from pdf-ref
+ int nextI = ((int) parentTreeNums.size() / 2); // know the "Number Trees" data structure from pdf-ref
this.parentTreeNextKey = new PdfNumber(nextI);
- structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey); // write ParentTreeNextKey entry
+ structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey); // write ParentTreeNextKey entry
}
-
+
parentTreeKey = new PdfNumber(parentTreeNextKey.intValue());
parentTreeNextKey.increment();
page.put(PdfName.STRUCTPARENTS, parentTreeKey); // write /StructParents entry to page
@@ -583,7 +594,7 @@ public class StructContentHelper implements StructContentWriter { parentTreeEntry = new PdfArray();
numsIdx = parentTreeNums.size() - 1;
- } else { // structparents entry already available, find parenttree entry
+ } else { // structparents entry already available, find parenttree entry
//parentTreeKey = structParentsNr;
parentTreeNextKey = structTreeRoot.getAsNumber(PARENTTREENEXTKEY); // read next proposed key
if (parentTreeNextKey == null) { // this can be null if a non-perfact pdf creator was at work
@@ -593,10 +604,10 @@ public class StructContentHelper implements StructContentWriter { nextI = ((int) parentTreeNums.size() / 2);
}
this.parentTreeNextKey = new PdfNumber(nextI);
- structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey);
- }
+ structTreeRoot.put(PARENTTREENEXTKEY, this.parentTreeNextKey);
+ }
}
-
+
// add Structparents entry to xobject content stream
sigBlockObj.addAttribute(PdfName.STRUCTPARENTS, structParentsNr);
@@ -620,7 +631,7 @@ public class StructContentHelper implements StructContentWriter { }
return parentTreeEntry;
}
-
+
// private PdfIndirectReference createStructElem(String structType, PdfObject kid) throws IOException {
// return createStructElem(structType, kid, null);
// }
@@ -628,10 +639,10 @@ public class StructContentHelper implements StructContentWriter { private PdfIndirectReference createStructElem(String structType, PdfObject kid, PdfIndirectReference parentRef) throws IOException {
return createStructElem(structType, kid, null, parentRef);
}
-
+
private PdfIndirectReference createStructElem(String structType, PdfObject kid, String altText,
PdfIndirectReference parentRef) throws IOException {
-
+
PdfDictionary newStruct = new PdfDictionary();
newStruct.put(PdfName.S, new PdfName(structType));
//newStruct.put(PdfName.T, new PdfString("PDF-AS Signaturblock"));// eher nicht
@@ -649,21 +660,21 @@ public class StructContentHelper implements StructContentWriter { newStruct.put(PdfName.K, kid);
return stamper.getWriter().addToBody(newStruct).getIndirectReference();
- }
+ }
private boolean isFigureMarked() {
return this.figureMcid > -1;
}
-
+
private boolean isLinkMarked() {
return this.linkMcid > -1;
}
-
+
private PdfNumber getNewParentTreeKey() {
// new parent tree entry
if (parentTreeNextKey == null) {
- parentTreeNextKey = getStructTreeRoot().getAsNumber(PARENTTREENEXTKEY); // read next proposed key
+ parentTreeNextKey = getStructTreeRoot().getAsNumber(PARENTTREENEXTKEY); // read next proposed key
}
PdfNumber res = new PdfNumber(parentTreeNextKey.intValue());
parentTreeNextKey.increment();
@@ -676,28 +687,28 @@ public class StructContentHelper implements StructContentWriter { objr.put(PdfName.TYPE, new PdfName("OBJR"));
objr.put(PdfName.PG, page.getIndRef());
objr.put(new PdfName("Obj"), objRef);
-
+
return stamper.getWriter().addToBody(objr).getIndirectReference();
}
-
+
private PdfIndirectReference createMcrStructElem(int mcid, PdfIndirectReference streamRef) throws IOException {
PdfDictionary objr = new PdfDictionary();
objr.put(PdfName.TYPE, new PdfName("MCR"));
objr.put(PdfName.PG, page.getIndRef());
objr.put(PdfName.MCID, new PdfNumber(mcid));
objr.put(new PdfName("Stm"), streamRef);
-
+
return stamper.getWriter().addToBody(objr).getIndirectReference();
}
-
+
private PdfArray getParentTreeNums() {
return getStructTreeRoot().getAsDict(PdfName.PARENTTREE).getAsArray(PdfName.NUMS);
}
private PdfDictionary getStructTreeRoot() {
return stamper.getReader().getCatalog().getAsDict(PdfName.STRUCTTREEROOT);
- }
-
+ }
+
private static String getAltText(String sigProfile) {
return AdobeSignatureHelper.getDefaultableConfigProperty(sigProfile, ALT_TEXT_CONF_KEY, ALT_TEXT_DEFAULT);
}
|