I’m trying to set an image as an appearance of a signed sign field. I known that currently only supported appearance is showing text when signing a document through GemBox.Pdf. I known that you have mentioned that images will be supported in the future.
But in the meantime, I thought that I could workaround these limitations by setting the appearance stream of a form field manually through the PdfDictionary and PdfStream.
The only problem with this approach is that when the PdfSigner signs a document it sets the appearance stream to the text (Name, Date, etc.) and overwrites the appearance stream I have provided. Is there any way to make the signer not update the appearance stream of a sign field when signing the document?
Thanks for your reply. When I set appearance.DateFormat to string.Empty (also others like appearance.Name) then the signature is transparent. This allows me to add image below the signature and it looks OK to the end user.
However than the image is not part of the signature. I can imagine that this could brake a lot of other 3rd party tools which work with signatures.
Do you have any approximate ETA when there will be possibility to add images directly to signature fields? Or if there would be possibility to let the users of Gembox.PDF directly access the AP entry in signature field dictionary (I mean this possibility exists, but anything in AP is overwritten when signField.Sign(signer) is called).
And try running the following code snippet which is a customization of a visible signature example.
string logo = "logo.png";
using (var document = PdfDocument.Load("Reading.pdf"))
{
// Add a visible signature field to the first page of the PDF document.
var signatureField = document.Form.Fields.AddSignature(document.Pages[0], 300, 500, 250, 50);
// Retrieve signature appearance settings to customize it.
var signatureAppearance = signatureField.Appearance;
// Do not update signature appearance to the date/time of when the document is being saved to a file.
signatureAppearance.DateFormat = string.Empty;
// Make default signature appearance empty.
signatureAppearance.Name = string.Empty;
// Get a digital ID from PKCS#12/PFX file.
var digitalId = new PdfDigitalId("GemBoxRSA1024.pfx", "GemBoxPassword");
// Create a PDF signer that will create the digital signature.
var signer = new PdfSigner(digitalId);
// Adobe Acrobat Reader currently doesn't download certificate chain
// so we will also embed certificate of intermediate Certificate Authority in the signature.
// (see https://community.adobe.com/t5/acrobat/signature-validation-using-aia-extension-not-enabled-by-default/td-p/10729647)
signer.ValidationInfo = new PdfSignatureValidationInfo(new PdfCertificate[] { new PdfCertificate("GemBoxRSA.crt") }, null, null);
// Initiate signing of a PDF file with the specified signer.
signatureField.Sign(signer);
// Add an image behind the existing content of the appropriate signature appearance layer as specified in https://web.archive.org/web/20201020094806/https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PPKAppearances.pdf.
var sigFieldDict = signatureField.GetDictionary();
var ap = (PdfDictionary)sigFieldDict[PdfName.Create("AP")];
var normalAppearanceDict = ((PdfStream)((PdfIndirectObject)ap[PdfName.Create("N")]).Value).Dictionary;
var resources = (PdfDictionary)normalAppearanceDict[PdfName.Create("Resources")];
var xObjectResources = (PdfDictionary)resources[PdfName.Create("XObject")];
var formDict = ((PdfStream)((PdfIndirectObject)xObjectResources[PdfName.Create("FRM")]).Value).Dictionary;
resources = (PdfDictionary)formDict[PdfName.Create("Resources")];
xObjectResources = (PdfDictionary)resources[PdfName.Create("XObject")];
formDict = ((PdfStream)((PdfIndirectObject)xObjectResources[PdfName.Create("n2")]).Value).Dictionary;
resources = (PdfDictionary)formDict[PdfName.Create("Resources")];
resources.Add(PdfName.Create("XObject"), xObjectResources = PdfDictionary.Create());
var image = PdfImage.Load(logo);
var imageDict = image.GetDictionary();
if (imageDict.Stream.Indirect == null)
PdfIndirectObject.Create(imageDict.Stream);
xObjectResources.Add(PdfName.Create("Im0"), imageDict.Stream.Indirect);
PdfPoint point = new PdfPoint(0, 0);
PdfSize size = image.Size;
byte[] existingContent;
using (var streamData = formDict.Stream.Open(PdfStreamDataMode.Read, PdfStreamDataState.Decoded))
using (var memoryStream = new MemoryStream())
{
streamData.CopyTo(memoryStream);
existingContent = memoryStream.ToArray();
}
byte[] newContent = Encoding.ASCII.GetBytes(string.Format(CultureInfo.InvariantCulture, "q {0} 0 0 {1} {2} {3} cm /Im0 Do Q", size.Width, size.Height, point.X, point.Y));
using (var streamData = formDict.Stream.Open(PdfStreamDataMode.Write, PdfStreamDataState.Decoded))
{
streamData.Write(newContent, 0, newContent.Length);
if (existingContent.Length > 0)
{
streamData.WriteByte((byte)'\n');
streamData.Write(existingContent, 0, existingContent.Length);
}
}
// Finish signing of a PDF file.
document.Save("Visible Digital Signature.pdf");
}
Sorry for the late response. Your solution works without any issue, thanks a lot. I appreciate the effort you have given into the sample. The issue with my solution was that I was modifying the AP dictionary before calling the sign method.