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()
실행 결과


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()
실행 결과


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()
실행 결과


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()
실행 결과
