читать, выделять, сохранять PDF программно

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

Если бы кто-нибудь мог указать мне на учебник, пример или какую-то полезную документацию, чтобы я начал, я был бы очень признателен!


person Jake    schedule 30.09.2011    source источник
comment
Как правило, это не на 100% надежно, как любой PDF-компилятор - даже старый и надежный, такой как pdftex, может отображать pdf-инлайны в любом месте ... Вы уверены, что ваши PDF-файлы можно читать таким образом?   -  person Gleno    schedule 30.09.2011
comment
На мой взгляд, функция «найти» в Evince (или в большинстве других программ для чтения PDF-файлов, если уж на то пошло) делает в основном то, что мне нужно — выделяет совпадающий текст практически в любом PDF-файле. Если он может отобразить такую ​​подсветку на экране, почему бы не отобразить ее в файл?   -  person Jake    schedule 30.09.2011
comment
Это немного сложно, потому что PDF обычно не обеспечивает поток текста. Это больше похоже на изображение — текст может появиться где угодно. Часто это выглядит хорошо для читателя, но внутренне беспорядок. А именно: часто выравнивание текста достигается путем разбиения текста и простого размещения встроенных строк, чтобы он выглядел выравниваемым. В любом случае, когда Evince выделяет что-то, это либо умно, либо ваш PDF-файл ведет себя хорошо, либо вам просто повезло, потому что эта конкретная строка находится в PDF-файле как непрерывный объект. В любом случае, взгляните на itextpdf.com — это лучшая бесплатная библиотека.   -  person Gleno    schedule 30.09.2011
comment
Вы когда-нибудь находили ответ на этот вопрос? Если да, то хотелось бы услышать :)   -  person mitchus    schedule 09.04.2013
comment
Для тех, кто приходит сюда через Google: Как извлечь выделенные части из файлов PDF   -  person Martin Thoma    schedule 01.09.2020


Ответы (3)


Пробовали ли вы использовать PDFMiner? Похоже, он делает то, что вы хотите.

person Albert Perrien    schedule 30.09.2011
comment
Насколько я понимаю, PDFMiner нацелен на извлечение PDF-текста; не похоже, что он может выделить и преобразовать измененный PDF в файл. - person Jake; 30.09.2011

Да, это возможно с комбинацией pdfminer (pip install pdfminer.six) и PyPDF2.

Сначала найдите координаты (например, как это). Затем выделите его:

#!/usr/bin/env python

"""Create sample highlight in a PDF file."""

from PyPDF2 import PdfFileWriter, PdfFileReader

from PyPDF2.generic import (
    DictionaryObject,
    NumberObject,
    FloatObject,
    NameObject,
    TextStringObject,
    ArrayObject
)


def create_highlight(x1, y1, x2, y2, meta, color=[0, 1, 0]):
    """
    Create a highlight for a PDF.

    Parameters
    ----------
    x1, y1 : float
        bottom left corner
    x2, y2 : float
        top right corner
    meta : dict
        keys are "author" and "contents"
    color : iterable
        Three elements, (r,g,b)
    """
    new_highlight = DictionaryObject()

    new_highlight.update({
        NameObject("/F"): NumberObject(4),
        NameObject("/Type"): NameObject("/Annot"),
        NameObject("/Subtype"): NameObject("/Highlight"),

        NameObject("/T"): TextStringObject(meta["author"]),
        NameObject("/Contents"): TextStringObject(meta["contents"]),

        NameObject("/C"): ArrayObject([FloatObject(c) for c in color]),
        NameObject("/Rect"): ArrayObject([
            FloatObject(x1),
            FloatObject(y1),
            FloatObject(x2),
            FloatObject(y2)
        ]),
        NameObject("/QuadPoints"): ArrayObject([
            FloatObject(x1),
            FloatObject(y2),
            FloatObject(x2),
            FloatObject(y2),
            FloatObject(x1),
            FloatObject(y1),
            FloatObject(x2),
            FloatObject(y1)
        ]),
    })

    return new_highlight


def add_highlight_to_page(highlight, page, output):
    """
    Add a highlight to a PDF page.

    Parameters
    ----------
    highlight : Highlight object
    page : PDF page object
    output : PdfFileWriter object
    """
    highlight_ref = output._addObject(highlight)

    if "/Annots" in page:
        page[NameObject("/Annots")].append(highlight_ref)
    else:
        page[NameObject("/Annots")] = ArrayObject([highlight_ref])


def main():
    pdf_input = PdfFileReader(open("samples/test3.pdf", "rb"))
    pdf_output = PdfFileWriter()

    page1 = pdf_input.getPage(0)

    highlight = create_highlight(89.9206, 573.1283, 376.849, 591.3563, {
        "author": "John Doe",
        "contents": "Lorem ipsum"
    })

    add_highlight_to_page(highlight, page1, pdf_output)

    pdf_output.addPage(page1)

    output_stream = open("output.pdf", "wb")
    pdf_output.write(output_stream)


if __name__ == '__main__':
    main()
person Martin Thoma    schedule 13.07.2017
comment
привет, мы можем выделить всю строку, используя только одну координату Y? например только y1 и отмечать все слева направо? Благодарность! - person sygneto; 06.09.2019
comment
не уверен, почему за этот ответ больше не проголосовали :) .. спасение жизни .. большое спасибо автору - person Vikram Murthy; 24.02.2021

PDFlib имеет привязки Python и поддерживает эти операции. Вам понадобится PDI, если вы хотите открыть PDF. http://www.pdflib.com/products/pdflib-family/pdflib-pdi/ и ТЕТ.

К сожалению, это коммерческий продукт. Я использовал эту библиотеку в производстве в прошлом, и она отлично работает. Привязки очень функциональны и не очень Python. Я видел некоторые попытки сделать их более питоническими: https://github.com/alexhayes/pythonic-pdflib Вы можете использовать: open_pdi_document().

Похоже, вы захотите сделать какую-то подсветку поиска:

http://www.pdflib.com/tet-cookbook/tet-and-pdflib/highlight-search-terms/

person brianray    schedule 19.03.2015