如何使用itext创建多页TOC?

时间:2015-04-22 22:01:16

标签: itext

我需要在PDF中创建TOC。它可以是1页或多页,具体取决于PDF中的页数。我了解到PdfStamperPdfActionPdfAnnotaion可以用来实现这一目标。

我目前正在合并多个文档,并为JAVA中的所有文档创建书签和TOC。我已经摆脱了书签,却陷入了多页TOC。

另外,请解释你的代码的这一行 - link = new PdfAnnotation(copy,36,ct.getYLine(),559,y,action); ...我所理解的是你传递的是一个维度单击链接后,页面上的矩形(36,ct.getYLine(),559,y,)..因此,我面临的一个问题是,在单击时不会更正页面的位置如果页面大小与US Letter Portrait不同,则链接。

以下是片段 -

int tocPages = 1;
Document tocDocument = new Document();
String tocFilename ="toc-filename";
Phrase tocPhrase =
            new Phrase("Table of Contents", new Font(Font.FontFamily.HELVETICA, 20, Font.BOLD, BaseColor.BLACK));
PdfWriter writer = PdfWriter.getInstance(tocDocument, new FileOutputStream(tocFilename));
tocDocument.open();
tocDocument.add(new Paragraph(tocPhrase));
PdfReader reader = new PdfReader(tocFilename);
page = copy.getImportedPage(reader, tocPages);
stamp = copy.createPageStamp(page);

float y = 770;
ColumnText ct = new ColumnText(stamp.getOverContent());
ct.setSimpleColumn(36, 36, 559, y);
for (Map.Entry<Integer, String> entry : toc.entrySet()) {
if (y <= 20) {
copy.addPage(page);
                copy.newPage(); //(tried with writer.newPage() and tocDocument.newPage(), not working )
               page = copy.getImportedPage(reader, ++tocPages);
            }
            p = new Paragraph(entry.getValue());
            p.add(new Chunk(new DottedLineSeparator()));
            p.add(String.valueOf(entry.getKey() + 1));
            ct.addElement(p);
            ct.go();
            action = PdfAction.gotoLocalPage("p" + entry.getKey(), false);
            link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
            stamp.addAnnotation(link);
            y = ct.getYLine();
        }
        ct.go();
        stamp.alterContents();
        copy.addPage(page);
        tocDocument.close();
        reader.close();          

com.itextpdf.text.exceptions.InvalidPdfException:找不到PDF标头签名。     at com.itextpdf.text.pdf.PRTokeniser.getHeaderOffset(PRTokeniser.java:227)     at com.itextpdf.text.pdf.PdfReader.getOffsetTokeniser(PdfReader.java:442)     在com.itextpdf.text.pdf.PdfReader。(PdfReader.java:176)     在com.itextpdf.text.pdf.PdfReader。(PdfReader.java:219)     在com.itextpdf.text.pdf.PdfReader。(PdfReader.java:207)     在com.itextpdf.text.pdf.PdfReader。(PdfReader.java:197)

  

行上的异常 - PdfReader reader = new PdfReader(tocFilename);

1 个答案:

答案 0 :(得分:0)

您已根据我对Create Index File(TOC) for merged pdf using itext library in java

的回答对您的问题进行了调整,以便对此代码段进行调整
Paragraph p;
PdfAction action;
PdfAnnotation link;
float y = 770;
ColumnText ct = new ColumnText(stamp.getOverContent());
ct.setSimpleColumn(36, 36, 559, y);
for (Map.Entry<Integer, String> entry : toc.entrySet()) {
    p = new Paragraph(entry.getValue());
    p.add(new Chunk(new DottedLineSeparator()));
    p.add(String.valueOf(entry.getKey()));
    ct.addElement(p);
    ct.go();
    action = PdfAction.gotoLocalPage("p" + entry.getKey(), false);
    link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);
    stamp.addAnnotation(link);
    y = ct.getYLine();
}
ct.go();

您的问题已缩减为:请解释您的代码行:

link = new PdfAnnotation(copy, 36, ct.getYLine(), 559, y, action);

我已粘贴完整的代码段,因为此行无法解释断章取义

在代码段中,我们使用PdfAnnotation类创建链接注释。链接注释是页面上某个区域,在单击时会触发操作。

在这种情况下会触发哪个操作?这就是action对象的内容,在这种情况下,它会跳转到由命名目标定义的本地页面。这与您拥有<a name="dest" /><a href="#dest">Jump to a specific destination on the current page</a>的HTML非常相似。

创建PdfAnotation时,您始终需要PdfWriter个实例。在这种情况下,我们使用名为PdfCopy的{​​{1}}实例合并文档。当copy扩展PdfCopy时,我们可以将PdfWriter实例作为参数传递。

最后,我们定义可点击区域。这总是一个使用两个坐标定义的矩形:左下角的坐标和右上角的坐标。

在上面的代码段中,我们使用copy添加段落。 ColumnText可让您在添加内容后获取有关当前ColumnText位置的信息。例如,当我们这样做时:

y

我们可以这样做以获得当前的Y坐标:

ct.addElement(p);
ct.go();

在我们的代码段中,我们会跟踪之前的float y = ct.getYLine(); 值(在我们添加y 之前的Y位置)并使用当前值{{1获取当前p位置。

这样,我可以像这样定义左下角的坐标:

ct.getYLine()

右上角的坐标如下:

y

这些是我们在构建链接注释时可以看到的值。

我对float llx = 36; float lly = ct.getYLine(); 值进行了硬编码。它们基于这样一个事实:我正在创建一个A4大小和半英寸边距的文档。 A-4页面是595个用户单位宽。在左边,我有36个用户单位的边际;在右边我也有36个用户单位的边距,我必须从页面的宽度中减去:595 - 36 = 559。

如果您的页面格式为LETTER,则需要调整这些值。但是:根据现有页面的MediaBox / CropBox的实际值来计算它们会更好。这样,当您意外地遇到具有不同页面大小的文档时,您的代码将继续工作。

您可以在我对这个问题的回答中阅读有关MediaBox和CropBox的更多信息:How to get dimensions of each page of a pdf file