繁体   English   中英

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

[英]Add named destinations to an existing PDF document with iText

我有一个以前使用FOP创建的PDF,我需要为其添加一些命名的目的地,以便以后另一个程序可以使用Adobe PDF打开参数(即#namedest = destination_name参数)打开和导航该文档。

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

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

我正在使用PdfReader和PdfStamper阅读和处理文档。 我已经事先知道了在使用自定义的Listener和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,但是我仍然设法获取注释,但是没有定义命名的目标,这是行不通的。

有什么解决办法吗? 我是否需要在现有的“块”或其他内容上添加一些“鬼影”内容?

提前致谢。


编辑2016年1月27日 :我最近发现一个回答我的问题在iText的网站的示例部分, 在这里

不幸的是,如果我使用没有预先定义目标的pdf测试它,那么提供的示例对我不起作用,因为原始Primes.pdf已经包含/ Dests数组。 此行为似乎与iText代码一致,因为编写者将目的地加载到PdfDocument的map属性中,该属性在关闭时未被压模“继承”。

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

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

希望这对其他人有帮助。

以前,我一直对我的项目有同样的需求。 必须使用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();

以为会对您有所帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM