首页 > 解决方案 > 如何识别 PDF 文件是否包含表单域

问题描述

我们允许用户上传 PDF 文件供我们存储。我们警告用户在上传之前必须将 PDF 拼合,但许多人仍然上传包含表单字段的 PDF 文档。我们希望通过在上传到我们的存储之前验证 PDF 文件来防止这种情况。

我们正在使用 iText-5.1 将文件作为 byte[] 读取并使用 PdfReader 打开它。然后我们使用 AcroFields() 提取字段并测试是否存在。目前 getFields().size() 总是返回 0 [见下面的代码],即使我知道包含表单字段的测试 PDF 也是如此。

PdfReader reader = new PdfReader(bytes);
AcroFields fields = reader.getAcroFields()
boolean hasFormFields = 
   (fields != null && fields.getFields() != null && fields.getFields().size() > 0);
if (hasFormFields) {
   // Report Error to User - throw exception, etc.
}

当 PDF 包含表单字段元素时,我希望 getFields().size() 大于 0。是否有其他方法可以使用 Java 和 iText 识别表单字段?

标签: javapdfitext

解决方案


您使用了正确的方法来识别(有效的)PDF 文件是否包含表单域。您描述的问题是如何处理不符合标准的 PDF 文件,这些文件也包含表单字段但确实存在一些问题,例如缺少 AcroField 字典、缺少字段数组或其他。你有三种可能:

  1. 忽略这些情况,因为这些是边缘情况
  2. 确定问题(例如使用 Acrobat Preflight)并编写一个方法来检查这些情况。您可以在下面找到一个示例,其中我编写了一个方法来识别缺少Fields数组的文档。
  3. 只需将所有上传的文件展平即可。

以下代码检查您的方法返回 true 但仍包含表单字段的文档。这些字段也将显示在 *dobe 阅读器中。

   public boolean containsFormFields2() {

        AcroFields acroFields = reader.getAcroFields();

        if (acroFields.getFields() == null || acroFields.getFields().size() == 0) {
            // recheck "manually"
            for (int i = 1; i <= super.reader.getNumberOfPages(); i++) {
                PdfDictionary page = super.reader.getPageN(i);
                PdfArray annots = page.getAsArray(PdfName.ANNOTS);

                if (annots != null) {
                    // check for form fields in general
                    for (int j = 0; j < annots.size(); j++) {
                        PdfDictionary po2 = (PdfDictionary) annots.getDirectObject(j);

                        // FT key only exists for form fields
                        PdfName type = (PdfName) po2.get(PdfName.FT);
                        if (type != null) {
                           return true;
                        }
                    }
                }
            }
         return false;
        }
        else{
         return true;
        }
   }

推荐阅读