我正在使用PDFBox从表单中提取文本,并且我有一个未使用密码加密的PDF,但PDFBox表示已加密。我怀疑某种Adobe“功能”,因为当我打开它时说(安全),而其他我没有问题的PDF却没有。 isEncrypted()
返回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());
}
}
}
答案 0 :(得分:2)
Brunos注释解释了为什么即使您不需要输入密码也要对PDF进行加密:
可以使用两个密码来加密PDF:用户密码和所有者密码。当使用用户密码加密PDF时,如果不输入该密码,则无法在PDF查看器中打开该文档。仅使用所有者密码加密PDF时,每个人都可以不使用该密码打开PDF,但是可能会有一些限制。您可以识别使用所有者密码加密的PDF,因为它们在Adobe 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]"
的表单域的值。如果您不知道要从中提取内容的字段的名称,则PDAcroForm
返回的doc.getDocumentCatalog().getAcroForm()
对象还有许多其他方法可以访问字段内容。
顺便说一句, AcroForm 定义中的字段名称,例如"form1[0].#subform[3].address[0]"
表示PDF的另一个特色:它实际上包含两个表单定义,核心PDF AcroForm 定义和更独立的 XFA 定义。两者描述相同的视觉形式。这样的PDF表单称为混合PDF表单。
混合表单的优点是可以使用仅了解 AcroForm 表单(基本上是Adobe以外的所有软件)的PDF工具查看和填写它们,而具有XFA支持的PDF工具(基本上仅Adobe的软件)可以使用其他XFA功能。
混合表单的缺点是,如果使用不具有XFA支持的工具来填写它们,则仅 AcroForm 信息会被更新,而XFA信息则保持不变。因此,混合文档可以在同一字段中包含不同的数据...