Setting appearance of sign field

Hi,

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 in advance,
Jindrich

Hi Jindrich,

Can you try setting the PdfSignatureAppearance.DateFormat to string.empty:

var signatureAppearance = signatureField.Appearance;
signatureAppearance.DateFormat = string.Empty;
// ...

Does this work for you?

Regards,
Mario

Hi Mario,

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).

Thanks in advance,
Jindrich

Hi Jindrich,

GemBox.Pdf updates signature’s appearance on several occasions:

  • when the signature field is added to the document,
  • when signature appearance font settings are changed,
  • when the signature field value is changed (when calling PdfSignatureField.Sign method) and,
  • when the signed document is being saved to a file if the signature’s date should be updated to the latest value (if PdfSignatureAppearance.DateFormat is not String.Empty).

So, PdfSignatureAppearance.DateFormat should be set to String.Empty and signature appearance should be customized after calling PdfSignatureField.Sign method.

Please try using this latest bugfix version:
https://www.gemboxsoftware.com/pdf/nightlybuilds/GBA15v1101.zip
Or this latest package:
Install-Package GemBox.Pdf -Version 15.0.1101-hotfix

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");
}

I hope this helps.

Regards,
Mario

Hi Mario,

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.

Thanks, once again.

Jindrich

1 Like

Hi,

We have recently released a new version of GemBox.Pdf which supports specifying both text and image for signature appearance.

The Digitally sign a PDF file with a visible signature example demonstrates how to use the new API improvements.

Regards,
Mario

Hi,

Thanks for the notification! I will take a look at the new API.

Thanks
Jindrich