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/main/java | |
| 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/main/java')
| -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);
     }
 | 
