Form Signature Fields ​
Signature fields are a special type of form field in PDF documents, designed specifically for adding and managing electronic signatures. This chapter explains in detail how to use Foxit PDF SDK for Web to work with form signature fields, including adding, editing, and verifying signatures, as well as customizing the signing workflow and user interface (UI).
For signature features, Foxit PDF SDK for Web provides support for:
- Creating, editing, and deleting signature widgets and fields
- Signing and verifying signatures
- Customizing signer configuration information and signature handlers
- Customizing signature verification handlers
- Customizing signature-related UI, including the signing dialog, signature verification dialog, and signature information dialog
Add, Edit, and Delete Signature Fields in PDF Documents ​
Create a Signature Field ​
You can add a new signature field to a PDF document by calling the createSignature method of the PDFForm class. This method requires a CreateSignatureOptions object to configure the signature field properties.
javascript
const options = {
pdfRect: {left: 100, top: 100, right: 300, bottom: 200}, // Set the position and size of the signature field
pageIndex: 0, // Specify the page index where the signature field will be added
rotate: 0, // Optional. Set the rotation angle of the Widget. Valid values are 0, 1, 2, or 3, representing 0, 90, 180, and 270 degrees respectively
fieldName: 'SignatureField1' // Optional. Specify the signature field name. If omitted, a unique field name is generated automatically
};
pdfForm.createSignature(options).then(widget => {
console.log("Signature field created successfully:", widget);
}).catch(error => {
console.error("Error creating signature field:", error);
});After the signature field is created successfully, Foxit PDF SDK for Web inserts a new signature widget into the page and triggers the ViewerEvents.annotationAdded event. When handling this event, you can determine whether a signature widget has been added by using Annot.getType and PDFFormField.getType.
javascript
pdfui.addViewerEventListener(PDFViewCtrl.ViewerEvents.annotationAdded, (annotations) => {
const signatureWidgets = annotations.filter(it => {
return it.getType() === PDF.annots.constant.Annot_Type.widget && it.getField().getType() === PDF.form.constant.FieldType.signature
});
// Use signatureWidgets for follow-up operations
})Delete a Signature ​
Deleting a signature here means deleting the signature widget rather than deleting the signature field directly. Removing a signature widget is done the same way as removing an annotation, through the PDFPage.removeAnnotByObjectNumber method.
javascript
pdfPage.removeAnnotByObjectNumber(widget.getObjectNumber()).then((removedAnnots) => {
if (removedAnnots.length === 1) {
console.log("Signature widget deleted successfully");
} else {
console.log("Signature widget to delete was not found");
}
}, reason => {
console.error("Error deleting signature widget:", reason);
});After a signature widget is removed successfully, an array containing the removed widget is returned. If the target signature widget is not found, an empty array is returned. Therefore, after deletion you should check whether the returned array length is 1 to confirm success.
In addition, once the signature widget is removed, if its parent form field no longer contains any other widgets, that field is automatically cleared and the DataEvents.formFieldRemoved event is triggered.
If you are not familiar with the relationship between form fields and widgets, see Introduction to Basic Form Concepts.
Start Signing ​
After the signature field is created successfully, you can sign it by calling the PDFDoc.sign method. Signature-related information, such as the signer identity, reason, and location, can be defined in detail in the signInfo object.
javascript
const signInfo = {
filter: 'Adobe.PPKLite',
subfilter: 'adbe.pkcs7.sha1',
flag: 0x1f0,
distinguishName: '[email protected]',
location: 'bj',
reason: 'TestBJ',
signer: 'web sdk11',
showTime: true,
signTime: Date.now(),
defaultContentsLength: 7942,
image: 'data:image/png;base64,iVBORw0...',
rotation: 90,
timeFormat: {
format: 'YYYY-MM-DD HH:mm:ss Z',
timeZoneOptions: {prefix: 'GMT'}
},
};
// Example signature service URL
const signature_server = 'https://webviewer-demo.foxitsoftware.com/signature'; // Or use your own deployed signature service URL
const signedDocBlobData = await pdfDoc.sign(signInfo, async function sign(signInfo, plainContent) {
const formdata = new FormData();
formdata.append("plain", new Blob([plainContent]), "plain");
const response = await fetch(signature_server + '/digest_and_sign', {
method: 'POST',
body: formdata
});
return response.arrayBuffer();
});During signing, Foxit PDF SDK for Web calls the sign callback and submits signature-related data to the signature service. After the signature service completes signing, it returns the signed data.
For signature service implementation, Foxit PDF SDK for Web provides sample implementations for both Windows and Linux. You can refer to /server/signature-server-for-linux/README.md and /server/signature-server-for-win/readme.md in the release package.
To help you verify the signing feature quickly, we provide the following test services:
US services:
China services:
NOTE
These services are for testing only and must not be used in production environments. If the Node.js implementations we provide for signature-server-for-linux and signature-server-for-win do not meet your requirements, you can refer to their source code and reimplement them with another technology stack as needed to ensure stability and availability in production.
After signing succeeds, the returned blob object contains the signed PDF file. You can save the file locally or open it directly with PDFViewer.openPDFByFile:
javascript
pdfViewer.openPDFByFile(signedDocBlobData, {fileName: 'signed.pdf'});Verify Signatures ​
Verification API ​
After signing succeeds, you can verify the signature by calling PDFSignature.verify to ensure that the signature field is valid.
javascript
const signatureField = form.getField("Signature field name");
// Example signature service URL
const signature_server = 'https://webviewer-demo.foxitsoftware.com/signature'; // Or use your own deployed signature service URL
const result = await signatureField.verify({
force: false,
handler: async (signatureField, plainContent, signedData, hasDataOutOfScope) => {
const filter = await signatureField.getFilter();
const subfilter = await signatureField.getSubfilter();
const signer = await signatureField.getSigner();
const formdata = new FormData();
formdata.append("filter", filter);
formdata.append("subfilter", subfilter);
formdata.append("signer", signer);
formdata.append("plainContent", new Blob([plainContent]), "plainContent");
formdata.append("signedData", new Blob([signedData]), "signedData");
const response = await fetch(signature_server + '/verify', {
method: 'POST',
body: formdata
});
const result = parseInt(await response.text());
return result;
}
});After verification is completed, a result value of type Signature_State is returned to indicate the verification result:
Signature validation status:
verifyValid (4): The signature is validverifyInvalid (8): The signature is invalidverifyErrorByteRange (64): Unexpected byte rangeverifyUnknown (2147483648): Unknown signature
Document change status:
verifyChange (128): The document has been changed within the signed range, making the signature invalidverifyIncredible (256): The signature is untrusted and may present a riskverifyNoChange (1024): The document has not been changed within the signed rangeverifyChangeLegal (134217728): The document has been changed outside the signed range, but the change is allowedverifyChangeIllegal (268435456): The document has been changed outside the signed range, and the change invalidates the signature
Issuer validation status:
verifyIssueUnknown (2048): The issuer validation status is unknownverifyIssueValid (4096): The issuer validation status is validverifyIssueRevoke (16384): The issuer certificate used for validation has been revokedverifyIssueExpire (32768): The issuer certificate used for validation has expiredverifyIssueUncheck (65536): The issuer has not been checkedverifyIssueCurrent (131072): The verified issuer is the current issuer
Timestamp status:
verifyTimestampNone (262144): No timestamp is present or the timestamp was not checkedverifyTimestampDoc (524288): The signature is a timestamp signatureverifyTimestampValid (1048576): The timestamp is validverifyTimestampInvalid (2097152): The timestamp is invalidverifyTimestampExpire (4194304): The timestamp has expiredverifyTimestampIssueUnknown (8388608): The timestamp issuer validation status is unknownverifyTimestampIssueValid (16777216): The timestamp issuer validation status is validverifyTimestampTimeBefore (33554432): The timestamp is valid because the time is before the expiration date
NOTE
Before verifying a signature, make sure the signature field has already been signed. If it has not been signed, calling verify throws an error, so you should check the signed state first.
javascript
const isSigned = await signatureField.isSigned();
if (isSigned) {
// Verify the signature here
}Custom Verification Handler ​
A verification handler is an asynchronous function that submits data to the signature verification service and returns the verification result. You can get the signature service by calling PDFViewer.getSignatureService and set a global default verification handler.
NOTE
Once a global default verification handler is set, Foxit PDF SDK for Web automatically uses it. When PDFSignature.verify is called at the application layer without explicitly specifying the handler parameter, the custom verification handler is also used automatically.
javascript
const signatureService = pdfViewer.getSignatureService();
// Example signature service URL
const signature_server = 'https://webviewer-demo.foxitsoftware.com/signature'; // Or use your own deployed signature service URL
signatureService.setVerifyHandler(
async (signatureField, plainContent, signedData, hasDataOutOfScope) => {
const filter = await signatureField.getFilter();
const subfilter = await signatureField.getSubfilter();
const signer = await signatureField.getSigner();
const formdata = new FormData();
formdata.append("filter", filter);
formdata.append("subfilter", subfilter);
formdata.append("signer", signer);
formdata.append("plainContent", new Blob([plainContent]), "plainContent");
formdata.append("signedData", new Blob([signedData]), "signedData");
const response = await fetch(signature_server + '/verify', {
method: 'POST',
body: formdata
});
return parseInt(await response.text());
}
)Get Signature Information ​
The PDFSignature.getSignInfo method is used to retrieve signature information. If the signature field has been signed, it returns a SignedFormSignatureInfo object; otherwise, it returns an UnsignedFormSignatureInfo object.
Customize Signature UI ​
Foxit PDF SDK for Web provides a set of interfaces for customizing signature-related UI elements. These interfaces are defined in ISignatureUI and can be obtained through IViewerUI.getSignatureUI(). The main interfaces include:
ISignDocDialog: Displays the document signing dialogISignVerifiedResultDialog: Displays the signature verification result dialogISignedSignaturePropertiesDialog: Displays the properties dialog for a signed signature field
To customize signature-related UI elements, you can extend a built-in Viewer UI class provided by the SDK, such as XViewerUI or TinyViewerUI, and override the getSignatureUI method to return a custom ISignatureUI implementation. For example:
ts
class CustomSignDocDialog implements ISignDocDialog {
private signatureField: ISignatureField;
private _isOpened = false;
async openWith(
signature: ISignatureField,
okCallback: (data: SignDocInfo, sign: DigestSignHandler) => Promise<void> | void,
cancelCallback?: () => Promise<void> | void
): Promise<void> {
this._isOpened = true;
this.signatureField = signature;
// Create the signature dialog UI
// Display all required information
// Register the okCallback and cancelCallback handlers, which are called when the user confirms or cancels
}
isOpened(): boolean {
return this._isOpened;
}
getCurrentSignature(): ISignatureField | undefined {
return this.signatureField;
}
hide(): void {
this._isOpened = false;
// Hide the signature dialog
}
destroy(): void {
// Release resources
}
}
class CustomSignatureUI implements ISignatureUI {
// Implement methods from the ISignatureUI interface
getSignDocumentDialog() {
return Promise.resolve(new CustomSignDocDialog())
}
...
}
class CustomViewerUI extends UIExtension.XViewerUI {
getSignatureUI() {
return Promise.resolve(new CustomSignatureUI());
}
}
// Use the custom ViewerUI
new PDFUI({
viewerOptions: {
viewerUI: new CustomViewerUI()
}
})Within a custom ISignatureUI implementation, you can tailor the appearance and behavior of each dialog based on your requirements. For example, by overriding ISignDocDialog.openWith, you can run specific custom logic when the signing dialog is opened.