Append a New Page for Digital Signature
Contracts often need the signature on a page of its own rather than over the existing
content. That takes two passes over the document: one that writes out a copy with the
extra page, and one that signs the result. It cannot be done in a single appender
revision, because PdfAppender.Sign resolves the page number against the reader’s
page list, and a page added with AddPages exists only in the appender.
Adding the page
writer, err := reader.ToWriter(&model.ReaderToWriterOpts{})
if err != nil {
return nil, err
}
page := model.NewPdfPage()
page.MediaBox = &model.PdfRectangle{Urx: 612, Ury: 792}
if err := writer.AddPage(page); err != nil {
return nil, err
}
buf := bytes.NewBuffer(nil)
if err := writer.Write(buf); err != nil {
return nil, err
}ToWriter with a zero-valued ReaderToWriterOpts copies everything across: form
fields, outlines, metadata, page labels. Each Skip* field drops one of those, which
matters here only if the input already had form fields you would rather not carry over.
model.NewPdfPage produces a page with no MediaBox, and since it has no parent to
inherit one from, the size falls back to whatever the reader chooses. Set it
explicitly to match the rest of the document.
Signing the new page
Reopen the buffer, ask the fresh reader how many pages there are, and sign the last one:
reader, err = model.NewPdfReader(bytes.NewReader(buf.Bytes()))
if err != nil {
return err
}
totalPage, err := reader.GetNumPages()
if err != nil {
return err
}
appender, err := model.NewPdfAppender(reader)
if err != nil {
return err
}
// ... build signature and sigField ...
if err := appender.Sign(totalPage, sigField); err != nil {
return err
}
return appender.WriteToFile(outputPath)bytes.NewReader satisfies the appender’s need for a seekable, random-access source,
so the intermediate document never has to touch disk.
Limitations
The extra page is not part of the signed revision’s changes, it is part of the document the signature covers. Anyone comparing the signed file against the original sees a different base document, not an incremental update, which is the point: the signature vouches for the version that includes the signature page.
Sign returns page N not found when the number is outside 1..GetNumPages(). Page
numbers are 1-based throughout the appender.
A page created by NewPdfPage has no content stream, so it comes out blank apart from
the signature widget. Text, headings or a signature block need the creator package
or a content stream written by hand.
Run the example
addPage writes the document plus one empty page to a buffer, and addSignature
signs the last page of the reopened result with a red 8pt appearance.
git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/signatures
go run pdf_sign_new_page.go <IN.pdf> <OUT.pdf>If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.
View the full source
Sample output
The original page is untouched:

The appended page carries the signature:
