如何解决将超链接添加到内部 PDF 文件
我必须通过使用 Java 中的 iText 在生成的 PDF 文件中添加两个 PDF 文件作为树结构来创建 PDF 文件。
我必须创建带有 PDF 文件名的书签,并向书签添加超链接。单击书签时,应在该 PDF 文件本身中打开相应的 PDF,而不是作为单独的 PDF。
PDFTREE
pdf1
pdf2
解决方法
此类书签在 PDF 规范(PDF 32000-1:2008,p.367)中被称为大纲元素: >
大纲由大纲项(有时称为书签)的树状层次结构组成,它们作为一个可视化的目录,向用户展示文档的结构。用户。
如果您使用 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,pdfDocument2.getNumberOfPages(),filename2);
merger.writeOutline();
}
}
结果如下(Preview 和 Adobe Acrobat Reader 在 macOS 上):
另一种选择是通过嵌入 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,null,null);
doc.addFileAttachment(name,fileSpec);
}
在 macOS 上的 Adobe Acrobat Reader 中的结果:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。