使用 iText 将命名目的地添加到现有 PDF 文档

Posted

技术标签:

【中文标题】使用 iText 将命名目的地添加到现有 PDF 文档【英文标题】:Add named destinations to an existing PDF document with iText 【发布时间】:2015-04-26 23:24:40 【问题描述】:

我以前使用 FOP 创建了一个 PDF,我需要向其中添加一些命名的目标,以便稍后另一个程序可以使用 Adob​​e PDF 打开参数打开和导航文档,即 #namedest=destination_name em> 参数。

我不需要添加书签或其他动态内容,只需添加一些带有名称的目的地,从而注入一个 /Dests 集合,其名称在生成的 PDF 中定义。

我使用 iText 5.3.0 并阅读了 iText in Action(第 2 版)的第 7 章,但我仍然无法弄清楚如何添加目的地,因此将它们与 #nameddest 一起使用在浏览器中。

我正在使用 PdfReader 和 PdfStamper 阅读和操作文档。在使用自定义侦听器和 PdfContentStreamProcessor 解析文档并在每个页面上搜索特定文本标记后,我已经提前知道将每个目的地放在哪里。

这是我的代码的缩短版本:

PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new BufferedOutputStream(dest));

// search text markers for destinations, page by page
for (int i=1; i<reader.getNumberOfPages(); i++) 
  // get a list of markers for this page, as obtained with a custom Listener and a PdfContentStreamProcessor
  List<MyDestMarker> markers = ((MyListener)listener).getMarkersForThisPage();

  // add a destination for every text marker in the current page
  Iterator<MyDestMarker> it = markers.iterator();
  while(it.hasNext()) 
    MyDestMarker marker = it.next();
    String name = marker.getName();
    String x = marker.getX();
    String y = marker.getY();

    // create a new destination
    PdfDestination dest = new PdfDestination(PdfDestination.FITH, y); // or XYZ

    // add as a named destination -> does not work, only for new documents?
    stamper.getWriter().addNamedDestination(name, i /* current page */, dest);

    // alternatives
    PdfContentByte content = stamper.getOverContent(i);
    content.localDestination(name, dest); // doesn't work either -> no named dest found

    // add dest name to a list for later use with Pdf Open Parameters
    destinations.add(name);
     


stamper.close();
reader.close();

我还尝试使用 PdfFormField.createLink() 创建一个 PdfAnnotation,但我仍然设法获取注释,但没有定义命名目标,它不起作用。

有什么解决办法吗?我是否需要在现有内容的基础上添加一些“幽灵”内容,使用 Chunks 或其他内容?

提前致谢。


编辑 01-27-2016: 我最近在 iText 网站的示例部分找到了我的问题的答案,here。

不幸的是,如果我使用未在其中定义目标的 pdf 对其进行测试,则提供的示例对我不起作用,就像源 primes.pdf 已经包含 /Dests 数组。这种行为似乎与 iText 代码一致,因为作者将目的地加载到 PdfDocument 的地图属性中,该属性在关闭时不是由压模“继承”的。

也就是说,我使用 5.5.7 版添加的 PdfStamper 的方法 addNamedDestination() 让它工作了;此方法在类的本地地图属性中加载命名目的地,稍后在关闭压模时处理并合并到文档中。

这种方法引发了一个新问题:使用 Pdf 打开参数 (#, #nameddest=) 的导航在 IE 上运行良好,但在 Chrome v47(可能还有 Firefox)上运行良好。我将问题追溯到文档中定义和引用 dest 名称的顺序;压模使用 HashMap 作为目的地的容器,这当然不能保证其对象的顺序,并且无论出于何种原因,Chrome 都拒绝识别未按“自然”顺序列出的目的地。所以,我让它工作的唯一方法是用自然排序的 TreeMap 替换 namedDestinations HashMap。

希望这可以帮助其他有同样问题的人。

【问题讨论】:

我刚刚查了一下,没有简单的方法可以做你想做的事。这可能需要在 iText 中进行额外的核心开发。 谢谢布鲁诺,很遗憾,我认为有一种方法可以用压模来做......你认为有没有一种方法可以用书签创建轮廓并可能“隐藏”它们?顺便说一句,感谢您使用 iText 的工作,我觉得这非常有用。 我还不知道。我现在没有时间,但我已经“收藏”了这个问题,这样我就不会在出差后忘记它(我经常出差)。 没关系,感谢。 【参考方案1】:

我以前对我的项目也有同样的需求。必须使用 acrobat.jar 查看器显示和导航 pdf 文档。要导航,我需要 pdf 中的命名目的地。我在网上寻找可能的解决方案,但对我来说并不幸运。然后我想到了这个想法。

我尝试使用 itext 重新创建现有的 pdf,浏览每个页面并将本地目的地添加到每个页面,我得到了我想要的。以下是我的代码片段

OutputStream outputStream = new FileOutputStream(new File(filename));
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
document.open();
PdfContentByte cb = writer.getDirectContent();
PdfOutline pol = cb.getRootOutline();
PdfOutline oline1 = null;
InputStream in1 = new FileInputStream(new File(inf1));
PdfReader reader = new PdfReader(in1);
for (int i = 1; i <= reader.getNumberOfPages(); i++)

    document.newPage();
    document.setMargins(0.0F, 18.0F, 18.0F, 18.0F);
    PdfImportedPage page = writer.getImportedPage(reader, i);
    document.add(new Chunk(new Integer(i).toString()).setLocalDestination(new Integer(i).toString()));
    System.out.println(i);
    cb.addTemplate(page, 0.0F, 0.0F);

outputStream.flush();
document.close();
outputStream.close();

认为它会帮助你。

【讨论】:

谢谢,确实是一个有趣的解决方案。顺便说一句,我不认为我可以使用带有 document.add() 的 Chunk,因为我需要在页面内的特定位置有一个目的地……也许是一个矩形和 DrawInterface 类,但我必须尝试一下……

以上是关于使用 iText 将命名目的地添加到现有 PDF 文档的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 iText 将没有所有者密码的仅用户密码添加到 PDF

如何使用 itext7 Java 将多个图像添加到 PDF?

使用 itext 7 在 PDF 中添加新页面

iText:如何在提交 Pdf 表单后重定向到 url,当它显示在 iframe 中时?

使用 iText 进行 Acroform 编辑的 Pdf

如何将背景颜色添加到GridView的最后一行