PDFBOX-1766: 
- visible signature generator
- example
- new method in the SignatureOptions for the new PDVisibleSigProperties

git-svn-id: https://svn.apache.org/repos/asf/pdfbox/trunk@1541625 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
new file mode 100644
index 0000000..9523ae7
--- /dev/null
+++ b/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java
@@ -0,0 +1,266 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.examples.signature;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Enumeration;
+import java.util.List;
+
+import org.apache.pdfbox.exceptions.COSVisitorException;
+import org.apache.pdfbox.exceptions.SignatureException;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureInterface;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSignDesigner;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.CMSSignedDataGenerator;
+import org.bouncycastle.cms.CMSSignedGenerator;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+
+/**
+ * <p>
+ * This is an example for signing a pdf with bouncy castle.
+ * </p>
+ * <p>
+ * And also you can create visible signature too
+ * </p>
+ * <p>
+ * A keystore can be created with the java keytool (e.g. keytool -genkeypair -storepass 123456 -storetype pkcs12 -alias
+ * test -validity 365 -v -keyalg RSA -keystore keystore.p12 )
+ * </p>
+ * 
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ */
+public class CreateVisibleSignature implements SignatureInterface
+{
+
+  private static BouncyCastleProvider provider = new BouncyCastleProvider();
+
+  private PrivateKey privKey;
+
+  private Certificate[] cert;
+
+  private SignatureOptions options;
+
+  /**
+   * Initialize the signature creator with a keystore (pkcs12) and pin that
+   * should be used for the signature.
+   * 
+   * @param keystore
+   *          is a pkcs12 keystore.
+   * @param pin
+   *          is the pin for the keystore / private key
+   */
+  public CreateVisibleSignature(KeyStore keystore, char[] pin)
+  {
+    try {
+      /*
+       * grabs the first alias from the keystore and get the private key. An
+       * alternative method or constructor could be used for setting a specific
+       * alias that should be used.
+       */
+      Enumeration<String> aliases = keystore.aliases();
+      String alias = null;
+      if (aliases.hasMoreElements()) {
+        alias = aliases.nextElement();
+      } else {
+        throw new RuntimeException("Could not find alias");
+      }
+      privKey = (PrivateKey) keystore.getKey(alias, pin);
+      cert = keystore.getCertificateChain(alias);
+    } catch (KeyStoreException e) {
+      e.printStackTrace();
+    } catch (UnrecoverableKeyException e) {
+      System.err.println("Could not extract private key.");
+      e.printStackTrace();
+    } catch (NoSuchAlgorithmException e) {
+      System.err.println("Unknown algorithm.");
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * Signs the given pdf file.
+   * 
+   * @param document is the pdf document
+   * @param signatureProperties
+   * @return the signed pdf document
+   * @throws IOException
+   * @throws COSVisitorException
+   * @throws SignatureException
+   */
+  public File signPDF(File document, PDVisibleSigProperties signatureProperties) throws IOException,
+      COSVisitorException, SignatureException
+  {
+    byte[] buffer = new byte[8 * 1024];
+    if (document == null || !document.exists()) {
+      new RuntimeException("Document for signing does not exist");
+    }
+
+    // creating output document and prepare the IO streams.
+    String name = document.getName();
+    String substring = name.substring(0, name.lastIndexOf("."));
+
+    File outputDocument = new File(document.getParent(), substring + "_signed.pdf");
+    FileInputStream fis = new FileInputStream(document);
+    FileOutputStream fos = new FileOutputStream(outputDocument);
+
+    int c;
+    while ((c = fis.read(buffer)) != -1) {
+      fos.write(buffer, 0, c);
+    }
+    fis.close();
+    fis = new FileInputStream(outputDocument);
+
+    // load document
+    PDDocument doc = PDDocument.load(document);
+
+    // create signature dictionary
+    PDSignature signature = new PDSignature();
+    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); // default filter
+    // subfilter for basic and PAdES Part 2 signatures
+    signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
+    signature.setName("signer name");
+    signature.setLocation("signer location");
+    signature.setReason("reason for signature");
+
+    // the signing date, needed for valid signature
+    signature.setSignDate(Calendar.getInstance());
+
+    // register signature dictionary and sign interface
+
+    if (signatureProperties != null && signatureProperties.isVisualSignEnabled()) {
+      options = new SignatureOptions();
+      options.setVisualSignature(signatureProperties);
+      // options.setPage(signatureProperties.getPage());
+      // options.setPreferedSignatureSize(signatureProperties.getPreferredSize());
+      doc.addSignature(signature, this, options);
+    } else {
+      doc.addSignature(signature, this);
+    }
+
+    // write incremental (only for signing purpose)
+    doc.saveIncremental(fis, fos);
+
+    return outputDocument;
+  }
+
+  /**
+   * <p>
+   * SignatureInterface implementation.
+   * </p>
+   * <p>
+   * This method will be called from inside of the pdfbox and create the pkcs7 signature. The given InputStream contains
+   * the bytes that are providen by the byte range.
+   * </p>
+   * <p>
+   * This method is for internal use only.
+   * </p>
+   * <p>
+   * Here the user should use his favorite cryptographic library and implement a pkcs7 signature creation.
+   * </p>
+   */
+  @Override
+  public byte[] sign(InputStream content) throws SignatureException, IOException
+  {
+    CMSProcessableInputStream input = new CMSProcessableInputStream(content);
+    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
+    // CertificateChain
+    List<Certificate> certList = Arrays.asList(cert);
+
+    CertStore certStore = null;
+    try {
+      certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), provider);
+      gen.addSigner(privKey, (X509Certificate) certList.get(0), CMSSignedGenerator.DIGEST_SHA256);
+      gen.addCertificatesAndCRLs(certStore);
+      CMSSignedData signedData = gen.generate(input, false, provider);
+      return signedData.getEncoded();
+    } catch (Exception e) {
+      // should be handled
+      System.err.println("Error while creating pkcs7 signature.");
+      e.printStackTrace();
+    }
+    throw new RuntimeException("Problem while preparing signature");
+  }
+
+  /**
+   * Arguments are
+   * [0] key store
+   * [1] pin
+   * [2] document that will be signed
+   * [3] image of visible signature
+   */
+  public static void main(String[] args) throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
+      FileNotFoundException, IOException, COSVisitorException, SignatureException
+  {
+
+    if (args.length != 4) {
+      usage();
+      System.exit(1);
+    } else {
+      File ksFile = new File(args[0]);
+      KeyStore keystore = KeyStore.getInstance("PKCS12", provider);
+      char[] pin = args[1].toCharArray();
+      keystore.load(new FileInputStream(ksFile), pin);
+
+      File document = new File(args[2]);
+
+      CreateVisibleSignature signing = new CreateVisibleSignature(keystore, pin.clone());
+
+      FileInputStream image = new FileInputStream(args[3]);
+
+      PDVisibleSignDesigner visibleSig = new PDVisibleSignDesigner(args[2], image, 1);
+      visibleSig.xAxis(0).yAxis(0).zoom(-50).signatureFieldName("signature");
+
+      PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
+
+      signatureProperties.signerName("name").signerLocation("location").signatureReason("Security").preferredSize(0)
+          .page(1).visualSignEnabled(true).setPdVisibleSignature(visibleSig).buildSignature();
+
+      signing.signPDF(document, signatureProperties);
+    }
+
+  }
+
+  /**
+   * This will print the usage for this program.
+   */
+  private static void usage()
+  {
+    System.err.println("Usage: java " + CreateSignature.class.getName()
+        + " <pkcs12-keystore-file> <pin> <input-pdf> <sign-image>");
+  }
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java
index 918ad53..c305c42 100644
--- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/SignatureOptions.java
@@ -21,6 +21,7 @@
 
 import org.apache.pdfbox.cos.COSDocument;
 import org.apache.pdfbox.pdfparser.VisualSignatureParser;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible.PDVisibleSigProperties;
 
 
 public class SignatureOptions
@@ -65,6 +66,20 @@
         visParser.parse();
         visualSignature = visParser.getDocument();
     }
+    
+    /**
+     * Reads the visual signature from the given visual signature properties
+     *  
+     * @param is the <code>PDVisibleSigProperties</code> object containing the visual signature
+     * 
+     * @throws IOException when something went wrong during parsing
+     * 
+     * @since 1.8.3
+     */
+    public void setVisualSignature(PDVisibleSigProperties visSignatureProperties) throws IOException
+    { 
+        setVisualSignature(visSignatureProperties.getVisibleSignature());
+    }
 
     /**
      * Get the visual signature.
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java
new file mode 100644
index 0000000..b4cfd7f
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateBuilder.java
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+
+/**
+ * That class builds visible signature template
+ * which will be added in our pdf document
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ *
+ */
+public interface PDFTemplateBuilder {
+
+    /**
+     * In order to create  Affine Transform, using parameters
+     * @param params
+     */
+	public void createAffineTransform(byte [] params);
+	
+	/**
+	 * Creates specified size page
+	 * @param properties
+	 */
+	public void createPage(PDVisibleSignDesigner properties);
+	
+	/**
+	 * Creates template using page
+	 * @param page
+	 * @throws IOException
+	 */
+	public void createTemplate(PDPage page) throws IOException;
+	
+	/**
+	 * Creates Acro forms in the template
+	 * @param template
+	 */
+	public void createAcroForm(PDDocument template);
+	
+	/**
+	 * Creates signature fields
+	 * @param acroForm
+	 * @throws IOException
+	 */
+	public void createSignatureField(PDAcroForm acroForm) throws IOException;
+	
+	/**
+	 * Creates PDSignature
+	 * @param pdSignatureField
+	 * @param page
+	 * @param signatureName
+	 * @throws IOException
+	 */
+	public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName) throws IOException;
+	
+	/**
+	 * Create AcroForm Dictionary
+	 * @param acroForm
+	 * @param signatureField
+	 * @throws IOException
+	 */
+	public void createAcroFormDictionary(PDAcroForm acroForm, PDSignatureField signatureField) throws IOException;
+	
+	/**
+	 * Creates SingatureRectangle
+	 * @param signatureField
+	 * @param properties
+	 * @throws IOException
+	 */
+	public void createSignatureRectangle(PDSignatureField signatureField, PDVisibleSignDesigner properties) throws IOException;
+	
+	/**
+	 * Creates procSetArray of PDF,Text,ImageB,ImageC,ImageI    
+	 */
+	public void createProcSetArray();
+	
+    /**
+     * Creates signature image
+     * @param template
+     * @param InputStream
+     * @throws IOException
+     */
+	public void createSignatureImage(PDDocument template, InputStream InputStream) throws IOException;
+	
+	/**
+	 * 
+	 * @param params
+	 */
+	public void createFormaterRectangle(byte [] params);
+	
+	/**
+	 * 
+	 * @param template
+	 */
+	public void createHolderFormStream(PDDocument template);
+	
+	/**
+	 * Creates resources of form
+	 */
+	public void createHolderFormResources();
+	
+	/**
+	 * Creates Form
+	 * @param holderFormResources
+	 * @param holderFormStream
+	 * @param formrect
+	 */
+	public void createHolderForm(PDResources holderFormResources, PDStream holderFormStream, PDRectangle formrect);
+	
+	/**
+	 * Creates appearance dictionary
+	 * @param holderForml
+	 * @param signatureField
+	 * @throws IOException
+	 */
+	public void createAppearanceDictionary(PDXObjectForm holderForml, PDSignatureField signatureField) throws IOException;
+	
+	/**
+	 * 
+	 * @param template
+	 */
+	public void createInnerFormStream(PDDocument template);
+	
+	
+	/**
+	 * Creates InnerForm
+	 */
+	public void createInnerFormResource();
+	
+	/**
+	 * 
+	 * @param innerFormResources
+	 * @param innerFormStream
+	 * @param formrect
+	 */
+	public void createInnerForm(PDResources innerFormResources, PDStream innerFormStream, PDRectangle formrect);
+	
+	
+	/**
+	 * 
+	 * @param innerForm
+	 * @param holderFormResources
+	 */
+	public void insertInnerFormToHolerResources(PDXObjectForm innerForm, PDResources holderFormResources);
+	
+	/**
+	 * 
+	 * @param template
+	 */
+	public void createImageFormStream(PDDocument template);
+	
+	/**
+	 * Create resource of image form
+	 */
+	public void createImageFormResources();
+	
+	/**
+	 * Creates Image form
+	 * @param imageFormResources
+	 * @param innerFormResource
+	 * @param imageFormStream
+	 * @param formrect
+	 * @param affineTransform
+	 * @param img
+	 * @throws IOException
+	 */
+	public void createImageForm(PDResources imageFormResources, PDResources innerFormResource, PDStream imageFormStream, PDRectangle formrect,
+			AffineTransform affineTransform, PDJpeg img) throws IOException;
+	
+	/**
+	 * Inject procSetArray 
+	 * @param innerForm
+	 * @param page
+	 * @param innerFormResources
+	 * @param imageFormResources
+	 * @param holderFormResources
+	 * @param procSet
+	 */
+	public void injectProcSetArray(PDXObjectForm innerForm, PDPage page, PDResources innerFormResources, PDResources imageFormResources,
+			PDResources holderFormResources, COSArray procSet);
+	
+	/**
+	 * injects appearance streams
+	 * @param holderFormStream
+	 * @param innterFormStream
+	 * @param imageFormStream
+	 * @param imageObjectName
+	 * @param imageName
+	 * @param innerFormName
+	 * @param properties
+	 * @throws IOException
+	 */
+	public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream, String imageObjectName,
+			String imageName, String innerFormName, PDVisibleSignDesigner properties) throws IOException;
+	
+	/**
+	 * just to create visible signature
+	 * @param template
+	 */
+	public void createVisualSignature(PDDocument template);
+	
+	/**
+	 * adds Widget Dictionary
+	 * @param signatureField
+	 * @param holderFormResources
+	 * @throws IOException
+	 */
+	public void createWidgetDictionary(PDSignatureField signatureField, PDResources holderFormResources) throws IOException;
+	
+	/**
+	 * 
+	 * @return - PDF template Structure
+	 */
+	public PDFTemplateStructure getStructure();
+	
+	/**
+	 * Closes template
+	 * @param template
+	 * @throws IOException
+	 */
+	public void closeTemplate(PDDocument template) throws IOException;
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java
new file mode 100644
index 0000000..5641051
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateCreator.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.awt.geom.AffineTransform;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.exceptions.COSVisitorException;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+
+/**
+ * 
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ * 
+ */
+public class PDFTemplateCreator
+{
+
+    PDFTemplateBuilder pdfBuilder;
+    private static final Log logger = LogFactory.getLog(PDFTemplateCreator.class);
+
+    /**
+     * sets PDFBuilder
+     * 
+     * @param bookBuilder
+     */
+    public PDFTemplateCreator(PDFTemplateBuilder bookBuilder)
+    {
+        this.pdfBuilder = bookBuilder;
+    }
+
+    /**
+     * that method returns object of PDFStructur
+     * 
+     * @return PDFStructure
+     */
+    public PDFTemplateStructure getPdfStructure()
+    {
+        return this.pdfBuilder.getStructure();
+    }
+
+    /**
+     * this method build pdf, step by step, and finally it returns stream of visible signature
+     * 
+     * @param properties
+     * @return InputStream
+     * @throws IOException
+     * @throws COSVisitorException
+     */
+
+    public InputStream buildPDF(PDVisibleSignDesigner properties) throws IOException
+    {
+        logger.info("pdf building has been started");
+        PDFTemplateStructure pdfStructure = pdfBuilder.getStructure();
+
+        this.pdfBuilder.createProcSetArray();
+        this.pdfBuilder.createPage(properties);
+        PDPage page = pdfStructure.getPage();
+
+        this.pdfBuilder.createTemplate(page);
+        PDDocument template = pdfStructure.getTemplate();
+        this.pdfBuilder.createAcroForm(template);
+        PDAcroForm acroForm = pdfStructure.getAcroForm();
+
+        this.pdfBuilder.createSignatureField(acroForm);
+        PDSignatureField pdSignatureField = pdfStructure.getSignatureField();
+        this.pdfBuilder.createSignature(pdSignatureField, page, properties.getSignatureFieldName());
+        this.pdfBuilder.createAcroFormDictionary(acroForm, pdSignatureField);
+        this.pdfBuilder.createAffineTransform(properties.getAffineTransformParams());
+        AffineTransform transform = pdfStructure.getAffineTransform();
+        this.pdfBuilder.createSignatureRectangle(pdSignatureField, properties);
+        this.pdfBuilder.createFormaterRectangle(properties.getFormaterRectangleParams());
+        PDRectangle formater = pdfStructure.getFormaterRectangle();
+
+        this.pdfBuilder.createSignatureImage(template, properties.getImageStream());
+
+        this.pdfBuilder.createHolderFormStream(template);
+        PDStream holderFormStream = pdfStructure.getHolderFormStream();
+        this.pdfBuilder.createHolderFormResources();
+        PDResources holderFormResources = pdfStructure.getHolderFormResources();
+        this.pdfBuilder.createHolderForm(holderFormResources, holderFormStream, formater);
+        this.pdfBuilder.createAppearanceDictionary(pdfStructure.getHolderForm(), pdSignatureField);
+        this.pdfBuilder.createInnerFormStream(template);
+        this.pdfBuilder.createInnerFormResource();
+        PDResources innerFormResource = pdfStructure.getInnerFormResources();
+        this.pdfBuilder.createInnerForm(innerFormResource, pdfStructure.getInnterFormStream(), formater);
+        PDXObjectForm innerForm = pdfStructure.getInnerForm();
+        this.pdfBuilder.insertInnerFormToHolerResources(innerForm, holderFormResources);
+        this.pdfBuilder.createImageFormStream(template);
+        PDStream imageFormStream = pdfStructure.getImageFormStream();
+        this.pdfBuilder.createImageFormResources();
+        PDResources imageFormResources = pdfStructure.getImageFormResources();
+        this.pdfBuilder.createImageForm(imageFormResources, innerFormResource, imageFormStream, formater, transform,
+                pdfStructure.getJpedImage());
+        this.pdfBuilder.injectProcSetArray(innerForm, page, innerFormResource, imageFormResources, holderFormResources,
+                pdfStructure.getProcSet());
+
+        String imgFormName = pdfStructure.getImageFormName();
+        String imgName = pdfStructure.getImageName();
+        String innerFormName = pdfStructure.getInnerFormName();
+
+        this.pdfBuilder.injectAppearanceStreams(holderFormStream, imageFormStream, imageFormStream, imgFormName,
+                imgName, innerFormName, properties);
+        this.pdfBuilder.createVisualSignature(template);
+        this.pdfBuilder.createWidgetDictionary(pdSignatureField, holderFormResources);
+        
+        ByteArrayInputStream in = null;
+        try
+        {
+            in = pdfStructure.templateAppearanceStream();
+        }
+        catch (COSVisitorException e)
+        {
+            logger.error("COSVisitorException: cant get apereance stream ", e);
+        }
+        logger.info("stream returning started, size= " + in.available());
+        
+        template.close();
+        
+        return in;
+
+    }
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java
new file mode 100644
index 0000000..f8fa1da
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDFTemplateStructure.java
@@ -0,0 +1,365 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.awt.geom.AffineTransform;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSDocument;
+import org.apache.pdfbox.exceptions.COSVisitorException;
+import org.apache.pdfbox.pdfwriter.COSWriter;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+
+/**
+ * Structure of PDF document with visible signature
+ * 
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ * 
+ */
+public class PDFTemplateStructure
+{
+
+    private PDPage page;
+    private PDDocument template;
+    private PDAcroForm acroForm;
+    private PDSignatureField signatureField;
+    private PDSignature pdSignature;
+    private COSDictionary acroFormDictionary;
+    private PDRectangle singatureRectangle;
+    private AffineTransform affineTransform;
+    private COSArray procSet;
+    private PDJpeg jpedImage;
+    private PDRectangle formaterRectangle;
+    private PDStream holderFormStream;
+    private PDResources holderFormResources;
+    private PDXObjectForm holderForm;
+    private PDAppearanceDictionary appearanceDictionary;
+    private PDStream innterFormStream;
+    private PDResources innerFormResources;
+    private PDXObjectForm innerForm;
+    private PDStream imageFormStream;
+    private PDResources imageFormResources;
+    private List<PDField> acroFormFields;
+    private String innerFormName;
+    private String imageFormName;
+    private String imageName;
+    private COSDocument visualSignature;
+    private PDXObjectForm imageForm;
+    private COSDictionary widgetDictionary;
+
+    public PDPage getPage()
+    {
+        return page;
+    }
+
+    public void setPage(PDPage page)
+    {
+        this.page = page;
+    }
+
+    public PDDocument getTemplate()
+    {
+        return template;
+    }
+
+    public void setTemplate(PDDocument template)
+    {
+        this.template = template;
+    }
+
+    public PDAcroForm getAcroForm()
+    {
+        return acroForm;
+    }
+
+    public void setAcroForm(PDAcroForm acroForm)
+    {
+        this.acroForm = acroForm;
+    }
+
+    public PDSignatureField getSignatureField()
+    {
+        return signatureField;
+    }
+
+    public void setSignatureField(PDSignatureField signatureField)
+    {
+        this.signatureField = signatureField;
+    }
+
+    public PDSignature getPdSignature()
+    {
+        return pdSignature;
+    }
+
+    public void setPdSignature(PDSignature pdSignature)
+    {
+        this.pdSignature = pdSignature;
+    }
+
+    public COSDictionary getAcroFormDictionary()
+    {
+        return acroFormDictionary;
+    }
+
+    public void setAcroFormDictionary(COSDictionary acroFormDictionary)
+    {
+        this.acroFormDictionary = acroFormDictionary;
+    }
+
+    public PDRectangle getSingatureRectangle()
+    {
+        return singatureRectangle;
+    }
+
+    public void setSignatureRectangle(PDRectangle singatureRectangle)
+    {
+        this.singatureRectangle = singatureRectangle;
+    }
+
+    public AffineTransform getAffineTransform()
+    {
+        return affineTransform;
+    }
+
+    public void setAffineTransform(AffineTransform affineTransform)
+    {
+        this.affineTransform = affineTransform;
+    }
+
+    public COSArray getProcSet()
+    {
+        return procSet;
+    }
+
+    public void setProcSet(COSArray procSet)
+    {
+        this.procSet = procSet;
+    }
+
+    public PDJpeg getJpedImage()
+    {
+        return jpedImage;
+    }
+
+    public void setJpedImage(PDJpeg jpedImage)
+    {
+        this.jpedImage = jpedImage;
+    }
+
+    public PDRectangle getFormaterRectangle()
+    {
+        return formaterRectangle;
+    }
+
+    public void setFormaterRectangle(PDRectangle formaterRectangle)
+    {
+        this.formaterRectangle = formaterRectangle;
+    }
+
+    public PDStream getHolderFormStream()
+    {
+        return holderFormStream;
+    }
+
+    public void setHolderFormStream(PDStream holderFormStream)
+    {
+        this.holderFormStream = holderFormStream;
+    }
+
+    public PDXObjectForm getHolderForm()
+    {
+        return holderForm;
+    }
+
+    public void setHolderForm(PDXObjectForm holderForm)
+    {
+        this.holderForm = holderForm;
+    }
+
+    public PDResources getHolderFormResources()
+    {
+        return holderFormResources;
+    }
+
+    public void setHolderFormResources(PDResources holderFormResources)
+    {
+        this.holderFormResources = holderFormResources;
+    }
+
+    public PDAppearanceDictionary getAppearanceDictionary()
+    {
+        return appearanceDictionary;
+    }
+
+    public void setAppearanceDictionary(PDAppearanceDictionary appearanceDictionary)
+    {
+        this.appearanceDictionary = appearanceDictionary;
+    }
+
+    public PDStream getInnterFormStream()
+    {
+        return innterFormStream;
+    }
+
+    public void setInnterFormStream(PDStream innterFormStream)
+    {
+        this.innterFormStream = innterFormStream;
+    }
+
+    public PDResources getInnerFormResources()
+    {
+        return innerFormResources;
+    }
+
+    public void setInnerFormResources(PDResources innerFormResources)
+    {
+        this.innerFormResources = innerFormResources;
+    }
+
+    public PDXObjectForm getInnerForm()
+    {
+        return innerForm;
+    }
+
+    public void setInnerForm(PDXObjectForm innerForm)
+    {
+        this.innerForm = innerForm;
+    }
+
+    public String getInnerFormName()
+    {
+        return innerFormName;
+    }
+
+    public void setInnerFormName(String innerFormName)
+    {
+        this.innerFormName = innerFormName;
+    }
+
+    public PDStream getImageFormStream()
+    {
+        return imageFormStream;
+    }
+
+    public void setImageFormStream(PDStream imageFormStream)
+    {
+        this.imageFormStream = imageFormStream;
+    }
+
+    public PDResources getImageFormResources()
+    {
+        return imageFormResources;
+    }
+
+    public void setImageFormResources(PDResources imageFormResources)
+    {
+        this.imageFormResources = imageFormResources;
+    }
+
+    public PDXObjectForm getImageForm()
+    {
+        return imageForm;
+    }
+
+    public void setImageForm(PDXObjectForm imageForm)
+    {
+        this.imageForm = imageForm;
+    }
+
+    public String getImageFormName()
+    {
+        return imageFormName;
+    }
+
+    public void setImageFormName(String imageFormName)
+    {
+        this.imageFormName = imageFormName;
+    }
+
+    public String getImageName()
+    {
+        return imageName;
+    }
+
+    public void setImageName(String imageName)
+    {
+        this.imageName = imageName;
+    }
+
+    public COSDocument getVisualSignature()
+    {
+        return visualSignature;
+    }
+
+    public void setVisualSignature(COSDocument visualSignature)
+    {
+        this.visualSignature = visualSignature;
+    }
+
+    public List<PDField> getAcroFormFields()
+    {
+        return acroFormFields;
+    }
+
+    public void setAcroFormFields(List<PDField> acroFormFields)
+    {
+        this.acroFormFields = acroFormFields;
+    }
+    
+    public ByteArrayInputStream templateAppearanceStream() throws IOException, COSVisitorException
+    {
+        COSDocument visualSignature = getVisualSignature();
+
+        ByteArrayOutputStream memoryOut = new ByteArrayOutputStream();
+        COSWriter memoryWriter = new COSWriter(memoryOut);
+        memoryWriter.write(visualSignature);
+
+        ByteArrayInputStream input = new ByteArrayInputStream(memoryOut.toByteArray());
+
+        getTemplate().close();
+
+        return input;
+    }
+
+    public COSDictionary getWidgetDictionary()
+    {
+        return widgetDictionary;
+    }
+
+    public void setWidgetDictionary(COSDictionary widgetDictionary)
+    {
+        this.widgetDictionary = widgetDictionary;
+    }
+
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java
new file mode 100644
index 0000000..f28637c
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigBuilder.java
@@ -0,0 +1,398 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.awt.geom.AffineTransform;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.PDResources;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.pdmodel.common.PDStream;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
+import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceDictionary;
+import org.apache.pdfbox.pdmodel.interactive.annotation.PDAppearanceStream;
+import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
+import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
+import org.apache.pdfbox.pdmodel.interactive.form.PDField;
+import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+
+/**
+ * 
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ * 
+ */
+public class PDVisibleSigBuilder implements PDFTemplateBuilder
+{
+
+    private PDFTemplateStructure pdfStructure;
+    private static final Log logger = LogFactory.getLog(PDVisibleSigBuilder.class);
+
+    @Override
+    public void createPage(PDVisibleSignDesigner properties)
+    {
+        PDPage page = new PDPage();
+        page.setMediaBox(new PDRectangle(properties.getPageWidth(), properties.getPageHeight()));
+        pdfStructure.setPage(page);
+        logger.info("PDF page has been created");
+    }
+
+    @Override
+    public void createTemplate(PDPage page) throws IOException
+    {
+        PDDocument template = new PDDocument();
+        template.addPage(page);
+        pdfStructure.setTemplate(template);
+    }
+
+    public PDVisibleSigBuilder()
+    {
+        pdfStructure = new PDFTemplateStructure();
+        logger.info("PDF Strucure has been Created");
+
+    }
+
+    @Override
+    public void createAcroForm(PDDocument template)
+    {
+        PDAcroForm theAcroForm = new PDAcroForm(template);
+        template.getDocumentCatalog().setAcroForm(theAcroForm);
+        pdfStructure.setAcroForm(theAcroForm);
+        logger.info("Acro form page has been created");
+
+    }
+
+    @Override
+    public PDFTemplateStructure getStructure()
+    {
+        return pdfStructure;
+    }
+
+    @Override
+    public void createSignatureField(PDAcroForm acroForm) throws IOException
+    {
+        PDSignatureField sf = new PDSignatureField(acroForm);
+        pdfStructure.setSignatureField(sf);
+        logger.info("Signature field has been created");
+    }
+
+    @Override
+    public void createSignature(PDSignatureField pdSignatureField, PDPage page, String signatureName)
+            throws IOException
+    {
+        PDSignature pdSignature = new PDSignature();
+        pdSignatureField.setSignature(pdSignature);
+        pdSignatureField.getWidget().setPage(page);
+        page.getAnnotations().add(pdSignatureField.getWidget());
+        pdSignature.setName(signatureName);
+        pdSignature.setByteRange(new int[] { 0, 0, 0, 0 });
+        pdSignature.setContents(new byte[4096]);
+        pdfStructure.setPdSignature(pdSignature);
+        logger.info("PDSignatur has been created");
+    }
+
+    @Override
+    public void createAcroFormDictionary(PDAcroForm acroForm, PDSignatureField signatureField) throws IOException
+    {
+        @SuppressWarnings("unchecked")
+        List<PDField> acroFormFields = acroForm.getFields();
+        COSDictionary acroFormDict = acroForm.getDictionary();
+        acroFormDict.setDirect(true);
+        acroFormDict.setInt(COSName.SIG_FLAGS, 3);
+        acroFormFields.add(signatureField);
+        acroFormDict.setString(COSName.DA, "/sylfaen 0 Tf 0 g");
+        pdfStructure.setAcroFormFields(acroFormFields);
+        pdfStructure.setAcroFormDictionary(acroFormDict);
+        logger.info("AcroForm dictionary has been created");
+    }
+
+    @Override
+    public void createSignatureRectangle(PDSignatureField signatureField, PDVisibleSignDesigner properties)
+            throws IOException
+    {
+
+        PDRectangle rect = new PDRectangle();
+        rect.setUpperRightX(properties.getxAxis() + properties.getWidth());
+        rect.setUpperRightY(properties.getTemplateHeight() - properties.getyAxis());
+        rect.setLowerLeftY(properties.getTemplateHeight() - properties.getyAxis() - properties.getHeight());
+        rect.setLowerLeftX(properties.getxAxis());
+        signatureField.getWidget().setRectangle(rect);
+        pdfStructure.setSignatureRectangle(rect);
+        logger.info("rectangle of signature has been created");
+    }
+
+    @Override
+    public void createAffineTransform(byte[] params)
+    {
+        AffineTransform transform = new AffineTransform(params[0], params[1], params[2], params[3], params[4],
+                params[5]);
+        pdfStructure.setAffineTransform(transform);
+        logger.info("Matrix has been added");
+    }
+
+    @Override
+    public void createProcSetArray()
+    {
+        COSArray procSetArr = new COSArray();
+        procSetArr.add(COSName.getPDFName("PDF"));
+        procSetArr.add(COSName.getPDFName("Text"));
+        procSetArr.add(COSName.getPDFName("ImageB"));
+        procSetArr.add(COSName.getPDFName("ImageC"));
+        procSetArr.add(COSName.getPDFName("ImageI"));
+        pdfStructure.setProcSet(procSetArr);
+        logger.info("ProcSet array has been created");
+    }
+
+    @Override
+    public void createSignatureImage(PDDocument template, InputStream inputStream) throws IOException
+    {
+        PDJpeg img = new PDJpeg(template, inputStream);
+        pdfStructure.setJpedImage(img);
+        logger.info("Visible Signature Image has been created");
+        // pdfStructure.setTemplate(template);
+        inputStream.close();
+
+    }
+
+    @Override
+    public void createFormaterRectangle(byte[] params)
+    {
+
+        PDRectangle formrect = new PDRectangle();
+        formrect.setUpperRightX(params[0]);
+        formrect.setUpperRightY(params[1]);
+        formrect.setLowerLeftX(params[2]);
+        formrect.setLowerLeftY(params[3]);
+
+        pdfStructure.setFormaterRectangle(formrect);
+        logger.info("Formater rectangle has been created");
+
+    }
+
+    @Override
+    public void createHolderFormStream(PDDocument template)
+    {
+        PDStream holderForm = new PDStream(template);
+        pdfStructure.setHolderFormStream(holderForm);
+        logger.info("Holder form Stream has been created");
+    }
+
+    @Override
+    public void createHolderFormResources()
+    {
+        PDResources holderFormResources = new PDResources();
+        pdfStructure.setHolderFormResources(holderFormResources);
+        logger.info("Holder form resources have been created");
+
+    }
+
+    @Override
+    public void createHolderForm(PDResources holderFormResources, PDStream holderFormStream, PDRectangle formrect)
+    {
+
+        PDXObjectForm holderForm = new PDXObjectForm(holderFormStream);
+        holderForm.setResources(holderFormResources);
+        holderForm.setBBox(formrect);
+        holderForm.setFormType(1);
+        pdfStructure.setHolderForm(holderForm);
+        logger.info("Holder form has been created");
+
+    }
+
+    @Override
+    public void createAppearanceDictionary(PDXObjectForm holderForml, PDSignatureField signatureField)
+            throws IOException
+    {
+
+        PDAppearanceDictionary appearance = new PDAppearanceDictionary();
+        appearance.getCOSObject().setDirect(true);
+
+        PDAppearanceStream appearanceStream = new PDAppearanceStream(holderForml.getCOSStream());
+
+        appearance.setNormalAppearance(appearanceStream);
+        signatureField.getWidget().setAppearance(appearance);
+
+        pdfStructure.setAppearanceDictionary(appearance);
+        logger.info("PDF appereance Dictionary has been created");
+
+    }
+
+    @Override
+    public void createInnerFormStream(PDDocument template)
+    {
+        PDStream innterFormStream = new PDStream(template);
+        pdfStructure.setInnterFormStream(innterFormStream);
+        logger.info("Strean of another form (inner form - it would be inside holder form) has been created");
+    }
+
+    @Override
+    public void createInnerFormResource()
+    {
+        PDResources innerFormResources = new PDResources();
+        pdfStructure.setInnerFormResources(innerFormResources);
+        logger.info("Resources of another form (inner form - it would be inside holder form) have been created");
+    }
+
+    @Override
+    public void createInnerForm(PDResources innerFormResources, PDStream innerFormStream, PDRectangle formrect)
+    {
+        PDXObjectForm innerForm = new PDXObjectForm(innerFormStream);
+        innerForm.setResources(innerFormResources);
+        innerForm.setBBox(formrect);
+        innerForm.setFormType(1);
+        pdfStructure.setInnerForm(innerForm);
+        logger.info("Another form (inner form - it would be inside holder form) have been created");
+
+    }
+
+    @Override
+    public void insertInnerFormToHolerResources(PDXObjectForm innerForm, PDResources holderFormResources)
+    {
+        String name = holderFormResources.addXObject(innerForm, "FRM");
+        pdfStructure.setInnerFormName(name);
+        logger.info("Alerady inserted inner form  inside holder form");
+    }
+
+    @Override
+    public void createImageFormStream(PDDocument template)
+    {
+        PDStream imageFormStream = new PDStream(template);
+        pdfStructure.setImageFormStream(imageFormStream);
+        logger.info("Created image form Stream");
+
+    }
+
+    @Override
+    public void createImageFormResources()
+    {
+        PDResources imageFormResources = new PDResources();
+        pdfStructure.setImageFormResources(imageFormResources);
+        logger.info("Created image form Resources");
+    }
+
+    @Override
+    public void createImageForm(PDResources imageFormResources, PDResources innerFormResource,
+            PDStream imageFormStream, PDRectangle formrect, AffineTransform affineTransform, PDJpeg img)
+            throws IOException
+    {
+
+        /*
+         * if you need text on the visible signature 
+         * 
+         * PDFont font = PDTrueTypeFont.loadTTF(this.pdfStructure.getTemplate(), new File("D:\\arial.ttf")); 
+         * font.setFontEncoding(new WinAnsiEncoding());
+         * 
+         * Map<String, PDFont> fonts = new HashMap<String, PDFont>(); fonts.put("arial", font);
+         */
+        PDXObjectForm imageForm = new PDXObjectForm(imageFormStream);
+        imageForm.setBBox(formrect);
+        imageForm.setMatrix(affineTransform);
+        imageForm.setResources(imageFormResources);
+        imageForm.setFormType(1);
+        /*
+         * imageForm.getResources().addFont(font); 
+         * imageForm.getResources().setFonts(fonts);
+         */
+
+        imageFormResources.getCOSObject().setDirect(true);
+        String imageFormName = innerFormResource.addXObject(imageForm, "n");
+        String imageName = imageFormResources.addXObject(img, "img");
+        this.pdfStructure.setImageForm(imageForm);
+        this.pdfStructure.setImageFormName(imageFormName);
+        this.pdfStructure.setImageName(imageName);
+        logger.info("Created image form");
+    }
+
+    @Override
+    public void injectProcSetArray(PDXObjectForm innerForm, PDPage page, PDResources innerFormResources,
+            PDResources imageFormResources, PDResources holderFormResources, COSArray procSet)
+    {
+
+        innerForm.getResources().getCOSDictionary().setItem(COSName.PROC_SET, procSet); //
+        page.getCOSDictionary().setItem(COSName.PROC_SET, procSet);
+        innerFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet);
+        imageFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet);
+        holderFormResources.getCOSDictionary().setItem(COSName.PROC_SET, procSet);
+        logger.info("inserted ProcSet to PDF");
+    }
+
+    @Override
+    public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream,
+            String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties)
+            throws IOException
+    {
+
+        // 100 means that document width is 100% via the rectangle. if rectangle
+        // is 500px, images 100% is 500px.
+        // String imgFormComment = "q "+imageWidthSize+ " 0 0 50 0 0 cm /" +
+        // imageName + " Do Q\n" + builder.toString();
+        String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + " Do Q\n";
+        String holderFormComment = "q 1 0 0 1 0 0 cm /" + innerFormName + " Do Q \n";
+        String innerFormComment = "q 1 0 0 1 0 0 cm /" + imageObjectName + " Do Q\n";
+
+        appendRawCommands(pdfStructure.getHolderFormStream().createOutputStream(), holderFormComment);
+        appendRawCommands(pdfStructure.getInnterFormStream().createOutputStream(), innerFormComment);
+        appendRawCommands(pdfStructure.getImageFormStream().createOutputStream(), imgFormComment);
+        logger.info("Injected apereance stream to pdf");
+
+    }
+
+    public void appendRawCommands(OutputStream os, String commands) throws IOException
+    {
+        os.write(commands.getBytes("UTF-8"));
+        os.close();
+    }
+
+    @Override
+    public void createVisualSignature(PDDocument template)
+    {
+        this.pdfStructure.setVisualSignature(template.getDocument());
+        logger.info("Visible signature has been created");
+
+    }
+
+    @Override
+    public void createWidgetDictionary(PDSignatureField signatureField, PDResources holderFormResources)
+            throws IOException
+    {
+
+        COSDictionary widgetDict = signatureField.getWidget().getDictionary();
+        widgetDict.setNeedToBeUpdate(true);
+        widgetDict.setItem(COSName.DR, holderFormResources.getCOSObject());
+
+        pdfStructure.setWidgetDictionary(widgetDict);
+        logger.info("WidgetDictionary has been crated");
+    }
+
+    @Override
+    public void closeTemplate(PDDocument template) throws IOException
+    {
+        template.close();
+        this.pdfStructure.getTemplate().close();
+
+    }
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigProperties.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigProperties.java
new file mode 100644
index 0000000..6b595b0
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSigProperties.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.pdfbox.cos.COSDictionary;
+import org.apache.pdfbox.cos.COSDocument;
+
+/**
+ * This builder class is in order to create visible signature properties.
+ * 
+ * @author Vakhtang koroghlishvili (Gogebashvili)
+ * 
+ */
+public class PDVisibleSigProperties
+{
+    private String signerName;
+    private String signerLocation;
+    private String signatureReason;
+    private boolean visualSignEnabled;
+    private int page;
+    private int preferredSize;
+
+    private InputStream visibleSignature;
+    private PDVisibleSignDesigner pdVisibleSignature;
+
+    /**
+     * start building of visible signature
+     * 
+     * @throws IOException
+     */
+    public void buildSignature() throws IOException
+    {
+        PDFTemplateBuilder builder = new PDVisibleSigBuilder();
+        PDFTemplateCreator creator = new PDFTemplateCreator(builder);
+        setVisibleSignature(creator.buildPDF(getPdVisibleSignature()));
+    }
+
+    /**
+     * 
+     * @return - signer name
+     */
+    public String getSignerName()
+    {
+        return signerName;
+    }
+
+    /**
+     * sets signer name
+     * @param signerName
+     * @return
+     */
+    public PDVisibleSigProperties signerName(String signerName)
+    {
+        this.signerName = signerName;
+        return this;
+    }
+
+    /**
+     * 
+     * @return - location
+     */
+    public String getSignerLocation()
+    {
+        return signerLocation;
+    }
+
+    /**
+     * Sets location
+     * @param signerLocation
+     * @return
+     */
+    public PDVisibleSigProperties signerLocation(String signerLocation)
+    {
+        this.signerLocation = signerLocation;
+        return this;
+    }
+
+    /**
+     * gets reason of signing
+     * @return 
+     */
+    public String getSignatureReason()
+    {
+        return signatureReason;
+    }
+
+    /**
+     * sets reason of signing
+     * @param signatureReason
+     * @return
+     */
+    public PDVisibleSigProperties signatureReason(String signatureReason)
+    {
+        this.signatureReason = signatureReason;
+        return this;
+    }
+
+    /**
+     * returns your page
+     * @return 
+     */
+    public int getPage()
+    {
+        return page;
+    }
+
+    /**
+     * sets page number
+     * @param page
+     * @return
+     */
+    public PDVisibleSigProperties page(int page)
+    {
+        this.page = page;
+        return this;
+    }
+
+    /**
+     * gets our preferred size
+     * @return
+     */
+    public int getPreferredSize()
+    {
+        return preferredSize;
+    }
+
+    /**
+     * sets our preferred size
+     * @param preferredSize
+     * @return
+     */
+    public PDVisibleSigProperties preferredSize(int preferredSize)
+    {
+        this.preferredSize = preferredSize;
+        return this;
+    }
+
+    /**
+     * checks if we need to add visible signature
+     * @return
+     */
+    public boolean isVisualSignEnabled()
+    {
+        return visualSignEnabled;
+    }
+
+    /**
+     * sets visible signature to be added or not
+     * @param visualSignEnabled
+     * @return
+     */
+    public PDVisibleSigProperties visualSignEnabled(boolean visualSignEnabled)
+    {
+        this.visualSignEnabled = visualSignEnabled;
+        return this;
+    }
+
+    /**
+     * this method gets visible signature configuration object
+     * @return
+     */
+    public PDVisibleSignDesigner getPdVisibleSignature()
+    {
+        return pdVisibleSignature;
+    }
+
+    /**
+     * Sets visible signature configuration Object
+     * @param pdVisibleSignature
+     * @return
+     */
+    public PDVisibleSigProperties setPdVisibleSignature(PDVisibleSignDesigner pdVisibleSignature)
+    {
+        this.pdVisibleSignature = pdVisibleSignature;
+        return this;
+    }
+
+    /**
+     * returns visible signature configuration object
+     * @return
+     */
+    public InputStream getVisibleSignature()
+    {
+        return visibleSignature;
+    }
+
+    /**
+     * sets configuration object of visible signature
+     * @param visibleSignature
+     */
+    public void setVisibleSignature(InputStream visibleSignature)
+    {
+        this.visibleSignature = visibleSignature;
+    }
+
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java
new file mode 100644
index 0000000..a69e94c
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/PDVisibleSignDesigner.java
@@ -0,0 +1,457 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.digitalsignature.visible;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * 
+ * That class is in order to build  your 
+ * visible signature design. Because of 
+ * this is builder, instead of setParam()
+ * we use param() methods.
+ * @author Vakhtang koroghlishvili (Gogebashvili) 
+ */
+public class PDVisibleSignDesigner
+{
+
+    private Float sigImgWidth;
+    private Float sigImgHeight;
+    private float xAxis;
+    private float yAxis;
+    private float pageHeight;
+    private float pageWidth;
+    private InputStream imgageStream;
+    private String signatureFieldName = "sig"; // default
+    private byte[] formaterRectangleParams = { 0, 0, 100, 50 }; // default
+    private byte[] AffineTransformParams =   { 1, 0, 0, 1, 0, 0 }; // default
+    private float imageSizeInPercents;
+    private PDDocument document = null;
+  
+    
+
+    /**
+     * 
+     * @param originalDocumenStream
+     * @param imageStream
+     * @param page-which page are you going to add visible signature
+     * @throws IOException
+     */
+    public PDVisibleSignDesigner(InputStream originalDocumenStream, InputStream imageStream, int page) throws IOException
+    {
+        signatureImageStream(imageStream);
+        document = PDDocument.load(originalDocumenStream);
+        calculatePageSize(document, page);
+    }
+
+    /**
+     * 
+     * @param documentPath
+     * @param imageStream
+     * @param page -which page are you going to add visible signature
+     * @throws IOException
+     */
+    public PDVisibleSignDesigner(String documentPath, InputStream imageStream, int page) throws IOException
+    {
+
+        // set visible singature image Input stream
+        signatureImageStream(imageStream);
+
+        // create PD document
+        document = PDDocument.load(documentPath);
+
+        // calculate height an width of document
+        calculatePageSize(document, page);
+
+        document.close();
+    }
+
+    public PDVisibleSignDesigner(PDDocument doc, InputStream imageStream, int page) throws IOException
+    {
+        signatureImageStream(imageStream);
+        calculatePageSize(doc, page);
+    }
+
+    /**
+     * Each page of document can be different sizes.
+     * 
+     * @param document
+     * @param page
+     */
+    private void calculatePageSize(PDDocument document, int page)
+    {
+
+        if (page < 1)
+        {
+            throw new IllegalArgumentException("First page of pdf is 1, not " + page);
+        }
+
+        List<?> pages = document.getDocumentCatalog().getAllPages();
+        PDPage firstPage =(PDPage) pages.get(page - 1);
+        PDRectangle mediaBox = firstPage.findMediaBox();
+        this.pageHeight(mediaBox.getHeight());
+        this.pageWidth = mediaBox.getWidth();
+
+        float x = this.pageWidth;
+        float y = 0;
+        this.pageWidth = this.pageWidth + y;
+        float tPercent = (100 * y / (x + y));
+        this.imageSizeInPercents = 100 - tPercent;
+
+    }
+
+    /**
+     * 
+     * @param path  of image location
+     * @return image Stream
+     * @throws IOException
+     */
+    public PDVisibleSignDesigner signatureImage(String path) throws IOException
+    {
+        InputStream fin = new FileInputStream(path);
+        return signatureImageStream(fin);
+    }
+
+    /**
+     * zoom signature image with some percent.
+     * 
+     * @param percent- x % increase image with x percent.
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner zoom(float percent)
+    {
+        sigImgHeight = sigImgHeight + (sigImgHeight * percent) / 100;
+        sigImgWidth = sigImgWidth + (sigImgWidth * percent) / 100;
+        return this;
+    }
+
+    /**
+     * 
+     * @param xAxis - x coordinate 
+     * @param yAxis - y coordinate
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner coordinates(float x, float y)
+    {
+        xAxis(x);
+        yAxis(y);
+        return this;
+    }
+
+    /**
+     * 
+     * @return xAxis - gets x coordinates
+     */
+    public float getxAxis()
+    {
+        return xAxis;
+    }
+
+    /**
+     * 
+     * @param xAxis  - x coordinate 
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner xAxis(float xAxis)
+    {
+        this.xAxis = xAxis;
+        return this;
+    }
+
+    /**
+     * 
+     * @return yAxis
+     */
+    public float getyAxis()
+    {
+        return yAxis;
+    }
+
+    /**
+     * 
+     * @param yAxis
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner yAxis(float yAxis)
+    {
+        this.yAxis = yAxis;
+        return this;
+    }
+
+    /**
+     * 
+     * @return signature image width
+     */
+    public float getWidth()
+    {
+        return sigImgWidth;
+    }
+
+    /**
+     * 
+     * @param sets signature image width
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner width(float signatureImgWidth)
+    {
+        this.sigImgWidth = signatureImgWidth;
+        return this;
+    }
+
+    /**
+     * 
+     * @return signature image height
+     */
+    public float getHeight()
+    {
+        return sigImgHeight;
+    }
+
+    /**
+     * 
+     * @param set signature image Height
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner height(float signatureImgHeight)
+    {
+        this.sigImgHeight = signatureImgHeight;
+        return this;
+    }
+
+    /**
+     * 
+     * @return template height
+     */
+    protected float getTemplateHeight()
+    {
+        return getPageHeight();
+    }
+
+    /**
+     * 
+     * @param templateHeight
+     * @return Visible Signature Configuration Object
+     */
+    private PDVisibleSignDesigner pageHeight(float templateHeight)
+    {
+        this.pageHeight = templateHeight;
+        return this;
+    }
+
+    /**
+     * 
+     * @return signature field name
+     */
+    public String getSignatureFieldName()
+    {
+        return signatureFieldName;
+    }
+
+    /**
+     * 
+     * @param signatureFieldName
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner signatureFieldName(String signatureFieldName)
+    {
+        this.signatureFieldName = signatureFieldName;
+        return this;
+    }
+
+    /**
+     * 
+     * @return image Stream
+     */
+    public InputStream getImageStream()
+    {
+        return imgageStream;
+    }
+
+    /**
+     * 
+     * @param imgageStream- stream of your visible signature image
+     * @return Visible Signature Configuration Object
+     * @throws IOException
+     */
+    private PDVisibleSignDesigner signatureImageStream(InputStream imgageStream) throws IOException
+    {
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        byte[] buffer = new byte[1024];
+        int len;
+        while ((len = imgageStream.read(buffer)) > -1)
+        {
+            baos.write(buffer, 0, len);
+        }
+        baos.flush();
+        baos.close();
+
+        byte[] byteArray = baos.toByteArray();
+        byte[] byteArraySecond = Arrays.clone(byteArray);
+
+        InputStream inputForBufferedImage = new ByteArrayInputStream(byteArray);
+        InputStream revertInputStream = new ByteArrayInputStream(byteArraySecond);
+
+        if (sigImgHeight == null || sigImgWidth == null)
+        {
+            calcualteImageSize(inputForBufferedImage);
+        }
+
+        this.imgageStream = revertInputStream;
+
+        return this;
+    }
+
+    /**
+     * calculates image width and height. sported formats: all
+     * 
+     * @param fis - input stream of image
+     * @throws IOException
+     */
+    private void calcualteImageSize(InputStream fis) throws IOException
+    {
+
+        BufferedImage bimg = ImageIO.read(fis);
+        int width = bimg.getWidth();
+        int height = bimg.getHeight();
+
+        sigImgHeight = (float) height;
+        sigImgWidth = (float) width;
+
+    }
+
+    /**
+     * 
+     * @return Affine Transform parameters of for PDF Matrix
+     */
+    public byte[] getAffineTransformParams()
+    {
+        return AffineTransformParams;
+    }
+
+    /**
+     * 
+     * @param affineTransformParams
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner affineTransformParams(byte[] affineTransformParams)
+    {
+        AffineTransformParams = affineTransformParams;
+        return this;
+    }
+
+    /**
+     * 
+     * @return formatter PDRectanle parameters
+     */
+    public byte[] getFormaterRectangleParams()
+    {
+        return formaterRectangleParams;
+    }
+
+    /**
+     * sets formatter PDRectangle;
+     * 
+     * @param formaterRectangleParams
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner formaterRectangleParams(byte[] formaterRectangleParams)
+    {
+        this.formaterRectangleParams = formaterRectangleParams;
+        return this;
+    }
+
+    /**
+     * 
+     * @return page width
+     */
+    public float getPageWidth()
+    {
+        return pageWidth;
+    }
+
+    /**
+     * 
+     * @param sets pageWidth
+     * @return Visible Signature Configuration Object
+     */
+    public PDVisibleSignDesigner pageWidth(float pageWidth)
+    {
+        this.pageWidth = pageWidth;
+        return this;
+    }
+
+    /**
+     * 
+     * @return page height
+     */
+    public float getPageHeight()
+    {
+        return pageHeight;
+    }
+
+    /**
+     * get image size in percents
+     * @return
+     */
+    public float getImageSizeInPercents()
+    {
+        return imageSizeInPercents;
+    }
+
+   /**
+    * 
+    * @param imageSizeInPercents
+    */
+    public void imageSizeInPercents(float imageSizeInPercents)
+    {
+        this.imageSizeInPercents = imageSizeInPercents;
+    }
+
+    /**
+     * returns visible signature text
+     * @return
+     */
+    public String getSignatureText()
+    {
+        throw new UnsupportedOperationException("That method is not yet implemented");
+    }
+
+    /**
+     * 
+     * @param signatureText - adds the text on visible signature
+     * @return
+     */
+    public PDVisibleSignDesigner signatureText(String signatureText)
+    {
+        throw new UnsupportedOperationException("That method is not yet implemented");
+    }
+
+}
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/package.html b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/package.html
new file mode 100644
index 0000000..cabf72c
--- /dev/null
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/digitalsignature/visible/package.html
@@ -0,0 +1,25 @@
+<!--
+ ! Licensed to the Apache Software Foundation (ASF) under one or more
+ ! contributor license agreements.  See the NOTICE file distributed with
+ ! this work for additional information regarding copyright ownership.
+ ! The ASF licenses this file to You under the Apache License, Version 2.0
+ ! (the "License"); you may not use this file except in compliance with
+ ! the License.  You may obtain a copy of the License at
+ !
+ !      http://www.apache.org/licenses/LICENSE-2.0
+ !
+ ! Unless required by applicable law or agreed to in writing, software
+ ! distributed under the License is distributed on an "AS IS" BASIS,
+ ! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ! See the License for the specific language governing permissions and
+ ! limitations under the License.
+ !-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+
+</head>
+<body>
+This is the visual signature part that help creating the visual representation for the digital signature.  
+</body>
+</html>