Signature Zones
This guide details the creation of signature zones on PDF documents.
The ZoneBuilder Class
The ZoneBuilder class is the recommended approach for creating signature zones. It opens the PDF document once and caches page dimensions for optimal performance.
using (var zoneBuilder = new ZoneBuilder("document.pdf", isPki: false))
{
var signZone = zoneBuilder.CreateFieldSignZone(1, "signature1", 10, 300, 100, 40);
var textZone = zoneBuilder.CreateFieldTextZone(1, "text1", 10, 400, 200, 30);
var dateZone = zoneBuilder.CreateFieldDateSignZone(2, "date1", 10, 500, 100, 25);
}
Properties
| Property | Type | Description |
|---|---|---|
PageCount |
int | Total number of pages in the PDF document |
FilePath |
string | PDF file path |
IsPki |
bool | Indicates whether PKI mode is enabled (allows TextArea, OptionList, Dropdown) |
Constructor
public ZoneBuilder(string filePath, bool isPki)
| Parameter | Type | Description |
|---|---|---|
filePath |
string | Path to the PDF file |
isPki |
bool | Enables PKI mode for advanced zone types |
Common Parameters
All CreateField*Zone methods share these parameters:
| Parameter | Type | Description |
|---|---|---|
page |
int | Page number (1 = first page) |
fieldName |
string | Unique field identifier |
x |
float | Horizontal position (from left) |
y |
float | Vertical position (from top) |
width |
float | Field width |
height |
float | Field height |
Note
Standard Letter page dimensions are 612 x 792 points (72 DPI).
Use GetPageDimensions(page) to get the exact dimensions of a page.
Getting Page Dimensions
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: false))
{
var (pageWidth, pageHeight) = zoneBuilder.GetPageDimensions(1);
Console.WriteLine($"Page 1: {pageWidth} x {pageHeight} points");
}
Zone Types
Signature Zone
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: false))
{
var signZone = zoneBuilder.CreateFieldSignZone(
page: 1,
fieldName: "client_signature",
x: 100, y: 650,
width: 200, height: 50
);
}
Initials Zone
var initialsZone = zoneBuilder.CreateFieldInitialZone(
page: 1,
fieldName: "client_initials",
x: 500, y: 700,
width: 60, height: 30
);
Text Zone
var textZone = zoneBuilder.CreateFieldTextZone(
page: 1,
fieldName: "full_name",
x: 100, y: 600,
width: 200, height: 25,
defaultValue: "", // Default value
fontSize: 12,
required: true // Required field
);
Number Zone
var numberZone = zoneBuilder.CreateFieldNumberZone(
page: 1,
fieldName: "amount",
x: 100, y: 550,
width: 100, height: 25,
defaultValue: 0,
fontSize: 12,
required: true
);
Date Zone (Auto-filled on Signature)
This zone is automatically filled with the signature date.
var dateSignZone = zoneBuilder.CreateFieldDateSignZone(
page: 1,
fieldName: "signature_date",
x: 100, y: 500,
width: 100, height: 25,
fontSize: 12
);
Date Zone (Picker)
Allows the signer to choose a date via a picker.
var dateZone = zoneBuilder.CreateFieldDateZone(
page: 1,
fieldName: "contract_date",
x: 100, y: 450,
width: 100, height: 25,
fontSize: 12,
required: true
);
Checkbox
var checkbox = zoneBuilder.CreateFieldCheckBoxZone(
page: 1,
fieldName: "accept_terms",
x: 100, y: 400,
isChecked: false, // Default checked state
required: true, // Required
requiredFocus: false // Must receive focus before submission
);
Note
Checkbox dimensions are fixed (10x10 points).
If required is true, the checkbox cannot be pre-checked (isChecked will be ignored).
Radio Button
Radio buttons are grouped by groupId. Only one button can be selected per group.
// Radio button group
var radio1 = zoneBuilder.CreateFieldRadioZone(
page: 1,
fieldName: "Option A", // Value of this option
x: 100, y: 350,
groupId: "option_choice", // Group identifier
isSelected: true // Default selected option
);
var radio2 = zoneBuilder.CreateFieldRadioZone(
page: 1,
fieldName: "Option B", // Value of this option
x: 130, y: 350,
groupId: "option_choice", // Same group
isSelected: false
);
Note
Radio button dimensions are fixed (10x10 points).
PKI-Only Zone Types
The following zone types require isPki: true when initializing the ZoneBuilder.
Multiline Text Zone (TextArea)
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: true))
{
var textAreaZone = zoneBuilder.CreateFieldTextAreaZone(
page: 1,
fieldName: "description",
x: 100, y: 300,
width: 300, height: 100,
defaultValue: "Enter your description here...",
fontSize: 12,
required: false
);
}
Option List (Multiple Selection)
var optionListZone = zoneBuilder.CreateFieldOptionListZone(
page: 1,
fieldName: "services",
x: 100, y: 150,
width: 200, height: 80,
options: new[] { "Service A", "Service B", "Service C", "Service D" },
selectedValues: new[] { "Service A", "Service C" }, // Pre-selected values (optional)
multiSelect: true,
required: false
);
For single selection:
var singleSelectZone = zoneBuilder.CreateFieldOptionListZone(
page: 1,
fieldName: "country",
x: 100, y: 250,
width: 150, height: 25,
options: new[] { "Canada", "United States", "France", "Belgium" },
selectedValues: new[] { "Canada" },
multiSelect: false,
required: true
);
Dropdown
var dropdownZone = zoneBuilder.CreateFieldDropdownZone(
page: 1,
fieldName: "province",
x: 100, y: 200,
width: 150, height: 25,
options: new[] { "Quebec", "Ontario", "Alberta", "British Columbia" },
selectedValue: "Quebec", // Pre-selected value (optional)
fontSize: 12,
required: true
);
Complete Example: Contract Form
public SignZoneDetails[] CreateContractFormZones(string filePath)
{
var zones = new List<SignZoneDetails>();
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: false))
{
// Client information
zones.Add(zoneBuilder.CreateFieldTextZone(1, "last_name", 150, 700, 200, 25, "", 12, true));
zones.Add(zoneBuilder.CreateFieldTextZone(1, "first_name", 150, 670, 200, 25, "", 12, true));
zones.Add(zoneBuilder.CreateFieldTextZone(1, "email", 150, 640, 250, 25, "", 12, true));
// Amount
zones.Add(zoneBuilder.CreateFieldNumberZone(1, "amount", 150, 600, 100, 25, 0, 12, true));
// Terms acceptance
zones.Add(zoneBuilder.CreateFieldCheckBoxZone(1, "terms", 50, 400, false, true));
// Auto-filled date
zones.Add(zoneBuilder.CreateFieldDateSignZone(1, "contract_date", 350, 300, 100, 25, 12));
// Signature
zones.Add(zoneBuilder.CreateFieldSignZone(1, "signature", 100, 150, 200, 60));
// Initials on each page
for (int i = 1; i <= zoneBuilder.PageCount; i++)
{
zones.Add(zoneBuilder.CreateFieldInitialZone(i, $"initials_p{i}", 500, 50, 50, 25));
}
}
return zones.ToArray();
}
Example with PKI Mode
public SignZoneDetails[] CreateAdvancedFormZones(string filePath)
{
var zones = new List<SignZoneDetails>();
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: true))
{
// Standard text fields
zones.Add(zoneBuilder.CreateFieldTextZone(1, "name", 150, 700, 200, 25));
// Multiline text zone (PKI only)
zones.Add(zoneBuilder.CreateFieldTextAreaZone(1, "comments", 150, 500, 300, 100));
// Dropdown (PKI only)
zones.Add(zoneBuilder.CreateFieldDropdownZone(
1, "contract_type", 150, 450, 200, 25,
new[] { "Standard", "Premium", "Enterprise" },
"Standard"
));
// Signature
zones.Add(zoneBuilder.CreateFieldSignZone(1, "signature", 100, 150, 200, 60));
}
return zones.ToArray();
}
Assigning Zones to Recipients
string filePath = @"c:\temp\document.pdf";
// Get the SHA512 hash of the PDF file
string sha512 = CryptoHelper.GetSHA512OfFile(filePath);
// Create the recipient
var recipient = new RecipientInfo { Email = "signer@example.com" };
// Build zone definitions
var zones = CreateContractFormZones(filePath);
var recipientIndex = new Dictionary<RecipientInfo, List<FileZoneDefinition>>
{
{
recipient,
new List<FileZoneDefinition>
{
new FileZoneDefinition
{
UniqueName = sha512,
ZonesDef = new SignZoneDefinition
{
Mode = "define",
Zones = zones
}
}
}
}
};
// Convert to list for the API
var zoneDefList = SignHelper.ConvertRecipientIndexToList(recipientIndex);
Error Handling
Constructor Exceptions
| Exception | Cause |
|---|---|
ArgumentException |
File path is empty or null |
FileNotFoundException |
PDF file does not exist |
CreateField*Zone Method Exceptions
| Exception | Cause |
|---|---|
ArgumentOutOfRangeException |
Page number is invalid (< 1 or > number of pages) |
ObjectDisposedException |
The ZoneBuilder has been disposed |
NotSupportedException |
PKI zone type used without isPki: true |
ArgumentException |
Invalid options (e.g., empty list for OptionList/Dropdown) |
try
{
using (var zoneBuilder = new ZoneBuilder(filePath, isPki: false))
{
var zone = zoneBuilder.CreateFieldSignZone(1, "signature", 100, 100, 200, 50);
}
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"File not found: {ex.FileName}");
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"Invalid page: {ex.Message}");
}
catch (NotSupportedException ex)
{
Console.WriteLine($"Unsupported zone type: {ex.Message}");
}
Best Practices
Use
using: TheZoneBuilderimplementsIDisposable. Always use ausingblock to release resources.Create all zones for a PDF in a single session: For better performance, create all your zones for a PDF within a single
usingblock.Unique field names: Ensure each
fieldNameis unique within the document, except for radio buttons in the same group.