PDFBox:PDDocument和PDPage是否互相引用?

时间:2019-01-10 00:30:59

标签: java apache pdfbox

PDPage对象是否包含对其所属PDDocument的引用?
换句话说,PDPage是否了解其PDDocument?
在应用程序的某个位置,我有一个PDDocuments列表。
这些文档合并为一个新的PDDocument:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return categories.count
}

然后将此PdDocument分成10个捆:

PDFMergerUtility pdfMerger = new PDFMergerUtility();

PDDocument mergedPDDocument = new PDDocument();
for (PDDocument pdfDocument : documentList) {
    pdfMerger.appendDocument(mergedPDDocument, pdfDocument);
}

我现在的问题是:
如果我遍历列表中这些拆分的PDDocument的页面,是否有办法知道页面最初属于哪个PDDocument?

此外,如果您有一个PDPage对象,是否可以从中获取信息,例如页码,...。 还是可以通过其他方式获得此信息?

1 个答案:

答案 0 :(得分:2)

  1. PDPage对象是否包含对其所属的PDDocument的引用?换句话说,PDPage是否了解其PDDocument
  

不幸的是,PDPage不包含对其父项PDDocument的引用,但是具有文档中所有其他页面的列表,这些列表可用于在页面之间导航而无需引用父项PDDocument

  1. 如果您有一个PDPage对象,您可以从中获取信息,例如其页码,还是可以通过其他方式获取?
  

有一种变通方法来获取有关PDPage在文档中的位置的信息,而没有PDDocument可用。每个PDPage都有一个字典,其中包含有关页面大小,资源,字体,内容等的信息。这些属性之一称为 Parent ,即 Pages 数组,这些数组具有使用构造函数PDPage创建PDPage(COSDictionary)的浅表克隆所需的所有信息。页面的顺序正确,因此可以通过记录在数组中的位置来获取页码。

  1. 如果我遍历列表中这些PDDocuments的页面,是否有办法知道页面最初属于哪个PDDocument
  

将文档列表合并为一个文档后,所有对原始文档的引用都将丢失。您可以通过查看PDPage内的 Parent 对象来确认这一点,转到 Parent>孩子> COSObject [n]> Parent ,然后查看是否父元素对于数组中的所有元素都是相同的。在此示例中,所有页面的父级均为COSName {Parent} : 1781256139;

COSName {Parent} : COSObject {
  COSDictionary {
    COSName {Kids} : COSArray {
      COSObject {
        COSDictionary {
          COSName {TrimBox} : COSArray {0; 0; 612; 792;};
          COSName {MediaBox} : COSArray {0; 0; 612; 792;};
          COSName {CropBox} : COSArray {0; 0; 612; 792;};
          COSName {Resources} : COSDictionary {
            ...
          };
          COSName {Contents} : COSObject {
            ...
          };
          COSName {Parent} : 1781256139;
          COSName {StructParents} : COSInt {68};
          COSName {ArtBox} : COSArray {0; 0; 612; 792; };
          COSName {BleedBox} : COSArray {0; 0; 612; 792; };
          COSName {Type} : COSName {Page};
        }
    }

    ...

    COSName {Count} : COSInt {4};
    COSName {Type} : COSName {Pages};
  }
};

源代码

我编写了以下代码,以显示PDPage词典中的信息如何用于前后导航页面并使用数组中的位置获取页面编号。

public class PDPageUtils {
    public static void main(String[] args) throws InvalidPasswordException, IOException {
        System.setProperty("sun.java2d.cmm", "sun.java2d.cmm.kcms.KcmsServiceProvider");

        PDDocument document = null;
        try {
            String filename = "src/main/resources/pdf/us-017.pdf";
            document = PDDocument.load(new File(filename));

            System.out.println("listIterator(PDPage)");
            ListIterator<PDPage> pageIterator = listIterator(document.getPage(0));
            while (pageIterator.hasNext()) {
                PDPage page = pageIterator.next();
                System.out.println("page #: " + pageIterator.nextIndex() + ", Structural Parent Key: " + page.getStructParents());
            }
        } finally {
            if (document != null) {
                document.close();
            }
        }
    }

    /**
     * Returns a <code>ListIterator</code> initialized with the list of pages from
     * the dictionary embedded in the specified <code>PDPage</code>. The current
     * position of this <code>ListIterator</code> is set to the position of the
     * specified <code>PDPage</code>.
     * 
     * @param page the specified <code>PDPage</code>
     * 
     * @see {@link java.util.ListIterator}
     * @see {@link org.apache.pdfbox.pdmodel.PDPage}
     */
    public static ListIterator<PDPage> listIterator(PDPage page) {
        List<PDPage> pages = new LinkedList<PDPage>();

        COSDictionary pageDictionary = page.getCOSObject();
        COSDictionary parentDictionary = pageDictionary.getCOSDictionary(COSName.PARENT);
        COSArray kidsArray = parentDictionary.getCOSArray(COSName.KIDS);

        List<? extends COSBase> kidList = kidsArray.toList();
        for (COSBase kid : kidList) {
            if (kid instanceof COSObject) {
                COSObject kidObject = (COSObject) kid;
                COSBase type = kidObject.getDictionaryObject(COSName.TYPE);
                if (type == COSName.PAGE) {
                    COSBase kidPageBase = kidObject.getObject();
                    if (kidPageBase instanceof COSDictionary) {
                        COSDictionary kidPageDictionary = (COSDictionary) kidPageBase;
                        pages.add(new PDPage(kidPageDictionary));
                    }
                }
            }
        }
        int index = pages.indexOf(page);
        return pages.listIterator(index);
    }
}

示例输出

在此示例中,PDF文档有4页,并且迭代器已从第一页初始化。请注意,页码是previousIndex()

System.out.println("listIterator(PDPage)");
ListIterator<PDPage> pageIterator = listIterator(document.getPage(0));
while (pageIterator.hasNext()) {
    PDPage page = pageIterator.next();
    System.out.println("page #: " + pageIterator.previousIndex() + ", Structural Parent Key: " + page.getStructParents());
}
listIterator(PDPage)
page #: 0, Structural Parent Key: 68
page #: 1, Structural Parent Key: 69
page #: 2, Structural Parent Key: 70
page #: 3, Structural Parent Key: 71

您也可以从最后一页开始向后导航。现在注意,页码是nextIndex()

ListIterator<PDPage> pageIterator = listIterator(document.getPage(3));
pageIterator.next();
while (pageIterator.hasPrevious()) {
    PDPage page = pageIterator.previous();
    System.out.println("page #: " + pageIterator.nextIndex() + ", Structural Parent Key: " + page.getStructParents());
}
listIterator(PDPage)
page #: 3, Structural Parent Key: 71
page #: 2, Structural Parent Key: 70
page #: 1, Structural Parent Key: 69
page #: 0, Structural Parent Key: 68