【问题标题】:PDFBox extracting blanks from PDF encrypted with no passwordPDFBox从无密码加密的PDF中提取空白
【发布时间】:2018-08-27 22:55:11
【问题描述】:

我正在使用 PDFBox 从表单中提取文本,并且我有一个未使用密码加密的 PDF,但 PDFBox 表示已加密。我怀疑某种 Adob​​e“功能”,因为当我打开它时,它会显示 (SECURED),而我没有遇到问题的其他 PDF 则没有。 isEncrypted() 返回true,因此尽管没有密码,但它似乎以某种方式受到保护。

我怀疑它没有正确解密,因为它能够提取表单的文本提示,但不能提取响应本身。在下面的代码中,它从示例 PDF 中提取 Address (Street Name and Number)City,但不是它们之间的响应。

我使用的是 PDFBox 2.0,但我也尝试过 1.8。

我已经尝试了所有可以为 PDFBox 找到的解密方法,包括已弃用的方法(为什么不)。我得到的结果与根本不尝试解密的结果相同,只是地址和城市提示。

PDF 绝对是他们的噩梦,这个 PDF 很可能是以某种非标准方式创建的。感谢您在识别这一点并再次行动方面提供任何帮助。

Sample PDF

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.pdmodel.encryption.StandardDecryptionMaterial;
import org.apache.pdfbox.text.PDFTextStripperByArea;
import java.io.File;
import org.apache.pdfbox.pdmodel.PDPage;
import java.awt.Rectangle;
import java.util.List;


class Scratch {

    private static float pwidth;
    private static float pheight;

    private static int widthByPercent(double percent) {
        return (int)Math.round(percent * pwidth);
    }

    private static int heightByPercent(double percent) {
        return (int)Math.round(percent * pheight);
    }

    public static void main(String[] args) {
        try {
            //Create objects
            File inputStream = new File("ocr/TestDataFiles/i-9_08-07-09.pdf");

            PDDocument document = PDDocument.load(inputStream);

            // Try every decryption method I've found
            if(document.isEncrypted()) {

                // Method 1
                document.decrypt("");

                // Method 2
                document.openProtection(new StandardDecryptionMaterial(""));

                // Method 3
                document.setAllSecurityToBeRemoved(true);

                System.out.println("Removed encryption");
            }

            PDFTextStripperByArea stripper = new PDFTextStripperByArea();

            //Get the page with data on it
            PDPageTree allPages = document.getDocumentCatalog().getPages();
            PDPage page = allPages.get(3);

            pheight = page.getMediaBox().getHeight();
            pwidth = page.getMediaBox().getWidth();

            Rectangle LastName = new Rectangle(widthByPercent(0.02), heightByPercent(0.195), widthByPercent(0.27), heightByPercent(0.1));
            stripper.addRegion("LastName", LastName);
            stripper.setSortByPosition(true);
            stripper.extractRegions(page);
            List<String> regions = stripper.getRegions();

            System.out.println(stripper.getTextForRegion("LastName"));

        } catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

【问题讨论】:

  • 为什么不使用 Acroform 字段呢? doc.getDocumentCatalog().getAcroForm().getField("form1[0].#subform[3].address[0]").getValueAsString()。要获取所有字段的列表,请参阅源代码下载中的 PrintFields 示例。
  • 可以使用两个密码加密 PDF:user 密码和 owner 密码。当 PDF 使用 user 密码加密时,如果不输入密码,您将无法在 PDF 查看器中打开文档。当 PDF 仅使用 owner 密码加密时,每个人都可以在没有该密码的情况下打开 PDF,但可能存在一些限制。您可以识别使用所有者密码加密的 PDF,因为它们在 Adob​​e Reader 中提及“安全”。您需要找到一种方法来忽略这种安全性,类似于在 iText 中使用“unethicalreading”标志。
  • @TilmanHausherr 是的!看来我的文档正在使用浮动注释,所以我的问题不在于解密,而是数据不在我认为的位置。我在一个信号很差的地区,所以 16MB 的信号源太多了,不过谢谢你,我什么时候回家看看!

标签: java encryption pdfbox


【解决方案1】:

Brunos 评论解释了为什么即使您不需要输入密码,PDF 也会被加密:

可以使用两个密码对 PDF 进行加密:user 密码和 owner 密码。当 PDF 使用 user 密码加密时,如果不输入密码,您将无法在 PDF 查看器中打开文档。当 PDF 仅使用 owner 密码加密时,每个人都可以在没有该密码的情况下打开 PDF,但可能存在一些限制。您可以识别使用所有者密码加密的 PDF,因为它们在 Adob​​e Reader 中提及“安全”。

您的 PDF 仅使用所有者密码进行加密,即用户密码为空。因此,您可以在 PDFBox 版本中使用空密码"" 对其进行解密:

document.decrypt("");

(顺便说一下,这个“方法1”和你的“方法2”完全一样

document.openProtection(new StandardDecryptionMaterial(""));

加上一些异常包装。)


Tilman 的评论暗示了您不检索表单值的原因:您的代码使用PDFTextStripperByArea 进行文本提取,但此文本提取仅提取固定页面内容,而不是浮动在该页面上的注释的内容。

您要提取的内容是其小部件为注释的表单字段的内容。

蒂尔曼的提议

doc.getDocumentCatalog().getAcroForm().getField("form1[0].#subform[3].address[0]").getValueAsString()

展示了如何提取您知道名称的表单字段的值,在这种情况下为"form1[0].#subform[3].address[0]"。如果您不知道要从中提取内容的字段的名称,doc.getDocumentCatalog().getAcroForm() 返回的 PDAcroForm 对象还有许多其他方法可以访问字段内容。


顺便说一下,AcroForm 定义中的 "form1[0].#subform[3].address[0]" 之类的字段名称表明您的 PDF 的另一个特点:它实际上包含 两个表单定义,即核心 PDF AcroForm 定义和更独立的XFA 定义。两者都描述了相同的视觉形式。这样的 PDF 表单称为混合 PDF 表单

混合表单的优点是可以使用仅知道 AcroForm 表单的 PDF 工具(基本上是除 Adob​​e 之外的所有软件)查看和填写它们,而支持 XFA 的 PDF 工具(基本上只有Adobe 的软件)可以利用额外的 XFA 功能。

混合表单的缺点是,如果使用不支持 XFA 的工具填写它们,则只会更新 AcroForm 信息,而 XFA 信息将保持不变。因此,混合文档可以包含同一字段的不同数据...

【讨论】:

  • 看起来就是这样,@TilmanHausherr 是对的。源文件中的示例包含了我再次移动所需的一切。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-01-19
  • 1970-01-01
  • 1970-01-01
  • 2020-11-28
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多