본문 바로가기
Project/pre-print-project

poppler-pdfinfo을 사용하여 pdf 페이지 수 계산 - 장고 프로젝트

by 지식을 쌓는 개구리 2023. 8. 12.

2023 pre-print 개발일지

 

8-10~8-12

 

기존에는 PyPDF2 라는 파이썬 pdf라이브러리를 사용하여 pdf페이지 수를 측정하고 있었는데

일부 pdf에서는 페이지 수를 파악할 수 없는 현상이 발생했다.

 

pdf의 서로다른 형식 때문인지, 한글, 워드, ppt등에서 pdf로 변환될 때 설정 때문인건지

pdf의 자체의 버전, 보안 때문인지 알 수 없었다.

 

정말 오랜 시간을 들여 PyPDF2 뿐 아니라 PyMuPDF, pdfminer 이 두가지 라이브러리도 설치하여

진행해 보았으나 특정 pdf의 페이지수를 파악하지 못하는 상황이 반복되었다.

 

그렇게 계속 도전 끝에 문제를 해결하였는데

해답은 외부라이브러리인 poppler의 pdfinfo를 사용하는 것이다.

 

외부 라이브러리 poppler의 설치방법과 pdfinfo를 통해 모든 pdf의 페이지 수를 파악할 수 있는 방법을

기록하려 한다.

 

아나콘다 다운로드

리눅스나 맥os 환경의 경우는 정말 쉽게 Poppler를 다운받을 수 있다.

-Linux- 패키지 관리자

sudo apt-get install poppler-utils

-macOS- 홈브류

brew install poppler

 

하지만 윈도우의 경우 쉽게 다운받기 힘들기 때문에 poppler의 설치를 위해 아나콘다를 다운받아야 한다.

아래 링크에서 설치를 완료하자.

https://www.anaconda.com/download

 

Free Download | Anaconda

Anaconda's open-source Distribution is the easiest way to perform Python/R data science and machine learning on a single machine.

www.anaconda.com

 

설치가 완료되었다면

윈도우 검색창에 Anaconda Powershell Prompt를 실행해준다.

이후 콘다 프롬프트에서 아래의 단계에 걸쳐 poppler를 설치해준다.

 

1. 콘다 환경 생성 

conda create --name poppler_env

 

2. 콘다 환경 활성화

conda activate poppler_env

 

3. poppler 설치

conda install -c conda-forge poppler

 

이렇게 하면 poppler가 설치되며 pdfinfo도 설치가 완료된다.

 

pdfinfo의 위치

위와 같이 잘 과정을 잘 따라왔다면 

내pc > 로컬디스크C > 사용자 > anaconda3 > Library > bin 

=> 이 경로에서 pdfinfo를 찾을 수 있다.

 

터미널로 1차 테스트 하기

poppler 를 잘 설치완료 하였다면 이제 터미널에서 pdf파일 아무거나 잘 나오는지 테스트 해보자

 

-터미널-

C:\Users\Owner\anaconda3\Library\bin\pdfinfo.exe "C:\Users\Owner\Documents\test\noCount.pdf"

=> 이와 같은 형식으로 맨 앞에 pdfinfo.exe의 경로를 쓴 후 그 뒤에 따옴표로 테스트할 pdf의 경로를 입력해주면 된다.

 

-출력결과-

Title:
Subject:
Author:
Creator:         Canon iR-ADV 4545 III
Producer:        Adobe PSL 1.3e for Canon
CreationDate:    Mon Jul 24 12:03:34 2023 대한민국 표준시
Custom Metadata: no
Metadata Stream: yes
Tagged:          no
UserProperties:  no
Suspects:        no
Form:            none
JavaScript:      no
Pages:           5
Encrypted:       no
Page size:       595.2 x 841.8 pts (A4)
Page rot:        0
File size:       17664592 bytes
Optimized:       no
PDF version:     1.4

=> 이렇게 정상적으로 문제가 있던 pdf의 모든 정보와 페이지 수까지 잘 나오는 것을 확인할 수 있다.

 

장고 프로젝트에서 파이썬으로 페이지 수 확인하기

문제가 잘 해결되었으니 이제 파이썬으로 이를 자동화 해보자.

import subprocess
import tempfile
 
def get_pdf_page_count(pdf_path):
    cmd = ["C:\\Users\\Owner\\anaconda3\\Library\\bin\\pdfinfo.exe", pdf_path]
    try:
        output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
        for line in output.stdout.decode('utf-8').splitlines():
            if "Pages:" in line:
                return int(line.split(":")[1].strip())
        return 0
    except subprocess.CalledProcessError:
        return 0

def print_detail(req):
    if req.method == "GET":
        if not req.user.is_authenticated:
            return redirect('accounts:login')
        else:
            return render(req, "print_detail.html")
    elif req.method == "POST":
        files = req.FILES.getlist('files')
        color = req.POST['color']
        pw = req.POST['pw']

        if not files or not pw:
            messages.error(req, "비밀번호 4자리를 채워주세요")
            return render(req, "print_detail.html")
       
        # 페이지 계산
        total_pages = 0
        for file in files:
            with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmpfile:
                for chunk in file.chunks():
                    tmpfile.write(chunk)
               
                total_pages += get_pdf_page_count(tmpfile.name)
       
        order_price = total_pages * 100

        order = Order.objects.create(order_user=req.user, order_price=order_price, order_pw=pw, order_color=color)

        for file in files:
            OrderFile.objects.create(order=order, file=file)
       
        return redirect('payment')

=> 전체코드는 다음과 같다. 

자세히 설명해보자면

 

-페이지 수 추출 함수-

import subprocess

def get_pdf_page_count(pdf_path):
    cmd = ["C:\\Users\\Owner\\anaconda3\\Library\\bin\\pdfinfo.exe", pdf_path]
    try:
        output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True)
        for line in output.stdout.decode('utf-8').splitlines():
            if "Pages:" in line:
                return int(line.split(":")[1].strip())
        return 0
    except subprocess.CalledProcessError:
        return 0

=> 위 함수에서 pdfinfo를 호출하여 PDF파일의 페이지수를 얻는다. 이후 subprocess모듈을 통해 외부명령을 실행하고 결과를 파싱한다.

 

-페이지 수 계산 로직-

        total_pages = 0
        for file in files:
            with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as tmpfile:
                for chunk in file.chunks():
                    tmpfile.write(chunk)
               
                total_pages += get_pdf_page_count(tmpfile.name)
       

=> preprint의 경우 웹에서 파일을 업로드 하기에 웹에서 업로드된 파일을 임시파일로 저장하고 이 이미 파일의 경로를

get_pdf_page_count함수로 전달하여 페이지 수를 얻는다.

 

 

 

 

페이지 수 계산 문제 때문에 2~3일 동안 꽤나 골머리를 앓았는데

일반 적인 pdf라이브러리에서 왜 일부 pdf가 페이지 수 파악이 안되는지는 알 수가 없다.

추가로 공부해봐야할 사항이지만 이 문제를 해결해나가면서 여러 파이썬 라이브러리와 모듈들을

사용해보는 경험을 해본 것이 참 값지다고 생각한다.

또 문제를 해결했으니까!