diff options
author | pdanner <pdanner@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c> | 2010-11-02 14:43:44 +0000 |
---|---|---|
committer | pdanner <pdanner@7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c> | 2010-11-02 14:43:44 +0000 |
commit | 52326ca09c4ca269bf07d2af8b4dd5df682691f5 (patch) | |
tree | 492b4e2cefa78a2033c388eef44959a376de64a3 | |
parent | de3ef5f4bf180f96c2e0c01b7b7b6255ef85af63 (diff) | |
download | pdf-as-3-52326ca09c4ca269bf07d2af8b4dd5df682691f5.tar.gz pdf-as-3-52326ca09c4ca269bf07d2af8b4dd5df682691f5.tar.bz2 pdf-as-3-52326ca09c4ca269bf07d2af8b4dd5df682691f5.zip |
added helper for WAI / struct content
git-svn-id: https://joinup.ec.europa.eu/svn/pdf-as/trunk@595 7b5415b0-85f9-ee4d-85bd-d5d0c3b42d1c
-rw-r--r-- | src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java | 277 |
1 files changed, 277 insertions, 0 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 new file mode 100644 index 0000000..07f2328 --- /dev/null +++ b/src/main/java/at/knowcenter/wag/egov/egiz/pdf/StructContentHelper.java @@ -0,0 +1,277 @@ +package at.knowcenter.wag.egov.egiz.pdf;
+
+import org.apache.log4j.Logger;
+
+import at.gv.egiz.pdfas.exceptions.ErrorCode;
+import at.knowcenter.wag.egov.egiz.exceptions.PresentableException;
+
+import com.lowagie.text.pdf.PdfArray;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfDictionary;
+import com.lowagie.text.pdf.PdfFormField;
+import com.lowagie.text.pdf.PdfIndirectReference;
+import com.lowagie.text.pdf.PdfName;
+import com.lowagie.text.pdf.PdfNumber;
+import com.lowagie.text.pdf.PdfObject;
+import com.lowagie.text.pdf.PdfStamper;
+import com.lowagie.text.pdf.PdfStamperImp;
+
+/**
+ * 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
+ * defined order. The object cannot be reused for several signatures.
+ * @author exthex
+ *
+ */
+public class StructContentHelper {
+ private static Logger logger = Logger.getLogger(StructContentHelper.class);
+
+ private int nextMcid = 0;
+ private boolean isTagged = false;
+
+ private PdfStamper stamper;
+ private PdfStamperImp stamperImp;
+ private PdfContentByte content;
+ private PdfDictionary page;
+ private PdfNumber parentTreeNextKey = null;
+ private PdfNumber annotationParentTreeKey = null;
+ private PdfArray rootKids = null;
+
+ StructContentHelper(PdfStamper stamper, PdfContentByte content, int pageNr) {
+ this.stamper = stamper;
+ this.content = content;
+ stamperImp = ((PdfStamperImp) stamper.getWriter());
+ page = stamper.getReader().getPageN(pageNr);
+ }
+
+ /**
+ * Create and write structured content for signature block
+ * @throws PresentableException
+ */
+ void buildMainStructData() throws PresentableException {
+ // TODO titel/alttext woher?
+
+ try {
+
+ PdfDictionary markDict = stamper.getReader().getCatalog().getAsDict(PdfName.MARKINFO);
+ if (markDict != null) {
+ isTagged = markDict.getAsBoolean(PdfName.MARKED).booleanValue();
+ }
+ if (!isTagged) {
+ BinarySignature.logger
+ .debug("input document is not tagged. no structure/wai information is written");
+ return;
+ }
+
+ PdfDictionary root = getStructTreeRoot();
+ stamperImp.markUsed(root);
+
+ PdfArray parentTreeNums = getParentTreeNums();
+
+ PdfNumber parentTreeKey = null;
+ int numsIdx = -1;
+ PdfNumber strucParNr = page.getAsNumber(PdfName.STRUCTPARENTS);
+ PdfArray parentTreeEntry = null;
+ if (page.getAsName(new PdfName("Tabs")) == null) {
+ page.put(new PdfName("Tabs"), PdfName.S); // set explicit annotation order
+ stamperImp.markUsed(page);
+ }
+
+ if (strucParNr == null) { // no StructParents entry yet, make new one
+ parentTreeNextKey = root.getAsNumber(new PdfName("ParentTreeNextKey")); // read next proposed key
+ parentTreeKey = new PdfNumber(parentTreeNextKey.intValue());
+ parentTreeNextKey.increment();
+ page.put(PdfName.STRUCTPARENTS, parentTreeKey); // write /StructParents entry to page
+
+ stamperImp.markUsed(page);
+ // create new entry in ParentTree
+ parentTreeNums.add(parentTreeKey);
+ parentTreeEntry = new PdfArray();
+ // parentTreeNums.add(stamper.getWriter().addToBody(parentTreeEntry).getIndirectReference());
+ // simpl.markUsed(parentTreeNums);
+ // simpl.markUsed(root.getAsDict(PdfName.PARENTTREE));
+ numsIdx = parentTreeNums.size() - 1;
+
+ } else {
+ parentTreeKey = strucParNr;
+ }
+
+
+ // find my structParentEntry
+ if (numsIdx < 0) {
+ // it's a weird data structure: "number tree", see pdf reference if you really want to understand
+
+ // if the array has no gaps it is easy:
+ numsIdx = strucParNr.intValue() * 2;
+ if (parentTreeNums.getAsNumber(numsIdx).intValue() != strucParNr.intValue()) { // there seem to be gaps
+ for (numsIdx = 0; numsIdx < parentTreeNums.size(); numsIdx += 2) { // search manually
+ if (parentTreeNums.getAsNumber(numsIdx).intValue() == strucParNr.intValue()) {
+ break;
+ }
+ }
+ }
+ numsIdx += 1;
+ }
+ if (parentTreeEntry == null) {
+ parentTreeEntry = parentTreeNums.getAsArray(numsIdx);
+ }
+ nextMcid = parentTreeEntry.size();
+
+ PdfObject root_k = root.getDirectObject(PdfName.K);
+ stamperImp.markUsed(root_k);
+ if (root_k instanceof PdfDictionary) {
+ rootKids = new PdfArray();
+ stamperImp.markUsed(rootKids);
+ rootKids.add(root_k.getIndRef());
+ root.put(PdfName.K, rootKids);
+
+ } else { // has to be array
+ rootKids = (PdfArray) root_k;
+ }
+ PdfDictionary newStruct = new PdfDictionary();
+ // simpl.markUsed(newStruct);
+ newStruct.put(PdfName.S, new PdfName("Table"));
+ //newStruct.put(PdfName.T, new PdfString("mein Titel"));
+ newStruct.put(PdfName.P, root.getIndRef());
+ newStruct.put(PdfName.TYPE, new PdfName("StructElem"));
+
+ newStruct.put(PdfName.PG, page.getIndRef());
+ //newStruct.put(PdfName.ALT, new PdfString("meine feiner signaturblock alttext"));
+ newStruct.put(PdfName.K, new PdfNumber(nextMcid));
+
+
+ // ADD everything at the end because nothing can be written after
+
+ PdfIndirectReference newStructRef = stamper.getWriter().addToBody(newStruct)
+ .getIndirectReference();
+ rootKids.add(newStructRef);
+
+ parentTreeEntry.add(newStructRef);
+
+ stamperImp.markUsed(parentTreeEntry);
+
+ if (strucParNr == null) {
+ parentTreeNums.add(stamper.getWriter().addToBody(parentTreeEntry)
+ .getIndirectReference());
+ stamperImp.markUsed(parentTreeNums);
+ stamperImp.markUsed(root.getAsDict(PdfName.PARENTTREE));
+ }
+
+ } catch (Exception ex) {
+ logger.error("error", ex);
+ throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF,
+ "error writing structured signature content", ex);
+ }
+
+ }
+
+ /**
+ * Start tag for signature block content stream. Place this before the signature block is written to a content stream.
+ * Call {@link #endSigBlockContent()} afterwards
+ */
+ void beginSigBlockContent() {
+ if (isTagged) {
+ content.getInternalBuffer().append(new PdfName("Table").getBytes()).append(" <</MCID ")
+ .append(nextMcid).append(">> BDC").append_i('\n');
+ }
+ }
+
+ /**
+ * End tag for signature block content stream. Place this after the signature block is written to a content stream
+ */
+ void endSigBlockContent() {
+ if (isTagged) {
+ content.endMarkedContentSequence();
+ }
+ }
+
+
+ /**
+ * Build new StructParent entry for signature annotation.
+ * @return
+ */
+ public PdfNumber buildAnnotStructParent() {
+ if (this.isTagged) {
+ // new parent tree entry
+ if (parentTreeNextKey == null) {
+ parentTreeNextKey = getStructTreeRoot().getAsNumber(new PdfName("ParentTreeNextKey")); // read next proposed key
+ }
+ annotationParentTreeKey = new PdfNumber(parentTreeNextKey.intValue());
+ parentTreeNextKey.increment();
+
+ return annotationParentTreeKey;
+ } else {
+ return null;
+ }
+
+ }
+
+ /**
+ * Build and write structured content for adobe signature anntotation
+ * @param sigFormField
+ * @param title
+ * @throws PresentableException
+ */
+ public void buildAdobeSigStruct(PdfFormField sigFormField, String title) throws PresentableException {
+ if (!isTagged)
+ return;
+ try {
+ PdfDictionary root = getStructTreeRoot();
+ PdfDictionary adobeSigStruct = new PdfDictionary();
+ adobeSigStruct.put(PdfName.S, new PdfName("Link")); // TODO what type? link, annot (1.5) Form
+ //adobeSigStruct.put(PdfName.T, new PdfString(title));
+ adobeSigStruct.put(PdfName.P, root.getIndRef());
+ adobeSigStruct.put(PdfName.TYPE, new PdfName("StructElem"));
+
+ adobeSigStruct.put(PdfName.PG, page.getIndRef());
+ // adobeSigStruct.put(PdfName.ALT, new
+ // PdfString("mein feiner signaturtag"));
+
+ PdfDictionary objr = new PdfDictionary();
+ objr.put(PdfName.TYPE, new PdfName("OBJR"));
+ objr.put(PdfName.PG, page.getIndRef());
+ objr.put(new PdfName("Obj"), sigFormField.getIndirectReference());
+
+ PdfIndirectReference objrRef = stamper.getWriter().addToBody(objr).getIndirectReference();
+ adobeSigStruct.put(PdfName.K, objrRef);
+ PdfIndirectReference adobeSigStructRef = stamper.getWriter().addToBody(adobeSigStruct)
+ .getIndirectReference();
+
+ // root_a.add(adobeSigStructRef);
+
+ PdfArray parentTreeNums = getParentTreeNums();
+ // create new entry in ParentTree
+ parentTreeNums.add(annotationParentTreeKey);
+ //PdfArray parentTreeEntry = new PdfArray();
+
+ // parentTreeNums.add(stamper.getWriter().addToBody(parentTreeEntry).getIndirectReference());
+ // simpl.markUsed(parentTreeNums);
+ // simpl.markUsed(root.getAsDict(PdfName.PARENTTREE));
+ // parentTreeEntry.add(adobeSigStructRef);
+ // parentTreeNums.add(stamper.getWriter().addToBody(parentTreeEntry).getIndirectReference());
+ parentTreeNums.add(adobeSigStructRef);
+
+ rootKids.add(adobeSigStructRef);
+ stamperImp.markUsed(rootKids);
+
+ stamperImp.markUsed(parentTreeNums);
+ stamperImp.markUsed(root.getAsDict(PdfName.PARENTTREE));
+
+ } catch (Exception ex) {
+ logger.error("error", ex);
+ throw new PresentableException(ErrorCode.CANNOT_WRITE_PDF,
+ "error writing structured signature content", ex);
+ }
+
+ }
+
+ private PdfArray getParentTreeNums() {
+ return getStructTreeRoot().getAsDict(PdfName.PARENTTREE).getAsArray(PdfName.NUMS);
+ }
+
+ private PdfDictionary getStructTreeRoot() {
+ return stamper.getReader().getCatalog().getAsDict(PdfName.STRUCTTREEROOT);
+ }
+
+}
|