Как извлечь аннотации из PDF файла

Категория: Linux

Эта статья-руководство отражает пройденный мною путь от постановки вопроса "как извлечь выделенный текст (highlight) из PDF книги" до найденного решения. Времени на поиск решения я потратил немало, из-за чего не решился удалить описание тех программ и способов получения аннотаций, которые меня не устроили, либо работали не корректно.

Зачем это нужно?

Я читаю книги.. Когда я читаю печатное издание, то всегда оставляю липкие закладки на полях, отмечая тем самым интересную и важную для меня информацию. Через некоторое время после прочтения книги, я перелистываю эти закладки и сохраняю, либо анализирую отмеченную информацию. И такое ощущение, что так никто не делает.. По крайней мере, при чтении электронных книг. Ни один линуксовый PDF ридер (Foxit, Okular) не умеет экспортировать аннотации! Лишь немногие могут более-менее сносно показывать их в меню. Тем не менее, я обнаружил платный сервис, который умеет извлекать примечания из PDF - sumnotes.net. Импорт 50 примечаний (или страниц) бесплатный, а за 500 просят $7 в год.


Извлечение аннотаций на сервисе sumnotes, есть экспорт в TXT

Я задался целью найти именно консольную утилиту, которая умела бы извлекать аннотации. Сразу приведу работающее решение, а после него те, которые обнаружил в процессе.

Все действия проводились в Ubuntu 14.04.

Извлечение аннотаций из PDF с помощью poppler

Poppler - это python библиотека для работы с PDF файлами, которая умеет извлекать аннотации.

Ставим библиотеку python-poppler: (предполагается, что python уже установлен в системе)

sudo apt-get install python-poppler

Скрипт pdf_extract_annotations.py, который будет извлекать заметки/аннотации с помощью poppler:

import poppler
import sys
import urllib
import os

def main():
  input_filename = sys.argv[1]
  # http://blog.hartwork.org/?p=612
  document = poppler.document_new_from_file('file://%s' % \
    urllib.pathname2url(os.path.abspath(input_filename)), None)
  n_pages = document.get_n_pages()
  all_annots = 0

  for i in range(n_pages):
        page = document.get_page(i)
        annot_mappings = page.get_annot_mapping ()
        num_annots = len(annot_mappings)
        if num_annots > 0:
            for annot_mapping in annot_mappings:
                if  annot_mapping.annot.get_annot_type().value_name != 'POPPLER_ANNOT_LINK':
                    all_annots += 1
                    print 'page: {0:3}, {1:10}, type: {2:10}, content: {3}'.format(i+1, annot_mapping.annot.get_modified(), annot_mapping.annot.get_annot_type().value_nick, annot_mapping.annot.get_contents())

  if all_annots > 0:
    print str(all_annots) + " annotation(s) found"
  else:
    print "no annotations found"

if __name__ == "__main__":
    main()

Извлекаем аннотации из PDF файла:

python pdf_extract_annotations.py book.pdf

Пример вывода аннотаций:

page:   6, D:20160204112641Z00'00, type: text      , content: Тестовая заметка Adobe PDF Reader
page:   8, D:20160204113002+02'00', type: highlight , content: good practices

Leela PDF Annotation Extractor

Это C библиотека, которая предоставляет консольную утилиту leela (неужели та самая, из футурамы). Импортирует аннотации в XML формате, но структура не валидная. В общем использовать можно, но с костылями.

Установка зависимостей и компиляция:

git clone git@github.com:TrilbyWhite/Leela.git
sudo aptitude install libpoppler-glib-dev
cd Leela
make

Извлечь аннотации:

./leela annots book.pdf

Обработанный формат вывода:

<annot page="7" index="5" type="text">
  <rect x1="315.000000" y1="731.000000" x2="333.000000" y2="749.000000"/>
  <name>c9ff65f3-0caf-480b-9833-71c73f71c500</name>
  <color r="65535" g="65535" b="0"/>
  <label>Stanislav</label>
  </markup>
  <text>Тестовая заметка Adobe PDF Reader</text>
</annot>
<annot page="7" index="6" type="highlight">
  <rect x1="128.919000" y1="682.944000" x2="211.297000" y2="700.228000"/>
  <name>f4c04f7f-da60-4653-ac3e-343825a667fd</name>
  <color r="65535" g="65535" b="0"/>
  <text>good practices</text>
</annot>

Для получения нормальной разметки я набросал скрипт pdf_annotate_extract.sh:

annotations=$(./leela annots "$1" \
    | sed -r 's/\s<\/markup>//g' \
    | sed '/^\s*$/d' \
    | pcregrep -iM '<annot.*? type="(text|highlight)">(.|\n)+?</annot>')

xml=$(echo $annotations | xml_wrap.sh)

echo $xml

Формирование валидного XML (xml_wrap.sh):

echo '<?xml version="1.0"?><container>' $(cat) '</container>'

Другие утилиты для извлечения аннотаций

Изначально, я пытался получить аннотации с помощью таких утилит, как pdftotextpdftohtml и pdfgrep. Забудьте! Все они извлекают лишь "сырой" текст, никаких аннотаций.

PDF Xchange Viewer

Также, я нашел упоминание про хорошую поддержку аннотаций в виндовой программе pdf-xchange-viewer. Скачал портативную версию, запустил под wine. Есть функция экспорта аннотаций, называется "сводка комментариев", но только в PDF. 


Панель экспорта сводки комментариев и аннотаций

Сказано, что DEMO версия оставляет водяные знаки, но я их не обнаружил, м.б. где-то внизу листа.


Пример сводки комментариев

В общем, это не совсем то, что мне было нужно, идем дальше...

Mendeley

Это система обмена документами. Для моей задачи это избыточно, но я все же зарегистрировался и установил десктопную версию.

Интерфейс приятный, создание примечаний простое, но.. Утилита не от отображает список аннотаций, которые я добавил через Adobe и Foxit, хотя видит посдсвеченный текст и примечания. Дают 2GB места под документы, интегрируется с Zotero.


Клиентское приложение сервиса mendeley.com

pdfannotextractor.pl

Вот с этой штуковиной я изрядно повозился, но ничего толкового у меня не вышло - примеяания не удалось извлечь из-за ошибки "java.lang.Exception: Unsupported annotation subtype".

Нам понадобятся утилиты pax и texlive-latex-extra (весит не мало):

sudo apt-get install texlive-latex-extra pax

Установим зависимость PDFBox:

pdfannotextractor --install

* будет установлен PDFBox в ~/.texmf-var/scripts/pax/PDFBox-0.7.3.zip.

Извлекаем аннотации:

pdfannotextractor book.pdf

И в итоге я получил:

* Processing file `modern_php.pdf' ...
!!! Warning: Annotation on page 8 not recognized!
    java.lang.Exception: Unsupported annotation subtype: Text
!!! Warning: Annotation on page 8 not recognized!
    java.lang.Exception: Unsupported annotation subtype: Popup
!!! Warning: Annotation on page 8 not recognized!
    java.lang.Exception: Unsupported annotation subtype: Highlight

Копать дальше не хватило терпения.. Да и жавовский PDFBox довольно медленная штука.


Утилиты, которые я не проверил:

  • marginalia - https://github.com/nichtich/marginalia
  • PDFMiner - http://www.unixuser.org/~euske/python/pdfminer/

#extract annotations, #linux pdf highlight extractor

категория: Linux