5
def EncryptPDFFiles(password, directory):
    pdfFiles = []
    success = 0

    # Get all PDF files from a directory
    for folderName, subFolders, fileNames in os.walk(directory):
        for fileName in fileNames:
            if (fileName.endswith(".pdf")):
                pdfFiles.append(os.path.join(folderName, fileName))
    print("%s PDF documents found." % str(len(pdfFiles)))

    # Create an encrypted version for each document
    for pdf in pdfFiles:
        # Copy old PDF into a new PDF object
        pdfFile = open(pdf,"rb")
        pdfReader = PyPDF2.PdfFileReader(pdfFile)
        pdfWriter = PyPDF2.PdfFileWriter()
        for pageNum in range(pdfReader.numPages):
            pdfWriter.addPage(pdfReader.getPage(pageNum))
        pdfFile.close()

        # Encrypt the new PDF and save it
        saveName = pdf.replace(".pdf",ENCRYPTION_TAG)
        pdfWriter.encrypt(password)
        newFile = open(saveName, "wb")
        pdfWriter.write(newFile)
        newFile.close()
        print("%s saved to: %s" % (pdf, saveName))


        # Verify the the encrypted PDF encrypted properly
        encryptedPdfFile = open(saveName,"rb")
        encryptedPdfReader = PyPDF2.PdfFileReader(encryptedPdfFile)
        canDecrypt = encryptedPdfReader.decrypt(password)
        encryptedPdfFile.close()
        if (canDecrypt):
            print("%s successfully encrypted." % (pdf))
            send2trash.send2trash(pdf)
            success += 1

    print("%s of %s successfully encrypted." % (str(success),str(len(pdfFiles))))

I am following along with Pythons Automate the Boring Stuff section. I've had off and on issues when doing the copy for a PDF document but as of right now everytime I run the program my copied PDF is all blank pages. There are the correct amount of pages of my newly encrypted PDF but they are all blank (no content on the pages). I've had this happen before but was not able to recreate. I've tried throwing in a sleep before closing my files. I'm not sure what the best practice for opening and closing files are in Python. For reference I'm using Python3.

stryker14
  • 53
  • 1
  • 7

2 Answers2

7

Try moving the pdfFile.close to the very end of your for loop.

for pdf in pdfFiles:
    #
    # {stuff}
    #
    if (canDecrypt):
        print("%s successfully encrypted." % (pdf))
        send2trash.send2trash(pdf)
        success += 1

    pdfFile.close()

The thought is that the pdfFile needs to be available and open when the pdfWriter finally writes out, otherwise it cannot access the pages to write the new file.

James C. Taylor
  • 430
  • 3
  • 8
  • 2
    Thank you, this appears to have worked (had to close it before sending it to the trash however in my particular example). You definitely seem to be correct in that the pdfReader needs to remain open until the pdfWriter has written and closed. I guess I had the false assumption that the "getPage" function created all the information needed for the writer. If the writer is dependant on the reader still being opened even though you've stored a page object from it, it seems counter-intuitive. Thanks again! – stryker14 Jun 07 '17 at 10:58
1

The issue with getting a blank page even after adding a page to your pdf with writer.addPage(your_page_name) is the context manager. You have to make sure that you're not closing the pdf from which you're reading the page.

For Example:

with open(str(_pdf), "rb") as in_f:
    reader = PdfFileReader(in_f)
    _page = reader.getPage(0)
    writer = PdfFileWriter()
    writer.addPage(_page)

with open(_filename, "wb+") as out_f:
    writer.write(out_f)

This will NOT WORK since the file handle is being closed by the context manager. The file has to be open So we would have to indent it. Like the following:

with open(str(_pdf), "rb") as in_f:
    reader = PdfFileReader(in_f)
    _page = reader.getPage(0)
    writer = PdfFileWriter()
    writer.addPage(_page)

    with open(_filename, "wb+") as out_f:
        writer.write(out_f)

I know it's not a big deal but this literally made me pull out my hair, indentation wasted my 6 hours. That's why I thought I should write an answer for others

Mujeeb Ishaque
  • 2,259
  • 24
  • 16