Signing Existing Signature Fields
| Minimum Version | Q2 2026 |
|---|
RadPdfProcessing enables you to sign multiple pre-existing signature fields in a PDF document while preserving the validity of previously applied signatures. The PdfStreamSigner class applies each signature through an incremental update, which appends data to the original PDF instead of rewriting it. This approach ensures that each subsequent signature does not invalidate earlier ones.
PDF documents often contain multiple unsigned signature fields, for example, a contract that requires approval from several parties. When you sign these fields one at a time, each signing operation must preserve the integrity of all previous signatures. The SignExistingField method of the PdfStreamSigner class addresses this requirement. It locates a pre-existing signature field by name, applies a digital signature, and writes the result as an incremental update to the output stream. You can chain multiple signing operations by feeding the output of one step as the input to the next.
API Reference
The following table lists the SignExistingField method overloads available on the PdfStreamSigner class.
| Method signature | Description |
|---|---|
SignExistingField(Stream originalStream, string fieldName, Signature signature) | Signs an existing signature field identified by fieldName in the PDF document from originalStream. Uses incremental update to preserve previously applied signatures. |
SignExistingField(Stream originalStream, string fieldName, Signature signature, FormSource appearance) | Signs an existing signature field and replaces the widget visual appearance with the specified FormSource content. Pass null for appearance to preserve the existing appearance. |
The following table describes the parameters accepted by the SignExistingField method.
| Parameter | Type | Description |
|---|---|---|
originalStream | Stream | The stream that contains the current PDF document. |
fieldName | string | The name of the pre-existing signature field to sign. |
signature | Signature | The digital signature to apply to the field. |
appearance | FormSource | The visual appearance to set on the signature widget. Pass null to keep the existing appearance. Available only in the overload that accepts a FormSource parameter. |
Signing Existing Fields
To sign multiple existing signature fields in a PDF document:
- Import the PDF and identify the unsigned signature fields by name.
- Create a
PdfStreamSignerinstance with an output stream. - Call
SignExistingFieldfor each field, passing the current document stream and the field name. - Use the output stream from each step as the input for the next signing operation.
Example 1: Import a PDF and Sign All Signature Fields
The following example imports an existing PDF that contains unsigned signature fields and signs each field sequentially using incremental updates.
// 1. Load the existing PDF that contains unsigned signature fields.
Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.PdfFormatProvider provider =
new Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.PdfFormatProvider();
RadFixedDocument document;
using (FileStream inputFile = File.OpenRead(@"MultipleSignatureFields.pdf"))
{
document = provider.Import(inputFile, Timeout.InfiniteTimeSpan);
}
// 2. Collect the names of all unsigned signature fields.
string[] unsignedFieldNames = document.AcroForm.FormFields
.Where(f => f.FieldType == FormFieldType.Signature)
.Cast<SignatureField>()
.Where(f => f.Signature == null)
.Select(f => f.Name)
.ToArray();
// 3. Load the certificate used for signing.
System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new X509Certificate2(@"JohnDoe.pfx", "johndoe");
// 4. Sign each field sequentially using incremental updates.
// Each iteration reads the current PDF, signs one field, and produces
// a new stream that becomes the input for the next iteration.
MemoryStream currentStream = new MemoryStream(File.ReadAllBytes(@"MultipleSignatureFields.pdf"));
for (int i = 0; i < unsignedFieldNames.Length; i++)
{
MemoryStream outputStream = new MemoryStream();
PdfStreamSigner signer = new PdfStreamSigner(outputStream);
Telerik.Windows.Documents.Fixed.Model.DigitalSignatures.Signature signature =
new Telerik.Windows.Documents.Fixed.Model.DigitalSignatures.Signature(certificate);
signer.SignExistingField(currentStream, unsignedFieldNames[i], signature);
currentStream = outputStream;
}
// 5. Save the fully signed PDF to disk.
currentStream.Seek(0, SeekOrigin.Begin);
using (FileStream outputFile = File.Create(@"contract_signed.pdf"))
{
currentStream.CopyTo(outputFile);
}
The code first imports the document to discover the names of all unsigned SignatureField instances. It then iterates over the field names and calls SignExistingField for each one. Because each call produces an incremental update, previously applied signatures remain valid in the final output.
Signing with Custom Appearance
When a PDF contains empty (unsigned) signature fields, you can generate and apply a visual appearance during signing. Create a FormSource, draw content into it with FixedContentEditor, and pass it to the SignExistingField overload that accepts an appearance parameter. Each signing step produces an incremental update, so previously applied signatures remain valid.
Example 2: Sign Existing Fields with Custom Appearance
The following example signs two signature fields and applies a custom visual appearance to each widget at signing time.
// 1. Load the PDF that contains two unsigned signature fields (e.g., received from another party).
MemoryStream currentStream = new MemoryStream(File.ReadAllBytes("contract.pdf"));
// 2. Load the signer's certificate.
X509Certificate2 certificate = new X509Certificate2(@"JohnDoe.pfx", "johndoe");
string signerName = certificate.GetNameInfo(X509NameType.SimpleName, false);
// 3. Sign the first field with an "Approver" appearance.
FormSource approverAppearance = BuildAppearance(signerName, "Approver", new Size(250, 80));
MemoryStream afterFirstSign = new MemoryStream();
PdfStreamSigner signer = new PdfStreamSigner(afterFirstSign);
Telerik.Windows.Documents.Fixed.Model.DigitalSignatures.Signature firstSignature = new Signature(certificate);
signer.SignExistingField(currentStream, "ApproverSignature", firstSignature, approverAppearance);
// 4. Sign the second field — the first signature remains valid thanks to incremental update.
FormSource reviewerAppearance = BuildAppearance(signerName, "Reviewer", new Size(250, 80));
MemoryStream afterSecondSign = new MemoryStream();
signer = new PdfStreamSigner(afterSecondSign);
Telerik.Windows.Documents.Fixed.Model.DigitalSignatures.Signature secondSignature = new Signature(certificate);
signer.SignExistingField(afterFirstSign, "ReviewerSignature", secondSignature, reviewerAppearance);
// 5. Save the fully signed PDF.
afterSecondSign.Seek(0, SeekOrigin.Begin);
using (FileStream outputFile = File.Create("contract_signed.pdf"))
{
afterSecondSign.CopyTo(outputFile);
}
The helper method below builds a visual appearance that displays the signer name, role, and signing date:
// Helper: builds an Adobe "Standard Text" style appearance for a given role.
static FormSource BuildAppearance(string signerName, string role, Size size)
{
FormSource appearance = new FormSource();
appearance.Size = size;
FixedContentEditor editor = new FixedContentEditor(appearance);
// Left side: signer name in large text.
editor.Position.Translate(5, 10);
editor.TextProperties.FontSize = 20;
editor.DrawText(signerName);
// Right side: role and signing details.
editor.Position.Translate(120, 10);
editor.TextProperties.FontSize = 8;
editor.DrawText("Digitally signed");
editor.Position.Translate(120, 22);
editor.DrawText("by " + signerName);
editor.Position.Translate(120, 34);
editor.DrawText("Role: " + role);
editor.Position.Translate(120, 46);
editor.DrawText("Date: " + DateTime.Now.ToString("yyyy.MM.dd"));
editor.Position.Translate(120, 58);
editor.DrawText(DateTime.Now.ToString("HH:mm:ss zzz"));
return appearance;
}
Each call to SignExistingField with a FormSource replaces the widget appearance of the target field. Pass null for the appearance parameter to preserve the existing widget appearance.