태지쌤

로봇 & 코딩교육 No.1 크리에이터

파이썬

pdf 아웃라인 파이썬으로 무료 체크하는 방법

태지쌤 2025. 9. 10. 20:42
반응형

https://link.coupang.com/a/cP09xt

 

LG전자 2025 그램 Pro AI 16 WQXGA Ultra5 루나레이크 - 노트북 | 쿠팡

쿠팡에서 LG전자 2025 그램 Pro AI 16 WQXGA Ultra5 루나레이크 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 노트북 제품도 바로 쿠팡에서 확인할 수 있습니다.

www.coupang.com

 

저는 여태껏 pdf는 글자가 깨지는 일이 없을거라 생각했는데

인쇄를 위해 중국쪽 업체에 보냈더니

아래 이미지처럼 글자가 깨지더라구요.

 

이를 방지하는 작업을 ‘아웃라인

(글자를 벡터 도형으로 바꿔 폰트 미설치·

대체로 인한 깨짐을 방지)’이라고 합니다.

문제는 이렇게 해도 표 안에 있는 글자의 경우에는

아웃라인이 적용되지 않는 경우가 생겨요.

아웃라인이 제대로 적용되었는지

최종 테스트 하는 방법이 있습니다.

PitStop Pro 또는 callas pdfToolbox를 사용할 수도 있지만

이 경우에는 어도비 프로에 유료 사용자에게만 제공해요.

무료로 검사하고자 하는 경우에는 파이썬으로 쉽게 할 수 있어요.

아래의 모듈을 설치해주고

pip install pypdf pdfminer.six pymupdf

아래의 코드를 활용하면 되구요.

# check_outline.py
# 대상 파일: C:\Windows\System32\test.pdf

import sys
from dataclasses import dataclass
from typing import List

from pypdf import PdfReader
from pypdf.generic import ContentStream
from pdfminer.high_level import extract_text
import fitz  # PyMuPDF

PDF_PATH = r"C:\Windows\System32\test.pdf"


@dataclass
class PageReport:
    page_index: int
    has_text_ops: bool
    bt_blocks: int
    font_resources: bool
    mined_chars: int
    drawings: int
    verdict: str


def _pypdf_text_signals(reader: PdfReader, page_obj):
    has_text_ops = False
    bt_blocks = 0
    font_resources = False

    try:
        res = page_obj.get("/Resources")
        if res and res.get("/Font"):
            font_resources = True
    except Exception:
        pass

    try:
        contents = page_obj.get_contents()
        if contents is not None:
            cs = ContentStream(contents, reader)
            for operands, op in cs.operations:
                op = op if isinstance(op, bytes) else bytes(op, "latin1")
                if op == b"BT":
                    bt_blocks += 1
                if op in (b"Tj", b"TJ", b"'", b'"'):
                    has_text_ops = True
    except Exception:
        pass

    return has_text_ops, bt_blocks, font_resources


def _pdfminer_char_count(pdf_path: str, page_index: int) -> int:
    try:
        txt = extract_text(pdf_path, page_numbers=[page_index])
        return len(txt.strip()) if txt else 0
    except Exception:
        return 0


def _pymupdf_drawings(doc: fitz.Document, page_index: int) -> int:
    try:
        p = doc.load_page(page_index)
        return len(p.get_drawings())
    except Exception:
        return 0


def analyze_pdf(pdf_path: str) -> List[PageReport]:
    reader = PdfReader(pdf_path)
    doc = fitz.open(pdf_path)

    reports: List[PageReport] = []
    for i, page in enumerate(reader.pages):
        has_text_ops, bt_blocks, font_resources = _pypdf_text_signals(reader, page)
        mined_chars = _pdfminer_char_count(pdf_path, i)
        drawings = _pymupdf_drawings(doc, i)

        if (not has_text_ops) and mined_chars == 0:
            verdict = "텍스트 없음(아웃라인/이미지 가능성 높음)" if not font_resources \
                      else "텍스트 미표시 추정(아웃라인 또는 비표준 텍스트)"
        else:
            verdict = "실제 텍스트 있음(완전 아웃라인 아님)"

        reports.append(PageReport(
            page_index=i + 1,
            has_text_ops=has_text_ops,
            bt_blocks=bt_blocks,
            font_resources=font_resources,
            mined_chars=mined_chars,
            drawings=drawings,
            verdict=verdict
        ))
    doc.close()
    return reports


def print_summary(reports: List[PageReport]):
    total = len(reports)
    no_text_pages = sum(1 for r in reports if "텍스트 없음" in r.verdict)

    print("페이지별 결과")
    for r in reports:
        print(f"- p{r.page_index:>3}: "
              f"text_ops={r.has_text_ops}, BT={r.bt_blocks}, fonts={r.font_resources}, "
              f"chars(pdfminer)={r.mined_chars}, drawings={r.drawings} -> {r.verdict}")

    print("\n요약")
    if no_text_pages == total:
        print(f"전체 {total}쪽 모두 텍스트 없음 → 전면 아웃라인/이미지 PDF 추정")
    elif no_text_pages == 0:
        print(f"전체 {total}쪽 모두 텍스트 존재 → 아웃라인 처리되지 않음")
    else:
        print(f"혼합: 텍스트 없는 페이지 {no_text_pages}/{total}쪽 → 일부 페이지만 아웃라인/이미지")


if __name__ == "__main__":
    # 고정 경로 검사. 필요 시 다른 파일을 인수로 받아도 됩니다.
    path = PDF_PATH if len(sys.argv) < 2 else sys.argv[1]
    reports = analyze_pdf(path)
    print_summary(reports)

이때 내가 점검할 pdf의 경로와 파일명을 아래와 같이 수정해주면 됩니다.

PDF_PATH = r"C:\Windows\System32\cata2.pdf"

정상이라면 이렇게 결과 요약이 나와요.

아웃라인이 제대로 되지 않은 경우

‘실제 텍스트 있음’이라고 알려주고,

몇 페이지가 문제인지도 알려줍니다.

파이썬에 대한 기본 지식 문법 없이도

생성형AI가 코드 다 짜줬어요.

완전 신세계입니다.

pdfchecker.zip
0.00MB

#PDF #아웃라인 #폰트아웃라인 #글자깨짐 #인쇄전검사 #프리플라이트 #프리프레스 #폰트임베딩 #텍스트아웃라인 #표텍스트 #무료점검 #파이썬 #pypdf #pdfminer #PyMuPDF #fitz #PDF검사 #PDF체크 #인쇄소오류예방 #CJK폰트 #한글폰트 #벡터화 #PitStop대체 #pdfToolbox대체 #AdobeAcrobat #자동화 #워크플로우 #디자인가이드 #출력오류해결 #튜토리얼

반응형