从投资组合pdf java中提取文件夹

时间:2015-08-03 14:22:27

标签: pdf itext directory portfolio

我有一个包含文件夹,子文件夹和文件的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>

1 个答案:

答案 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