Добавить именованные места назначения в существующий документ PDF с помощью iText
У меня есть PDF, ранее созданный с помощью FOP, и мне нужно добавить к нему несколько именованных мест назначения, чтобы позже другая программа могла открывать документ и перемещаться по нему с помощью параметров открытия Adobe PDF, а именно параметра #namedest=destination_name.
Мне не нужно добавлять закладки или другой динамический контент, а только некоторые места назначения с именем и, таким образом, вводить коллекцию /Dests с именами, определенными в итоговом PDF.
Я использую iText 5.3.0 и читаю главу 7 iText в действии (2-е издание), но все же не могу понять, как добавить места назначения и использовать их с #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();
Я также попытался создать PdfAnnotation с помощью PdfFormField.createLink(), но, тем не менее, мне просто удается получить аннотацию, но без указания имени назначения она не работает.
Любое решение для этого? Нужно ли добавить какой-нибудь "призрачный" контент поверх существующего с помощью чанков или чего-то еще?
Заранее спасибо.
edit 27-27-2016: я недавно нашел ответ на свой вопрос в разделе примеров на сайте iText, здесь.
К сожалению, приведенный пример не работает для меня, если я протестирую его с pdf без мест назначения, ранее определенных в нем, как это имеет место с исходным файлом primes.pdf, который уже содержит массив /Dests. Такое поведение согласуется с кодом iText, поскольку средство записи загружает места назначения в атрибут карты PdfDocument, который не "наследуется" штампом при закрытии.
Тем не менее, я получил его с помощью метода addNamedDestination() из PdfStamper, добавленного в версии 5.5.7; этот метод загружает именованный пункт назначения в атрибут локальной карты класса, который позже обрабатывается и консолидируется в документе при закрытии штампа.
Однако при таком подходе возникла новая проблема: навигация с открытыми параметрами Pdf (#, # nameddest =) прекрасно работает с IE, но не с Chrome v47 (и, вероятно, Firefox тоже). Я проследил проблему до порядка, в котором имена десстов определены и указаны внутри документа; штамп использует HashMap в качестве контейнера для пунктов назначения, что, конечно, не гарантирует порядок его объектов, и по любой причине Chrome отказывается распознавать пункты назначения, не перечисленные в "естественном" порядке. Таким образом, единственный способ заставить его работать - это заменить namedDestination HashMap естественным образом упорядоченным TreeMap.
Надеюсь, что это поможет другим с той же проблемой.
1 ответ
Я был в той же потребности в моем проекте ранее. Пришлось отображать и перемещаться по документу PDF с помощью средства просмотра acrobat.jar. Для навигации мне понадобились названные направления в формате PDF. Я искал в Интернете возможное решение, но мне не повезло. Тогда мне эта идея приходит в голову.
Я попытался воссоздать существующий pdf с itext, перемещаясь по каждой странице и добавляя локальные назначения для каждой страницы, и я получил то, что хотел. ниже фрагмент моего кода
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();
Думала, это поможет тебе.