PDFBox 从没有密码加密的 PDF 中提取空白
PDFBox extracting blanks from PDF encrypted with no password
我正在使用 PDFBox 从表单中提取文本,我有一个未使用密码加密的 PDF,但 PDFBox 显示已加密。我怀疑是某种 Adobe "feature",因为当我打开它时它说 (SECURED),而我没有问题的其他 PDF 则没有。 isEncrypted()
returns true
所以尽管没有密码,但它似乎以某种方式受到保护。
我怀疑它没有正确解密,因为它能够提取表单的文本提示,但不能提取响应本身。在下面的代码中,它从示例 PDF 中提取 Address (Street Name and Number)
和 City
,但不提取它们之间的响应。
我正在使用 PDFBox 2.0,但我也尝试过 1.8。
我已经尝试了我能为 PDFBox 找到的所有解密方法,包括已弃用的方法(为什么不呢)。我得到的结果与根本不尝试解密的结果相同,只是地址和城市提示。
由于 PDF 是绝对的噩梦,因此此 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());
}
}
}
Brunos 评论解释了为什么即使您不需要输入密码,PDF 也会被加密:
A PDF can be encrypted with two passwords: a user password and an owner password. When a PDF is encrypted with a user password, you can't open the document in a PDF viewer without entering that password. When a PDF is encrypted with an owner password only, everyone can open a PDF without that password, but some restrictions may be in place. You can recognize PDFs encrypted with an owner password because they mention "SECURED" in Adobe Reader.
您的 PDF 仅使用所有者密码加密,即用户密码为空。因此,您可以在您的 PDFBox 版本中使用空密码 ""
解密它:
document.decrypt("");
(这个"method 1",和你的"method 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 的另一个特点:它实际上包含 两种形式definitions,核心 PDF AcroForm 定义和更独立的 XFA 定义。两者都描述了相同的视觉形式。这样的 PDF 表单称为 混合 PDF 表单.
混合表单的优点是可以使用只知道 AcroForm 表单(基本上是除 Adobe 之外的所有软件)的 PDF 工具来查看和填写它们,而 PDF 工具与XFA 支持(基本上只有 Adobe 的软件)可以利用额外的 XFA 功能。
混合表单的缺点是如果使用不支持XFA的工具填写,只有AcroForm信息更新,而XFA信息保持不变。因此,混合文档可以包含同一字段的不同数据...
我正在使用 PDFBox 从表单中提取文本,我有一个未使用密码加密的 PDF,但 PDFBox 显示已加密。我怀疑是某种 Adobe "feature",因为当我打开它时它说 (SECURED),而我没有问题的其他 PDF 则没有。 isEncrypted()
returns true
所以尽管没有密码,但它似乎以某种方式受到保护。
我怀疑它没有正确解密,因为它能够提取表单的文本提示,但不能提取响应本身。在下面的代码中,它从示例 PDF 中提取 Address (Street Name and Number)
和 City
,但不提取它们之间的响应。
我正在使用 PDFBox 2.0,但我也尝试过 1.8。
我已经尝试了我能为 PDFBox 找到的所有解密方法,包括已弃用的方法(为什么不呢)。我得到的结果与根本不尝试解密的结果相同,只是地址和城市提示。
由于 PDF 是绝对的噩梦,因此此 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());
}
}
}
Brunos 评论解释了为什么即使您不需要输入密码,PDF 也会被加密:
A PDF can be encrypted with two passwords: a user password and an owner password. When a PDF is encrypted with a user password, you can't open the document in a PDF viewer without entering that password. When a PDF is encrypted with an owner password only, everyone can open a PDF without that password, but some restrictions may be in place. You can recognize PDFs encrypted with an owner password because they mention "SECURED" in Adobe Reader.
您的 PDF 仅使用所有者密码加密,即用户密码为空。因此,您可以在您的 PDFBox 版本中使用空密码 ""
解密它:
document.decrypt("");
(这个"method 1",和你的"method 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 的另一个特点:它实际上包含 两种形式definitions,核心 PDF AcroForm 定义和更独立的 XFA 定义。两者都描述了相同的视觉形式。这样的 PDF 表单称为 混合 PDF 表单.
混合表单的优点是可以使用只知道 AcroForm 表单(基本上是除 Adobe 之外的所有软件)的 PDF 工具来查看和填写它们,而 PDF 工具与XFA 支持(基本上只有 Adobe 的软件)可以利用额外的 XFA 功能。
混合表单的缺点是如果使用不支持XFA的工具填写,只有AcroForm信息更新,而XFA信息保持不变。因此,混合文档可以包含同一字段的不同数据...