使用iText

时间:2015-04-26 23:24:41

标签: java pdf itext itextpdf pdfstamper

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

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

我使用iText 5.3.0并阅读了iText in Action(第2版)的第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但是,我仍然设法获取注释但没有定义命名目标但它不起作用。

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

提前致谢。

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

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

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

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

希望这能帮助其他人解决同样的问题。

1 个答案:

答案 0 :(得分:0)

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

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

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

认为它会对你有帮助。