How to digitally sign PDFs in C# with Nutrient .NET SDK
Table of contents
Nutrient .NET SDK (formerly GdPicture.NET) signs PDFs in C# with a certificate-based digital signature in four steps: install the GdPicture.API NuGet package, load the PDF, set the signing certificate from a PKCS#12 (.pfx) digital ID with SetSignatureCertificateFromP12, and apply the signature with ApplySignature. The signature can be invisible (cryptographic only) or visible with text and a handwritten-signature image. The C# examples for both are below, and the linked signing guide includes VB.NET variants.
This tutorial implements a certificate-based digital signature in C# that protects the signed revision and links it to a signing certificate. With Nutrient .NET SDK and a PKCS#12 digital ID, the signature can be invisible or a visible stamp with text and an image.
Three things “sign a PDF” can mean in C#
Each meaning calls for a different implementation:
- A certificate-based digital signature cryptographically binds a signer identity to the document and makes any later modification detectable. This tutorial implements this mechanism. Identifying the individual and recording consent depend on the surrounding workflow.
- An ink or image eSignature places a drawn or scanned signature on the page as visual content, with no cryptographic protection. Nutrient .NET SDK adds these with the ink annotation API.
- A signature form field reserves a place in the document for someone else to sign later. Nutrient .NET SDK creates and fills these fields. See the signature field guide.
A visible digital signature (this tutorial’s second example) combines the first two: the cryptographic signature plus a visible appearance in the signed PDF.
What signing a PDF in C# requires
Signing needs two inputs:
- A digital ID — A PKCS#12 file (
.pfx/.p12) containing a certificate and its private key. Production documents use an ID issued by a certificate authority (CA); a self-signed certificate works for development and testing. - The SDK — The signing API lives on the
GdPicturePDFclass, and one method call applies the signature and writes the output file.
Adobe Acrobat and other compatible readers can validate the resulting signature and show the supplied signer name, reason for signing, and changes since signing.
Setup
Use the .NET 8 SDK for the commands below and a Nutrient .NET SDK license or demo key that includes DigitalSignatures and PDF Processing. Check the system compatibility guide for supported platforms and native dependencies.
Create a console project and install the SDK:
dotnet new console -n SignPdf -f net8.0cd SignPdfdotnet add package GdPicture.APIPlace an unencrypted source.pdf and a certificate.pfx digital ID in the project directory. The visible example also needs a JPEG signature image named source.jpg. Use a test certificate and sample document while evaluating, and keep private keys and passwords out of source control.
Replace Program.cs with the shared setup below, enter the SDK key and PFX password, and append exactly one signing example. Run the examples separately. See the downloads guide for evaluation options.
using System;using System.IO;using GdPicture14;using GdPicture14.Imaging;
const string licenseKey = "YOUR_LICENSE_KEY";const string certificatePassword = "YOUR_PFX_PASSWORD";
static string RequireFile(string fileName){ string path = Path.GetFullPath(fileName); if (!File.Exists(path)) throw new FileNotFoundException($"Required input is missing: {path}", path); return path;}
static void Check(GdPictureStatus status, string operation){ if (status != GdPictureStatus.OK) throw new InvalidOperationException($"{operation} failed: {status}");}
static void Run(Action sign){ try { sign(); } catch (Exception error) { Console.Error.WriteLine($"Signing failed: {error.Message}"); Environment.ExitCode = 1; }}After appending one example, run it from the project directory:
dotnet runA successful run prints the output path. A failed run prints an error and exits with a nonzero status. SDK licensing failures can throw exceptions, while other operations return a status. The examples handle both. They write separate output files and leave source.pdf unchanged. A rerun overwrites the corresponding output file, so choose a new path to retain earlier results.
Sign a PDF with an invisible digital signature
The minimal signing flow loads the document, sets the certificate, and applies the signature. Skipping the signature-position step makes the signature invisible. The PDF is cryptographically signed, but nothing is drawn on the page:
Run(() =>{ string sourcePath = RequireFile("source.pdf"); string certificatePath = RequireFile("certificate.pfx"); LicenseManager licence = new LicenseManager(); licence.RegisterKEY(licenseKey); using GdPicturePDF gdPicturePDF = new GdPicturePDF(); Check(gdPicturePDF.LoadFromFile(sourcePath), "LoadFromFile"); Check(gdPicturePDF.SetSignatureCertificateFromP12(certificatePath, certificatePassword), "SetSignatureCertificateFromP12"); Check(gdPicturePDF.SetSignatureInfo("John Smith", "Document approval", "Vienna (Austria)", "john.smith@example.com"), "SetSignatureInfo"); string outputPath = Path.GetFullPath("signed-invisible.pdf"); Check(gdPicturePDF.ApplySignature(outputPath, PdfSignatureMode.PdfSignatureModeAdobePPKMS, false), "ApplySignature"); Console.WriteLine($"Signed PDF saved to {outputPath}");});SetSignatureInfo is optional. The name, reason, location, and contact information it records are what signature validators display. The second parameter of SetSignatureCertificateFromP12 is the digital ID’s password.
This signing API requires an unencrypted PDF.
Sign a PDF with a visible text and image signature
A visible signature adds a positioning step and a drawing step. The example below places a signature box on the last page, draws the signer’s name as text, and stamps a handwritten-signature image next to it:
Run(() =>{ string sourcePath = RequireFile("source.pdf"); string certificatePath = RequireFile("certificate.pfx"); LicenseManager licence = new LicenseManager(); licence.RegisterKEY(licenseKey); using GdPicturePDF gdPicturePDF = new GdPicturePDF(); Check(gdPicturePDF.LoadFromFile(sourcePath), "LoadFromFile"); Check(gdPicturePDF.SetSignatureCertificateFromP12(certificatePath, certificatePassword), "SetSignatureCertificateFromP12"); Check(gdPicturePDF.SetSignatureInfo("John Smith", "Document approval", "Vienna (Austria)", "john.smith@example.com"), "SetSignatureInfo"); string imagePath = RequireFile("source.jpg"); gdPicturePDF.SetMeasurementUnit(PdfMeasurementUnit.PdfMeasurementUnitCentimeter); gdPicturePDF.SetOrigin(PdfOrigin.PdfOriginTopLeft); int pageCount = gdPicturePDF.GetPageCount(); Check(gdPicturePDF.GetStat(), "GetPageCount"); Check(gdPicturePDF.SelectPage(pageCount), "SelectPage"); float width = gdPicturePDF.GetPageWidth(); Check(gdPicturePDF.GetStat(), "GetPageWidth"); float height = gdPicturePDF.GetPageHeight(); Check(gdPicturePDF.GetStat(), "GetPageHeight"); // Reserve a 5 by 2 cm box with 2 cm right and bottom margins. if (width < 7 || height < 4) throw new InvalidOperationException("The last page is too small for this signature layout."); Check(gdPicturePDF.SetSignaturePos(width - 7, height - 4, 5, 2), "SetSignaturePos"); // Use a standard PDF font without requiring an installed script font. string fontName = gdPicturePDF.AddStandardFont(PdfStandardFont.PdfStandardFontHelvetica); Check(gdPicturePDF.GetStat(), "AddStandardFont"); var center = TextAlignment.TextAlignmentCenter; Check(gdPicturePDF.SetSignatureText("John Smith", fontName, 12, GdPictureColor.Blue, center, center, true), "SetSignatureText"); string stampImage = gdPicturePDF.AddJpegImageFromFile(imagePath); Check(gdPicturePDF.GetStat(), "AddJpegImageFromFile"); Check(gdPicturePDF.SetSignatureStampImage(stampImage), "SetSignatureStampImage"); string outputPath = Path.GetFullPath("signed-visible.pdf"); Check(gdPicturePDF.ApplySignature(outputPath, PdfSignatureMode.PdfSignatureModeAdobePPKMS, false), "ApplySignature"); Console.WriteLine($"Signed PDF saved to {outputPath}");});What each call does:
SetSignaturePos(x, y, width, height)places the signature bounding box on the currently selected page, in the unit set bySetMeasurementUnit. The example sets a top-left origin and useswidth - 7andheight - 4for a 5 × 2 cm box with 2 cm right and bottom margins. It rejects pages too small for that layout.SetSignatureTextdraws text inside the box. Passing an empty string displays the data fromSetSignatureInfoinstead.SetSignatureStampImageplaces an image resource (added withAddJpegImageFromFile) inside the box. When text is also set, the image sits at the right side of the box.ApplySignaturesigns the document and writes the output. ThePdfSignatureModeenumeration selects the signature technology, and the final Boolean controls linearization of the output.
The same flow in VB.NET is in the add a digital signature guide, along with signing from certificate stores and other sources.
Verify it worked
Open the output PDF in a conforming reader. The signature panel shows the signer name, reason, and location from SetSignatureInfo, and it reports whether the document has been modified since signing. A self-signed development certificate shows as untrusted until its certificate is added to the reader’s trust store. A CA-issued digital ID also needs a certificate chain trusted by the reader. Validation depends on the reader’s trust settings, certificate status, and any timestamp and revocation information.
Timestamps, hash algorithms, and certification levels
Timestamping, the hash algorithm, and permitted changes are configured between SetSignatureCertificateFromP12 and ApplySignature:
- Timestamping —
SetSignatureTimestampInfoadds trusted timestamp information to the signature, so its signing time doesn’t depend on the local clock. - Hash algorithm —
SetSignatureHashselects the digest algorithm used in signing, via thePdfSignatureHashenumeration. - Certification level —
SetSignatureCertificationLeveldefines what changes remain permitted after signing (form filling, annotations, or none), via thePdfSignatureCertificationLevelenumeration.
The add a digital signature guide documents these options under additional signing settings.
Beyond a single signature
- Certifying a document — A certification signature restricts what changes are allowed after signing (form filling, annotations, or nothing at all). See the certify a document guide.
- Signing PDF/UA documents — Signatures can be applied without breaking PDF/UA accessibility conformance. See sign a PDF/UA document.
- Signature workflows in an app UI — For letting end users draw, type, or place signatures interactively, the .NET PDF signing page covers the UI-level options.
Conclusion
To digitally sign a PDF in C#, load the PDF, set the PKCS#12 certificate, configure any visible appearance, and apply the signature. Compatible PDF readers can then validate the signature and its certificate chain. A certificate-backed signature gives attribution and tamper evidence that a plain image stamp can’t.
For the standards and legal side of digital signatures — including PDF Advanced Electronic Signatures (PAdES), the electronic IDentification, Authentication and trust Services (eIDAS) regulation, and the Electronic Signatures in Global and National Commerce (ESIGN) Act — see the digital signatures explainer.
FAQ
Load the PDF with the GdPicturePDF class, set the signing certificate from a PKCS#12 (.pfx) file with SetSignatureCertificateFromP12, optionally record signer details with SetSignatureInfo, and call ApplySignature to sign and save the document.
A digital ID (a PKCS#12 file containing a certificate and private key) and a PDF library with a signing API. Production signatures use a CA-issued digital ID; a self-signed certificate works for development.
Both use the same certificate-based signing mechanism. A visible signature additionally draws an appearance (text, an image, or both) inside a bounding box on a page. Skipping the position step produces an invisible signature that still validates in the signature panel.
A signature protects the signed revision. Changes to signed content invalidate its integrity check, but permitted incremental updates, such as form filling or additional signatures, can preserve the earlier signature’s validity. A certification signature specifies which changes are allowed. Check the reader’s validation report for both signature validity and subsequent changes.
Yes. The signing API is the same in C# and VB.NET, and the add a digital signature guide shows each sample in both languages.
A digital signature is cryptographic: It binds a certificate-backed identity to the document and makes tampering detectable. An ink or image signature alone adds visual content but doesn’t cryptographically protect the PDF. The two can be combined. A visible digital signature shows a signature appearance backed by a certificate.
Yes. Calling SetSignatureTimestampInfo before ApplySignature adds trusted timestamp information to the signature, so the signing time doesn’t depend on the signer’s local clock.