我正在尝试使用iText 5.5
库来处理PDF中的信息。我想扫描PDF以获取附件,如果有附件,则为它们制作物理副本(不删除/编辑原始文件)。当附加了.joboptions文件的PDF时,我遇到了问题。
我正在使用以下代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfArray;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfString;
public class extractAttachments{
public extractAttachments(String src, String dir) throws IOException {
File folder = new File(dir);
folder.mkdirs();
PdfReader reader = new PdfReader(src);
PdfDictionary root = reader.getCatalog();
PdfDictionary names = root.getAsDict(PdfName.NAMES);
PdfDictionary embedded = names.getAsDict(PdfName.EMBEDDEDFILES);
PdfArray filespecs = embedded.getAsArray(PdfName.NAMES);
for (int i = 0; i < filespecs.size(); ) {
extractAttachment(reader, folder, filespecs.getAsString(i++),
filespecs.getAsDict(i++));
}
}
protected void extractAttachment(PdfReader reader, File dir, PdfString name, PdfDictionary filespec)
throws IOException {
PRStream stream;
FileOutputStream fos;
String filename;
PdfDictionary refs = filespec.getAsDict(PdfName.EF);
for (PdfName key : refs.getKeys()) {
stream = (PRStream)PdfReader.getPdfObject(refs.getAsIndirectObject(key));
filename = filespec.getAsString(key).toString();
fos = new FileOutputStream(new File(dir, filename));
fos.write(PdfReader.getStreamBytes(stream));
fos.flush();
fos.close();
}
}
}
一旦到达PdfArray filespecs = embedded.getAsArray(PdfName.NAMES);
,则返回null。我不关心.joboptions文件是否被复制,但我确实希望复制其他附件(如果有的话)。我有什么想法可以解决这个问题吗?
此外,如果要创建包含所述.joboptions文件的PDF打开PDF文档,请转到打印菜单并将打印机更改为“Adobe PDF”。现在选择属性,单击确定,然后在主打印菜单中单击打印。这将提示您选择保存文档的位置,新文档将具有.joboptions作为附件。
答案 0 :(得分:0)
您的代码不完整,因为它只能理解非常原始的 EmbeddedFiles 结构。您的示例文件具有稍微复杂的 EmbeddedFiles 结构。您需要改进代码以了解更复杂的结构。
指定 EmbeddedFiles 字典包含名称树:
EmbeddedFiles 名称树(可选; PDF 1.4)名称树将名称字符串映射到文件 嵌入式文件流的规范(见7.11.4,“嵌入式 文件流“)。
(ISO 32000-1表31 - 名称词典中的条目
名称树应由节点构成,每个节点都应是字典对象。表36显示了节点字典中的条目。节点应为三种,具体取决于它们包含的具体条目。树应始终只有一个根节点,它应包含一个条目:孩子或名称,但不能同时包含两者。如果根节点具有名称条目,则它应该是树中的唯一节点。如果它有 Kids 条目,则每个剩余节点应为中间节点,其中包含限制条目和孩子条目或叶节点,应包含限制条目和名称条目。
(ISO 32000-1第7.9.6节 - 名称树)
您的代码只能理解根节点有名称条目的多样性,因此是树中唯一的节点 :
...
PdfDictionary embedded = names.getAsDict(PdfName.EMBEDDEDFILES);
PdfArray filespecs = embedded.getAsArray(PdfName.NAMES);
...
另一方面,在您的示例PDF文件中, EmbeddedFiles 字典有一个孩子条目,因此您的代码无法理解: