Java 如何使用iText从书签在PDF文件中创建目录页?

Java 如何使用iText从书签在PDF文件中创建目录页?,java,pdf,itext,Java,Pdf,Itext,我需要在PDF中创建一个页面来显示表的内容。我将创建PDF格式的阅读书签 在iText中,我使用: tmp = SimpleBookmark.getBookmark (reader); 使用此PDF进行测试: 返回此映射: [{Action = GoTo, Named = __ WKANCHOR_2, Title = Secretariat Teste0}, {Action = GoTo, Named = __ WKANCHOR_4, Title = Secretariat TestBook

我需要在PDF中创建一个页面来显示表的内容。我将创建PDF格式的阅读书签

在iText中,我使用:

tmp = SimpleBookmark.getBookmark (reader);
使用此PDF进行测试:

返回此映射:

[{Action = GoTo, Named = __ WKANCHOR_2, Title = Secretariat Teste0}, {Action = GoTo, Named = __ WKANCHOR_4, Title = Secretariat TestBook1}, {Action = GoTo, Named = __ WKANCHOR_6, Title = Secretariat Test2}, {Action = GoTo , Named = __ WKANCHOR_8 ...
没有页码

如何显示带有标题和页码的表格内容

我想展示一下:


请阅读此问题的答案:

它解释了如何使用
SimpleBookmark
方法获取大纲树的标题(这是PDF规范中如何调用“书签”)

这是我写的一本关于iText的书中的一个屏幕截图,它显示了书签条目中可以使用的键:

从这个表中可以看出,链接也可以表示为命名目的地。在这种情况下,您将不会得到页码,而是一个名称。要获取页码,您需要提取指定目的地的列表。此列表将为您获取与命名目的地对应的显式目的地

这一点也在书中解释过,也在书中解释过

一旦有了标题和页码(使用基于上述指针编写的代码检索),就可以使用
PdfStamper
insertPage()
方法将页面插入PDF文件。您可以使用
ColumnText
将TOC放在这些页面上,也可以为TOC创建单独的PDF并将其与原始PDF合并。请参阅以了解有关这两种技术的更多信息

您还将受益于此示例:

至于标题和页码之间的虚线,则使用分隔符,更确切地说是虚线分隔符。你应该先阅读这个问题:

然后读这个问题:(或这个问题)

请注意,您的问题实际上是离题的。这是一个“家庭作业”问题。它邀请人们在你的位置上做你的工作。既然您已经具备了所需的所有要素,您应该能够自己完成这项工作。如果你没有成功,你应该写一个关于主题堆栈溢出的问题。这是一个问题,在这个问题中,你展示了你的尝试,并解释了你遇到的技术问题

更新:

您与以下大纲树共享了一个文档:

如您所见,书签是使用命名目的地定义的,例如
/\uuuuuwkanch\u2
/\uuuwkanch\u4
,等等。从
/
字符可以看出,名称存储为PDF名称对象(PDF 1.1),而不是PDF字符串对象(从1.2开始)。最新的PDF标准建议使用PDF字符串对象而不是PDF名称对象,您可能希望要求PDF生成软件的供应商更新软件,以满足最新PDF标准的建议

然而,我们可以很容易地获得与那些命名目的地对应的显式目的地。它们存储在根词典的
/Dests
条目中:

当您查看目的地的方式时,您会发现另一个应向wkhtmltopdf报告的问题。让我们看一下ISO标准告诉我们要用于目的地的语法:

PDF中不存在页码的概念。页面使用页面字典进行描述,页码从页面在页面树中的位置派生。在页面树中遇到的第一个页面是第1页,遇到的第二个页面是第2页,依此类推

在您的示例中,解释目的地的定义如下:
[9/XYZ 30.2400000 524.179999 0]
[9/XYZ 30.2400000 231.379999 0]
,等等

这是错误的。ISO标准规定数组中的第一个值必须是间接引用。间接引用的格式为
9 0 R
,而不是
9
。我查看了文档的结构,发现wkhtmltopdf使用了页码-1,而不是间接引用。如果我看一下
/\uuuuwkanch\u2
,它指的是
[0/XYZ 30.240000781.459999 0]
,而
0
应该指向第1页。由于Adobe Reader容忍蹩脚的软件,这在Adobe Reader中起作用,但由于该文件违反了ISO-32000,iText不知道如何处理这些误导目的地,至少Convenience类
SimpleNamedDEstination
不知道如何处理它

幸运的是,iText是一个非常多功能的库,它允许您深入到PDF的底层。在这种情况下,我们只需要更深一层。我们可以使用以下方法代替
SimpleNamedDestination.getNamedDestination(reader,true)

HashMap<String, PdfObject> names = reader.getNamedDestinationFromNames();
for (Map.Entry<String, PdfObject> entry: names.entrySet()) {
    System.out.print(entry.getKey());
    System.out.print(": p");
    PdfArray arr = (PdfArray)entry.getValue();
    System.out.println(arr.getAsNumber(0).intValue() + 1);
}
reader.close();
如果我们检查
\uuuwkanch\u2
,我们会看到它正确地指向第1页。我检查了提纲中的最后一个链接,它指向了名为
\uuuuwkanch\u1s
的指定目的地,事实上:应该链接到第13页


您的问题是“垃圾输入垃圾输出”问题的一个明显例子。您的工具生成的PDF文件违反了PDF的ISO标准,因此您会浪费大量时间来找出错误所在。但更糟糕的是:你让我因为别人的过错而失去了时间。

你的问题被称为“家庭作业”问题。也就是说:您要求stackoverflow上的读者在您的位置上完成您的工作。你可以通过展示你所做的尝试,在主题问题中更改此问题。我已经提供了一个关于堆栈溢出的答案和以前的答案的链接。现在,你需要花些时间来试验这些指针。如果你的下一条评论听起来像“我没有时间这么做,就给我代码吧”,我预测你会得到很多反对票。指向你的PDF的链接不是指向PDF的链接。这是一个屏幕截图的链接。我希望你明白这不是专业的
public void createXml(String src, String dest) throws IOException {
    PdfReader reader = new PdfReader(src);
    List<HashMap<String, Object>> list = SimpleBookmark.getBookmark(reader);
    SimpleBookmark.exportToXML(list,
            new FileOutputStream(dest), "ISO8859-1", true);
    reader.close();
}
HashMap<String, PdfObject> names = reader.getNamedDestinationFromNames();
for (Map.Entry<String, PdfObject> entry: names.entrySet()) {
    System.out.print(entry.getKey());
    System.out.print(": p");
    PdfArray arr = (PdfArray)entry.getValue();
    System.out.println(arr.getAsNumber(0).intValue() + 1);
}
reader.close();
__WKANCHOR_w: p7
__WKANCHOR_y: p7
__WKANCHOR_2: p1
__WKANCHOR_4: p1
__WKANCHOR_16: p9
__WKANCHOR_14: p8
__WKANCHOR_18: p9
__WKANCHOR_1s: p13
__WKANCHOR_a: p2
__WKANCHOR_1q: p13
__WKANCHOR_1o: p12
__WKANCHOR_12: p8
__WKANCHOR_1m: p12
__WKANCHOR_e: p3
__WKANCHOR_10: p7
__WKANCHOR_1k: p12
__WKANCHOR_c: p3
__WKANCHOR_1i: p11
__WKANCHOR_i: p4
__WKANCHOR_8: p2
__WKANCHOR_g: p3
__WKANCHOR_1g: p11
__WKANCHOR_6: p1
__WKANCHOR_1e: p10
__WKANCHOR_m: p5
__WKANCHOR_1c: p10
__WKANCHOR_k: p4
__WKANCHOR_q: p5
__WKANCHOR_1a: p9
__WKANCHOR_o: p5
__WKANCHOR_u: p6
__WKANCHOR_s: p6