我有一个包含文件夹,子文件夹和文件的PDF文件夹。我需要使用java中的iText提取与文件夹,子文件夹和文件相同的结构。我只收到带有EMBEDEDFILES的文件。什么是获取文件夹的方式。
请找到我正在使用的代码。此代码仅为我提供文件夹中的文件。
<div class="form-group">
<label class="col-sm-2 control-label">Text</label>
<div class="col-sm-10">
<div class="checkbox">
<label class="checkbox-inline">
<input id="123" name="Checkbox" value="a" type="checkbox">
</label>
</div>
</div>
</div>
答案 0 :(得分:2)
在Adobe® Supplement to the ISO 32000, BaseVersion: 1.7, ExtensionLevel: 3中指定了OP在提取组合文件时尝试复制的文件夹结构。因此,它不是不当前PDF标准的一部分,因此,不需要PDF处理软件来理解这种信息。看起来好像是为了加入即将推出的PDF-2(ISO 32000-2)标准。
要将组合文件提取到关联的文件夹结构中,我们必须检索Adobe®Supplement中指定的文件夹信息:
从扩展级别3开始,可移植集合可以包含文件夹对象,用于 将文件组织成分层结构。该结构由具有单个根文件夹的树表示 充当集合中所有其他文件夹和文件的共同祖先。单根文件夹是 在第28页的表8.6的
Folders
条目中引用。表8.6c描述了文件夹字典中的条目
ID
整数(必需; ExtensionLevel 3)非负整数值 表示唯一文件夹标识号。两个文件夹 不得共享相同的ID
值。文件夹
ID
值显示为任何文件的名称树键的一部分 与此文件夹关联。详细说明 文件夹和文件之间的关联可以在此表后找到。
Name
文字字符串(必填; ExtensionLevel 3)表示名称的文件名 文件夹。两个兄弟文件夹不得共享相同的名称 以下案例规范化。
Child
字典(如果文件夹中有任何后代,则为必需; ExtensionLevel 3) 间接引用此文件夹的第一个子文件夹。
Next
字典(除了每个级别的最后一项以外的所有项目都需要; ExtensionLevel 3) 间接引用此级别的下一个兄弟文件夹。(第8.2.4节收集)
E.g。像这样:
static Map<Integer, File> retrieveFolders(PdfReader reader, File baseDir) throws DocumentException
{
Map<Integer, File> result = new HashMap<Integer, File>();
PdfDictionary root = reader.getCatalog();
PdfDictionary collection = root.getAsDict(PdfName.COLLECTION);
if (collection == null)
throw new DocumentException("Document has no Collection dictionary");
PdfDictionary folders = collection.getAsDict(FOLDERS);
if (folders == null)
throw new DocumentException("Document collection has no folders dictionary");
collectFolders(result, folders, baseDir);
return result;
}
static void collectFolders(Map<Integer, File> collection, PdfDictionary folder, File baseDir)
{
PdfString name = folder.getAsString(PdfName.NAME);
File folderDir = new File(baseDir, name.toString());
folderDir.mkdirs();
PdfNumber id = folder.getAsNumber(PdfName.ID);
collection.put(id.intValue(), folderDir);
PdfDictionary next = folder.getAsDict(PdfName.NEXT);
if (next != null)
collectFolders(collection, next, baseDir);
PdfDictionary child = folder.getAsDict(CHILD);
if (child != null)
collectFolders(collection, child, folderDir);
}
final static PdfName FOLDERS = new PdfName("Folders");
final static PdfName CHILD = new PdfName("Child");
(摘自PortfolioFileExtraction.java)
并在编写文件时使用这些检索到的文件夹信息。
文件和文件夹的关联在Adobe®Supplement中指定,如下所示:
如前所述,
EmbeddedFiles
名称树中的文件与特殊文件夹相关联 应用于名称树键字符串的命名约定。服务符合以下规则的字符串 将相应的文件与文件夹关联:
- 名称树键是PDF文本字符串。
- 第一个字符(不包括任何字节顺序标记)是U + 003C,LESS-THAN SIGN(&lt;)。
- 以下字符应为一个或多个数字(0到9),然后是关闭U + 003E, 大大的标志(&gt;)
- 字符串的其余部分是文件名。
由LESS-THAN SIGN GREATER-THAN SIGN(&lt;&gt;)包围的字符串部分被解释为 数值,指定与文件关联的文件夹的ID值。价值应该 对应于文件夹ID。文件夹ID标记后面的字符串部分表示文件名 嵌入文件。
EmbeddedFiles名称树中不符合这些规则的文件应视为关联 使用根文件夹。
(第8.2.4节收集)
您的方法可以扩展为这样:
public static void extractAttachmentsWithFolders(PdfReader reader, String dir) throws IOException, DocumentException
{
File folder = new File(dir);
folder.mkdirs();
Map<Integer, File> folders = retrieveFolders(reader, folder);
PdfDictionary root = reader.getCatalog();
PdfDictionary names = root.getAsDict(PdfName.NAMES);
System.out.println("" + names.getKeys().toString());
PdfDictionary embedded = names.getAsDict(PdfName.EMBEDDEDFILES);
System.out.println("" + embedded.toString());
PdfArray filespecs = embedded.getAsArray(PdfName.NAMES);
for (int i = 0; i < filespecs.size();)
{
extractAttachment(reader, folders, folder, filespecs.getAsString(i++), filespecs.getAsDict(i++));
}
}
protected static void extractAttachment(PdfReader reader, Map<Integer, File> dirs, File dir, PdfString name, PdfDictionary filespec) throws IOException
{
PRStream stream;
FileOutputStream fos;
String filename;
PdfDictionary refs = filespec.getAsDict(PdfName.EF);
File dirHere = dir;
String nameString = name.toUnicodeString();
if (nameString.startsWith("<"))
{
int closing = nameString.indexOf('>');
if (closing > 0)
{
int folderId = Integer.parseInt(nameString.substring(1, closing));
File folderFile = dirs.get(folderId);
if (folderFile != null)
dirHere = folderFile;
}
}
for (PdfName key : refs.getKeys())
{
stream = (PRStream) PdfReader.getPdfObject(refs.getAsIndirectObject(key));
filename = filespec.getAsString(key).toString();
fos = new FileOutputStream(new File(dirHere, filename));
fos.write(PdfReader.getStreamBytes(stream));
fos.flush();
fos.close();
}
}
(摘自PortfolioFileExtraction.java)
将这些方法应用于您的示例PDF(例如,使用PortfolioFileExtraction.java中的测试方法testSamplePortfolio11Folders
),
Root
│ ThumbImpression.pdf
│
├───Folder 1
│ │ EStampPdf.pdf
│ │ Presentation.pdf
│ │
│ ├───Folder 11
│ │ │ Test.pdf
│ │ │
│ │ └───Folder 111
│ └───Folder 12
└───Folder 2
SealDeed.pdf