Submit ink signatures with form

Q: How can I submit ink signatures along with the form that is submitted?

A: Ink signatures are not part of the signature form field properties, but instead they are just ink annotations that overlap the signature form field and thus are considered ink signatures. Therefore, by default they’re not included with the payload that is sent when the form is submitted.

However, we can store the ink signature data as a string in a hidden text form field. When the form is submitted, the string would be sent along with the rest of the form data.

This is how you could retrieve the signatures for the corresponding form fields:

async function getStringifiedInkSignatures(instance) {
  let stringifiedSignatures = {};
  const pagesPromises = Array.from({ length: instance.totalPageCount }).map(
    (_, index) => {
      return instance.getAnnotations(index);
    }
  );
  const annotationsByPage = await Promise.all(pagesPromises);
  const inkSignatureAnnotations = annotationsByPage.reduce(
    (acc, pageAnnotations) => {
      const pageInkSignatureAnnotations = pageAnnotations.filter(
        annotation => annotation.isSignature
      );
      return pageInkSignatureAnnotations.size > 0
        ? acc.concat(pageInkSignatureAnnotations.toArray())
        : acc;
    },
    []
  );
  const formFields = await instance.getFormFields();
  const signatureWidgetAnnotations = annotationsByPage.reduce(
    (acc, pageAnnotations) => {
      const pageWidgetAnnotations = pageAnnotations.filter(
        annotation => annotation.formFieldName
      );
      const pageSignatureWidgetAnnotations = pageWidgetAnnotations.filter(
        annotation =>
          formFields.find(
            formField =>
              formField.name === annotation.formFieldName &&
              formField instanceof PSPDFKit.FormFields.SignatureFormField
          )
      );
      return pageSignatureWidgetAnnotations.size > 0
        ? acc.concat(pageSignatureWidgetAnnotations.toArray())
        : acc;
    },
    []
  );
  inkSignatureAnnotations.forEach(inkSignatureAnnotation => {
    const inkSignatureWidgetAnnotation = signatureWidgetAnnotations.find(
      signatureWidgetAnnotation => {
        return signatureWidgetAnnotation.boundingBox.isRectOverlapping(
          inkSignatureAnnotation.boundingBox
        );
      }
    );
    if (inkSignatureWidgetAnnotation) {
      stringifiedSignatures[
        inkSignatureWidgetAnnotation.formFieldName
      ] = JSON.stringify(inkSignatureAnnotation.toJS());
    }
  });
  return stringifiedSignatures;
}

In order to submit this info as part of the form, the PDF document needs to have an additional hidden text form field for each signature form field in the document (you can create it on the fly if you have the Form Creator component in your license).

Then you can call the following function just before submitting the form. Let’s say you name these form fields with the pattern "inksignature*for*[signature form field name here]":

async function submitForm() {
  let stringifiedInkSignaturesFormFieldValues = {};
  const stringifiedInkSignatures = await getStringifiedInkSignatures(instance);
  Object.entries(stringifiedInkSignatures).forEach(
    ([formFieldName, stringifiedInkSignature]) => {
      stringifiedInkSignaturesFormFieldValues[
        `inksignature_for_${formFieldName}`
      ] = stringifiedInkSignature;
    }
  );
  instance.setFormFieldValues(stringifiedInkSignaturesFormFieldValues);
  // Now submit the form!
}

This has been tested with PSPDFKit for Web 2020.2.3