You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by le...@apache.org on 2011/06/25 18:51:58 UTC

svn commit: r1139570 - in /pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox: cos/COSName.java pdmodel/PDDocument.java pdmodel/interactive/digitalsignature/SignatureOptions.java

Author: lehmi
Date: Sat Jun 25 16:51:57 2011
New Revision: 1139570

URL: http://svn.apache.org/viewvc?rev=1139570&view=rev
Log:
PDFBOX-1031: added a preferred signature size to the SignatureOptions as proposed by Thomas Chojecki

Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java?rev=1139570&r1=1139569&r2=1139570&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/cos/COSName.java Sat Jun 25 16:51:57 2011
@@ -391,12 +391,16 @@ public final class COSName extends COSBa
     public static final COSName DP = new COSName( "DP" );
 
     /**
-    * A common COSName value.
-    */
+     * A common COSName value.
+     */
+    public static final COSName DR = new COSName( "DR" );
+    /**
+     * A common COSName value.
+     */
     public static final COSName DV = new COSName( "DV" );
     /**
-    * A common COSName value.
-    */
+     * A common COSName value.
+     */
     public static final COSName DW = new COSName( "DW" );
 
     /**
@@ -537,6 +541,10 @@ public final class COSName extends COSBa
     /**
     * A common COSName value.
     */
+    public static final COSName FORM = new COSName( "Form" );
+    /**
+     * A common COSName value.
+     */
     public static final COSName FORMTYPE = new COSName( "FormType" );
     /**
      * A common COSName value.
@@ -1193,6 +1201,10 @@ public final class COSName extends COSBa
      * A common COSName value.
      */
     public static final COSName SIG = new COSName("Sig");
+    /**
+     * A common COSName value.
+     */
+    public static final COSName SIG_FLAGS = new COSName("SigFlags");
 
     
     private String name;

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java?rev=1139570&r1=1139569&r2=1139570&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java Sat Jun 25 16:51:57 2011
@@ -82,19 +82,9 @@ import org.apache.pdfbox.pdmodel.interac
  */
 public class PDDocument implements Pageable
 {
-    private static final String COSDictionary = null;
 
     private COSDocument document;
 
-    // NOTE BGUILLON: this property must be removed because it is
-    // not the responsability of this class to know
-    //private boolean encryptOnSave = false;
-
-
-    // NOTE BGUILLON: these properties are not used anymore. See getCurrentAccessPermission() instead
-    //private String encryptUserPassword = null;
-    //private String encryptOwnerPassword = null;
-
     //cached values
     private PDDocumentInformation documentInformation;
     private PDDocumentCatalog documentCatalog;
@@ -105,13 +95,6 @@ public class PDDocument implements Pagea
     private PDEncryptionDictionary encParameters = null;
 
     /**
-     * This will tell if the document was decrypted with the master password.
-     * NOTE BGUILLON: this property is not used anymore. See getCurrentAccessPermission() instead
-     */
-   //private boolean decryptedWithOwnerPassword = false;
-
-
-    /**
      * The security handler used to decrypt / encrypt the document.
      */
     private SecurityHandler securityHandler = null;
@@ -166,8 +149,7 @@ public class PDDocument implements Pagea
         // or references to arrays which have references to pages
         // or references to arrays which have references to arrays which have references to pages
         // or ... (I think you get the idea...)
-				processListOfPageReferences(getDocumentCatalog().getPages().getKids());
-
+        processListOfPageReferences(getDocumentCatalog().getPages().getKids());
     }
     
     private void processListOfPageReferences(List<Object> pageNodes)
@@ -279,10 +261,9 @@ public class PDDocument implements Pagea
 
     public void addSignature(PDSignature sigObject, SignatureInterface signatureInterface) throws IOException, SignatureException
     {
-      SignatureOptions defaultOptions = new SignatureOptions();
-      defaultOptions.setPage(1);
-      
-      addSignature(sigObject, signatureInterface,defaultOptions);
+        SignatureOptions defaultOptions = new SignatureOptions();
+        defaultOptions.setPage(1);
+        addSignature(sigObject, signatureInterface,defaultOptions);
     }
     
     /**
@@ -295,155 +276,175 @@ public class PDDocument implements Pagea
      */
     public void addSignature(PDSignature sigObject, SignatureInterface signatureInterface, SignatureOptions options) throws IOException, SignatureException
     {
-      // Content reservieren
-      // Um auch grosse Zertifikatsketten unterbringen zu koennen, 
-      // wird ein sehr grosser Bereich reserviert
-      sigObject.setContents(new byte[0x2500 * 2 + 2]);
-
-      // ByteRange reservieren
-      sigObject.setByteRange(new int[] {0,1000000000,1000000000,1000000000});
-      
-      getDocument().setSignatureInterface(signatureInterface);
-      
-      // #########################################
-      // # SignatureForm fuer Signatur erstellen #
-      // # und mit an das Dokument haengen.      #
-      // #########################################
-      
-      // Erste Seite besorgen
-      PDDocumentCatalog root = getDocumentCatalog();
-      PDPageNode rootPages = root.getPages();
-      List<PDPage> kids = new ArrayList<PDPage>();
-      rootPages.getAllKids(kids);
-      
-      int size = (int)rootPages.getCount();
-      PDPage page = null;
-      if (size == 0)
-        throw new SignatureException(SignatureException.INVALID_PAGE_FOR_SIGNATURE, "The PDF file has no pages");
-      if (options.getPage()>size)
-        page = kids.get(size-1);
-      else if(options.getPage()<=0)
-        page = kids.get(0);
-      else
-        page = kids.get(options.getPage()-1);
+        // Reserve content
+        // We need to reserve some space for the signature. Some signatures including
+        // big certificate chain and we need enough space to store it.
+        int preferedSignatureSize = options.getPreferedSignatureSize();
+        if (preferedSignatureSize > 0)
+        {
+            sigObject.setContents(new byte[preferedSignatureSize * 2 + 2]);
+        }
+        else
+        {
+            sigObject.setContents(new byte[0x2500 * 2 + 2]);
+        }
+        
+        // Reserve ByteRange
+        sigObject.setByteRange(new int[] {0,1000000000,1000000000,1000000000});
       
-
-      // AcroForm aus dem Root dict besorgen und Annotation einfügen
-      PDAcroForm acroForm = root.getAcroForm();
-      root.getCOSObject().setNeedToBeUpdate(true); 
-
-      if (acroForm==null) 
-      {
-        acroForm = new PDAcroForm(this);
-        root.setAcroForm(acroForm);
-      } else 
-        acroForm.getCOSObject().setNeedToBeUpdate(true);
+        getDocument().setSignatureInterface(signatureInterface);
       
-      /*
-       *  For invisible signatures, the annotation has a rectangle array with values [ 0 0 0 0 ]. 
-       *  This annotation is usually attached to the viewed page when the signature is created. 
-       *  Despite not having an appearance, the annotation AP and N dictionaries may be present 
-       *  in some versions of Acrobat. If present, N references the DSBlankXObj (blank) XObject.
-       */
-
-      // Annotation / Field für die Signatur erzeugen
-      PDSignatureField signatureField = new PDSignatureField(acroForm);
-      signatureField.setSignature(sigObject);              // Signaturobjekt vermerken
-      signatureField.getWidget().setPage(page);            // Rückverkettung 
+        // #########################################
+        // # Create SignatureForm for signature    #
+        // # and appending it to the document      #
+        // #########################################
+
+        // Get the first page
+        PDDocumentCatalog root = getDocumentCatalog();
+        PDPageNode rootPages = root.getPages();
+        List<PDPage> kids = new ArrayList<PDPage>();
+        rootPages.getAllKids(kids);
+  
+        int size = (int)rootPages.getCount();
+        PDPage page = null;
+        if (size == 0)
+        {
+            throw new SignatureException(SignatureException.INVALID_PAGE_FOR_SIGNATURE, "The PDF file has no pages");
+        }
+        if (options.getPage()>size)
+        {
+            page = kids.get(size-1);
+        }
+        else if(options.getPage()<=0)
+        {
+            page = kids.get(0);
+        }
+        else
+        {
+            page = kids.get(options.getPage()-1);
+        }
       
-      // AcroForm Fields setzen
-      List acroFormFields = acroForm.getFields();
-      COSDictionary acroFormDict = acroForm.getDictionary();
-      acroFormDict.setDirect(true);
-      acroFormDict.setInt("SigFlags", 3);
-      acroFormFields.add(signatureField);
-
-      // Objekte aus der visuellen Signatur besorgen
-      COSDocument visualSignature = options.getVisualSignature();
 
-      // Fallunterscheidung zwischen sichtbarer und unsichtbarer Signatur vorbereiten
-      if (visualSignature == null) // unsichtbare Signatur
-      {
-        // Rectangle fuer unsichtbare Signatur auf 0 0 0 0 setzen
-        signatureField.getWidget().setRectangle(new PDRectangle());  // rectangle array [ 0 0 0 0 ]
-        // AcroForm leere DefaultRessource setzen
-        acroFormDict.setItem("DR", null);
-        // Leeres Appearance-Dictionary setzten
-        PDAppearanceDictionary ap = new PDAppearanceDictionary();
-        COSStream apsStream = new COSStream(getDocument().getScratchFile());
-        apsStream.createUnfilteredStream();
-        PDAppearanceStream aps = new PDAppearanceStream(apsStream);
-        COSDictionary cosObject = (COSDictionary)aps.getCOSObject();
-        cosObject.setItem(COSName.SUBTYPE, COSName.getPDFName("Form"));
-        cosObject.setItem(COSName.BBOX, new PDRectangle());
+        // Get the AcroForm from the Root-Dictionary and append the annotation
+        PDAcroForm acroForm = root.getAcroForm();
+        root.getCOSObject().setNeedToBeUpdate(true); 
         
-        ap.setNormalAppearance(aps);
-        ap.getDictionary().setDirect(true);
-        signatureField.getWidget().setAppearance(ap);
-      }
-      else // sichtbare Signatur
-      {
-        // Visuelle Objekte besorgen
-        List<COSObject> cosObjects = visualSignature.getObjects();
-
-        boolean annotNotFound = true;
-        boolean sigFieldNotFound = true;
-
-        for ( COSObject cosObject : cosObjects )
+        if (acroForm==null) 
+        {
+            acroForm = new PDAcroForm(this);
+            root.setAcroForm(acroForm);
+        } 
+        else 
         {
-          COSBase base = cosObject.getObject();
-          if (base != null && base instanceof COSDictionary)
-          {
-            COSBase ft = ((COSDictionary)base).getItem(COSName.getPDFName("FT"));
-            COSBase type = ((COSDictionary)base).getItem(COSName.TYPE);
-            COSBase apDict = ((COSDictionary)base).getItem(COSName.AP);
+            acroForm.getCOSObject().setNeedToBeUpdate(true);
+        }
+      
+        /*
+         * For invisible signatures, the annotation has a rectangle array with values [ 0 0 0 0 ]. 
+         * This annotation is usually attached to the viewed page when the signature is created. 
+         * Despite not having an appearance, the annotation AP and N dictionaries may be present 
+         * in some versions of Acrobat. If present, N references the DSBlankXObj (blank) XObject.
+         */
+
+        // Create Annotation / Field for signature
+        PDSignatureField signatureField = new PDSignatureField(acroForm);
+        signatureField.setSignature(sigObject);              // append the signature object
+        signatureField.getWidget().setPage(page);            // backward linking
+      
+        // Set the AcroForm Fields
+        List acroFormFields = acroForm.getFields();
+        COSDictionary acroFormDict = acroForm.getDictionary();
+        acroFormDict.setDirect(true);
+        acroFormDict.setInt(COSName.SIG_FLAGS, 3);
+        acroFormFields.add(signatureField);
+
+        // Get the object from the visual signature
+        COSDocument visualSignature = options.getVisualSignature();
+
+        // Distinction of case for visual and non-visual signature
+        if (visualSignature == null) // non-visual signature
+        {
+            // Set rectangle for non-visual signature to 0 0 0 0
+            signatureField.getWidget().setRectangle(new PDRectangle());  // rectangle array [ 0 0 0 0 ]
+            // Clear AcroForm / Set DefaultRessource
+            acroFormDict.setItem(COSName.DR, null);
+            // Set empty Appearance-Dictionary
+            PDAppearanceDictionary ap = new PDAppearanceDictionary();
+            COSStream apsStream = new COSStream(getDocument().getScratchFile());
+            apsStream.createUnfilteredStream();
+            PDAppearanceStream aps = new PDAppearanceStream(apsStream);
+            COSDictionary cosObject = (COSDictionary)aps.getCOSObject();
+            cosObject.setItem(COSName.SUBTYPE, COSName.FORM);
+            cosObject.setItem(COSName.BBOX, new PDRectangle());
             
-            // Nach Signatur-Annotation suchen
-            if (annotNotFound && COSName.getPDFName("Annot").equals(type))
+            ap.setNormalAppearance(aps);
+            ap.getDictionary().setDirect(true);
+            signatureField.getWidget().setAppearance(ap);
+        }
+        else // visual signature
+        {
+            // Obtain visual signature object
+            List<COSObject> cosObjects = visualSignature.getObjects();
+    
+            boolean annotNotFound = true;
+            boolean sigFieldNotFound = true;
+
+            for ( COSObject cosObject : cosObjects )
             {
-              COSDictionary cosBaseDict = (COSDictionary)base;
+                COSBase base = cosObject.getObject();
+                if (base != null && base instanceof COSDictionary)
+                {
+                    COSBase ft = ((COSDictionary)base).getItem(COSName.FT);
+                    COSBase type = ((COSDictionary)base).getItem(COSName.TYPE);
+                    COSBase apDict = ((COSDictionary)base).getItem(COSName.AP);
+            
+                    // Search for signature annotation
+                    if (annotNotFound && COSName.ANNOT.equals(type))
+                    {
+                        COSDictionary cosBaseDict = (COSDictionary)base;
               
-              // Rectangle fuer visuelle Signatur auslesen und setzen
-              COSArray rectAry = (COSArray)cosBaseDict.getItem(COSName.getPDFName("Rect"));
-              PDRectangle rect = new PDRectangle(rectAry);
-              signatureField.getWidget().setRectangle(rect);
-              annotNotFound = false;
-            }
+                        // Read and set the Rectangle for visual signature
+                        COSArray rectAry = (COSArray)cosBaseDict.getItem(COSName.RECT);
+                        PDRectangle rect = new PDRectangle(rectAry);
+                        signatureField.getWidget().setRectangle(rect);
+                        annotNotFound = false;
+                    }
             
-            // Nach Signatur-Field suchen
-            if (sigFieldNotFound && COSName.getPDFName("Sig").equals(ft) && apDict != null)
-            {
-              COSDictionary cosBaseDict = (COSDictionary)base;
+                    // Search for Signature-Field
+                    if (sigFieldNotFound && COSName.SIG.equals(ft) && apDict != null)
+                    {
+                        COSDictionary cosBaseDict = (COSDictionary)base;
               
-              // Appearance Dictionary auslesen und setzen
-              PDAppearanceDictionary ap = new PDAppearanceDictionary((COSDictionary)cosBaseDict.getItem(COSName.AP));
-              ap.getDictionary().setDirect(true);
-              signatureField.getWidget().setAppearance(ap);
+                        // Appearance Dictionary auslesen und setzen
+                        PDAppearanceDictionary ap = new PDAppearanceDictionary((COSDictionary)cosBaseDict.getItem(COSName.AP));
+                        ap.getDictionary().setDirect(true);
+                        signatureField.getWidget().setAppearance(ap);
               
-              // AcroForm DefaultRessource auslesen und setzen
-              COSBase dr = cosBaseDict.getItem(COSName.getPDFName("DR"));
-              dr.setDirect(true);
-              dr.setNeedToBeUpdate(true);
-              acroFormDict.setItem("DR", dr);
-              sigFieldNotFound=false;
+                        // AcroForm DefaultRessource auslesen und setzen
+                        COSBase dr = cosBaseDict.getItem(COSName.DR);
+                        dr.setDirect(true);
+                        dr.setNeedToBeUpdate(true);
+                        acroFormDict.setItem(COSName.DR, dr);
+                        sigFieldNotFound=false;
+                    }
+                }
             }
-          }
-        }
         
-        if (annotNotFound || sigFieldNotFound )
-          throw new SignatureException(SignatureException.VISUAL_SIGNATURE_INVALID, "Could not read all needed objects from template");
-      }
-      
-      // Seite besorgen und Signatur-Annotation anbringen
-      List annotations = page.getAnnotations();
-      if (annotations== null) 
-      {
-        annotations = new COSArrayList();
-      }
-      annotations.add(signatureField.getWidget());
-      page.setAnnotations(annotations);
-      page.getCOSObject().setNeedToBeUpdate(true);
+            if (annotNotFound || sigFieldNotFound )
+            {
+                throw new SignatureException(SignatureException.VISUAL_SIGNATURE_INVALID, "Could not read all needed objects from template");
+            }
+        }
       
+        // Get the annotations of the page and append the signature-annotation to it
+        List annotations = page.getAnnotations();
+        if (annotations== null) 
+        {
+            annotations = new COSArrayList();
+        }
+        annotations.add(signatureField.getWidget());
+        page.setAnnotations(annotations);
+        page.getCOSObject().setNeedToBeUpdate(true);
     }
 
     /**

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java?rev=1139570&r1=1139569&r2=1139570&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java Sat Jun 25 16:51:57 2011
@@ -25,28 +25,77 @@ import org.apache.pdfbox.pdfparser.Visua
 
 public class SignatureOptions
 {
-  private COSDocument visualSignature;
+    private COSDocument visualSignature;
 
-  private int pageNo;
+    private int preferedSignatureSize;
+    
+    private int pageNo;
   
-  public void setPage(int pageNo)
-  {
-    this.pageNo = pageNo;
-  }
+    /**
+     * Set the page number.
+     * 
+     * @param pageNo the page number
+     * 
+     */
+    public void setPage(int pageNo)
+    {
+        this.pageNo = pageNo;
+    }
   
-  public int getPage() {
-    return pageNo;
-  }
+    /**
+     * Get the page number.
+     * 
+     * @return the page number
+     */
+    public int getPage() 
+    {
+        return pageNo;
+    }
   
-  public void setVisualSignature(InputStream is) throws IOException
-  {
-    VisualSignatureParser visParser = new VisualSignatureParser(is);
-    visParser.parse();
-    visualSignature = visParser.getDocument();
-  }
+    /**
+     * Reads the visual signature from the given input stream.
+     *  
+     * @param is the input stream containing the visual signature
+     * 
+     * @throws IOException when something went wrong during parsing 
+     */
+    public void setVisualSignature(InputStream is) throws IOException
+    { 
+        VisualSignatureParser visParser = new VisualSignatureParser(is);
+        visParser.parse();
+        visualSignature = visParser.getDocument();
+    }
 
-  public COSDocument getVisualSignature()
-  {
-    return visualSignature;
-  }
+    /**
+     * Get the visual signature.
+     * 
+     * @return the visual signature
+     */
+    public COSDocument getVisualSignature()
+    {
+        return visualSignature;
+    }
+  
+    /**
+     * Get the preferred size of the signature.
+     * 
+     * @return the preferred size
+     */
+    public int getPreferedSignatureSize()
+    {
+      return preferedSignatureSize;
+    }
+  
+    /**
+     * Set the preferred size of the signature.
+     * 
+     * @param size the size of the signature
+     */
+    public void setPreferedSignatureSize(int size)
+    {
+        if (size > 0)
+        {
+            preferedSignatureSize = size;
+        }
+    } 
 }