[Python] PDF 파일 잠금 해제하기

1. 개요

 일을 하다보면 암호가 걸려있는 PDF 파일을 수정해야 할 일이 있습니다. 물론 서명을 위조하거나, 암호를 알아내는 것은 불가능하지만, 파일 내용을 그대로 복사하여 내용이 동일한 새로운 PDF 파일을 생성하는 방법으로 잠금을 해제하여 사용할 수 있습니다. (읽기가 막혀있는 파일은 안 됩니다.)

 

 다시 말해서, 암호가 걸려있는 파일과 동일한 내용의 새로운 파일을 생성하는 것입니다. 

 

 

이렇게 서명이 되어있거나
암호가 걸려있어 편집이나 인쇄가 불가한 경우가 있습니다.

 

 

2. 방법

pikepdf(pypi.org/project/pikepdf/)를 이용합니다.

 

준비물

1) pikepdf를 설치합니다.

 

커맨드창에서 입력

pip install pikepdf

2) 테스트를 위한 PDF 파일을 준비합니다. 

 

코드 순서

1) PDF 파일을 열고, 2) 내용을 복사하고 3)새로운 파일로 저장합니다.

 

과거에는 PyPDF2를 사용했으나, Acrobat이 아닌 다른 프로그램으로 작성한 PDF 파일은 오류가 발생하여 pikepdf로 변경하였고, 여러 파일에서 테스트 결과 문제 없이 작동이 잘 됩니다.

 

PyPDF2를 이용할 경우 발생한 에러

(PyPDF2.utils.PdfReadError: File has not been decrypted 에러 발생)

 

3. 코드

main2.py

import pikepdf

input_pdf = pikepdf.Pdf.open('test.pdf')
pdf = pikepdf.Pdf.new()

for n, page in enumerate(input_pdf.pages):
    pdf.pages.append(page)
    
pdf.save('test_decrypted.pdf')

 별도 설명이 필요가 없을 정도로 간단합니다.

 (1) input_pdf 변수에 test.pdf 파일을 불러오고,

 (2) pdf 변수에 새로운 PDF 인스턴스를 생성합니다.

 (3) input_pdf 파일을 읽어서 내용을 pdf 변수에 추가(append)하고 

 (4) test.decrypted.pdf 파일로 저장합니다.

 

 

 

다듬은 버전

실행할 때 파일 이름을 입력하도록 변경하였습니다.

 

main.py

import os
import pikepdf

def decrypt_pdf(file_name):
    input_path = os.path.join(os.getcwd(), file_name)
    output_path = os.path.join(os.getcwd(), "decrypted_"+file_name)
    input_pdf = pikepdf.Pdf.open(input_path)
    pdf = pikepdf.Pdf.new()

    for _, page in enumerate(input_pdf.pages):
        pdf.pages.append(page)
        
    pdf.save(output_path)
    input_pdf.close()
    print("saved at : {}".format(output_path))

if __name__ == "__main__":
    if len(os.sys.argv)>1:
        decrypt_pdf(os.sys.argv[1])
    else:
        print("re-run with file name")

위와 거의 동일하지만,

 1) 파일 이름 앞에 'decrypted_'가 들어가도록 변경하였고

 2) 커맨드라인에서 파일 이름과 함께 실행하도록 바꾸었습니다.

 

아래와 같은 방식으로 커맨드라인에서 실행합니다.

python main.py test.pdf

 

출력 결과

 

 

작동 영상

 

4. GUI로 만들기 (번외)

최근 PyQt를 조금 다룰 수 있게 되어,  GUI 프로그램으로 만들어 보았습니다.

 

실행 화면

'Select' 버튼을 눌러 파일을 선택하고 'Run' 버튼을 누르면 선택된 파일이 같은 경로에 암호 없이 복사됩니다.

 

코드 

gui.py

    import os
    import sys
    import pikepdf
    from PyQt5.QtWidgets import *

    class Window(QWidget):
        def __init__(self):
            super().__init__()
            self.setWindowTitle("decrypt pdf")
            self.setGeometry(350,150,400,100)
            self.UI()

        def UI(self):
            vbox=QVBoxLayout()
            hbox1=QHBoxLayout()
            hbox2=QHBoxLayout()
            
            self.pathEdit=QLineEdit()
            fileButton = QPushButton("Select")
            fileButton.clicked.connect(self.openFile)
            runButton = QPushButton("Run")
            runButton.clicked.connect(self.convert)

            hbox1.addWidget(self.pathEdit)
            hbox1.addWidget(fileButton)

            vbox.addLayout(hbox1)
            vbox.addLayout(hbox2)
        
            hbox2.addStretch()
            hbox2.addWidget(runButton)
            hbox2.addStretch()
            self.setLayout(vbox)
            self.show()

        def openFile(self):
            url = QFileDialog.getOpenFileName(self,"Select a File","","*.pdf")
            
            fileUrl = url[0]
            self.pathEdit.setText(fileUrl)

        def convert(self):

            file_path = self.pathEdit.text()
            if file_path == "":
                QMessageBox.about(self,"select a file")

            input_pdf = pikepdf.Pdf.open(file_path)
            pdf = pikepdf.Pdf.new()

            for _, page in enumerate(input_pdf.pages):
                pdf.pages.append(page)
            pdf.save(os.path.splitext(file_path)[0]+"_decrypt.pdf")
            
            QMessageBox.about(self,"done", "<p align='center'>Saved<br>"+os.path.splitext(file_path)[0]+"_decrypt.pdf</p>")
            print("done")        

    def main():
        App = QApplication(sys.argv)
        window = Window()
        sys.exit(App.exec_())

    if __name__ == '__main__':
        main()

 

 

모든 코드는 아래 깃허브에 있습니다.

감사합니다.

 

github 주소 : github.com/kminito/decrypt_pdf

 

kminito/decrypt_pdf

Contribute to kminito/decrypt_pdf development by creating an account on GitHub.

github.com

 

댓글

Designed by JB FACTORY