투고 규정에 “모든 글꼴을 임베드할 것”이라고 적혀 있는데, 내 PDF가 그런지 알 수가 없습니다. 이탤릭으로 지정한 대목이 기울지 않습니다. fontspec에 Numbers=OldStyle이라고 썼는데 아무것도 달라지지 않습니다. 이런 상황을 정리하는 것은 짐작이 아니라 조사하는 도구입니다. 이 페이지는 LaTeX 주변의 글꼴 검사 도구를 실제로 실행해 얻은 출력과 함께 늘어놓습니다. pdffonts, fc-list, otfinfo, \fontname\font, 글리프 표를 찍는 nfssfont, 그리고 가상 글꼴(.vf) 을 사람이 읽을 수 있게 여는 vftovp입니다. 덤으로 TeX의 글꼴 이름이 왜 phvbc8t 같은 암호인지도 풀립니다.
지금 조판되는 것은 어느 글꼴인가 — \fontname과 \showthe\font
문서의 어느 지점에서 무엇이 선택되어 있는지는 \fontname\font 가 실제 파일 이름으로, \showthe\font 가 NFSS의 다섯 좌표로 답합니다. 앞의 것은 cmr10, cmbx10, cmti10처럼 TeX이 실제로 읽어들인 메트릭의 이름을 돌려주고, 뒤의 것은 로그에 > \OT1/cmr/m/n/10 . 을 찍습니다. 둘이 어긋나는 일은 없습니다. 뒤의 것이 요구이고 앞의 것이 결과입니다. 둘 다 보면 요구한 대로 글꼴이 왔는지, 중간에 대체되었는지가 한눈에 보입니다.
% \typeout{fontname = \fontname\font} in a default article
fontname = cmr10
bf fontname = cmbx10
it fontname = cmti10
% \showthe\font stops the run and prints the NFSS name
> \OT1/cmr/m/n/10 .
% \showfont is NOT a LaTeX command; it belongs to ConTeXt.
% In LaTeX it fails with:
! Undefined control sequence.여기서 한 가지 바로잡아 둡니다. \showfont는 LaTeX의 명령이 아닙니다. 현재 글꼴 정보를 내보내는 방법으로 자주 소개되지만 LaTeX2e 커널에도 어떤 패키지에도 존재하지 않으며, 실행하면 ! Undefined control sequence. 가 납니다(같은 이름의 명령은 ConTeXt에 있습니다). LaTeX에서 같은 일을 하려면 위의 두 가지에 더해 내부 매크로를 직접 읽는 방법이 있습니다. \makeatletter 안에서 \f@encoding, \f@family, \f@series, \f@shape, \f@size를 늘어놓으면 다섯 좌표를 원하는 서식으로 \typeout 할 수 있습니다.
글꼴 로딩 자체를 추적하고 싶을 때는 tracefnt 패키지입니다. \tracingfonts=2로 두면 실제 글꼴을 읽을 때마다 “어떤 외부 글꼴을 어떤 NFSS 이름으로 읽었는지”가 로그에 남습니다. 대체가 일어난 원인을 추적할 때는 대체 경고보다 정보량이 많습니다. 다만 출력이 방대하므로, 문제가 되는 \section만 최소 문서로 잘라 내어 돌리는 편이 현실적입니다.
% \usepackage{tracefnt} + \tracingfonts=2, document set in T1
LaTeX Font Info: External font `ecbx1000 at10.0pt' loaded as
(Font) T1/cmr/bx/n/10 on input line 6.
LaTeX Font Info: External font `ecti1000 at10.0pt' loaded as
(Font) T1/cmr/m/it/10 on input line 6.PDF에 임베드된 글꼴 확인하기 — pdffonts
pdffonts(Poppler / Xpdf에 딸림)는 완성된 PDF에 어떤 글꼴이 어떤 형식으로 들어 있고 임베드되었는지를 글꼴당 한 줄씩 표로 보여 줍니다. 볼 열은 셋입니다. emb는 임베드 여부, sub는 서브셋 여부(실제로 쓴 글리프만 남겼는지), uni는 Unicode로의 역대응(PDF에서 글자를 복사할 수 있는지)입니다. 투고 전 확인은 이 명령 하나로 끝나며, emb 열이 전부 yes라면 “글꼴 미임베드”로 반려될 걱정은 없습니다.
# a document compiled with pdfLaTeX and \usepackage[T1]{fontenc}
$ pdffonts pf.pdf
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
OSZFFG+SFRM1000 Type 1 Custom yes yes yes 4 0
PCDLRW+SFBX1000 Type 1 Custom yes yes yes 5 0
IEKZWO+SFTI1000 Type 1 Custom yes yes yes 6 0
GFIBPT+CMMI10 Type 1 Builtin yes yes yes 8 0
# the same document via XeLaTeX + fontspec with an OpenType face
$ pdffonts pfx.pdf
PPMQXL+TeXGyrePagella-Regular-Identity-H CID Type 0C Identity-H yes yes yes 4 0
AXDTQU+TeXGyrePagella-Bold-Identity-H CID Type 0C Identity-H yes yes yes 6 0이 출력은 엔진의 지문 노릇도 합니다. pdfLaTeX는 Type 1 글꼴을 Custom / Builtin 인코딩으로 임베드하는 반면, XeLaTeX나 LuaLaTeX가 fontspec을 거쳐 OpenType을 쓰면 CID Type 0C와 Identity-H가 나옵니다. 남에게 받은 PDF가 무엇으로 조판되었는지 이것으로 거의 가려낼 수 있습니다. 이름 앞에 붙는 여섯 글자(OSZFFG+ 등)는 서브셋 식별자로, 같은 글꼴을 따로 서브셋하면 서로 다른 접두사가 붙습니다. 반대로 emb가 no인 줄이 있다면 그 글꼴은 독자의 환경에 맡겨진 상태입니다. 표준 14개 PostScript 서체라면 대개 문제가 없지만, 투고에서는 걸립니다.
시스템에 있는 글꼴 조사하기 — fc-list와 otfinfo
fontspec에 넘기는 이름은 글꼴 자신의 이름이어야 하며, 마음대로 지어 써서는 통하지 않습니다. 설치된 글꼴을 이름과 파일의 대응과 함께 나열하는 것이 fc-list(fontconfig에 딸림)입니다. 인수 없이 부르면 전부, fc-list : family는 패밀리 이름만, 패턴을 주면 좁혀서 보여 줍니다. LuaTeX 쪽에는 같은 역할의 luaotfload-tool 이 있어 --find로 이름을 해석하고 --update로 글꼴 이름 데이터베이스를 다시 만듭니다. 참고로 fontconfig는 Linux에서는 표준이지만 macOS에는 기본으로 들어 있지 않습니다(Homebrew 등으로 따로 설치하게 됩니다).
# every installed font, one line each (this machine reports 2799 lines)
$ fc-list | wc -l
2799
# narrow to one family: file, then all its names, then the style
$ fc-list "Hiragino Mincho ProN" file family style
/System/Library/Fonts/HiraginoMinchoProN.ttc: Hiragino Mincho ProN,\
Hiragino Mincho ProN W6:style=W6,Regular
# what would fontconfig pick for a generic request?
$ fc-match sans
Verdana.ttf: "Verdana" "Regular"그 글꼴이 무엇을 할 수 있는지는 otfinfo(lcdf-typetools, TeX Live에 동봉)의 일입니다. -i는 이름・판・저작권을, -f는 OpenType 기능 태그를, -s는 지원하는 문자 체계와 언어를, -t는 테이블 목록을 보여 줍니다. 그중 -f가 실용적 값어치가 큽니다. fontspec에 Numbers=OldStyle이나 Letters=SmallCaps를 쓰기 전에 여기서 onum이나 smcp가 있는지 확인하면 “썼는데 안 먹는다”는 사례의 대부분을 미리 막을 수 있습니다. 기능이 없는 글꼴에 기능 이름을 적어도 조용히 무시될 뿐이기 때문입니다.
$ otfinfo -i $(kpsewhich texgyrepagella-regular.otf)
Family: TeX Gyre Pagella
Subfamily: Regular
PostScript name: TeXGyrePagella-Regular
Version: Version 2.501;PS 2.501;ffdkm 0.1
Copyright: Copyright 2006-2018 for TeX Gyre extensions by B. Jackowski,
J.M. Nowacki, et al. Vietnamese characters were added by Han The Thanh.
$ otfinfo -f $(kpsewhich texgyrepagella-regular.otf)
c2sc Small Capitals From Capitals
dlig Discretionary Ligatures
kern Kerning
liga Standard Ligatures
lnum Lining Figures
onum Oldstyle Figures
size Optical Size
smcp Small Capitals
ss01 Stylistic Set 1이 -i 출력에는 자그마한 인연도 함께 찍혀 있습니다. TeX Gyre Pagella에 베트남어 문자를 추가한 사람은 Hàn Thế Thành, 곧 pdfTeX의 작성자이자 박사 논문으로 마이크로타이포그래피를 TeX에 들여온 인물이며, 이 사이트의 microtype 페이지가 다루는 주제의 장본인입니다. 글꼴의 저작권 표시는 의외로 그런 내력을 남깁니다.
글꼴의 모든 글리프 찍어 보기 — nfssfont.tex와 fonttable
글꼴에 실제로 어떤 글리프가 들어 있는지 눈으로 확인하려면 글리프 표를 찍습니다. 오래전부터 TeX에 딸려 오는 대화형 도구가 nfssfont.tex 입니다. 실행하면 Input external font name, e.g., cmr10 이라고 물으므로 cmr10 등으로 답하고, \table로 표를 내고 \bye로 끝냅니다. 여기서 한 가지 바로잡습니다. 널리 퍼져 있는 tex nfssfont 라는 실행법은 동작하지 않습니다. nfssfont.tex의 48행은 \documentclass{article}이며, 이것은 LaTeX 문서입니다. plain TeX으로 실행하면 ! Emergency stop. 으로 죽습니다. 올바른 명령은 latex nfssfont 또는 pdflatex nfssfont입니다.
$ pdflatex nfssfont
Input external font name, e.g., cmr10
(or <enter> for NFSS classification of font): cmr10
Now type a test command or \help for help [ \table \bye ]: \table
...
Output written on nfssfont.pdf (1 page, 71803 bytes).
# \help lists the whole repertoire:
# \init switches to another font; \stop or \bye finishes the run;
# \table prints the font layout in tabular format;
# \text prints a sample text, assuming TeX text font conventions;
# \sample combines \table and \text;
# \lowers \uppers \digits \math \punct \names \bigtest ...
# Knuth's original is plain TeX and does start under tex:
$ tex testfont
Name of the font to test = cmr10
Now type a test command (\help for help): \table대화형이 번거롭다면 문서 안에서 같은 일을 하는 fonttable 패키지가 있습니다. \fonttable{cmr10}은 글꼴 이름(엄밀히는 .tfm 이름)을 받아 모든 글리프의 표를 조판하며(Zapf Dingbats를 들여다보려면 \fonttable{pzdr}), \xfonttable{T1}{cmr}{m}{n}은 NFSS의 네 속성으로 지정합니다. 표의 범위는 \fontrange{<low>}{<high>}로 16글리프 블록 단위로 좁힐 수 있으며 최대 256글리프입니다. 글리프 격자가 아니라 그 글꼴로 조판한 예문을 보고 싶다면 \fonttext{cmr10}입니다. 이 패키지 코드의 상당 부분은 nfssfont.tex의 수정판이고, 글리프 테스트 명령들은 Knuth의 testfont.tex를 다시 구현한 것입니다. 같은 도구의 세 얼굴인 셈입니다. 덧붙여 nfssfont의 첫 프롬프트에서 이름을 입력하지 않고 그냥 엔터를 치면 NFSS 다섯 속성으로 글꼴을 지정하는 모드로 들어갑니다.
가상 글꼴(.vf) — 존재하지 않는 글리프를 만들어 내는 층
가상 글꼴(.vf) 은 TeX이 보는 하나의 논리 글꼴을 실제 글리프와 저수준 조판 명령의 열로 번역하는 층입니다. TeX FAQ의 표현을 빌리면 가상 글꼴은 “글꼴의 글리프를 만들기 위해 여러 조각을 모으는 수단”이며, 그 조각은 다른 글꼴, 룰, 위치 정보가 붙은 조판 명령에서 옵니다. 추상적으로 들리지만 실물을 열어 보면 단번에 이해됩니다. T1 인코딩의 Times(ptmr8t)를 vftovp로 열면 ff 합자 자리에는 이렇게 적혀 있습니다. f를 놓고, 0.025 em 물러나고, f를 한 번 더 놓아라. 원래 Times에는 ff 글리프가 없으므로 가상 글꼴이 그 자리에서 만들어 내는 것입니다.
$ vftovp $(kpsewhich ptmr8t.vf) $(kpsewhich ptmr8t.tfm) ptmr8t.vpl
$ head -5 ptmr8t.vpl
(VTITLE )
(FAMILY UNSPECIFIED)
(CODINGSCHEME EXTENDED TEX FONT ENCODING - LATIN)
(DESIGNSIZE R 10.0)
(MAPFONT D 0 (FONTNAME ptmr8r) ...)
# slot O 33 (octal) is the ff ligature of T1 - assembled from two f glyphs
(CHARACTER O 33
(CHARWD R 0.640991)
(CHARHT R 0.677991)
(MAP
(SETCHAR C f)
(MOVERIGHT R -0.025)
(SETCHAR C f)
)
)이 구조는 역할 분담입니다. TeX 본체는 폭・높이・깊이라는 치수만 알면 되고, 그것은 짝이 되는 .tfm(TeX Font Metric) 에서 읽습니다. 각 글리프를 “실제로 어떻게 그릴지”는 .vf에 적히고 그것을 읽는 것은 DVI 드라이버(dvips, dvipdfmx)입니다. 따라서 가상 글꼴은 항상 .tfm과 .vf 두 개가 한 쌍입니다. 바이너리는 읽을 수 없으므로, 사람이 읽을 수 있는 .vpl(Virtual Property List) 과 서로 변환하는 프로그램 두 개가 어느 배포판에나 들어 있습니다. 서양문자 메트릭 단독에도 같은 관계의 .pl(Property List) 형식이 있어, tftopl로 열면 FONTDIMEN의 일곱 매개변수와 LIGTABLE의 합자・커닝 표를 읽을 수 있습니다.
vftovp—.vf+.tfm(바이너리) →.vpl(텍스트). 인수 순서는 가상 글꼴, 메트릭, 출력. 기존 가상 글꼴을 뜯어볼 때 쓰는 쪽입니다.vptovf—.vpl(텍스트) →.vf+.tfm(바이너리). 인수 순서는 설명, 가상 글꼴, 메트릭. 편집한 설명을 다시 구워 냅니다.tftopl/pltotf— 서양문자 메트릭 단독에 대한 같은 왕복 변환..tfm안의 내용(FONTDIMEN,LIGTABLE)을 읽을 때 씁니다.ppltotf/ptftopl— 위 한 쌍의 일본어판으로, pTeX 계열의 바이너리 JFM을 다룹니다.- 모두 확장자를 생략할 수 있으며 각각
.vf/.tfm/.vpl이 보충됩니다.
만들어진 .tfm은 texmf 트리의 .../fonts/tfm/<supplier>/ 아래에, .vf는 .../fonts/vf/<supplier>/ 아래에 두고 mktexlsr로 파일 이름 데이터베이스를 갱신하면 kpsewhich ptmr8t.vf로 찾을 수 있게 됩니다. TFM 이름과 실제 글꼴 파일을 짝지어 주는 표(글꼴 맵)를 관리하는 것은 updmap 의 몫입니다. 다만 요즘 작업에서 .vpl을 손으로 쓰는 일은 거의 없습니다. PostScript나 OpenType 글꼴에서 TeX용 메트릭과 가상 글꼴을 생성하는 것은 fontinst 의 몫입니다. 가상 글꼴은 처음부터 쓰는 대상이라기보다, 도구가 만들어 낸 것을 열어서 읽고 필요하면 손보는 대상으로 보는 편이 실정에 맞습니다.
TeX의 글꼴 이름은 왜 암호 같은가 — texdoc fontname
답은 “여덟 글자밖에 쓸 수 없었기 때문”입니다. texdoc fontname으로 열리는 Fontname 규약은 그 이유를 숨기지 않습니다. DOS 파일 시스템과, CD-ROM 배포에 쓰인 ISO 9660 표준과의 호환성을 위해 이름을 여덟 글자로 제한한다고 명시되어 있습니다. 쓸 수 있는 문자는 소문자 a–z, 숫자, 밑줄뿐입니다. 그 여덟 글자를 S TT W [V...] [N] [E] [DD], 곧 공급자・서체・굵기・변종・인코딩・폭・디자인 크기에 배분하는 것이 규약의 전부입니다.
| phvbc8t의 부분 | 규약상의 위치 | 의미 |
|---|---|---|
p | 공급자(S) | Adobe. supplier.map의 주석에 따르면 “PostScript의 p” |
hv | 서체(TT) | Helvetica(typeface.map의 hv helvetic) |
b | 굵기(W) | bold(weight.map에 b Bold) |
c | 폭(E) | condensed. NFSS 쪽에서는 b와 합쳐져 bc가 됩니다 |
8t | 인코딩(N) | variant.map에 8t ECEncoding CorkEncoding — 곧 T1 |
이 표를 한 번 읽어 두면 .fd 파일과 로그에 늘어선 이름들이 갑자기 말을 하기 시작합니다. ptmr8t는 Adobe의 Times 레귤러 T1, pcrr8t는 Courier 레귤러 T1, ptmb8c는 Times 볼드의 TS1(8c가 Text Companion)입니다. 7t는 “TeX text 인코딩”, 곧 OT1이고, 8r은 날것의 Type 1을 받아 내기 위한 TeX Base 1 로, T1용 가상 글꼴이 딛고 서는 실제 글꼴이 바로 이것입니다. 앞 절에서 ptmr8t.vf가 MAPFONT에 ptmr8r을 가지고 있었던 것이 그런 뜻이었습니다. 참고로 Fontname 자신도 여덟 글자가 옹색함을 인정하고, 긴 이름의 처리를 위해 별도의 절을 두고 있습니다.
일본어의 메트릭 — JFM과 문자 클래스
일본어 조판에는 서양문자용 .tfm만으로는 부족한 것이 있습니다. 한자와 가나는 기본적으로 정사각형(전각) 틀에 들어가고, 글자 사이는 단어 사이 공백이 아니라 문장부호(구두점・괄호) 앞뒤에서만 조이거나 벌어지기 때문입니다. 이 정보를 담는 것이 JFM(Japanese Font Metric) 이며, pTeX와 upTeX는 .tfm과 비슷한 바이너리 JFM을, LuaTeX-ja는 같은 역할을 Lua 테이블로 기술합니다. 전자는 ppltotf / ptftopl로 텍스트와 상호 변환할 수 있고, 후자는 애초에 텍스트라 그대로 읽을 수 있습니다.
서양문자 TFM과의 가장 큰 차이는 JFM이 문자를 “문자 클래스(character class)”로 묶어 다룬다는 점입니다. LuaTeX-ja 매뉴얼이 정하듯 JFM의 모든 길이는 디자인 크기를 단위로 하는 부동소수점 수로 쓰이며, zw(전각 폭)와 zh(전각 높이, height + depth)를 기준으로 각 클래스마다 width, height, depth, italic(이탤릭 보정)을 가집니다. 클래스 0은 반드시 존재하며 다른 어떤 클래스에도 속하지 않는 대다수 일본어 문자가 여기에 들어갑니다. 문장부호는 별도 클래스로 나누고, 클래스와 클래스 사이에 삽입할 글루와 커늘 표로 갖게 합니다. 이것이 문장부호 주변의 공간을 만드는 방식입니다.
-- A LuaTeX-ja JFM (excerpt); all lengths are in design-size units
luatexja.jfont.define_jfm {
version = 3,
dir = 'yoko', -- horizontal writing
zw = 1.0, zh = 1.0, -- full width, full height
[0] = { -- class 0: most kanji and kana
chars = { '漢' },
width = 1.0, height = 0.88, depth = 0.12, italic = 0.0,
},
[1] = { -- a class for stops and commas
chars = { '。', '、' },
width = 0.5, height = 0.88, depth = 0.12, italic = 0.0,
},
}pTeX 계열에서는 JAglue(일본어 문자끼리, 그리고 일본어 문자와 서양문자 사이에 들어가는 간격)가 조판 시 자동으로 삽입됩니다. 클래스 사이의 간격은 JFM이 정하고, 클래스가 지정되지 않은 일본어 문자 사이에는 기본 kanjiskip, 일본어와 서양문자의 경계에는 xkanjiskip이 들어갑니다. 이것들은 행 머리나 행 끝에 와서는 안 되는 문자를 제어하는 금칙 처리(kinsoku)와 함께 일본어 조판의 모양새를 지탱합니다. LuaTeX-ja에는 용도별 표준 JFM이 함께 제공됩니다. jfm-ujis.lua가 기본이며 upTeX용 메트릭 upnmlminr-h.tfm을 바탕으로 하고(대부분의 글자가 정사각형), jfm-jis.lua는 pTeX에서 널리 쓰이는 jis.tfm에 해당하며, jfm-min.lua는 pTeX 기본 min10.tfm에 해당합니다. 글꼴 정의에서는 \jfont\F=HaranoAjiMincho-Regular:jfm=ujis처럼 jfm=으로 고릅니다.