gpt4 book ai didi

java - 向内部 PDF 文件添加超链接

转载 作者:行者123 更新时间:2023-12-04 13:08:35 24 4
gpt4 key购买 nike

我必须通过使用 Java 中的 iText 在生成的 PDF 文件中添加两个 PDF 文件作为树结构来创建 PDF 文件。

我必须用 PDF 文件名创建书签,并向书签添加超链接。单击书签时,应在该 PDF 文件本身中打开相应的 PDF,而不是作为单独的 PDF。

PDF树

 pdf1 
pdf2

最佳答案

此类书签在 PDF 规范(PDF 32000-1:2008p.367)中称为大纲元素:

The outline consists of a tree-structured hierarchy of outline items (sometimes called bookmarks), which serve as a visual table of contents to display the document’s structure to the user.

如果您使用 PdfMerger 合并文档,默认情况下会将轮廓复制到生成的 PDF 中。但是,您希望每个文档有一个主节点,而不是一个简单的书签列表。由于克隆和复制大纲绝非易事,因此最好让 iText 处理它。不幸的是,我们几乎无法直接控制大纲的合并方式。

我们可以构建一个 SpecialMerger 作为 PdfMerger 的包装器来提取克隆的轮廓(第一步),然后将它们放入层次结构中(第二步)。每个合并的 PDF 的大纲与主节点的所需名称及其引用(合并的 PDF 中的页码)一起临时存储在 outlineList 中。合并所有 PDF 后,我们可以将临时存储的轮廓附加回根节点。

public static class SpecialMerger {

private final PdfDocument outputPdf;
private final PdfMerger merger;
private final PdfOutline rootOutline;
private final List<DocumentOutline> outlineList = new ArrayList<>();
private int nextPageNr = 1;

public SpecialMerger(final PdfDocument outputPdf) {
if (outputPdf.getNumberOfPages() != 0) {
throw new IllegalArgumentException("PDF must be empty");
}
this.outputPdf = outputPdf;
this.merger = new PdfMerger(outputPdf, true, true);
this.rootOutline = outputPdf.getOutlines(false);
}

public void merge(PdfDocument from, int fromPage, int toPage, String filename) {
merger.merge(from, fromPage, toPage); // merge with normal PdfMerger

// extract and clone outline of merged document
final List<PdfOutline> children = new ArrayList<>(rootOutline.getAllChildren());
rootOutline.getAllChildren().clear(); // clear root outline
outlineList.add(new DocumentOutline(filename, nextPageNr, children));
nextPageNr = outputPdf.getNumberOfPages() + 1; // update next page number
}

public void writeOutline() {
outlineList.forEach(o -> {
final PdfOutline outline = rootOutline.addOutline(o.getName()); // bookmark with PDF name
outline.addDestination(PdfExplicitDestination.createFit(outputPdf.getPage(o.getPageNr())));
outline.setStyle(PdfOutline.FLAG_BOLD);
o.getChildern().forEach(outline::addOutline); // add all extracted child bookmarks
});
}

private static class DocumentOutline {

private final String name;
private final int pageNr;
private final List<PdfOutline> childern;

public DocumentOutline(final String pdfName, final int pageNr, final List<PdfOutline> childern) {
this.name = pdfName;
this.pageNr = pageNr;
this.childern = childern;
}

public String getName() {
return name;
}

public int getPageNr() {
return pageNr;
}

public List<PdfOutline> getChildern() {
return childern;
}
}
}

现在,我们可以使用这个自定义合并来合并 PDF,然后使用 writeOutline 添加大纲:

public static void main(String[] args) throws IOException {
String filename1 = "pdf1.pdf";
String filename2 = "pdf2.pdf";
try (
PdfDocument generatedPdf = new PdfDocument(new PdfWriter("output.pdf"));
PdfDocument pdfDocument1 = new PdfDocument(new PdfReader(filename1));
PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(filename2))
) {
final SpecialMerger merger = new SpecialMerger(generatedPdf);
merger.merge(pdfDocument1, 1, pdfDocument1.getNumberOfPages(), filename1);
merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages(), filename2);
merger.writeOutline();
}
}

结果如下所示(预览Adobe Acrobat Reader 在 macOS 上): result-merge


另一种选择是通过嵌入 PDF 来制作作品集。但是,并非所有 PDF 查看器都支持此功能,并且大多数用户不习惯这些组合。

public static void main(String[] args) throws IOException {
String filename1 = "pdf1.pdf";
String filename2 = "pdf2.pdf";

try (PdfDocument generatedPdf = new PdfDocument(new PdfWriter("portfolio.pdf"))) {
Document doc = new Document(generatedPdf);
doc.add(new Paragraph("This PDF contains embedded documents."));
doc.add(new Paragraph("Use a compatible PDF viewer if you cannot see them."));

PdfCollection collection = new PdfCollection();
collection.setView(PdfCollection.TILE);
generatedPdf.getCatalog().setCollection(collection);

addAttachment(generatedPdf, filename1, filename1);
addAttachment(generatedPdf, filename2, filename2);
}
}

private static void addAttachment(PdfDocument doc, String attachmentPath, String name) throws IOException {
PdfFileSpec fileSpec = PdfFileSpec.createEmbeddedFileSpec(doc, attachmentPath, name, name, null, null);
doc.addFileAttachment(name, fileSpec);
}

macOS 上的 Adob​​e Acrobat Reader 中的结果:

result-portfolio

关于java - 向内部 PDF 文件添加超链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68190907/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com