본문 바로가기

카테고리 없음

[PyMuPDF] python으로 PDF에 텍스트 삽입하기

1. PyMuPDF 라이브러리란?

- 파이썬 라이브러리로 pdf 문서를 읽고, 쓰고, 수정 할 수 있는 라이브러리.

- python을 활용하여 pdf 편집하던지 pdf 편집 자동화 프로그램을 작성하고 싶을 때 유용한 라이브러리입니다.

 

(파이썬으로 PDF 문서 편집을 위해 가장 먼저 검색되는 파이썬 라이브러리는 PyPDF였음. 하지만 pypdf는 버전이 업그레이드되면서 기본 명령어들이 바뀌어서 검색되는 자료나 이슈 해결법들도 버전을 잘 구분해서 봐야한다는 점이 개인적으로 명령어나 사용법을 익히기에 헷갈렸고 chatGPT도 예전 버전 명령어를 알려줘서 chatCPT를 같이 쓰면서 코드를 작성하면 오류를 수정하는데에 한세월이 걸렸다. 그래서 개인적으로 PyMuPDF를 쓰는게 더 효율적이라고 느낌)

 

2. PyMuPDF 라이브러리 설치

pip 명령어로 쉽게 설치 가능합니다. 명령프롬프트나 터미널에 아래 명령어를 입력하여 설치하면 됩니다.

pip install pymupdf

 

pip 명령어가 없다면 pip를 먼저 설치해주시고, pip가 있는데 설치가 안 된다면 아래 명령어로 pip upgrade를 먼저 실행해보시길.

python -m pip install --upgrade pip

 

3. PyMuPDF 사용법

3-1. pdf 파일에 텍스트 삽입

import fitz

# 수정을 원하는 pdf 열기
doc = fitz.open("a.pdf") # 파일명 또는 파일 경로를 입력

# 삽입하고 싶은 텍스트 입력
text = "hello world!"

# 삽입할 위치 (x, y 좌표)
insert_position = (60, 60)  # 왼쪽 상단 (0,0) 기준으로 좌표 설정

#삽입할 페이지 선택
page = doc[0] #index가 0이면 첫번째 페이지 선택

#텍스트 삽입 함수 실행
page.insert_text(insert_position, text, fontsize=15, fontname="courier") # font 속성 수정가능

# Save the changes to a new PDF
doc.save('new.pdf')

# Close the PDF
doc.close()

 

실행 결과

왼쪽 이미지는 "a.pdf"로, 아무 내용이 없는 빈 페이지. 오른쪽 이미지는 "new.pdf"로 코드 실행으로 생성된 이미지.

3-2. 좌표를 다른 꼭지점 기준으로 설정하기

각 꼭지점을 기준으로 좌표값을 설정하는 간단한 예제입니다.

import fitz

#pdf 열기
doc = fitz.open('a.pdf')

# 삽입하고 싶은 텍스트 입력
text1 = "left_top"
text2 = "right_top"
text3 = "left_bottom"
text4 = "right_bottom"
text5 = "middle"

# 페이지의 넓이와 높이를 입력받는 함수
page_width = doc[0].rect.width # 첫번째 페이지의 가로 길이
page_height = doc[0].rect.height # 첫번째 페이지의 세로 길이

#삽입할 페이지 선택
page = doc[0] #index가 0이면 첫번째 페이지 선택

# left_top 삽입
insert_position = (30, 50)
#텍스트 삽입 함수 실행
page.insert_text(insert_position, text1, fontsize=15, fontname="courier")

# ritght_top 삽입
insert_position = (page_width-130, 50)
#텍스트 삽입 함수 실행
page.insert_text(insert_position, text2, fontsize=15, fontname="courier")

# left_bottom 삽입
insert_position = (30, page_height-50)
#텍스트 삽입 함수 실행
page.insert_text(insert_position, text3, fontsize=15, fontname="courier")

# right_bottom 삽입
insert_position = (page_width-130, page_height-50)
#텍스트 삽입 함수 실행
page.insert_text(insert_position, text4, fontsize=15, fontname="courier")

# middle 삽입
insert_position = (page_width//2, page_height//2)
#텍스트 삽입 함수 실행
page.insert_text(insert_position, text5, fontsize=15, fontname="courier")

# Save the changes to a new PDF
doc.save('new.pdf')

# Close the PDF
doc.close()

실행 결과

왼쪽 이미지는 "a.pdf"로, 아무 내용이 없는 빈 페이지. 오른쪽 이미지는 "new.pdf"로 코드 실행으로 생성된 이미지.

3-3. 여러장으로 구성된 pdf를 반목문을 사용하여 모든 페이지에 텍스트를 삽입하기

아래 예제는 모든 페이지에 페이지 번호를 다는 간단한 예제입니다.

import fitz

#pdf 열기
doc = fitz.open('b.pdf')

# 페이지의 넓이와 높이를 입력받는 함수
page_width = doc[0].rect.width # 첫번째 페이지의 가로 길이
page_height = doc[0].rect.height # 첫번째 페이지의 세로 길이

insert_position = (50, 50) # 좌측 상단에 위치

# 각 페이지의 인덱스 i와 page로 반복문 실행. 아래 주석으로 실행해도 가능
# for i in range(len(doc)):
#	page = doc[i]
#	text = f"{i+1}-page"
#   page.insert_text(insert_position, text, fontsize=15, fontname="courier")

for i, page in enumerate(doc):
    text = f"{i+1}-page"
    page.insert_text(insert_position, text, fontsize=15, fontname="courier")

# Save the changes to a new PDF
doc.save('new.pdf')

# Close the PDF
doc.close()

실행 결과

왼쪽 이미지는 "b.pdf"로, 아무 내용이 없는 빈 페이지 4장. 오른쪽 이미지는 "new.pdf"로 코드 실행으로 생성된 이미지.

4. 우리의 프로젝트에서 PyMuPDF 사용하기

요구사항

- 수능시험지를 입력받으면 시험지 세트마다 고유코드를 발급하고 각 페이지마다 그 코드에 몇번째 페이지인지 좌측 상단에 삽입한다.

- 첫번째 페이지의 우측 상단에는 응시자를 식별할 id 작성란을 만든다.

# 입력: 응시자수(생성할 시험지 부수), 시험지 파일
def insert_page_number(num_students, file_path):
    # 시험지 파일 열기
    pdf_document = fitz.open(file_path)
    
    # 시험지 한 부의 페이지 수
    num_pages = len(pdf_document)

    # 입력받은 파일의 넓이와 높이 구하기
    page_width = pdf_document[0].rect.width
    page_height = pdf_document[0].rect.height

    # 응시자 id 작성란 직선을 삽입할 위치
    start_point = (page_width - 180, 65)
    end_point = (page_width - 60, 65)


    for i in range(0, num_students):
    	# 저장할 경로 및 파일명 설정
        output_pdf_path = os.path.splitext(file_path)[0] + f"_{i+1}.pdf"
        pdf_document = fitz.open(file_path)

        # 첫 장에 응시자 ID 작성란 삽입
        page = pdf_document[0]
        text = "ID : "
        page.insert_text((page_width-220, 60), text, fontsize=16, fontname="courier")
        # 직선 그리는 함수 (시점, 종점) 
        page.draw_line(start_point, end_point)

        for j in range(0, num_pages):
            # 삽입할 코드는 "시험지 식별코드 - 페이지"로 구성 (예: "1-1", "1-2", ...)
            text = f"{i+1}-{j+1}"

            # 시험지 고유코드 삽입할 위치 (x, y 좌표)
            insert_position = (60, 60)  # 적절한 위치로 수정 필요

            page = pdf_document[j]
            page.insert_text(insert_position, text, fontsize=18, fontname="courier")

        # 한 세트 만들고 저장
        pdf_document.save(output_pdf_path)
        
        # pdf 닫기
        pdf_document.close()

실행 결과

코드 실행 결과, 첫번째 장 좌측 상단에는 시험지 식별코드, 우측 상단에는 ID 작성란