如何使用 OpenPDF 添加 table 个内容
How to add a table of contents using OpenPDF
我正在开发一种工具,用于生成代表评估结果的 PDF 文档。这些文档的结构以及一些文本和图像由非技术用户定义(这也是为什么例如 Apache FOP 和 XSL 不是一个选项的原因之一)。
OpenPDF 似乎是一个很有前途的库(Apache PDFBox 除外,它太低级了)。但是,生成的文档必须包含 table 的内容。
预期的文档结构是这样的:
1. Cover
2. Abstract
3. Table of Contents
4. Chapter 1 .. n
由于我不知道文档最终会有多少页,也不知道不同的章节将从哪几页开始,所以我无法在将每一章添加到文档之前定义 table 的内容。
由于 OpenPDF 直接将元素写入文档,因此似乎无法保留示例性 table 内容元素的引用并在添加所有章节后添加其内容。
我找到了一个解决方案,通过使用 com.lowagie.text.pdf.PdfWriter
的 reorderPages(int[])
方法来处理预期的结构:
首先,我保留 intended 目录 table 第一页(摘要后的第一页):
int intendedTocFirstPage = pdfWriter.getCurrentPageNumber() - 1; // - 1 because of a necessary `document.newPage();` before that
将所有章节添加到文档后,我将 table 内容添加到最后并保留第一页和最后一页(因为可能需要不止一页,具体取决于章节数和子章节):
int tocFirstPage = pdfWriter.getCurrentPageNumber();
document.add(new Paragraph("TBA: Actual Table of Contents")); // TODO replace with the table of contents based on the existing chapters and sections
document.newPage();
int tocLastpage = pdfWriter.getCurrentPageNumber();
然后我创建一个数组,表示基于三个 int
变量的页面的新顺序:
private int[] getReorderedPagesForTableOfContents(int intendedTocFirstPage, int tocFirstPage, int tocLastpage) {
int[] pages = IntStream
.range(1, tocLastpage)
.toArray();
/*
* Reorder the pages array by placing the toc page numbers at
* the indexes starting from targetedTocFirstPage (should be
* the page directly after the summary)
*/
int numberOfTocPages = tocLastpage - tocFirstPage;
if (numberOfTocPages >= 0) {
System.arraycopy(pages, tocFirstPage - 1, pages, intendedTocFirstPage, numberOfTocPages);
}
/* Shift the page numbers of all pages after the last toc page */
for (int i = intendedTocFirstPage + numberOfTocPages; i < pages.length; i++) {
pages[i] = i - numberOfTocPages + 1; // `+ 1` because page numbers start with 1 not 0
}
return pages;
}
最后,我正在重新排序文档的页面:
int[] reorderedPages = getReorderedPagesForTableOfContents(targetedTocFirstPage, tocFirstPage, tocLastpage);
pdfWriter.reorderPages(reorderedPages);
这可行,但会产生另一个问题:
使用页脚显示页码将不再正常工作,因为将保留重新排序之前的页码。
一个可能的解决方案是首先创建完整的文档,包括页面的重新排序,然后使用 PdfReader 添加页码,如本答案中所述:
如果有人有更好的解决方案,我会很高兴听到(因为这个有点乱,在我看来)。 :)
我正在开发一种工具,用于生成代表评估结果的 PDF 文档。这些文档的结构以及一些文本和图像由非技术用户定义(这也是为什么例如 Apache FOP 和 XSL 不是一个选项的原因之一)。
OpenPDF 似乎是一个很有前途的库(Apache PDFBox 除外,它太低级了)。但是,生成的文档必须包含 table 的内容。
预期的文档结构是这样的:
1. Cover
2. Abstract
3. Table of Contents
4. Chapter 1 .. n
由于我不知道文档最终会有多少页,也不知道不同的章节将从哪几页开始,所以我无法在将每一章添加到文档之前定义 table 的内容。
由于 OpenPDF 直接将元素写入文档,因此似乎无法保留示例性 table 内容元素的引用并在添加所有章节后添加其内容。
我找到了一个解决方案,通过使用 com.lowagie.text.pdf.PdfWriter
的 reorderPages(int[])
方法来处理预期的结构:
首先,我保留 intended 目录 table 第一页(摘要后的第一页):
int intendedTocFirstPage = pdfWriter.getCurrentPageNumber() - 1; // - 1 because of a necessary `document.newPage();` before that
将所有章节添加到文档后,我将 table 内容添加到最后并保留第一页和最后一页(因为可能需要不止一页,具体取决于章节数和子章节):
int tocFirstPage = pdfWriter.getCurrentPageNumber();
document.add(new Paragraph("TBA: Actual Table of Contents")); // TODO replace with the table of contents based on the existing chapters and sections
document.newPage();
int tocLastpage = pdfWriter.getCurrentPageNumber();
然后我创建一个数组,表示基于三个 int
变量的页面的新顺序:
private int[] getReorderedPagesForTableOfContents(int intendedTocFirstPage, int tocFirstPage, int tocLastpage) {
int[] pages = IntStream
.range(1, tocLastpage)
.toArray();
/*
* Reorder the pages array by placing the toc page numbers at
* the indexes starting from targetedTocFirstPage (should be
* the page directly after the summary)
*/
int numberOfTocPages = tocLastpage - tocFirstPage;
if (numberOfTocPages >= 0) {
System.arraycopy(pages, tocFirstPage - 1, pages, intendedTocFirstPage, numberOfTocPages);
}
/* Shift the page numbers of all pages after the last toc page */
for (int i = intendedTocFirstPage + numberOfTocPages; i < pages.length; i++) {
pages[i] = i - numberOfTocPages + 1; // `+ 1` because page numbers start with 1 not 0
}
return pages;
}
最后,我正在重新排序文档的页面:
int[] reorderedPages = getReorderedPagesForTableOfContents(targetedTocFirstPage, tocFirstPage, tocLastpage);
pdfWriter.reorderPages(reorderedPages);
这可行,但会产生另一个问题:
使用页脚显示页码将不再正常工作,因为将保留重新排序之前的页码。
一个可能的解决方案是首先创建完整的文档,包括页面的重新排序,然后使用 PdfReader 添加页码,如本答案中所述:
如果有人有更好的解决方案,我会很高兴听到(因为这个有点乱,在我看来)。 :)