使用iText将命名目标添加到现有PDF文档 [英] Add named destinations to an existing PDF document with iText

查看:210
本文介绍了使用iText将命名目标添加到现有PDF文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我之前使用FOP创建了一个PDF,我需要为它添加一些命名目标,以便以后另一个程序可以使用Adobe PDF打开参数打开和导航文档,即 #namedest = destination_name 参数。

I have a PDF previously created with FOP, and I need to add some named destinations to it so later another program can open and navigate the document with the Adobe PDF open parameters, namely the #namedest=destination_name parameter.

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

I don't need to add bookmarks or other dynamic content but just some destinations with a name and thus injecting a /Dests collection with names defined in the resulting PDF.

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

I use iText 5.3.0 and I read the chapter 7 of iText in Action (2nd edition), but still I cannot figure it out how to add the destinations and so use them with #nameddest in a browser.

我正在使用PdfReader和PdfStamper读取和操作文档。我已经事先知道在使用自定义的Listener和PdfContentStreamProcessor解析文档之后将每个目标放在哪里,在每个页面上搜索特定的文本标记。

I'm reading and manipulating the document with PdfReader and PdfStamper. I already know in advance where to put every destination after having parsed the document with a customized Listener and a PdfContentStreamProcessor, searching for a specific text marker on each page.

这是缩短版我的代码:

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但是,我只是设法得到了注释,但没有定义命名目标,它不起作用。

I also tried creating a PdfAnnotation with PdfFormField.createLink() but still, I just manage to get the annotation but with no named destination defined it does not work.

任何解决方案?我是否需要使用Chunks或其他内容在现有内容上添加一些幽灵内容?

Any solution for this? Do I need to add some "ghost" content over the existing one with Chunks or something else?

提前致谢。

编辑01-27-2016
我最近在iText网站的示例部分找到了我的问题的答案,< a href =http://itextpdf.com/examples/actions-and-annotations/named-destinations#1367-addnameddestinations.java\"rel =nofollow>此处。

不幸的是,如果我使用没有先前在其中定义的目标的pdf测试它,那么所提供的示例对我不起作用,因为源 primes.pdf 已经是这种情况包含 / Dests 数组。此行为似乎与iText代码一致,因为编写器在PdfDocument的map属性中加载目标,该属性在结束时不会被压模继承。

Unfortunately the example provided does not work for me if I test it with a pdf without destinations previously defined in it, as it is the case with the source primes.pdf which already contains a /Dests array. This behaviour appears to be consistent with the iText code, since the writer loads the destinations in a map attribute of PdfDocument which is not "inherited" by the stamper on closing.

也就是说,我使用添加版本5.5.7的PdfStamper方法 addNamedDestination()来实现它;此方法在类的本地map属性中加载一个命名目标,该属性稍后在关闭压模时在文档中进行处理和合并。

That said, I got it working using the method addNamedDestination() of PdfStamper added with version 5.5.7; this method loads a named destination in a local map attribute of the class which is later processed and consolidated in the document when closing the stamper.

这种方法虽然重新提出了一个新问题:使用Pdf打开参数(#,#nameddest = )的导航适用于IE,但不适用于Chrome v47(也可能是Firefox)。我将问题跟踪到了在文档中定义和引用dests名称的顺序;压模使用HashMap作为目的地的容器,当然不保证其对象的顺序以及Chrome拒绝识别未按自然顺序列出的目的地的原因。因此,我让它工作的唯一方法是用自然排序的TreeMap替换 namedDestinations HashMap。

This approach reaised a new issue though: the navigation with Pdf Open Parameters (#, #nameddest=) works fine with IE but not with Chrome v47 (and probably Firefox, too). I tracked the problem down to the order in which the dests names are defined and referenced inside the document; the stamper uses a HashMap as the container for the destinations, which of course does not guarantee the order of its objects and for whatever reason Chrome refuse to recognise destinations not listed in "natural" order. So, the only way I got it to work is replacing the namedDestinations HashMap with a natural-ordered TreeMap.

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

Hope this help others with the same issue.

推荐答案

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

I 've been in the same need for my project previously. Had to display and navigate pdf document with acrobat.jar viewer. To navigate i needed the named destinations in the pdf. I have looked around the web for a possible solution, but no fortunate for me. Then I this idea strikes my mind.

我尝试用itext重新创建现有的pdf,浏览每个页面并为每个页面添加localdestinations,我得到了我想要的东西。下面是我的代码片段

I tried to recreate the existing pdf with itext, navigating through each page and adding localdestinations to each page and i got what I wanted. below is the snip of my code

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();

以为它会对你有帮助。

这篇关于使用iText将命名目标添加到现有PDF文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆