首页 > 解决方案 > 使用附加模式属性后,iText7 将签名转换为不可见签名

问题描述

我遇到的问题是,如果我在文档中创建签名字段时使用UseAppendMode属性,则在签名时会创建不可见的签名。否则,它会显示我的自定义签名外观的内容并在 PDF 中创建一个可见的签名。以下是我的代码片段:

SigningResponse signingResponse = new SigningResponse();
Stream outputStream = new MemoryStream();
Org.BouncyCastle.X509.X509Certificate x509Certificate = null;
int estimatedSize = SigningProfile.ContainsKey(ProfileCommon.DICTIONARY_SIZE.ToString()) ? 
    int.Parse(SigningProfile[ProfileCommon.DICTIONARY_SIZE.ToString()]) * 1024 : 600 * 1024;
Stream readerStream = new MemoryStream(documentBytes);
PdfReader pdfReader = new PdfReader(readerStream);
PdfSigner pdfSigner = new PdfSigner(pdfReader, outputStream, new StampingProperties().UseAppendMode());
pdfSigner.SetFieldName("Signature1");
pdfSigner.GetDocument().GetCatalog().SetModified();
if (signingRequest.CertifyPolicy != (int)CertifyPolicy.NOT_CERTIFIED)
    pdfSigner.SetCertificationLevel(signingRequest.CertifyPolicy);

PdfSignatureAppearance signatureAppearance = pdfSigner.GetSignatureAppearance();
signatureAppearance.SetContact("Contact Info");
signatureAppearance.SetLocation("Location");
signatureAppearance.SetPageNumber(1);
signatureAppearance.SetReason("Signing Reason");
PdfFormXObject n0 = signatureAppearance.GetLayer0();
float x = n0.GetBBox().ToRectangle().GetLeft();
float y = n0.GetBBox().ToRectangle().GetBottom();
float width = n0.GetBBox().ToRectangle().GetWidth();
float height = n0.GetBBox().ToRectangle().GetHeight();
PdfCanvas canvas = new PdfCanvas(n0, pdfSigner.GetDocument());
canvas.SetFillColor(ColorConstants.LIGHT_GRAY);
canvas.Rectangle(x, y, width, height);
canvas.Fill();
// Set the signature information on layer 2
PdfFormXObject n2 = signatureAppearance.GetLayer2();
Paragraph p = new Paragraph("This document was signed by Bruno Specimen.");
new Canvas(n2, pdfSigner.GetDocument()).Add(p);

signatureAppearance.SetCertificate(x509Certificate);
PreSigning external = new PreSigning(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached);
pdfSigner.SignExternalContainer(external, estimatedSize);
signingResponse.DocumentHash = external.getHash();
signingResponse.D2S = signingResponse.DocumentHash;
signingResponse.DocumentBytes = ((MemoryStream)outputStream).ToArray();
return signingResponse;

并且创建签名字段的代码如下:

byte[] documentBytes = null;
foreach (PDFSignatureField field in signatureFields)
{
    using (Stream memoryStream = new MemoryStream())
    using (PdfReader _pdfReader = new PdfReader(new MemoryStream(_documentBytes)).SetUnethicalReading(true))
    using (PdfDocument pdfDocument = new PdfDocument(_pdfReader, new PdfWriter(memoryStream)))
    {
        PdfAcroForm pdfAcroForm = PdfAcroForm.GetAcroForm(pdfDocument, true);
        //Initializing signature position object
        PDFSignaturePosition SigPosition = field.Position;
        for (int i = 0 ; i < SigPosition.Pages.Length ; ++i)
        {
            //Getting PDF document page
            PdfPage page = pdfDocument.GetPage(SigPosition.Pages[i]);
            if (page == null)
            {
                page = pdfDocument.GetPage(SigPosition.PageNumber);
            }
            //Getting PDF document page rotation
            int rotation = page.GetRotation();
            //Getting signature field rects according to PDF page
            iText.Kernel.Geom.Rectangle rect;
            if (rotation > 0 && SigPosition.Position == PDFSignaturePosition.DefaultSignaturePosition.Custom)
            {
                rect = GetSignaturePositionAccordingToRotation(SigPosition.Rect, page.GetCropBox(), rotation);
            }
            else
            {
                rect = GetSignaturePositionRect(SigPosition.Position, SigPosition.Rect, page.GetCropBox());
            }
            //Creating signature field into PDF page
            PdfFormField sig = PdfFormField.CreateSignature(pdfDocument, rect);
            //Setting signature field visible flag
            if (field.Display == (int)SignatureDisplayType.INVISIBLE)
            {
                sig.SetFieldFlags(PdfFormField.HIDDEN);
                sig.SetVisibility(PdfFormField.HIDDEN);
            }
            else
            {
                sig.SetFieldFlags(PdfFormField.VISIBLE);
            }
            //Setting signature field font information
            sig.Put(PdfName.DA, new PdfString("/Helv 0 Tf 0 g"));
            //Setting signature field name
            sig.SetFieldName(i == 0 ? field.Name : field.Name + " - " + SigPosition.Pages[i]);
            //Setting signature field page
            sig.SetPage(SigPosition.Pages[i]);
            //Adding signature field into AcroForm
            pdfAcroForm.AddField(sig, page);
            //Making indirect reference of the added signature field into PDF
            sig.MakeIndirect(pdfDocument);
            //Closing PDF document object
            pdfDocument.Close();
            //Getting latest document bytes after adding PDF field
            documentBytes = ((MemoryStream)memoryStream).ToArray();
            if (i + 1 == SigPosition.Pages.Length)
            {
                break;
            }
        }
        _documentBytes = documentBytes;
    }
}

标签: c#.netpdfitext7

解决方案


由于您在显示的代码之外使用了许多定义、声明和填充的变量,因此我不得不大大减少您的代码。此外,我没有要测试的示例文档,因此必须使用我手头的文档进行测试。

尽管如此,我可以重现该问题并在我的设置中找到解决方案。我希望尽管设置存在所有差异,但您可以使用此解决方案。

签名字段在我的设置中变得不可见的原因是,在以追加模式将签名字段添加到文档时,文档范围的AcroForms字典中的Fields数组未标记为已修改。另一方面,签名者依靠签名字段来签名,以便在该Fields数组中找到。因此,签名者没有找到准备好的可见字段,并使用该名称创建了一个新的不可见字段。

一种解决方法是手动将有问题的数组标记为已修改:

pdfAcroForm.GetPdfObject().Get(PdfName.Fields).SetModified();
pdfAcroForm.GetPdfObject().SetModified();

//Closing PDF document object
pdfDocument.Close();

推荐阅读