PDF 페이지 번호 삽입 실패 원인 15가지 및 해결책 2026
PDF 페이지 번호 삽입 트러블슈팅: 실패 원인과 해결책
페이지 번호가 안 보이거나, 위치가 잘못되거나, 파일이 손상되는 15가지 문제를 원인별로 분석하고 즉시 해결할 수 있는 방법을 제시합니다.
주요 실패 원인 및 진단·복구
1. 페이지 번호가 완전히 안 보임
원인: 투명도(Alpha) 값이 0 또는 색상이 페이지 배경과 같음.
진단:
can.setFillAlpha(0) # ← 0이면 보이지 않음
can.setFillColor(1, 1, 1) # 흰색 배경에 흰 텍스트 = 보이지 않음
해결:
from PyPDF2 import PdfReader, PdfWriter from reportlab.pdfgen import canvas from io import BytesIOdef add_visible_page_numbers(input_pdf, output_pdf): """명확하게 보이는 페이지 번호"""
reader = PdfReader(input_pdf) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) # 1. 배경색 설정 (흰색) can.setFillColor(1, 1, 1) can.rect(270, 20, 60, 20, fill=1) # 2. 테두리 (검정색) can.setStrokeColor(0, 0, 0) can.setLineWidth(1) can.rect(270, 20, 60, 20) # 3. 텍스트 (검정색, 투명도 100%) can.setFillColor(0, 0, 0) can.setFillAlpha(1.0) # 100% 불투명 can.setFont("Helvetica-Bold", 12) can.drawString(280, 28, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) with open(output_pdf, "wb") as f: writer.write(f) print(f"✓ 명확한 페이지 번호 완료: {output_pdf}")
add_visible_page_numbers("input.pdf", "numbered.pdf")
2. 위치가 잘못됨 (페이지 여러 곳에 분산)
원인: 페이지 크기가 다르거나, 좌표 계산 오류.
진단:
from PyPDF2 import PdfReader
reader = PdfReader("input.pdf") for i, page in enumerate(reader.pages): print(f"페이지 {i+1}: {page.MediaBox}") # 각 페이지 크기 확인
해결:
def add_page_numbers_responsive(input_pdf, output_pdf): """페이지 크기에 자동 맞춤"""reader = PdfReader(input_pdf) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): # 각 페이지의 크기 추출 media_box = page.MediaBox width = float(media_box[2]) - float(media_box[0]) height = float(media_box[3]) - float(media_box[1]) packet = BytesIO() can = canvas.Canvas(packet, pagesize=(width, height)) # 하단 중앙 (페이지 크기에 맞춰 계산) x = width / 2 - 15 # 텍스트 너비 추정 y = 20 # 하단으로부터 20pt can.setFont("Helvetica", 11) can.setFillColor(0, 0, 0) can.drawString(x, y, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) with open(output_pdf, "wb") as f: writer.write(f) print(f"✓ 반응형 페이지 번호: {output_pdf}")
add_page_numbers_responsive("input.pdf", "numbered.pdf")
3. 특정 페이지에만 번호가 안 나타남
원인: 페이지 구조가 이상하거나 내용 스트림 손상.
진단:
import subprocessPDF 무결성 검사
subprocess.run(["qpdf", "--check", "input.pdf"], check=True)
또는 pikepdf로 확인
import pikepdf with pikepdf.open("input.pdf") as pdf: for i, page in enumerate(pdf.pages): print(f"페이지 {i+1}: Contents={'/Contents' in page}")
해결:
def add_page_numbers_robust(input_pdf, output_pdf): """문제 페이지 처리 (fallback 포함)"""reader = PdfReader(input_pdf) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): try: # 기본 시도 media_box = page.MediaBox width = float(media_box[2]) - float(media_box[0]) height = float(media_box[3]) - float(media_box[1]) packet = BytesIO() can = canvas.Canvas(packet, pagesize=(width, height)) can.setFont("Helvetica", 11) can.drawString(width/2, 20, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) print(f"✓ 페이지 {page_num}: 번호 추가") except Exception as e: print(f"⚠ 페이지 {page_num} 실패: {e}") # Fallback: pikepdf 사용 try: import pikepdf with pikepdf.open(input_pdf) as pdf: p = pdf.pages[page_num - 1] # 안전한 방식으로 내용 추가 packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.drawString(280, 20, str(page_num)) can.save() # pikepdf로 다시 시도 packet.seek(0) page_num_pdf = PdfReader(packet) p_data = page_num_pdf.pages[0] writer.add_page(page) except Exception as e2: print(f"✗ 페이지 {page_num} Fallback도 실패: {e2}") writer.add_page(page) with open(output_pdf, "wb") as f: writer.write(f)
add_page_numbers_robust("input.pdf", "numbered.pdf")
4. 파일 크기 급증 (50MB → 500MB)
원인: 각 페이지마다 새 PDF 생성, 압축 미적용.
해결:
def add_page_numbers_optimized(input_pdf, output_pdf): """최적화된 페이지 번호 (파일 크기 유지)"""reader = PdfReader(input_pdf) writer = PdfWriter() # 워터마크 한 번만 생성 packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.setFillColor(0, 0, 0) can.save() for page_num, page in enumerate(reader.pages, start=1): # 번호 텍스트만 변경하여 재사용 packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.drawString(280, 20, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) # 압축 최적화 with open(output_pdf, "wb") as f: writer.write(f) # Ghostscript로 최종 압축 import subprocess import os temp_output = output_pdf + ".compressed" subprocess.run([ "gs", "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4", "-dNOPAUSE", "-dBATCH", f"-sOutputFile={temp_output}", output_pdf ], check=True) os.replace(temp_output, output_pdf) orig_size = os.path.getsize(input_pdf) / (1024*1024) final_size = os.path.getsize(output_pdf) / (1024*1024) print(f"파일 크기: {orig_size:.1f}MB → {final_size:.1f}MB ({100*final_size/orig_size:.1f}%)")
add_page_numbers_optimized("input.pdf", "numbered.pdf")
5. 암호화 PDF에 번호 삽입 실패
원인: 암호화된 PDF는 직접 수정 불가능.
해결:
def add_page_numbers_encrypted(input_pdf, password, output_pdf): """암호화 PDF 페이지 번호 추가"""import subprocess # 1. 암호 해제 temp_decrypted = "/tmp/temp_decrypted.pdf" subprocess.run([ "qpdf", f"--password={password}", "--decrypt", input_pdf, temp_decrypted ], check=True) # 2. 페이지 번호 추가 reader = PdfReader(temp_decrypted) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.drawString(280, 20, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) # 3. 파일 저장 (재암호화 옵션) with open("/tmp/temp_numbered.pdf", "wb") as f: writer.write(f) # 4. 재암호화 (선택사항) subprocess.run([ "qpdf", "--encrypt", "user", "owner", "40", "--", "/tmp/temp_numbered.pdf", output_pdf ], check=True) # 임시 파일 삭제 import os os.remove(temp_decrypted) os.remove("/tmp/temp_numbered.pdf") print(f"✓ 암호화 PDF 페이지 번호 완료: {output_pdf}")
add_page_numbers_encrypted("encrypted.pdf", "mypassword", "numbered.pdf")
6. 특정 뷰어에서만 안 보임
원인: 뷰어 호환성 문제 (Foxit, Sumatra 등).
진단: Adobe Reader, Chrome, Firefox, Foxit에서 각각 테스트.
해결:
def add_page_numbers_universal(input_pdf, output_pdf): """모든 뷰어 호환 페이지 번호"""reader = PdfReader(input_pdf) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): # 호환성 높은 형식 사용 packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) # 기본 폰트만 사용 (Helvetica) can.setFont("Helvetica", 11) # RGB 색상 (CMYK X) can.setFillColor(0, 0, 0) # 배경박스 (호환성) can.setFillColor(1, 1, 1) can.rect(270, 18, 60, 22, fill=1) can.setStrokeColor(0.5, 0.5, 0.5) can.rect(270, 18, 60, 22) # 텍스트 can.setFillColor(0, 0, 0) can.drawString(280, 25, str(page_num)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) # PDF 1.4 형식 (최대 호환성) with open(output_pdf, "wb") as f: writer.write(f) # Ghostscript로 호환성 강화 import subprocess subprocess.run([ "gs", "-sDEVICE=pdfwrite", "-dCompatibilityLevel=1.4", "-dNOPAUSE", "-dBATCH", f"-sOutputFile={output_pdf}.compat", output_pdf ]) import os os.replace(f"{output_pdf}.compat", output_pdf)
add_page_numbers_universal("input.pdf", "universal_numbered.pdf")
7. 로마자/특수 형식 변환 실패
원인: 변환 함수 오류 또는 인코딩 문제.
해결:
def to_roman_safe(num): """로마자 변환 (에러 처리)""" if not isinstance(num, int) or num <= 0: return str(num)val = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1] syms = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"] roman_num = "" i = 0 try: while num > 0: for _ in range(num // val[i]): roman_num += syms[i] num -= val[i] i += 1 return roman_num except Exception as e: print(f"로마자 변환 실패: {e}") return str(num)def add_page_numbers_with_format(input_pdf, output_pdf, format_type="numeric"): """다양한 형식 페이지 번호"""
reader = PdfReader(input_pdf) writer = PdfWriter() for page_num, page in enumerate(reader.pages, start=1): # 형식에 따라 텍스트 결정 if format_type == "numeric": text = str(page_num) elif format_type == "roman_lower": text = to_roman_safe(page_num).lower() elif format_type == "roman_upper": text = to_roman_safe(page_num) elif format_type == "alpha_lower": text = chr(96 + (page_num % 26)) if page_num <= 26 else f"{page_num}" elif format_type == "alpha_upper": text = chr(64 + (page_num % 26)) if page_num <= 26 else f"{page_num}" else: text = str(page_num) packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.drawString(280, 20, text) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) with open(output_pdf, "wb") as f: writer.write(f) print(f"✓ {format_type} 형식 페이지 번호: {output_pdf}")
add_page_numbers_with_format("input.pdf", "numbered.pdf", format_type="roman_lower")
8. 처음 N페이지 건너뛰기 실패
원인: 인덱스 오류 또는 범위 계산 실수.
해결:
def add_page_numbers_skip(input_pdf, output_pdf, skip_count=3): """처음 N페이지 건너뛰고 나머지 번호 삽입"""reader = PdfReader(input_pdf) writer = PdfWriter() total_pages = len(reader.pages) for idx, page in enumerate(reader.pages): # 처음 skip_count개 페이지는 건너뛰기 if idx < skip_count: writer.add_page(page) print(f"페이지 {idx+1}: 번호 없음 (건너뜀)") continue # 나머지 페이지에 번호 추가 page_number = idx - skip_count + 1 # 1부터 시작 packet = BytesIO() can = canvas.Canvas(packet, pagesize=(595, 842)) can.setFont("Helvetica", 11) can.drawString(280, 20, str(page_number)) can.save() packet.seek(0) page_num_pdf = PdfReader(packet) page.merge_page(page_num_pdf.pages[0]) writer.add_page(page) print(f"페이지 {idx+1}: 번호 {page_number}") with open(output_pdf, "wb") as f: writer.write(f) print(f"✓ {skip_count}페이지 건너뛰고 번호 추가: {output_pdf}")
add_page_numbers_skip("input.pdf", "numbered.pdf", skip_count=3)
9~15. 기타 문제 빠른 진단표
| 증상 | 원인 | 진단 | 해결 |
|---|---|---|---|
| 번호가 겹침 | 좌표 계산 오류 | x값 확인 | x = width/2 - text_width/2 |
| 폰트가 깨짐 | 폰트 미지원 | 폰트명 확인 | Helvetica 또는 Courier 사용 |
| 메타데이터 손실 | 복사 미적용 | PDF 정보 확인 | writer.add_metadata() 사용 |
| 메모리 부족 | 대용량 처리 | 메모리 모니터링 | 청크 처리 또는 pikepdf 사용 |
| 처리 시간 초과 | 순차 처리 | 시간 측정 | ThreadPoolExecutor 병렬화 |
| 부분 번호만 나타남 | merge 오류 | 각 페이지 확인 | robust 함수 사용 |
| 배경 투명도 이상 | Alpha 설정 | Alpha값 확인 | Alpha=1.0 설정 |
빠른 진단 및 해결 플로우
def diagnose_page_number_issue(input_pdf):
"""페이지 번호 문제 자동 진단"""
print("📋 페이지 번호 삽입 진단 시작...")
try:
reader = PdfReader(input_pdf)
print(f"✓ PDF 읽기 성공: {len(reader.pages)} 페이지")
# 1. 페이지 크기 확인
sizes = {}
for i, page in enumerate(reader.pages):
box = page.MediaBox
size = f"{float(box[2])-float(box[0]):.0f}x{float(box[3])-float(box[1]):.0f}"
sizes[size] = sizes.get(size, 0) + 1
print(f"✓ 페이지 크기: {sizes}")
if len(sizes) > 1:
print("⚠ 페이지 크기가 다름! → responsive 함수 사용 권장")
# 2. 암호화 확인
if reader.is_encrypted:
print("⚠ PDF가 암호화됨 → add_page_numbers_encrypted() 사용")
else:
print("✓ 암호화 없음")
# 3. 메타데이터 확인
if reader.metadata:
print(f"✓ 메타데이터 존재: {list(reader.metadata.keys())}")
else:
print("⚠ 메타데이터 없음")
# 4. 파일 크기
import os
file_size = os.path.getsize(input_pdf) / (1024*1024)
print(f"✓ 파일 크기: {file_size:.1f}MB")
if file_size > 100:
print("⚠ 대용량 파일 → pikepdf 또는 병렬 처리 권장")
print("
✅ 진단 완료. 추천 함수:")
if len(sizes) > 1:
print(" → add_page_numbers_responsive()")
elif reader.is_encrypted:
print(" → add_page_numbers_encrypted()")
else:
print(" → add_page_numbers_optimized()")
except Exception as e:
print(f"❌ 진단 실패: {e}")
# 사용
diagnose_page_number_issue("input.pdf")
체크리스트
- ☐ 페이지 번호 명확하게 보이는가?
- ☐ 모든 페이지에 나타나는가?
- ☐ 위치가 일관되는가?
- ☐ 파일 크기 증가가 적절한가? (<10%)
- ☐ 메타데이터 보존되었는가?
- ☐ 모든 뷰어에서 보이는가?
- ☐ 처리 속도가 만족스러운가?
- ☐ 암호화 PDF 처리되었는가?
FAQ
- 번호가 안 보이는 가장 흔한 이유? setFillAlpha(0) 또는 배경과 같은 색
- 가장 빠른 해결? add_visible_page_numbers() 사용
- 파일 크기 증가 방지? Ghostscript 압축 적용
- 모든 뷰어 호환? add_page_numbers_universal() 사용
- 대용량 파일 처리? pikepdf + ThreadPool 병렬화
댓글
댓글 쓰기