签名定义。必须在 PdfSignatureAppearance 中关闭

Signature defined. Must be closed in PdfSignatureAppearance

我在签署 pdf 时遇到以下错误。错误是 “签名定义。必须在 PdfSignatureAppearance 中关闭。”

我第一次能够在 pdf 上签名。它在输出文件夹中创建一个带有第一页签名的 pdf 文件。到目前为止,代码工作正常。 现在,当我将最近生成的文件作为输入以登录第二页时,我收到错误“签名已定义。必须在 PdfSignatureAppearance 中关闭。”

我收到以下行中的错误

appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");

请在下面找到代码

if (File.Exists(fName))
{
    PdfReader.unethicalreading = true;
    using (PdfReader pdfReader = new PdfReader(fName))
    {
        //file name
       fName = fName.Substring(fName.LastIndexOf("\") + 1);
        outputFile = outputFolder + fName + ".pdf";
        if (!File.Exists(outputFile))
        {
            using (FileStream fout = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite))
            {
                using (PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '[=11=]'))
                {
                    PdfSignatureAppearance appearance = stamper.SignatureAppearance;
                    string imagePath = txtImage.Text;
                    iTextSharp.text.Image signatureFieldImage = iTextSharp.text.Image.GetInstance(imagePath);
                    appearance.SignatureGraphic = signatureFieldImage;

                    signatureFieldImage.SetAbsolutePosition(250, 50);
                    stamper.GetOverContent(pageNo).AddImage(signatureFieldImage);

                    appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");
                    appearance.Reason = txtReason.Text;

                    IExternalSignature es = new PrivateKeySignature(pk, "SHA-256");
                    MakeSignature.SignDetached(appearance, es, new X509Certificate[] { pk12.GetCertificate(alias).Certificate }, null, null, null, 0, CryptoStandard.CMS);
                    stamper.Close();
                }
            }
        }
    }
    this.Invoke(new BarDelegate(UpdateBar), fName);
}

有人可以帮助我吗?如果需要更多详细信息,请告诉我。

OP 的代码中存在多个问题:

正确的关闭调用

应用签名时,不能关闭压模对象本身,而是关闭签名外观对象。如果使用像 MakeSignature.SignDetached 这样的辅助方法,甚至不必编写关闭代码,因为 SignDetached 已经隐式关闭了最后一行的 appearance

因此,请

  • 删除 stamper.Close()
  • 不要将 PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '[=18=]') 放入 using 指令中,因为这会导致调用压模的 Dispose 方法,后者又会调用 Close.

通常你不会被这些行伤害,因为在 MakeSignature.SignDetached 中的隐式外观 close 之后,进一步的 close 调用将被忽略。

不过,如果你没有做到这一点,例如由于之前的一些错误情况,此类关闭调用会导致您观察到错误,在您的情况下,关闭调用是由 using 指令引起的。

SetVisibleSignature 中的问题

您遇到了

中的错误
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");

不幸的是,由于 using 指令,在 Dispose 调用期间,此行中发生的实际错误被替换为 Close 调用引起的错误。

考虑消息代码:

/**
 * Sets the signature to be visible. It creates a new visible signature field.
 * @param pageRect the position and dimension of the field in the page
 * @param page the page to place the field. The fist page is 1
 * @param fieldName the field name or <CODE>null</CODE> to generate automatically a new field name
 */
virtual public void SetVisibleSignature(Rectangle pageRect, int page, String fieldName) {
    if (fieldName != null) {
        if (fieldName.IndexOf('.') >= 0)
            throw new ArgumentException(MessageLocalization.GetComposedMessage("field.names.cannot.contain.a.dot"));
        AcroFields af = writer.GetAcroFields();
        AcroFields.Item item = af.GetFieldItem(fieldName);
        if (item != null)
            throw new ArgumentException(MessageLocalization.GetComposedMessage("the.field.1.already.exists", fieldName));
        this.fieldName = fieldName;
    }
    if (page < 1 || page > writer.reader.NumberOfPages)
        throw new ArgumentException(MessageLocalization.GetComposedMessage("invalid.page.number.1", page));
    this.pageRect = new Rectangle(pageRect);
    this.pageRect.Normalize();
    rect = new Rectangle(this.pageRect.Width, this.pageRect.Height);
    this.page = page;
}

明显的原因是

  • 带点的字段名,
  • 文档中已存在的命名字段,或
  • 页码无效。

正如您描述的那样

I am able to sign the pdf for the first time. It creates a pdf file in output folder with the signature in the first page. So far the code works fine. Now when I give the recently generated file as input to sign in a second page I get the error

我认为第二项是最可能的原因:如果要向同一文档添加多个签名,它们的字段名称必须不同。

附加模式

由于您表示对同一个文件应用多个签名,所以您必须使用追加模式。如果不这样做,您将使早期的签名无效:

PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '[=12=]', true);

比照。 CreateSignature 方法重载评论

/**
 * Applies a digital signature to a document, possibly as a new revision, making
 * possible multiple signatures. The returned PdfStamper
 * can be used normally as the signature is only applied when closing.
 * <p>
... (outdated Java example code) ...
 * @param reader the original document
 * @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
 * @param pdfVersion the new pdf version or '[=13=]' to keep the same version as the original
 * document
 * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
 *     If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
 *     In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
 *     no temporary file will be created and memory will be used
 * @param append if <CODE>true</CODE> the signature and all the other content will be added as a
 * new revision thus not invalidating existing signatures
 * @return a <CODE>PdfStamper</CODE>
 * @throws DocumentException on error
 * @throws IOException on error
 */
public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile, bool append)