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 BytesIO

def 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 subprocess

PDF 무결성 검사

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 병렬화

관련 자료

댓글

이 블로그의 인기 게시물

전기기사 인강 추천: 합격을 위한 최적의 온라인 강의 선택 가이드

ktx 경부선 상행선 시간표 2025 정리: 부산→서울 주요 열차 운행 정보

미리캔버스 한자 변환 사용법 완벽 정리: 입력, 변환, 디자인 적용까지