[]
Incremental update is a method to modify a PDF document without affecting its original content. It simply appends the changes at the end of the file that not only saves the time required to re-write the entire document but also minimizes the risk of data loss. This feature is especially important while updating the digitally signed PDF documents as it allows to add new signature to a document without invalidating the original signature.
GcPdf allows you to incrementally update and save a modified document using Save method. By default, this method saves the document without an incremental update. However, you can save the document incrementally by setting the incrementalUpdate parameter of the Save method to true. The Save method provides two more overloads which take SaveMode enumeration as a parameter. The SaveMode enumeration gives you option to save the PDF documents in default mode, linearized mode or incremental update mode. To save a document with incremental updates, you can also set the SaveMode enumeration to IncrementalUpdate while passing it as a parameter to the Save method. Note that incremental updates can not be included in a linearized document. That is, linearized and incremental update modes are mutually exclusive modes. For more information regarding linearized mode, see Linearization.
Additionally, GcPdf provides Sign method to sign and save a document which by default updates the document incrementally. Alternatively, you can also set the SaveMode enumeration to IncrementalUpdate and pass it as a parameter to Sign method. Both these methods let you sign a document multiple times without invalidating the original signature and without changing its original content. GcPdf allows three levels of subsequent changes on a signed document:
No changes
Modify fields
Modify fields and add annotations
Note that once a document has been signed, adding a new field invalidates the existing signature. Hence, a document must already have enough signature fields to accommodate all the subsequent signatures. Also, if you run a sample that uses a signed PDF without a valid license key of GcPdf, then the original signature in the generated PDF is invalidated. This happens because a license header is added to the PDF in such cases which changes the original signed document.
To incrementally update a PDF file:
Create an object of GcPdfDocument class.
Load any existing PDF file using the Load method of GcPdfDocument class.
Modify the document. For example, add some text or graphical element to the document.
Save the document using Save method of GcPdfDocument class and set incremental update parameter to true.
static void Main(string[] args)
{
// Load an existing PDF using FileStream
FileStream fileStream = File.OpenRead(args[0].ToString());
GcPdfDocument doc = new GcPdfDocument();
doc.Load(fileStream);
const float In = 72;
var tf = new TextFormat()
{
Font = StandardFonts.CourierItalic,
FontSize = 12
};
doc.Pages[0].Graphics.DrawString
("This is a sample text for incremental update", tf, new PointF(In, In));
doc.Save("IncUpdate", true);
// Alternatively, use the below overload.
// doc.Save("IncUpdate", SaveMode.IncrementalUpdate);
}
To add multiple digital signatures in a PDF document:
Use the SignatureProperties class to set up the first certificate for digital signature.
Initialize the SignatureField class to hold the first signature.
Add the signature field to the PDF document using the Add method.
Connect the signature field to signature properties.
Add the signature field to hold the second signature.
Sign the document using the Sign method of GcPdfDocument class.
Load the signed document using the Load method of GcPdfDocument class.
Setup the second certificate for signing.
Sign the document to include second signature.
public class SignIncremental
{
public void CreatePDF(Stream stream)
{
GcPdfDocument doc = new GcPdfDocument();
// Load a signed document (we use code similar to the SignDoc sample):
doc.Load(CreateAndSignPdf());
// Init a second certificate:
var pfxPath = Path.Combine("Resources", "Misc", "JohnDoe.pfx");
X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "secret",
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
SignatureProperties sp2 = new SignatureProperties()
{
Certificate = cert,
Location = "GcPdfWeb Sample Browser",
SignerName = "John Doe",
};
// Find the 2nd (not yet filled) signature field:
var sfld2 = doc.AcroForm.Fields["SecondSignature"] as SignatureField;
// Connect the signature field and signature props:
sp2.SignatureField = sfld2 ?? throw new Exception
("Unexpected: could not find 'SecondSignature' field");
// Sign and save the document:
// NOTES:
// - Signing and saving is an atomic operation, the two cannot be separated.
// - The stream passed to the Sign() method must be readable.
doc.Sign(sp2, stream);
// Rewind the stream to read the document just created
// into another GcPdfDocument and verify all signatures:
stream.Seek(0, SeekOrigin.Begin);
GcPdfDocument doc2 = new GcPdfDocument();
doc2.Load(stream);
foreach (var fld in doc2.AcroForm.Fields)
if (fld is SignatureField sfld)
if (!sfld.Value.VerifySignature())
throw new Exception($"Failed to verify signature for field {sfld.Name}");
// Done (the generated and signed docment has already been saved to 'stream').
}
// This method is almost exactly the same as the DigitalSignature sample,
// but adds a second signature field (does not sign it though):
private Stream CreateAndSignPdf()
{
GcPdfDocument doc = new GcPdfDocument();
Page page = doc.NewPage();
TextFormat tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 };
page.Graphics.DrawString(
"Hello, World!\r\nSigned below TWICE by GcPdfWeb SignIncremental sample" +
".\r\n(Note that some browser built-in viewers may not show the signatures.)",
tf, new PointF(72, 72));
// Init a test certificate:
var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx");
X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq",
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
SignatureProperties sp = new SignatureProperties();
sp.Certificate = cert;
sp.Location = "GcPdfWeb Sample Browser";
sp.SignerName = "GcPdfWeb";
// Init a signature field to hold the signature:
SignatureField sf = new SignatureField();
sf.Widget.Rect = new RectangleF(72, 72 * 2, 72 * 4, 36);
sf.Widget.Page = page;
sf.Widget.BackColor = Color.LightSeaGreen;
sf.Widget.TextFormat.Font = StandardFonts.Helvetica;
sf.Widget.ButtonAppearance.Caption = $"Signer: {sp.SignerName}"+
"\r\nLocation: {sp.Location}";
// Add the signature field to the document:
doc.AcroForm.Fields.Add(sf);
// Connect the signature field and signature props:
sp.SignatureField = sf;
// Add a second signature field:
SignatureField sf2 = new SignatureField() { Name = "SecondSignature" };
sf2.Widget.Rect = new RectangleF(72, 72 * 3, 72 * 4, 36);
sf2.Widget.Page = page;
sf2.Widget.BackColor = Color.LightYellow;
// Add the signature field to the document:
doc.AcroForm.Fields.Add(sf2);
var ms = new MemoryStream();
doc.Sign(sp, ms);
return ms;
}
For more information about how to make incremental updates in a PDF document using GcPdf, see GcPdf sample browser.