Add a Signature Field Anywhere in a PDF Using Nutrient's .NET SDK and DocuVieware


Working with forms in PDFs often requires giving users the freedom to choose where specific fields (like a signature box in this article) should appear. In this article, I’ll walk you through a simple but powerful integration we did using the Nutrient .NET SDK and DocuVieware WebViewer. The same logic can be applied to any kind of form field, annotation, or custom object.
We’re combining frontend interaction with backend PDF editing, allowing users to draw an area on the PDF and instantly convert it into a signature field server-side.
Let’s break it down step by step.
Step 1 — Let the user draw an area
The first part happens on the client side, using JavaScript and the DocuVieware WebViewer API.
First of all, let’s create a simple HTML button that starts the process by changing the MouseMode to "area selection”:
<button onclick="onSignatureFormFieldButtonClicked">Add Signature Field</button>
When the user clicks the custom button to insert a signature field, we change the mouse mode to allow rectangular selection:
var selectedArea;
function onSignatureFormFieldButtonClicked(){
DocuViewareAPI.SetMouseMode("DocuVieware1", 3); // 3 = Area selection
}
Once an area is selected, the coordinates are retrieved by the RegisterOnAreaSelected event, and sent to the server through a custom server action:
function RegisterOnAreaSelectedOnDocuViewareAPIReady() {
if (typeof DocuViewareAPI !== "undefined" && DocuViewareAPI.IsInitialized("DocuVieware1")) {
DocuViewareAPI.RegisterOnAreaSelected("DocuVieware1", function () {
selectedArea = DocuViewareAPI.GetSelectionAreaCoordinates("DocuVieware1");
DocuViewareAPI.PostCustomServerAction("DocuVieware1", false, "draw-signature-formfield", selectedArea);
DocuViewareAPI.SetMouseMode("DocuVieware1", 0);
});
} else {
setTimeout(RegisterOnAreaSelectedOnDocuViewareAPIReady, 10);
}
}
As you can see, the MouseMode is set to “0”, which means the user will be able to scroll their document right after selecting the area.
On page load, we register that event handler:
document.addEventListener("DOMContentLoaded", function () {
RegisterOnAreaSelectedOnDocuViewareAPIReady();
}, false);
Here is the full client-side code:
// Coordinates of the selected area
var selectedArea;
// When a button for setting the signature field is clicked by the user
function onSignatureFormFieldButtonClicked(){
DocuViewareAPI.SetMouseMode("DocuVieware1", 3);
}
// Event triggered when the user has selected the area
function RegisterOnAreaSelectedOnDocuViewareAPIReady() {
if (typeof DocuViewareAPI !== "undefined" && DocuViewareAPI.IsInitialized("DocuVieware1")) {
DocuViewareAPI.RegisterOnAreaSelected("DocuVieware1", function () {
selectedArea = DocuViewareAPI.GetSelectionAreaCoordinates("DocuVieware1");
DocuViewareAPI.PostCustomServerAction("DocuVieware1", false, "draw-signature-formfield", selectedArea);
DocuViewareAPI.SetMouseMode("DocuVieware1", 0);
});
}
else {
setTimeout(function () { RegisterOnAreaSelectedOnDocuViewareAPIReady() }, 10);
}
}
document.addEventListener("DOMContentLoaded", function () {
RegisterOnAreaSelectedOnDocuViewareAPIReady();
}, false);
Step 2 — Handle the request server-side
The myCustomAction
method is a server-side callback that handles a custom action triggered from the frontend via DocuVieware. In this example, the action is named "draw-signature-formfield"
, and it's used to add a signature field to a PDF at coordinates selected by the user.
How this method is registered
First, for this callback to work, you must bind it to the viewer events during application startup:
DocuViewareEventsHandler.CustomAction += myCustomAction;
This line ensures that whenever a custom action is triggered from the client side (using PostCustomServerAction
in JavaScript), it’s routed to this method.
What the method does
Here’s a step-by-step breakdown of what happens inside myCustomAction
:
if (e.actionName == "draw-signature-formfield")
Check the custom action name.
This ensures that the handler only responds to the specific action "draw-signature-formfield"
.
string jsonData = e.args as string ?? JsonConvert.SerializeObject(e.args);
DataObject selectedArea = JsonConvert.DeserializeObject<DataObject>(jsonData);
Deserialize the coordinates.
The selection area (from the frontend) is passed as JSON. It contains left
, top
, width
, and height
. This is deserialized into a DataObject
instance.
GdPicturePDF pdf = new GdPicturePDF();
Prepare a PDF object.
A new GdPicturePDF
instance is created to interact with the PDF document.
if (e.docuVieware.GetDocumentType() == DocumentType.DocumentTypePDF)
Check that the loaded document is a PDF.
This feature only works for PDFs, so we guard against other formats.
e.docuVieware.GetNativePDF(out pdf);
pdf.SetMeasurementUnit(PdfMeasurementUnit.PdfMeasurementUnitInch);
pdf.SetOrigin(PdfOrigin.PdfOriginTopLeft);
pdf.SelectPage(e.docuVieware.CurrentPage);
Set PDF parameters and select the page.
Units are set to inches.
The origin is set to top-left.
The current page is selected (the one visible in the viewer when the action was triggered).
pdf.AddSignatureFormField(
selectedArea.left,
selectedArea.top,
selectedArea.width,
selectedArea.height,
"signatureField"
);
Add the signature field.
Using the coordinates provided by the user, we add a new form field of type "signature".
if (pdf.GetStat() == GdPictureStatus.OK)
{
e.docuVieware.RedrawPage(); // Refresh the viewer
}
Check for success and refresh the viewer.
If everything worked, the viewer is told to redraw the page, so the signature field appears instantly to the user.
else
{
e.message = new DocuViewareMessage("Error while drawing the signature: " + pdf.GetStat());
}
Handle any PDF errors.
If the SDK call failed, we return a custom error message to the user in the viewer.
else
{
e.message = new DocuViewareMessage("This action can only be performed on PDFs.");
}
Handle non-PDF documents.
If the document isn’t a PDF, the action is rejected with a message.
However, we can use a conversion method from the GdPictureDocumentConverter class to turn our documen tloaded in the veiwer into a PDF, to be able to add fields.
Here’s the full server-side logic:
private void myCustomAction(object sender, CustomActionEventArgs e)
{
if (e.actionName == "draw-signature-formfield")
{
string jsonData = e.args as string ?? JsonConvert.SerializeObject(e.args);
DataObject selectedArea = JsonConvert.DeserializeObject<DataObject>(jsonData);
GdPicturePDF pdf = new GdPicturePDF();
if (e.docuVieware.GetDocumentType() == DocumentType.DocumentTypePDF)
{
e.docuVieware.GetNativePDF(out pdf);
pdf.SetMeasurementUnit(PdfMeasurementUnit.PdfMeasurementUnitInch);
pdf.SetOrigin(PdfOrigin.PdfOriginTopLeft);
pdf.SelectPage(e.docuVieware.CurrentPage);
pdf.AddSignatureFormField(
selectedArea.left,
selectedArea.top,
selectedArea.width,
selectedArea.height,
"signatureField"
);
if (pdf.GetStat() == GdPictureStatus.OK)
{
e.docuVieware.RedrawPage(); // Refresh the viewer
}
else
{
e.message = new DocuViewareMessage("Error while drawing the signature: " + pdf.GetStat());
}
}
else
{
e.message = new DocuViewareMessage("This action can only be performed on PDFs.");
}
}
}
Note:
DataObject
is just a simple DTO to deserialize the area:
public class DataObject
{
public float left { get; set; }
public float top { get; set; }
public float width { get; set; }
public float height { get; set; }
}
Step 3 — The result
The user draws a box on the PDF. One second later, it’s a signature field. Clean, simple, and fully integrated.
This pattern can be easily adapted to other field types:
AddTextFormField
for text inputsAddCheckBoxFormField
for checkboxesAddRadioButtonFormField
for optionsetc..
Just swap the method called on the GdPicturePDF
object.
Final Thoughts
This kind of front-to-back interaction is what makes the Nutrient .NET SDK so powerful: minimal code, fast UI feedback, and server-side reliability.
If you're looking to add form creation, annotation tools, or interactive features into your .NET apps, this approach is solid and scalable. And since it’s all built on standard DocuVieware APIs and .NET SDK methods, you're free to go far beyond just signature fields.
If you want me to help you extend this example or integrate it in your projects, do not hesitate to send me an email at fabio.derose@nutrient.io.
Cheers!
Fabio
Subscribe to my newsletter
Read articles from Fabio De Rose directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Fabio De Rose
Fabio De Rose
I love rock music, good wine, and .NET