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

Java 使用iText将命名目的地添加到现有PDF文档,java,pdf,itext,itextpdf,pdfstamper,Java,Pdf,Itext,Itextpdf,Pdfstamper,我有一个以前用FOP创建的PDF,我需要向其中添加一些命名的目的地,以便稍后另一个程序可以使用Adobe PDF open参数,即#namedest=destination_name参数打开和导航文档 我不需要添加书签或其他动态内容,只需要添加一些带有名称的目的地,从而使用结果PDF中定义的名称注入/Dests集合 我使用iText 5.3.0并阅读了iText in Action(第二版)的第7章,但我仍然不知道如何添加目的地,因此在浏览器中将它们与#namedTest一起使用 我正在用Pdf

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

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

我使用iText 5.3.0并阅读了iText in Action(第二版)的第7章,但我仍然不知道如何添加目的地,因此在浏览器中将它们与#namedTest一起使用

我正在用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();
PdfReader阅读器=新的PdfReader(src);
PdfStamper压模=新PdfStamper(读卡器,新缓冲输出流(dest));
//逐页搜索目的地的文本标记
for(int i=1;i不工作,仅适用于新文档?
stamper.getWriter().addNamedDestination(名称,i/*当前页*/,目标);
//替代品
PdfContentByte content=stamper.getOverContent(i);
content.localDestination(name,dest);//也不起作用->找不到命名的dest
//将dest name添加到列表中,以便以后与Pdf Open参数一起使用
目的地。添加(名称);
}   
}
压模关闭();
reader.close();
我还尝试使用PdfFormField.createLink()创建一个PdfAnnotation,但是,我还是设法得到了注释,但是没有定义命名的目的地,它不起作用

有什么解决方案吗?我是否需要在现有内容的基础上添加一些“ghost”内容,包括块或其他内容

提前谢谢


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

不幸的是,如果我使用之前未定义目的地的pdf对其进行测试,所提供的示例对我不起作用,因为source primes.pdf已经包含/Dests数组。这种行为似乎与iText代码一致,因为编写器在PdfDocument的map属性中加载目的地在结束时,压模不会“继承”该值

也就是说,我使用版本5.5.7中添加的PdfStamper的addNamedDestination()方法使其工作;该方法在类的本地映射属性中加载一个命名目的地,然后在关闭母版时在文档中进行处理和合并

不过,这种方法解决了一个新问题:带有Pdf开放参数(#,#nameddest=)的导航在IE上运行良好,但在ChromeV47(可能还有Firefox)上则不行。我将问题追溯到文档中定义和引用dests名称的顺序;stamp使用HashMap作为目的地的容器,这当然不能保证其对象的顺序,并且出于任何原因,Chrome拒绝识别“natural”中未列出的目的地所以,我让它工作的唯一方法就是用一个自然有序的树状图替换命名的Destinations HashMap


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

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

我尝试用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();
OutputStream OutputStream=新文件OutputStream(新文件(文件名));
文档=新文档();
PdfWriter writer=PdfWriter.getInstance(文档,outputStream);
document.open();
PdfContentByte cb=writer.getDirectContent();
PdfOutline pol=cb.getRootOutline();
PdfOutline oline1=null;
InputStream in1=新文件InputStream(新文件(inf1));
PdfReader读取器=新PdfReader(in1);

对于(int i=1;我刚查过这个,没有简单的方法来做你想做的事情。这可能需要在iText中进行额外的核心开发。谢谢Bruno,这很不幸,我认为有一种方法可以用压模来做……你认为有没有一种方法可以用书签创建一个大纲,或者“隐藏”呢他们?顺便说一句,谢谢你在iText上的工作,我觉得这非常有用。我还不知道。我现在没有时间,但我“喜欢”这个问题,这样我就不会在出差后忘记它(我经常出差)。当然可以,非常感谢。谢谢,这确实是一个有趣的解决方案。顺便说一句,我不认为我可以在document.add()中使用块,因为我需要在页面内的特定位置上指定目标…可能是一个矩形和类DrawInterface,但我必须尝试一下。。。