Слияние нестандартных PDF-файлов с pyPdf

Я хотел бы объединить пару файлов PDF в один документ PDF. Как оказалось, входные файлы не полностью соответствуют стандарту. За маркером EOF следует дополнительная информация:

>>
startxref
1994481
%%EOF

%%PPIRoute: 4

Очевидно, это приводит к pyPdf давая мне исключение:

pyPdf.utils.PdfReadError: EOF marker not found

Теперь вопрос: что мне делать? Я мог бы, вероятно, открыть каждый файл, удалить последние две строки и сохранить его, прежде чем бросать их в pyPdf. Однако мне эта идея не очень нравится. Может быть, есть лучший вариант?


person cyroxx    schedule 02.03.2013    source источник
comment
Создайте подкласс PdfFileReader, который делает то, что вы хотите, в своем методе read(). Либо создайте свой собственный смарт-объект stream и передайте его существующему методу read().   -  person martineau    schedule 02.03.2013
comment
Можно ли изменить pdf.py? Похоже, что было бы легко изменить его для решения проблемы (при условии, что можно удалить/игнорировать дополнительную информацию в файле (файлах)).   -  person martineau    schedule 02.03.2013


Ответы (1)


Я предлагаю изменить начало методаread()классаPdfFileReaderкласса в сценарии pdf.py с:

    def read(self, stream):
        # start at the end:
        stream.seek(-1, 2)
        line = ''
        while not line:
            line = self.readNextEndLine(stream)
        if line[:5] != "%%EOF":
            raise utils.PdfReadError, "EOF marker not found"

    ... etc

to:

    def read(self, stream):
        # start at the end:
        stream.seek(-1, 2)
        line = ''
        # read stream backwards while watching for end-of-file marker
        while line[:5] != "%%EOF":
            line = self.readNextEndLine(stream)

    ... etc

На мой взгляд, исходный код на самом деле не делает того, что подразумевается в разделе 3.4.4, «Трейлер файла» (стр. 628) в Adobe PDF 1.3 Reference документ, в котором говорится (курсив мой):

Программам просмотра Acrobat требуется только, чтобы маркер %%EOF отображался где-то в пределах последних 1024 байтов файла.

Другими словами, это нормально, если перед физическим концом файла после маркера "%%EOF" есть что-то еще. Изменения, которые я предлагаю, пытаются учесть это и заставить игнорировать все остальное, что могло быть добавлено в конец файла после маркера, а не вызывать исключение (однако это не требует, чтобы "%%EOF" было в последних 1 КБ, как указано в спецификации). говорит, хотя можно было бы добавить проверку на это). Это также означает, что файлы, которые вы пытаетесь объединить, могут фактически соответствовать спецификации.

Обновление:

Вот версия, которая также требует, чтобы the"%%EOF"marker находился в пределах последних 1024 байтов:

def read(self, stream):
    # start at the end
    stream.seek(-1, os.SEEK_END)
    last1K = stream.tell() - 1024 + 1 # offset of last 1024 bytes of stream

    # read stream backwards while watching for end-of-file marker
    line = ''
    while line[:5] != "%%EOF":
        line = self.readNextEndLine(stream)
        if stream.tell() < last1K:
            raise utils.PdfReadError, "EOF marker not found"

    ... etc
person martineau    schedule 02.03.2013
comment
cyroxx: Вы когда-нибудь пробовали то, что написано в моем ответе? - person martineau; 11.06.2013
comment
Пока нет, так как это небольшой проект, который я давно не изучал. Спасибо за ваш ответ, я прокомментирую / проголосую, как только попробую предложенное вами решение. - person cyroxx; 05.09.2013
comment
Когда строка пуста '', она говорит ... ValueError: недопустимый литерал для int() с основанием 10: '%%EOF' . Более ранний код не войдет в цикл. Какие мысли, Мартино? - person Nishant; 06.11.2013