아웃라인 처리된 PDF 텍스트의 폰트 크기·자간 정밀 역산 — 임베디드 폰트 메트릭 기반 방법론
초록
인쇄용으로 텍스트를 벡터 윤곽선(아웃라인)으로 변환한 PDF/AI 파일은 폰트/크기/자간 같은 원래 타이포그래피 파라미터가 남아있지 않다. 명함 디자인 파일을 참조본과 동일한 비율로 맞추는 실전 작업 과정에서, 콘텐츠 스트림 CTM 추적과 임베디드 폰트(FontFile2) 글리프 메트릭 직접 분석을 결합해 아웃라인 텍스트의 폰트 크기·위치·자간을 오차 없이 역산하는 방법을 정리했다. 픽셀 기반 비교의 함정(전체 폭 비교의 오류, 안티앨리어싱 오차)과, 폰트 크기 축소만으로는 해결되지 않는 기준선 고정 문제도 함께 다룬다.
아웃라인 처리된 PDF 텍스트의 폰트 크기·자간 정밀 역산 — 임베디드 폰트 메트릭 기반 방법론
배경
인쇄용 PDF/AI 파일에서는 폰트 호환성 문제를 피하기 위해 텍스트를 벡터 윤곽선(아웃라인)으로 변환해 저장하는 경우가 흔하다. 이 경우 원본 문서에는 더 이상 Tf(폰트/크기), Tm(위치), TJ(자간 조정) 같은 텍스트 연산자가 남아있지 않고, 오직 좌표점으로 이루어진 곡선(m/l/c/f)만 존재한다.
동일한 템플릿에서 파생된 두 개의 명함 PDF를 비교·수정하는 작업 중, 한쪽은 살아있는 텍스트(라이브 텍스트)였고 다른 한쪽(참조본)은 이미 아웃라인 처리되어 있었다. "참조본과 같은 비율로 폰트 크기·자간을 맞춰달라"는 요청을 해결하는 과정에서, 아웃라인 PDF에서도 원래 사용된 폰트 크기와 자간 값을 오차 없이 역산할 수 있는 방법을 정리한다.
배운 점 1 — 픽셀(래스터) 비교의 함정
처음에는 두 PDF를 300dpi로 래스터화한 뒤 픽셀 단위로 글자 폭·간격을 측정해 비교했다. 이 방식은 두 가지 문제를 일으켰다.
- 전체 폭 비교는 오해를 부른다. 두 이름의 "전체 텍스트 블록 폭"이 우연히 비슷하게 나왔다고 해서 자간이 같다는 뜻은 아니었다. 실제로는 글자 자체의 평균 폭이 서로 달라서, 전체 폭이 비슷해도 낱글자 사이 간격 비율은 크게 어긋나 있었다. → 자간 비교는 반드시 "간격 ÷ 글자폭" 비율로 해야 한다.
- 안티앨리어싱과 크롭 경계가 오차를 만든다. 곡선 위주의 글자(예: 받침이 없거나 획이 가는 글자)는 열(column) 단위 다크픽셀 분할에서 일부 획이 누락되어, 특정 글자 하나만 유독 폭이 작게 측정되는 현상이 발생했다. 여러 글자의 결과를 서로 교차검증하지 않으면 이 오류를 알아채기 어렵다.
배운 점 2 — 폰트 크기만으로는 "겹침"이 해결되지 않을 수 있다
이름 텍스트가 밑줄과 겹치는 문제를 "폰트 크기를 줄여서" 해결해달라는 요청이 있었다. 그러나 11.5pt에서 6.5pt까지(약 43% 축소) 단계적으로 줄여가며 렌더링해 봐도 글자 받침 하단이 계속 밑줄에 붙어 있었다.
원인은 해당 서체(둥근/각진 산세리프 계열의 한글 "정사각형" 그리드 폰트)의 특성상 받침 글자의 하단이 텍스트 기준선(baseline)에 매우 가깝게 설계되어 있고, PDF에서 폰트 크기 축소는 기준선을 기준으로 글자를 비례 축소하기 때문에, 기준선 자체와 밑줄 사이의 절대 간격은 폰트 크기와 무관하게 거의 고정되어 있었기 때문이다.
→ 폰트 크기 축소만으로는 기준선에 붙어있는 요소(받침 등)를 고정된 위치의 다른 요소로부터 분리할 수 없다. 실제로 필요한 조치는 텍스트의 수직 위치(Tm의 y값)를 함께 옮기는 것이었다. 이는 여러 크기를 실제로 렌더링해 비교하기 전까지는 예측하기 어려웠다 — 즉, 이런 종류의 문제는 분석적 추정보다 반복 렌더링·측정을 통한 경험적 검증이 더 안전하다.
배운 점 3 — 아웃라인 PDF도 "임베디드 폰트 자체"를 자로 쓰면 오차 없이 역산할 수 있다
참조본이 완전히 아웃라인 처리되어 있어 텍스트 연산자가 전혀 없었음에도, 다음 절차로 원래 사용된 폰트 크기를 소수점 단위까지 정확하게 복원할 수 있었다.
- 콘텐츠 스트림의 CTM(현재 변환 행렬)을
q/cm/Q스택까지 정확히 추적하며 모든m/l/c좌표를 페이지 좌표계로 변환한다. (CTM을 무시하고 원시 좌표만 읽으면 완전히 엉뚱한 위치의 도형을 글자로 착각하게 된다.) - 변환된 좌표를
f(fill) 단위로 묶어 하나의 글자에 해당하는 서브패스 묶음을 만들고, 이를 x좌표 클러스터링으로 낱글자 단위로 분리한다. - 해당 PDF가 참조하는 폰트(
/FontDescriptor/FontFile2)를 PDF에서 바이너리 그대로 추출해 TrueType 폰트 파일로 저장한다. fontTools같은 폰트 파싱 라이브러리로 그 폰트의 실제 글리프 윤곽선 바운딩박스(xMin/xMax/yMin/yMax)를 font-unit(보통 1em=1000) 단위로 직접 읽는다.- 다음 식으로 실제 사용된 폰트 크기를 역산한다.
실제 크기(pt) = PDF에서 측정한 잉크 폭(또는 높이, pt) ÷ 그 글자의 font-unit 폭(또는 높이)
- 같은 글자를 폭 기준·높이 기준으로 각각 계산하고, 서로 다른 글자 여러 개로 교차검증한다. 이번 사례에서는 서로 다른 글자·서로 다른 축(폭/높이)으로 계산한 4개의 독립적인 값이 소수점 둘째 자리까지 일치했고(예: 9.255 / 9.248 / 9.25 / 9.25), 반대로 서브패스 추출이 불완전했던 글자 하나는 다른 값들과 22%나 어긋나 즉시 이상치로 걸러낼 수 있었다.
이 방법은 폰트 자체가 "절대 기준자(ruler)" 역할을 하기 때문에, 래스터 픽셀 측정보다 훨씬 정밀하고, 여러 글자로 교차검증까지 가능해 신뢰도를 스스로 검증할 수 있다는 장점이 있다.
배운 점 4 — 자간(letter-spacing)도 "자연 간격"과 "의도된 조정값"을 분리해서 봐야 한다
CID 기반 폰트는 글자마다 고정된 "advance width"(다음 글자 시작 위치까지의 이동 거리)를 갖는다. 실제 렌더링된 두 글자 사이의 간격은 다음 두 요소로 나뉜다.
- 자연 간격:
advance width − 글자 잉크 폭(글자 자체의 좌우 여백 차이에서 오는 간격) - 디자이너가 추가한 조정값: PDF
TJ연산자의 숫자 인자(음수일수록 간격이 벌어짐)
전체 자간을 무작정 하나의 숫자로 비교하면 이 두 요소가 뒤섞여 잘못된 결론에 이른다. 이번 작업에서는 참조본의 각 글자쌍에 대해 "자연 간격을 폰트 메트릭으로 미리 계산해 빼고", 남은 부분만 "의도된 조정값"으로 보는 방식으로 대상 문서에 적용할 TJ 조정값을 정확히 역산했다.
결론 — 일반화
살아있는 텍스트(파라미터 존재)와 아웃라인 벡터(기하 정보만 존재)가 같은 폰트를 공유하고 있다면, 아웃라인 쪽도 파라미터(크기·위치·자간)를 오차 없이 복원할 수 있다. 핵심은 다음 세 가지다.
- 콘텐츠 스트림의 CTM을 정확히 추적해 좌표를 페이지 좌표계로 변환할 것.
- 픽셀이 아니라 임베디드 폰트 자체의 글리프 메트릭을 측정 기준으로 삼을 것.
- 하나의 값이 아니라 여러 독립적인 측정치를 교차검증해 이상치를 걸러낼 것.
이 절차는 이번 명함 사례에 국한되지 않고, "아웃라인 처리된 인쇄물 PDF에서 원래 타이포그래피 설정을 복원해야 하는" 모든 상황(로고 재현, 브랜드 가이드 역설계, 레거시 디자인 파일 수정 등)에 일반적으로 적용할 수 있다.
