Looking for a way to copy the signature from a Laserfiche Form into a PDF Form. The Fill Out PDF Form activity does not allow access to the signature fields, also how do I access the signature image?
Edit: Here is my final result for a solution.
Note: This may break with future updates to the application since we are calling an internal class.
I found that after a signature was entered a new image is available with class name form-sig-img.
The source of this image is a base64 encoded png.
After the form has been signed extract the source in JavaScript
var data = $('.form-sig-img').attr('src');
Make sure to replace the encoding information in the source right away. (Save to repository is vulnerable to code injection and your data will be replaced with the string "signed").
data = data.replace('data:image/png;base64,','');
Now we just need to put the data in a hidden field so that it can be submitted along with the form. We can create a couple data field with class names (datafield, datafield2) and then hide them.
$('.datafield').hide(); $('.datafield2').hide();
I need to diverge for a moment and explain the reason for two data fields.
The maximum field size in Laserfiche is 4000 characters and there are encoded signatures (if drawn) up to around 6000 characters. (If you scribble all over the place you can reach 10k but that is unrealistic). This means you will need to split your data at the 4000 character mark. You can do this with javascript.
Create a function to partition the string.
function partition(str, index) { return [str.substring(0, index), str.substring(index)]; }
Then if the data is greater than 4000 characters split the data and put the second half into a second hidden field.
if (data.length < 4001) { $('.datafield input').val(data); } else { var parts = partition(data, 4000); $('.datafield input').val(parts[0]); $('.datafield2 input').val(parts[1]); }
Whew. Now that this is done setup your save to repository task and drop each data field into a hidden “Text” type field set at 4000 character maximum.
Now we can use Workflow to stamp the image.
First Retrieve the field values and setup a condition for either one field value or both field values containing data.
If both contain data simply re-combine them. I did this in the script.
To place an image onto a PDF you will need a PDF editor library. I used a popular one called iTextSharp. If you are going to distribute this integration make sure to clear up your licensing costs http://itextpdf.com/purchase
Add a script object and under references add the reference to the iTextSharp Libarary (Make sure you are using Workflow 9.2 and the dll file is located directly in the root of the Laserfiche Workflow 9 program files folder.)
Define your master pdf file and your output file.
string masterFile = "c:\\unsigned.pdf"; string outputFile = "c:\\signed.pdf";
We also need to decode the encoded png file to a memory stream.
string sigimg = GetTokenValue("RetrieveFieldValues_SigImage").ToString(); byte[] imageBytes = Convert.FromBase64String(sigimg); MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
Now we can tell iTextSharp to stamp the PDF
using (FileStream fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write, FileShare.None)) { PdfStamper stamper = new PdfStamper(new PdfReader(masterFile), fs); iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(ms); //Scale it, change the signature size img.ScaleAbsolute(100, 50); //Position it set the position it should appear on the PDF img.SetAbsolutePosition(635, 320); //Add it to page 1 of the document, change 1 to page number stamper.GetOverContent(1).AddImage(img); stamper.Close(); }
The signature will be stamped directly over the PDF image and will look very natural. No fields required, just need to get the positioning right with trail and error.
Another option using a more affordable library called Dynamic PDF from ceTe Software. Only the byte array is required, no memory stream.
//Load master PDF form ceTe.DynamicPDF.Merger.MergeDocument document = new ceTe.DynamicPDF.Merger.MergeDocument("c:\\Laserfiche\\Workflow Files\\masterform.pdf"); //Apply License ceTe.DynamicPDF.Document.AddLicense ( "LICENCE KEY" ); //Create byte array from signature image data byte[] imageBytes = Convert.FromBase64String(GetTokenValue("RetrieveFieldValues_SigImage").ToString()); ceTe.DynamicPDF.Imaging.ImageData imgData = ceTe.DynamicPDF.Imaging.ImageData.GetImage(imageBytes); //Parameters: Image Byte Array, Y plane from top, X plane from right, transparency in float ceTe.DynamicPDF.PageElements.Image image = new ceTe.DynamicPDF.PageElements.Image(imgData, 250, 150, 1.0f); image.Width = 100; image.Height = 50; //The angle gets modified somehow with this library, rotate 270 degrees to set it back to original angle of 0 image.Angle = 270; ceTe.DynamicPDF.PageElements.TransparencyGroup group = new TransparencyGroup(1.0f); group.Add(image); //Add to page 1, change 0 to the page number you want document.Pages[0].Elements.Add(group); document.Tag = null; //Output File document.Draw("c:\\Laserfiche\\Import\\signed.pdf");