Запись PyPDF2 не работает с некоторыми файлами PDF (Python 3.5.1)

Прежде всего, я использую Python 3.5.1 (32-разрядная версия). Я написал следующую программу для добавления номера страницы на все страницы моих файлов PDF с использованием PyPDF2 и reportlab:

#import modules
from os import listdir
from PyPDF2 import PdfFileWriter, PdfFileReader
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
#initial values of variable declarations
PDFlist=[]
X_value=460
Y_value=820
#Make a list of al files in de directory
filelist = listdir()
#Make a list of all pdf files in the directory
for i in range(0,len(filelist)):
    filename=filelist[i]
    for j in range(0,len(filename)):
        char=filename[j]
        if char=='.':
            extension=filename[j+1:j+4]
            if extension=='pdf':
                PDFlist.append(filename)
        j=j+1
    i=i+1
# Give the horizontal position for the page number (Enter = use default value of 480)
User = input('Give horizontal position page number (ENTER = default 460): ')
if User != "":
    X_value=int(User)
# Give the vertical position for the page number (Enter = use default value of 820)
User = input('Give horizontal position page number (ENTER = default 820): ')
if User != "":
    Y_value=int(User)

for i in range(0,len(PDFlist)):
    filename=PDFlist[i]

    # read the PDF
    existing_pdf = PdfFileReader(open(filename, "rb"))
    print("File: "+filename)
    # count the number of pages
    number_of_pages = existing_pdf.getNumPages()
    print("Number of pages detected:"+str(number_of_pages))
    output = PdfFileWriter()

    for k in range(0,number_of_pages):
        packet = io.BytesIO()

        # create a new PDF with Reportlab
        can = canvas.Canvas(packet, pagesize=A4)
        Pagenumber=" Page "+str(k+1)+"/"+str(number_of_pages)
        # we first make a white rectangle to cover any existing text in the pdf
        can.setFillColorRGB(1,1,1)
        can.setStrokeColorRGB(1,1,1)
        can.rect(X_value-10,Y_value-5,120,20,fill=1)
        # set the font and size
        can.setFont("Helvetica",14)
        # choose color of page numbers (red)
        can.setFillColorRGB(1,0,0)
        can.drawString(X_value, Y_value, Pagenumber)
        can.save()
        print(Pagenumber)

        #move to the beginning of the StringIO buffer
        packet.seek(0)
        new_pdf = PdfFileReader(packet)
        # add the "watermark" (which is the new pdf) on the existing page
        page = existing_pdf.getPage(k)
        page.mergePage(new_pdf.getPage(0))
        output.addPage(page)
        k=k+1
    # finally, write "output" to a real file

    ResultPDF="Output/"+filename
    outputStream = open(ResultPDF, "wb")
    output.write(outputStream)
    outputStream.close()
    i=i+1

Эта программа отлично работает для большого количества PDF-файлов (хотя иногда генерируются предупреждения, такие как «PdfReadWarning: Superfluous whitespace found in object header b'16' b'0' [pdf.py:1666]», но полученный выходной файл меня устраивает). Однако программа просто не работает с некоторыми файлами PDF, хотя эти файлы прекрасно читаются и редактируются с помощью моего Adobe Acrobat. У меня сложилось впечатление, что ошибка появляется в основном в отсканированных PDF-файлах, но не во всех (я также пронумеровал отсканированные PDF-файлы, которые не вызвали никаких ошибок). Я получаю следующее сообщение об ошибке (первые 8 строк являются результатом моих собственных команд печати):

File: Scanned file.pdf
Number of pages detected:6
 Page 1/6
 Page 2/6
 Page 3/6
 Page 4/6
 Page 5/6
 Page 6/6
PdfReadWarning: Object 25 1 not defined. [pdf.py:1629]
Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\Sourcecode\PDFPager.py", line 83, in <module>
    output.write(outputStream)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 482, in write
    self._sweepIndirectReferences(externalReferenceMap, self._root)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 571, in _sweepIndirectReferences
    self._sweepIndirectReferences(externMap, realdata)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 547, in _sweepIndirectReferences
    value = self._sweepIndirectReferences(externMap, value)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 571, in _sweepIndirectReferences
    self._sweepIndirectReferences(externMap, realdata)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 547, in _sweepIndirectReferences
    value = self._sweepIndirectReferences(externMap, value)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 556, in _sweepIndirectReferences
    value = self._sweepIndirectReferences(externMap, data[i])
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 571, in _sweepIndirectReferences
    self._sweepIndirectReferences(externMap, realdata)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 547, in _sweepIndirectReferences
    value = self._sweepIndirectReferences(externMap, value)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 556, in _sweepIndirectReferences
    value = self._sweepIndirectReferences(externMap, data[i])
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 577, in _sweepIndirectReferences
    newobj = data.pdf.getObject(data)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\site-packages\PyPDF2\pdf.py", line 1631, in getObject
    raise utils.PdfReadError("Could not find object.")
PyPDF2.utils.PdfReadError: Could not find object.

По-видимому, страницы объединены с PDF-файлом, созданным reportlab (см. Строки до страницы 6/6), но, в конце концов, PyPDF2 не может создать выходной PDF-файл (я получаю нечитаемый выходной файл размером 0 байт). Может кто-нибудь пролить свет на то, как это решить? Я искал в Интернете, но не мог найти ответ.


person Max Eisert    schedule 31.08.2017    source источник
comment
У меня было такое же сообщение об ошибке при вызове той же функции. Можно ли заполнить ваш PDF-файл? Проблема была решена, когда я преобразовал PDF в обычный PDF только для чтения.   -  person SYK    schedule 01.08.2018
comment
Тем временем я также нашел обходной путь, распечатав файл PDF через принтер PDF, проблема решена.   -  person Max Eisert    schedule 02.08.2018
comment
ха-ха, да, это действительно эквивалентно.   -  person SYK    schedule 03.08.2018
comment
Я думаю, прежде чем сливать файлы, сначала проверьте, не битые ли файлы. Затем объедините их. Если файлы повреждены или загружены не полностью, слияние не удастся.   -  person GoingMyWay    schedule 20.06.2019
comment
Файлы не битые. Я мог читать их с помощью читалки PDF без проблем. Однако я не мог объединить их, используя код Python.   -  person Max Eisert    schedule 21.06.2019


Ответы (3)


В pdf.py внесите следующие изменения:

в строке 1633 pdf. py (что означает раскомментирование if self.strict)

    if self.strict:
        raise utils.PdfReadError("Could not find object.")

и в строке 501 в pdf.py внесите следующие изменения (добавив попытку, кроме блока)

    try:
        obj.writeToStream(stream, key)
        stream.write(b_("\nendobj\n"))
    except:
        pass

Ваше здоровье.

person bmg    schedule 07.10.2018
comment
Прохладный. Это исправление обязательно должно быть добавлено в master. Однако кажется, что pypdf2 сейчас не поддерживается :( - person Shaohua Li; 16.09.2019
comment
Это же исправление устраняет ту же проблему на pypdf4; Я разместил ссылку на эту тему в ветке для соответствующей ошибки. pypdf4 кажется менее активным, чем pypdf2. - person Watusimoto; 03.01.2020
comment
@Watusimoto, спасибо, что сообщили мне! Я добавил комментарий под ним. Будем надеяться, что владелец репо это заметит. - person bmg; 05.01.2020
comment
@bmg — я также разместил этот вопрос в соответствующей проблеме Github, не стесняйтесь отвечать здесь или там, и я X-пост. Мы хотим включить ваш обходной путь, чтобы обойти эту проблему, но не уверены в последствиях. Похоже, ошибка просто игнорируется, а преднамеренное, можно предположить, условное нефиксирование. Есть ли у вас понимание, почему это решает проблему и приведет ли это к удалению содержимого из документа? - person mwakerman; 17.06.2020

Использование «strict = false» заставило меня работать.

from PyPDF2 import PdfFileMerger

pdfs = [r'file 1.pdf', r'file 2.pdf']

merger = PdfFileMerger(strict=False)

for pdf in pdfs:
    merger.append(pdf)

merger.write(r"thanks mate.pdf")
person Ninga    schedule 10.06.2019
comment
Эй, да, я только что перезапустил его с установленным значением True, и документ все еще был создан, просто с кучей предупреждений. Я думал, что это устранило проблему с тем, что новый документ не создавался, однако моя проблема, должно быть, была другой. - person Ninga; 20.06.2019
comment
Я думаю, прежде чем сливать файлы, сначала проверьте, не битые ли файлы. Затем объедините их. Если файлы повреждены или загружены не полностью, слияние не удастся. - person GoingMyWay; 20.06.2019
comment
Я пытаюсь не объединять целые файлы PDF, а некоторые страницы. Я все еще получаю сообщение об ошибке со strict=False. Изменение pdf.py с указанными изменениями работает. Итак, pdf.py так и не был исправлен? - person Sudhik; 07.01.2021

Вот мое решение. Попробуйте записать файл в фиктивный поток ByteIO, чтобы проверить, не поврежден ли он.

    try:
        reader = PdfFileReader(input_file)
        print("Opening '{}', pages={}".format(file_path, reader.getNumPages()))
        # Try to write it into an dummy ByteIO stream to check whether pdf is broken
        writer = PdfFileWriter()
        writer.addPage(reader.getPage(0))
        writer.write(io.BytesIO())
    except PdfReadError:
        print("Error reading '{}".format(file_path))
        continue

    
person Yue Zhang    schedule 05.07.2020