我使用Apache PDFBox 2.0.1从PDF表单中提取文本,提取AcroForm字段的详细信息 . 从单选按钮字段中我挖出了外观词典 . 我对/ N和/ D条目感兴趣(正常和“向下”外观) . 像这样(交互式Bean shell):
field = form.getField(fieldName);
widgets = field.getWidgets();
print("Field Name: " + field.getPartialName() + " (" + widgets.size() + ")");
for (annot : widgets) {
ap = annot.getAppearance();
keys = ap.getCOSObject().getDictionaryObject("N").keySet();
keyList = new ArrayList(keys.size());
for (cosKey : keys) {keyList.add(cosKey.getName());}
print(String.join("|", keyList));
}
输出是
Field Name: Krematorier (6)
Off|Skogskrem
Off|R�cksta
Off|Silverdal
Off|Stork�llan
Off|St Botvid
Nyn�shamn|Off
问号斑点应该是瑞典字符“ä”或“å” . 使用iText RUPS我可以看到字典键是用ISO-8859-1编码的,而PDFBox假设它们是Unicode,我猜 .
有没有办法使用ISO-8859-1解码密钥?或者任何其他正确检索密钥的方法?
此示例PDF表格可在此处下载:http://www.stockholm.se/PageFiles/85478/KYF%20211%20Best%C3%A4llning%202014.pdf
1 回答
更改假定的编码
当从源PDF中读取名称时,PDFBox对名称中字节编码的解释(只有名称可以用作PDF中的字典键)发生在
BaseParser.parseCOSName()
中:如您所见,在读取名称字节并解释#转义序列后,PDFBox无条件地将结果字节解释为UTF-8编码 . 因此,要更改此设置,您必须修补此PDFBox类并替换底部命名的字符集 .
PDFBox在这里是否正确?
根据规范,将名称对象视为文本时
(第7.3.5节名称对象,ISO 32000-1)
BaseParser.parseCOSName()
实现了这一点 .但是,PDFBox的实现并不完全正确,因为已经将名称解释为字符串而不需要的行为是错误的:
因此,PDF库应该尽可能地将名称作为字节数组处理,并且只有在明确要求时才能找到字符串表示,并且只有上面的推荐(假定UTF-8)应该起作用 . 规范甚至指出了这可能导致麻烦的地方:
另一种情况在手头的文件中变得明显,如果字节序列不构成有效的UTF-8,它仍然是有效的名称 . 但是上述方法改变了这些名称,任何不可解析的字节或子序列都被Unicode替换字符'�'替换 . 因此,不同的名称可能会合并为一个名称 .
另一个问题是,当写回PDF时,PDFBox不是对称的,而是使用纯
US_ASCII
来解释名称的String
表示(如果从PDF中读取,则检索为UTF-8解释),参见 .COSName.writePDF(OutputStream)
:因此,任何有趣的Unicode字符都替换为US_ASCII默认替换字符,我假设它是'?' .
所以很幸运,PDF名称通常只包含ASCII字符...;)
历史上
根据PDF 1.4参考的实施说明,
因此,手头的样本文件似乎遵循Acrobat 4的惯例,即从上个世纪开始 .
源代码摘录来自PDFBox 2.0.0,但乍一看似乎没有在2.0.1或开发中继中更改 .