XFA在PDFBox 1.8.12中构建,而不是在2.0.4中构建

时间:2017-03-17 15:30:45

标签: pdf pdfbox xfa

我尝试从文件中提取XFA,它对我来说很好,直到我将PDFBox从1.8.12更新到2.0.4。

我有一个文件,我可以使用1.8.12提取XFA但不使用2.0.4。

当我使用2.0.4使用PDFBox提取它时,我得到了XFA的结构,但几乎所有的值都丢失了。另一方面,当我尝试使用1.8.12提取相同的表格时,它很好。

我在SO上查了一个类似的问题。它据说是在2.0.4中修复但我仍然面临着问题。

有什么想法吗?

我已经包含了文件

Generated XFA-1.8.12

Generated XFA-2.0.4

File used

EDIT#1

适用于2.0.4

    // returns PDXFA
    public static byte[] getParsableXFAForm(File file) {
        if (file == null)
            return null;
        PDDocument doc;
        PDDocumentCatalog catalog;
        PDAcroForm acroForm;

        PDXFAResource xfa;
        try {
//            String pass = null;
            doc = PDDocument.load(file);
            if (doc == null)
                return null;
//             flattenPDF(doc);
            doc.setAllSecurityToBeRemoved(true);
            // System.out.println("Security " + doc.isAllSecurityToBeRemoved());
            catalog = doc.getDocumentCatalog();
            if (catalog == null) {
                doc.close();
                return null;
            }
            acroForm = catalog.getAcroForm();
            if (acroForm == null) {
                doc.close();
                return null;
            }
            xfa = acroForm.getXFA();
            if (xfa == null) {
                doc.close();
                return null;
            }
            // TODO return byte[]
            byte[] xfaBytes = xfa.getBytes();
            doc.close();
            return xfaBytes;
        } catch (IOException e) {
            // handle IOException
            // happens when the file is corrupt.
            e.printStackTrace();
            System.out.println("XFAUtils-getParsableXFAForm-IOException");
            return null;
        }
    }

适用于1.8.12

public static byte[] getParsableXFAForm(File file) {
        if (file == null)
            return null;
        PDDocument doc;
        PDDocumentCatalog catalog;
        PDAcroForm acroForm;
        PDXFA xfa;
        try {
            doc = PDDocument.loadNonSeq(file, null);
            if (doc == null)
                return null;
            // flattenPDF(doc);
            doc.setAllSecurityToBeRemoved(true);
            // System.out.println("Security " + doc.isAllSecurityToBeRemoved());
            catalog = doc.getDocumentCatalog();
            if (catalog == null) {
                doc.close();
                return null;
            }
            acroForm = catalog.getAcroForm();

            if (acroForm == null) {
                doc.close();
                return null;
            }
            xfa = acroForm.getXFA();
            if (xfa == null) {
                doc.close();
                return null;
            }
            // TODO return byte[]
            byte[] xfaBytes = xfa.getBytes();
            doc.close();
            return xfaBytes;
        } catch (IOException e) {
            // handle IOException
            // happens when the file is corrupt.
//          e.printStackTrace();
            System.out.println("XFAUtils-getParsableXFAForm-IOException");
            return null;
        }
}

1 个答案:

答案 0 :(得分:2)

乍一看

您的PDF中有6个修订版,其中XFA表单已被越来越多地填写。您的1.8.12代码会提取最新版本的XFA表单,而您的2.0.4代码会提取最旧版本的XFA表单。

我使用PDFBox版本2.0.4,2.0.5和当前开发快照2.1.0-SNAPSHOT运行了2.0.4代码。在版本2.0.4中,我确实可以重现已加载最旧版本的XFA表单,但使用2.0.5或2.1.0-SNAPSHOT加载了当前版本。

这似乎是PDFBox 2.0.0 ... 2.0.4中的一个缺点,已在2.0.5中修复。

仔细检查

作为PDFBox 2.0.4中的错误从错误的文件修订版中读取XFA表单似乎相当难以置信,我对此进行了更多研究。

特别是我仔细看了一下PDF文件本身。实际上,事实证明该文件在实际PDF文件头之前有10个垃圾字节!

这些额外的垃圾字节使得相对于文件启动的交叉引用和偏移都是错误的。因此,PDFBox无法以常规方式解析文件,而是必须进行某种修复。

着眼于2.0.4和2.0.5之间的差异,特别是在修复具有损坏的交叉引用和偏移的PDF的代码中进行了重大更改。虽然PDFBox 2.0.4只能部分修复文件(仅查找初始XFA版本),因此,PDFBox 2.0.5成功进行了更完整的修复,特别是找到了最新的XFA版本。

修复了OP的PDF(即已删除了前导垃圾字节,参见XFA-File-fixed.pdf),我也可以使用PDFBox版本2.0.0 ... 2.0.4成功提取当前的XFA表单修订版。

因此,这不是我最初假设的PDFBox错误,而只是PDFBox文件修复功能在PDFBox 2.0.5改进之前无法正确修复的PDF文件。