2016-08-18 2 views
1

Мне нужно создать страницу в формате PDF для содержимого таблицы. Я создам закладку для чтения в формате PDF.Как создать страницу оглавления в PDF-файле из закладок с помощью iText?

С IText я использую:

tmp = SimpleBookmark.getBookmark (reader); 

Тестирование с этим PDF:

Download file PDF

Возвращает это карта:

[{Action = GoTo, Named = __ WKANCHOR_2, Title = Secretariat Teste0}, {Action = GoTo, Named = __ WKANCHOR_4, Title = Secretariat TestBook1}, {Action = GoTo, Named = __ WKANCHOR_6, Title = Secretariat Test2}, {Action = GoTo , Named = __ WKANCHOR_8 ... 

Без номера страницы.

Как можно показать содержимое таблицы с заголовком и номером страницы?

Я хотел бы показать это:

content of table

+0

Ваш вопрос сформулирован как вопрос «домашнего труда». То есть: вы просите читателей о переполнении стека выполнять свою работу на вашем месте. Вы можете изменить этот вопрос в вопросе * по теме *, указав, что вы пробовали. Я предоставил ответ со ссылками на [официальную документацию] (http://developers.itextpdf.com) и предыдущие ответы на переполнение стека. Теперь вам решать потратить некоторое время на эксперименты с этими указателями. Если ваш следующий комментарий звучит так: «У меня нет времени на это, просто дайте мне код», я предсказываю, что вы получите много голосов. –

+0

Ссылка на ваш PDF не является ссылкой на PDF. Это ссылка на экранный снимок. Надеюсь, вы понимаете, что это не профессионал. Мы можем просмотреть закладки в PDF, чтобы узнать, содержат ли они явные адресаты или названные адресаты. Мы не можем этого сделать, если вы используете PNG. Как разработчик вы должны это знать (но, может быть, вы не разработчик). –

+0

Bruno благодарит за комментарий. Я создаю pdf, используя wkhtmltopdf, сгенерирую PDF с закладками. Когда я иду по закладкам (с помощью itext), мне возвращается список карт без номера страницы, но со ссылкой на якорь. Мой главный вопрос - это один из способов получить номер страницы каждого якоря, не пройдя поиск в pdf-заголовке. –

ответ

3

Пожалуйста, прочитайте ответ на этот вопрос: Java: Reading PDF bookmark names with itext

Это объясняет, как вы можете использовать метод SimpleBookmark, чтобы получить название канвы дерева (так называются «закладки» в спецификации PDF).

public void inspectPdf(String filename) throws IOException, DocumentException { 
    PdfReader reader = new PdfReader(filename); 
    List<HashMap<String,Object>> bookmarks = SimpleBookmark.getBookmark(reader); 
    for (int i = 0; i < bookmarks.size(); i++){ 
     showTitle(bookmarks.get(i)); 
    } 
    reader.close(); 
} 

public void showTitle(HashMap<String, Object> bm) { 
    System.out.println((String)bm.get("Title")); 
    List<HashMap<String,Object>> kids = (List<HashMap<String,Object>>)bm.get("Kids"); 
    if (kids != null) { 
     for (int i = 0; i < kids.size(); i++) { 
      showTitle(kids.get(i)); 
     } 
    } 
} 

Затем прочитайте ответ на этот вопрос: Set inherit Zoom(action property) to bookmark in the pdf file

Вы увидите, что HashMap<String, Object> не только содержит запись с ключом "Title", но он может также содержать запись с ключом "Page". Это тот случай, когда закладка указывает на страницу. Значение будет явным назначением. Он будет состоять из номера страницы, такого как Fit, FitH, FitB, XYZ, а затем некоторые параметры, которые отмечают позицию.

Если вы посмотрите на CreateOutlineTree Например, вы увидите, что вы можете также извлекать закладки в виде файла XML:

public void createXml(String src, String dest) throws IOException { 
    PdfReader reader = new PdfReader(src); 
    List<HashMap<String, Object>> list = SimpleBookmark.getBookmark(reader); 
    SimpleBookmark.exportToXML(list, 
      new FileOutputStream(dest), "ISO8859-1", true); 
    reader.close(); 
} 

Это скриншот из книги, которую я написал о IText, которая показывает, ключи можно ожидать в записи закладки:

enter image description here

как вы можете сказать, из этой таблицы, ссылка может быть также выражена как названного пункта назначения. В этом случае вы не получите номер страницы, а имя. Чтобы получить номер страницы, вам нужно извлечь список названных пунктов назначения. В этом списке вы получите явный пункт назначения, соответствующий указанному адресату.

Это также объясняется в книге, а также в official documentation.

После того, как у вас есть названия и номера страниц (извлеченные с кодом, написанным на основе вышеуказанных указателей), вы можете вставлять страницы в файл PDF с помощью PdfStamper и метода insertPage().Вы можете поместить TOC на эти страницы, используя ColumnText, или вы можете создать отдельный PDF для TOC и объединить его с оригинальным. См. How to add a cover/PDF in a existing iText document, чтобы узнать больше об этих двух методах.

Вы также извлечь выгоду из этого примера: Create Index File(TOC) for merged pdf using itext library in java

Что касается пунктирной линии между заголовком и номером страницы, что делается с помощью сепаратора, более конкретно разделитель пунктирной линии. Вы должны прочитать этот вопрос первым: iTextSharp - Is it possible to set a different alignment in the same cell for text

Тогда прочитайте этот вопрос: How to Generate Table-of-Figures Dot Leaders in a PdfPCell for the Last Line of Wrapped Text (или этот вопрос It is possible with itext 5 which at the end of a paragraph justified the remaining space is filled with scripts?)

Обратите внимание, что ваш вопрос на самом деле не по теме. Это формулируется как вопрос «домашнего труда». Он приглашает людей выполнять вашу работу на вашем месте. Теперь, когда у вас есть все элементы, которые вам нужны, вы должны иметь возможность самостоятельно выполнять эту работу. Если вам не удалось, вы должны написать вопрос по теме «Переполнение стека». Это вопрос, в котором вы показываете, что вы пробовали, и объясните техническую проблему, которую вы испытываете.

Update:

Опубликуйте документ со следующим контурным деревом:

enter image description here

Как вы можете видеть, закладки определяются с использованием именованных назначения, такой как /__WKANCHOR_2, /__WKANCHOR_4, и так далее. Как вы можете сказать из символа /, имена хранятся как объекты имени PDF (PDF 1.1), а не как объекты строки PDF (начиная с версии 1.2). В последних версиях PDF рекомендуется использовать объекты строки PDF вместо объектов имен PDF, вы можете попросить поставщика программного обеспечения для создания PDF-файлов обновить программное обеспечение в соответствии с рекомендациями последних стандартов PDF.

Тем не менее, мы можем легко получить явные адресатов, которые соответствуют указанным пунктам назначения. Они хранятся в /Dests записи корневого словаря:

enter image description here

Когда вы смотрите на то, как направления вы видите другую проблему, которая следует сообщать в wkhtmltopdf. Давайте посмотрим на то, что стандарт ISO говорит нам о синтаксисе, которые будут использоваться для направления:

enter image description here

Понятие номера страниц не существует в формате PDF. Страницы описываются с помощью словарей страниц, а номер страницы выводится из позиции страницы в дереве страниц. Первая страница, которая встречается в дереве страниц, - это страница 1, вторая страница, с которой встречаются, - страница 2 и т. Д.

В вашем примере адресации экспликации определены следующим образом: [9/XYZ 30.2400000 524.179999 0], [9/XYZ 30.2400000 231.379999 0] и так далее.

Это неправильно. В стандарте ISO говорится, что первое значение в массиве должно быть косвенной ссылкой. Косвенная ссылка имеет формат 9 0 R, а не 9. Я посмотрел на структуру документа, и я вижу, что wkhtmltopdf использует номер страницы - 1 вместо косвенной ссылки. Если я посмотрю на /__WKANCHOR_2, он будет ссылаться на [0/XYZ 30.240000 781.459999 0] и что 0 должен указывать на страницу 1.Поскольку Adobe Reader поддерживает дрянное программное обеспечение, это работает в Adobe Reader, но поскольку файл нарушает ISO-32000, iText не знает, что делать с этими вводящими в заблуждение пунктами назначения, по крайней мере, класс convience SimpleNamedDEstination не знает, что делать это.

К счастью, iText - это очень универсальная библиотека, которая позволяет вам углубляться под капот PDF. В этом случае нам нужно идти только на один уровень глубже. Вместо SimpleNamedDestination.getNamedDestination(reader, true), мы можем использовать следующий подход:

HashMap<String, PdfObject> names = reader.getNamedDestinationFromNames(); 
for (Map.Entry<String, PdfObject> entry: names.entrySet()) { 
    System.out.print(entry.getKey()); 
    System.out.print(": p"); 
    PdfArray arr = (PdfArray)entry.getValue(); 
    System.out.println(arr.getAsNumber(0).intValue() + 1); 
} 
reader.close(); 

Выход этого метода:

__WKANCHOR_w: p7 
__WKANCHOR_y: p7 
__WKANCHOR_2: p1 
__WKANCHOR_4: p1 
__WKANCHOR_16: p9 
__WKANCHOR_14: p8 
__WKANCHOR_18: p9 
__WKANCHOR_1s: p13 
__WKANCHOR_a: p2 
__WKANCHOR_1q: p13 
__WKANCHOR_1o: p12 
__WKANCHOR_12: p8 
__WKANCHOR_1m: p12 
__WKANCHOR_e: p3 
__WKANCHOR_10: p7 
__WKANCHOR_1k: p12 
__WKANCHOR_c: p3 
__WKANCHOR_1i: p11 
__WKANCHOR_i: p4 
__WKANCHOR_8: p2 
__WKANCHOR_g: p3 
__WKANCHOR_1g: p11 
__WKANCHOR_6: p1 
__WKANCHOR_1e: p10 
__WKANCHOR_m: p5 
__WKANCHOR_1c: p10 
__WKANCHOR_k: p4 
__WKANCHOR_q: p5 
__WKANCHOR_1a: p9 
__WKANCHOR_o: p5 
__WKANCHOR_u: p6 
__WKANCHOR_s: p6 

Если мы проверяем __WKANCHOR_2, мы видим, что он правильно указывает на странице 1. Я проверил окончательная ссылка в очертаниях, указывает на названный пункт назначения с именем __WKANCHOR_1s и действительно: это должно быть указано на странице 13.

Ваша проблема - яркий пример проблемы «мусора в мусоре». Ваш инструмент создает PDF-файлы, которые нарушают стандарт ISO для PDF, и в результате вы теряете много времени, пытаясь понять, что не так. Но что еще хуже: вы заставили меня потерять время из-за чужой ошибки.

+0

Эта строка: 'HashMap map = SimpleNamedDestination.getNamedDestination (reader, false); ' return empty –

+0

У вас есть свойство в закладке, чтобы вернуть номер страницы. Или анкер обратно на какой странице? –

+0

О вопросе do 'getNamedDestination' возвращает пустую передачу true или false –

Смежные вопросы