Синтаксический анализ PDF на C++ (PoDoFo)

Привет, поэтому я пытаюсь разобрать текст из некоторых PDF-файлов, и я хотел бы использовать PoDoFo, теперь я попытался найти примеры того, как использовать PoDoFo для разбора pdf, однако все, что я могу придумать, это примеры того, как создавать и писать pdf-файл, который не то, что мне действительно нужно.

Если у кого-нибудь есть учебник или пример разбора PDF-файла с PoDoFo или есть предложения для другой библиотеки, которую я могу использовать, пожалуйста, дайте мне знать. Также я знаю, что есть pdftotext на linux, однако я не только не могу использовать это, но я бы предпочел сделать все, что мне нужно, внутри и не полагаться на внешние программы, устанавливаемые.

2 ответов


PoDoFo не предоставляет средства для легкого извлечения текста из документа, но это не трудно сделать.

загрузить документ PdfMemDocument:

PoDoFo::PdfMemDocument pdf("mydoc.pdf");

повторите каждую страницу:

for (int pn = 0; pn < pdf.GetPageCount(); ++pn) {
    PoDoFo::PdfPage* page = pdf.GetPage(pn);

повторите все команды PDF на этой странице:

    PoDoFo::PdfContentsTokenizer tok(page);
    const char* token = nullptr;
    PoDoFo::PdfVariant var;
    PoDoFo::EPdfContentsType type;
    while (tok.ReadNext(type, token, var)) {
        switch (type) {
            case PoDoFo::ePdfContentsType_Keyword:
                // process token: it contains the current command
                //   pop from var stack as necessary
                break;
            case PoDoFo::ePdfContentsType_Variant:
                // process var: push it onto a stack
                break;
            default:
                // should not happen!
                break;
        }
    }
}

комментарии "маркер процесса" и "process var" - это то, где он становится немного сложнее. Вам предоставляются необработанные команды PDF для обработки. К счастью, если вы на самом деле не представляя страницы и все, что вам нужно, это текст, вы можете игнорировать большинство из них. Команды, которые вам нужно обработать:

BT, ET, Td, TD, Ts, T, Tm, Tf, ", ', Tj и TJ

на BT и ET команды отмечают начало и конец текстового потока, поэтому вы хотите игнорировать все, что не находится между BT/ET пара.

язык PDF основан на RPN. Поток команд состоит из значения, которые помещаются в стек, и команды, которые выводят значения из стека и обрабатывают их.

на ", ', Tj и TJ команды являются единственными, которые фактически генерируют текст. ", ' и Tj возвращает одну строку. Использовать var.IsString() и var.GetString() для ее обработки.

TJ возвращает массив строк. Вы можете извлечь каждый из них с:

if (var.isArray()) {
    PoDoFo::PdfArray& a = var.GetArray();
    for (size_t i = 0; i < a.GetSize(); ++i)
        if (a[i].IsString())
            // do something with a[i].GetString()

другие команды используются, чтобы определить, когда ввести строку. " и ' также ввести разрывы строк. Лучше всего загрузить спецификацию PDF из Adobe и посмотреть раздел обработки текста. Он объясняет, что каждая команда делает более подробно.

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

Примечание: Если все, что вы делаете извлечение сырого текста без информации о местоположении, вы на самом деле не нужно поддерживать стек var значения. Все команды отрисовки текста имеют не более одного параметра. Вы можете просто предположить, что последнее значение в var содержит параметр для текущей команды.


Я не использовал PoDoFo, но быстрый просмотр иерархии классов на их веб-странице API показывает:

void PoDoFo::PdfMemDocument::Load( const char * pszFilename )

(API doc link)

поэтому я бы просто рискнул предположить здесь, что вы делаете:

PoDoFo::PdfMemDocument doc;
doc.Load( "somefile.pdf" );

тогда я представляю, что вы перемещаетесь по дереву документов, вызывая doc.GetObjects() и пройдя через этот массив (см. pdfdocument class)