웹폰트 경량화
폰트툴즈의 pyftsubset을 사용한 폰트 서브셋 만들기

현대 한글 11,172자. 적색은 KS X 1001 2,350자. 녹색은 ’KS 코드 완성형 한글의 추가 글자 제안’의 224자
현대 한글 11,172자. 적색은 KS X 1001 2,350자. 녹색은 ’KS 코드 완성형 한글의 추가 글자 제안’의 224자

들어가며: 한글 웹폰트와 폰트 서브셋팅

컴퓨터 상에서 폰트는 다루기 쉽지 않은 자원 중 하나입니다. 대부분의 저작용 애플리케이션은 폰트를 내장하지 않고, 사용하고자 하는 폰트의 이름만을 기록해둡니다. 다른 사람이 제작한 컨텐츠를 복사해서 내 컴퓨터에서 여는 상황을 상상해봅니다. 운이 좋게도 이 폰트가 설치되어있다면 컨텐츠는 제작자의 의 도대로 화면에 보여질 것입니다. 하지만 해당하는 폰트가 없다면 이야기는 달라집니다. 아예 출력이 되지 않을 수도 있고, 시스템에 설치된 다른 폰트로 바뀌어 보일 수도 있습니다. 분명한 건 처음 컨텐츠를 제작한 사람의 의도와는 다른 화면을 보게 된다는 점입니다.

이러한 문제는 웹에서도 마찬가지입니다. 웹 브라우저에서는 이를 해결하기 위해 웹 페이지를 열 때 폰트 파일을 동적으로 로드하는 방법을 제공합니다. 사용자에게 제공할 폰트를 컨텐츠 제작자가 미리 준비해두면 됩니다. 사용자는 이 폰트 파일을 동적으로 로드하기 때문에 별도의 절차로 없이도 웹 페이지에서 제작자가 의도한 폰트로 컨텐츠를 볼 수 있습니다. 이를 웹폰트라고 이야기합니다.

웹폰트는 표현의 가능성을 넓혀준다는 면에서 유익하지만, 동적으로 로드하는 방식이기 때문에 크기가 크면 느려지고 비용이 증가합니다. 표현할 수 있는 글자수와 폰트의 용량은 트레이드 오프 관계에 있습니다. 웹폰트를 최적화(경량화)하는 방식에는 크게 두 가지가 있습니다. 첫 번째는 폰트를 WOFFWeb Open Font Format나 WOFF2Web Open Font Format 2 방식으로 압축을 하는 방법이고, 두 번째는 글자수를 줄이는 방법입니다.

한글 웹폰트를 다룰 때는 특히 두 번째 방법이 중요합니다. 알파벳을 모두 표현할 수 있는 7비트 ASCII 코드는 이름에서 유추할 수 있듯이 128개의 공간을 가지고 있습니다. 이 정도 공간이면 영어 문자를 표현하고, 몇 가지 특수기호와 컨트롤 문자들을 표현하기에 충분합니다. 하지만 현대 한글은 음절를 기준으로 11,172자에 달합니다. 대소문자 알파벳 52자와 비교해보면 200배 이상 많은 글자수입니다. 너무 글자수가 많다보니 웹폰트 전용으로 폰트를 제작하는 경우 11,172자를 전부 지원하지 않고, 빈도수가 높은 글자들로 구성된 KS X 1001 표준의 2,350자만을 지원하기도 합니다. 웹폰트를 사용할 때는 유니코드의 Hangul Syllables가 전부 구현된 폰트를 가지고 있더라도, 동적 로드 성능을 개선하기 위해서 이와 같은 글자수를 줄이는 전략을 사용합니다. 이를 폰트 서브셋팅font subsetting이라고 합니다.

하나의 비트는 0이나 1로 둘 중 하나로 표현됩니다. 따라서 7비트는 2*2*2*2*2*2*2=128가지 다른 상태를 표현할 수 있습니다.

한글의 글자는 초성, 중성, 종성을 조합 되기 때문에 다른 언어들에 비해 음절이 압도적으로 많습니다. 유니코드에 정의된 Hangul Syllables 블록은 한글 11,172자를 모두 지원하며, 이는 단일 언어로서는 최상위권에 속하는 양입니다. 이는 어디까지나 현대 한글을 기준으로 한 것이며, 옛한글의 자모까지 포함한 모든 조합은 160만자에 이릅니다. 유니코드에서는 이를 개별 음절이 아닌, 자모 조합으로 글자를 만드는 첫가끝(초성중성종성) 코드 방식으로 지원하고 있으며, 은글꼴, 나눔옛한글, 노토 산스 등이 이 방식을 지원합니다.

UYEONG 님이 공개해둔 NotoSans-subset은 Noto Sans 폰트를 웹에서 사용할 수 있도록 만든 한글 2,350자 서브셋 폰트입니다. Noto Sans와 Lato를 기반으로 만들어진 스포카 한 산스도 웹폰트로 KS X 1001의 2,350자와 KS 코드 완성형 한글의 추가 글자 제안(노민지, 윤민구)에서 제안하는 224자를 더한 2,574자를 지원하는 서브셋 폰트입니다.

이 글에서는 pyftsubset을 사용하는 방법을 소개하고자 합니다.

44BITS 소식과 클라우드 뉴스를 전해드립니다. 지금 5,000명 이상의 구독자와 함께 하고 있습니다 📮

폰트툴즈fontTools

폰트툴즈는 파이썬 라이브러리입니다. 폰트툴즈는 폰트를 조작하기 위한 다양한 기능을 제공하며, 이러한 기능들을 커맨드라인 인터페이스로 제공합니다. 그 중에서 폰트 서브셋팅을 지원하는 도구가 바로 pyftsubset입니다. 여기서부터는 폰트툴즈를 설치하고, 한 단계씩 서브셋 폰트를 만드는 과정에 대해서 알아보도록 하겠습니다.

설치

pyftsubset을 사용하기 위해서는 파이썬 라이브러리인 폰트툴즈를 설치해야합니다. 여기서는 시스템에 파이썬이 설치되어있다고 가정합니다. 폰트툴즈는 공식적으로 파이썬 2.7과 3.4 이후 버전을 지원합니다. 예제 환경에서는 파이썬 3.6.3을 사용합니다. 폰트툴즈는 파이썬의 패키지 매니저 pip를 사용해 쉽게 설치할 수 있습니다. pip install fonttools 명령어를 실행합니다.

$ python --version
Python 3.6.3

$ pip install fonttools
Collecting fonttools
  Downloading fonttools-3.20.1-py2.py3-none-any.whl (587kB)
    100% |████████████████████████████████| 593kB 178kB/s
Installing collected packages: fonttools
Successfully installed fonttools-3.20.1

설치되었는지 확인하기 위해 pyftsubset 명령어를 실행해봅니다.

$ pyftsubset
usage: pyftsubset font-file [glyph...] [--option=value]...
Try pyftsubset --help for more information.

명령어가 정상적으로 실행되는 것을 알 수 있습니다.

서브셋을 만들 폰트 준비

구글Google과 어도비Adobe에서 만든 노토 산스 CJKNoto Sans CJK 폰트는 유니코드의 Hangul Syllables 블록 11,172자를 모두 지원하는 폰트입니다. 이 예제에서는 노토 산스 CJK KR을 사용하며 공식 사이트에서 다운로드 받을 수 있습니다. 압축을 풀면 9개의 .otf 파일, 라이센스 파일, README 파일을 볼 수 있습니다. 노토 산스는 CJK KR은 총 9개의 폰트로 구성되어 있으며 각 폰트에 대한 자세한 설명은 해설 페이지에서 찾아볼 수 있습니다. 크게 기본 폰트와 모노스페이스 폰트로 나누어져 있으며, 기본 폰트는 7개의 두께, 모노스페이스 폰트는 2개의 두께를 지원합니다. 각각의 폰트는 15MB에서 17MB 정도의 용량을 가지고 있습니다. 웹에서 동적으로 다운로드 받기에는 상당히 큰 용량이라는 것을 알 수 있습니다.

노트 산스Noto Sans소스 한 산스Source Han Sans라고도 부릅니다. 두 폰트는 구글과 어도비에서 협업을 통해 만들어진 하나의 폰트이지만, 구글에서 배포하는 버전은 노토 산스라고 부르며, 어도비에서 배포하는 버전은 소스 한 산스라고 부릅니다. 폰트명과 웨이트 이름 외에 폰트 자체는 같다고 보아도 무방합니다. 이 폰트는 이외에도 본고딕(한국어), 源ノ角ゴシック(일본어), 思源黑体(중국어 간체), 思源黑體(중국어 번체)라는 이름을 가지고 있습니다.

이 폰트 패밀리 중 하나인 NotoSansCJKkr-Regular.otf 폰트의 서브셋을 만들어보겠습니다. 서브셋을 만드는 과정은 동일하기 때문에, 서브셋으로 만들고자 하는 글리프들을 포함하고 있다면, 어떤 폰트인지는 크게 중요하지 않습니다.

맥OSmacOS에서는 폰트를 더블클릭하면 폰트 북Font Book 애플리케이션이 실행되고 폰트를 설치할 수 있습니다. 오른쪽 아래의 폰트 설치하기Install Font 버튼을 클릭합니다.

서브셋 폰트를 만들 때 폰트를 설치하는 과정은 필요하지 않습니다. 단순히 폰트를 확인하기 위한 용도로 설치를 진행합니다.

폰트 북으로 노토 산스 폰트를 설치
폰트 북으로 노토 산스 폰트를 설치

설치된 폰트는 폰트 북 애플리케이션에서 확인할 수 있습니다. 폰트를 선택하고 커스텀뷰(단축키: ⌘3)를 사용하면 원하는 폰트로 직접 글자를 입력해볼 수 있습니다.

맥OS의 폰트 북(Font Book) 애플리케이션에서 열어본 노토 세리프 CJK KR 폰트)
맥OS의 폰트 북(Font Book) 애플리케이션에서 열어본 노토 세리프 CJK KR 폰트)

“가나다라마바사아자차카타파하”를 입력해보았습니다. 이를 통해 Noto Sans CJK KR Regular는 한글을 정상적으로 표현할 수 있는 폰트라는 것을 알 수 있습니다.

pyftsubset을 사용한 서브셋 폰트 제작

서브셋 폰트를 만들 원본 폰트를 준비했으니 이제 pyftsubset 명령어로 서브셋을 만들어보겠습니다. 하지만 서브셋 폰트를 만들기 위해서는 한가지 준비물이 더 필요합니다. 바로 서브셋 폰트로 만들 문자집합니다. 앞서 이야기했지만 한글 웹폰트를 만드는 경우 경우 일반적으로 KS X 1001 표준의 2,350자를 주로 사용합니다. 이에 대한 좀 더 자세한 내용은 뒤에서 논의합니다. 우선은 한 글자로 시작해서 서브셋이 정상적으로 만들어지는 지부터 살펴보도록 하겠습니다(본격적인 작업에 앞서 pyftsubset --help 명령어로 옵션들을 살펴보시는 것도 좋습니다).

pyftsubset의 기본적인 사용법은 다음과 같습니다.

$ pyftsubset <폰트파일경로> --text="<글자목록>" --output-file=<출력경로>

<폰트파일경로>NotoSansCJKkr-Regular.otf를 지정합니다. 폰트가 위치한 디렉터리가 아닌 경우, 폰트의 전체 경로를 지정해주어야합니다. <글자목록>은 서브셋을 만들고자 하는 글자를 직접 지정합니다. ‘가’를 서브셋에 포함시키고자 하면 --text="가"와 같이 입력해줍니다. 여러글자를 입력하는 경우 이어붙여주면 됩니다. 예를 들어 ’가’, ‘나’, ’다’를 포함하고자 하는 경우 --text="가나다"와 같이 옵션을 지정합니다. <출력경로>는 서브셋 폰트가 저장될 위치입니다. --output-file 옵션을 지정하지 않을 경우 폰트 이름은 자동적으로 <폰트이름>.subset.<확장자>가 됩니다.

서브셋 폰트를 저장할 subset-fonts 디렉터리를 하나 만들어놓고 다음 명령어를 실행해 실제로 서브셋 폰트를 만들어봅니다.

$ mkdir subset-fonts
$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --text="나라바아차타하" \
  --output-file="./subset-fonts/NotoSansR.subset.1.otf"

만들어진 서브셋 폰트를 확인해봅니다.

$ ls -al *Regular.otf subset-fonts/NotoSansR.subset.1.otf
-rw-r----- 1 root root 16457008 Jun 15  2015 NotoSansCJKkr-Regular.otf
-rw-r--r-- 1 root root     2072 Dec  9 10:53 subset-fonts/NotoSansR.subset.1.otf

기존의 폰트 크기는 16MB였는데, 서브셋 폰트는 2KB밖에 되지 않습니다. 단, 이 폰트에는 나, 라, 바, 아, 차, 타, 하 7글자만 포함되어 있습니다. 이 폰트를 설치하고 앞서 Noto Sans CJK KR Regular 체에서 살펴본 “가나다라마바사아자차카타파하”와 비교해봅니다.

없는 글자가 표시되지 않는 것을 확인할 수 있다
없는 글자가 표시되지 않는 것을 확인할 수 있다

서브셋 폰트에 포함시킨 나, 라, 바, 아, 차, 타, 하 글자만 정상적으로 출력되는 것을 알 수 있습니다. ’가’부터 ’하’까지 서브셋에 포함시키고자 한다면, text 옵션을 다음과 같이 지정하면 됩니다.

같은 이름의 폰트가 등록되면서 폰트 이름이 조금 이상해졌습니다. 여기선 이 문제에는 따로 대응하지 않습니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --text="가나다라마바사아자차카타파하" \
  --output-file="./subset-fonts/NotoSansR.subset.2.otf"

NotoSansR.subset.2.otf 폰트는 원래의 폰트와 마찬가지로 “가나다라마바사아자차카타파하”를 모두 표현할 수 있지만, 용량은 3KB도 되지 않습니다. 단, 14글자만을 표현할 수 있는 서브셋 폰트입니다.

오리지널 폰트와 비교. 위가 오리지널 폰트, 아래는 서브셋 폰트
오리지널 폰트와 비교. 위가 오리지널 폰트, 아래는 서브셋 폰트

서브셋으로 만들 글자수가 많아지면 --text 인자에 직접 입력하기는 어렵습니다. --text-file를 사용하면 미리 서브셋을 만들 글자들을 텍스트 파일로 만들어놓고 경로를 지정할 수 있습니다. 이 때 테스트 파일 안의 줄바꿈 문자는 무시됩니다.

먼저 다음 내용으로 glyphs.txt를 만듭니다.

가나다라마바사아자차카타파하

pyftsubset 명령을 실행할 때 --text-file="glyphs.txt" 옵션을 지정해주면 위에서 만들었던 서브셋 폰트와 같은 폰트를 만들 수 있습니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --text-file="glyphs.txt" \
  --output-file="./subset-fonts/NotoSansR.subset.3.otf"

폰트 최적화를 위한 옵션

폰트에는 글리프 정보 이외에도 글자를 정상적으로 표현하기 위한 다양한 정보들이 포함되어 있습니다. pyftsubset 명령어로 서브셋 폰트를 생성할 때 글리프 정보 뿐만 아니라, 폰트에 있는 이러한 정보들이 유실될 수 있습니다. 예상치 못한 문제를 방지하기 위해서 방지하기 위해서 글리프만 줄이고, 그 외에는 최대한 원래 폰트의 정보를 유지하는 것이 좋습니다. 이를 위해 다음 옵션들을 사용합니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --output-file="./subset-fonts/NotoSansR.subset.4.otf" \
  --text="가나다라마바사아자차카타파하" \
  --layout-features='*' \
  --glyph-names \
  --symbol-cmap \
  --legacy-cmap \
  --notdef-glyph \
  --notdef-outline \
  --recommended-glyphs \
  --name-legacy \
  --drop-tables= \
  --name-IDs='*' \
  --name-languages='*'

각 옵션은 다음과 같은 의미를 가지고 있습니다. 옵션에 대한 자세한 정보는 pyftsubset 소스코드에서 찾아볼 수 있습니다.

옵션들을 정확히 이해하기 위해서는 폰트 파일 형식에 대한 이해가 필요합니다.

layout-fetaures
폰트에서 유지하고자 하는 레이아웃 기능을 지정합니다. * 을 지정하면 본래 폰트의 모든 레이아웃 기능을 유지합니다.
glyph-names
포스트스크립트PostScript 글리프 이름을 유지합니다.
symbol-cmap
심볼 cmap을 유지합니다.
legacy-cmap
레거시 cmap을 유지합니다.
notdef-glyph
.notdef 글리프를 서브셋에 유지합니다.
notdef-outline
.notdef 글리프의 아웃라인을 서브셋에 유지합니다.
recommended-glyphs
.notdef, .null, nonmarkingreturn, space 글래프를 서브셋에 유지합니다.
name-legacy
레거시 name 테이블을 유지합니다.
drop-tables
폰트의 특정 레이아웃 테이블 정보를 삭제합니다. 빈 값을 넣으면(--drop-tables=) 전부 유지합니다.
name-IDs
유지할 name 테이블의 ID 값들을 지정합니다. *을 지정하면 전부 유지합니다.
name-languages
유지할 name 테이블의 langID 값을 지정합니다. *을 지정하면 전부 유지합니다.

웹폰트 형식 WOFF / WOFF2로 변환하기

일반적으로 데스크탑에서는 OTFOpenType Font나 TTFTrueType Font를 사용합니다. WOFFWeb Open Font Format는 모질라Mozilla를 중심으로 웹에서 사용하기 위해 특별히 만들어진 폰트 형식입니다. WOFF는 OTF나 TTF에 기반해있지만, 내부적인 형식이 다르며 내부적으로 압축이 되어 좀 더 작은 크기를 가지고 있습니다. WOFF2는 내부적으로 brotli 압축 알고리즘을 사용하며, WOFF보다 높은 압축률을 가지고 있습니다.

pyftsubsetwoffwoff2 형식의 변환도 지원합니다.

WOFF 형식 변환

서브셋 폰트를 만들고 WOFF로 변환하는 경우 다음 옵션을 추가해줍니다.

$ pyftsubset ... --flavor='woff'

WOFF 형식의 경우 Zopfli 압축을 추가적으로 지원합니다. Zopfli 압축 방식을 사용하면 폰트 파일이 3-8% 더 작아집니다. 이를 사용하기 위해서는 먼저 zopfil 라이브러리를 설치해야합니다.

$ pip install zopfli

Zopfli 압축방식을 사용하려면 다음 옵션을 추가해줍니다.

$ pyftsubset ... --flavor='woff' --with-zopfli

WOFF2 형식 변환

pyftsubset은 WOFF2도 지원하지만, 변환에 앞서 brotli 파이썬 라이브러리를 설치해야합니다. pip로 brotli를 설치합니다.

$ pip install brotli

WOFF와 마찬가지로, 다음과 같이 flavor 옵션을 지정해서 WOFF2로 변환할 수 있습니다.

$ pyftsubset ... --flavor='woff2'

한글 폰트 서브셋을 만들기 위한 글자 목록

여기까지 pyftsubset 명령어를 사용해 서브셋 폰트를 만드는 방법에 대해 알아보았습니다. 한글 서브셋 폰트에서 가장 많이 사용되는 글자 목록은 KS X 1001 정보 교환용 부호계에 정의되어있는 2,350자입니다. 이 글자 목록은 부록 2에 포함되어 있으며, 여기에서 다운로드 받을 수 있습니다.

하지만 이 글자들은 어디까지나 한글만을 포함하고 있습니다. 한글 자모, 알파벳, 숫자, 구두점을 추가적으로 지원하는 것이 좋습니다.

ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ
ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ
0123456789
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
!"\#$%&'()*+,-./:;<=>?@[^_`|~

1행은 한글 자음입니다. 2행은 한글 모음입니다. 3행은 숫자입니다. 4행은 알파벳 대문자입니다. 5행은 알파벳 소문자입니다. 6행은 아스키코드에서 지원하는 특수문자들과 일반적인 키보드에서 입력가능한 문자들입니다. 이 내용은 여기에서 다운로드 받을 수 있습니다.

이 외에 포함될 글자들은 상황에 따라서 직접 결정해야합니다. 스포카 한 산스에서는 이와 더불어 ’KS 코드 완성형 한글의 추가 글자 제안(노민구, 윤민구)’에서 제안한 224자를 추가로 지원하고 있습니다. 이 목록은 부록 4에 포함되어 있으며, 여기에서 다운로드 받을 수 있습니다.

이 외에 KS X 1001의 특수문자 영역에 포함된 글자들도 고려해볼 수 있습니다. 이는 부록 3에 포함되어 있으며, 여기에서 다운로드 받을 수 있습니다.

한글 서브셋 웹폰트 제작

여기서는 KS X 1001의 한글 2350자, KS X 1001의 특수문자, 한글 자모, 알파벳, 숫자, 구두점, KS 코드 완성형 한글의 추가 글자 제안’에서 추가 제안한 224자를 모두 포함한 서브셋 폰트를 만들어보겠습니다. 전체 글자 목록은 여기에서 다운로드 받을 수 있습니다.

$ wget https://raw.githubusercontent.com/nacyot/korean_subset_glyphs/master/glyphs.txt

다음은 OTF 서브셋 폰트를 만드는 명령어입니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --output-file="./subset-fonts/NotoSansR.subset.5.otf" \
  --text-file="glyphs.txt" \
  --layout-features='*' \
  --glyph-names \
  --symbol-cmap \
  --legacy-cmap \
  --notdef-glyph \
  --notdef-outline \
  --recommended-glyphs \
  --name-legacy \
  --drop-tables= \
  --name-IDs='*' \
  --name-languages='*'

다음은 WOFF 서브셋 폰트를 만드는 명령어입니다. 여기선 추가적으로 Zopfli 압축을 합니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --flavor="woff" \
  --with-zopfli \
  --output-file="./subset-fonts/NotoSansR.subset.5.woff \
  --text-file="glyphs.txt" \
  --layout-features='*' \
  --glyph-names \
  --symbol-cmap \
  --legacy-cmap \
  --notdef-glyph \
  --notdef-outline \
  --recommended-glyphs \
  --name-legacy \
  --drop-tables= \
  --name-IDs='*' \
  --name-languages='*'

다음은 WOFF2 서브셋 폰트를 만드는 명령어입니다.

$ pyftsubset "NotoSansCJKkr-Regular.otf" \
  --flavor="woff2" \
  --output-file="./subset-fonts/NotoSansR.subset.5.woff2" \
  --text-file="glyphs.txt" \
  --layout-features='*' \
  --glyph-names \
  --symbol-cmap \
  --legacy-cmap \
  --notdef-glyph \
  --notdef-outline \
  --recommended-glyphs \
  --name-legacy \
  --drop-tables= \
  --name-IDs='*' \
  --name-languages='*'

최종적으로 만들어진 폰트들은 다음과 같습니다.

$ ls -al
-rw-r--r-- 1 root root 610K Dec 10 19:18 NotoSansR.subset.5.otf
-rw-r--r-- 1 root root 434K Dec 10 19:19 NotoSansR.subset.5.woff
-rw-r--r-- 1 root root 379K Dec 10 19:19 NotoSansR.subset.5.woff2

15MB에 달했던 폰트가 서브셋을 만들고 WOFF2 포맷으로 변환하니 379KB까지 줄었습니다. 물론 앞서 이야기했듯이 표현가능한 문자와 용량은 트레이드 오프 관계에 있고, 웹에서 폰트를 사용할 때는 적절한 서브셋을 정의하는 게 가장 중요하다고 할 수 있습니다. 이제 만들어진 폰트를 웹에서 사용하기만 하면 됩니다. 이 글에서는 웹폰트 사용법을 다루지 않지만, 부록 1에 CSS의 @font-face에 대한 기본적인 사용법을 소개합니다.

마치며

여기까지 파이썬 라이브러리 폰트툴즈로 서브셋 폰트를 만드는 과정에 대해 알아보았습니다. 서브셋을 만들 수 있는 GUI 도구들이 있지만, pyftsubset은 파이썬으로 실행되는 명령어이기 때문에 좀 더 유연하게 사용하는 것이 가능합니다. 필요하다면 서브셋 폰트 생성이나 변환 과정을 자동화하거나, 굵기별 폰트를 전부 서브셋으로 만들어 사용하는 것도 가능합니다.

여기서는 주로 한글 웹폰트의 용량을 줄이기 위해서 글자 수를 줄이는 방법 위주로 이야기했지만, 폰트 서브셋팅은 다양한 활용이 가능합니다. 특수한 목적으로 최소한의 글자만을 담은 아주 작은 폰트를 만들 수도 있고, 랜딩 페이지의 극단적인 최적화가 필요한 경우 페이지에서 사용하는 글자만을 담은 폰트를 만들 수도 있습니다. 이 글이 웹폰트 활용에 도움이 되기를 바랍니다.

이러한 접근 방법은 한 페이지짜리 랜딩 페이지에는 유용할 수 있지만, 페이지가 많아지면 폰트 생성 과정이 번거롭고 무엇보다 전체 폰트를 다운로드 받고 캐시해서 사용하는 것보다 훨씬 불리할 수 있습니다. 적절한 판단이 필요합니다.

부록

부록 1: CSS에서 폰트 정의 방법 및 브라우저 별 지원 여부

웹폰트는 CSS의 @font-face 문법으로 정의합니다. 일반적으로 아래와 같이 정의합니다.

@font-face {
  font-family: 'Awesome Font';
  font-weight: 400;
  src: local('Awesome Font'),
  url('https://example.com/awesome-font.woff2') format('woff2'),
  url('https://example.com/awesome-font.woff2') format('woff'),
  url('https://example.com/awesome-font.otf') format('opentype')
}

src 속성에 여러 개의 지정되어있으면 브라우저는 자신이 지원하는 가장 앞에 있는 방식을 사용합니다. 모던 브라우저들은 대부분 woff2woff를 지원하기 때문에 큰 문제가 없지만, 모든 브라우저에서 웹폰트를 정확히 지원하는 것은 간단하지 않습니다. CSS-Tricks의 Using font-face이나 WIT – NTS UIT Blog의 웹폰트 사용하기 (웹폰트의 모든 것)이 도움이 될 것입니다.

@font-face를 정의한 이후에는 다른 CSS 룰에서 font-family 속성의 값으로 참조할 수 있습니다.

body {
  font-family: 'Awesome Font';
}

각 폰트 형식의 브라우저 지원 여부는 Can I useWOFF, WOFF2, EOT, TTF/OTF 페이지에서 확인할 수 있습니다.

부록 2: KS X 1001 정보 교환용 부호계

KS X 1001의 한글 영역 2350자는 다음과 같습니다. 이 내용은 여기에서 다운로드 받을 수 있습니다.

가각간갇갈갉갊감갑값갓갔강갖갗같갚갛개객갠갤갬갭갯갰갱갸갹갼걀걋걍걔걘걜거걱건걷걸걺검겁것겄겅겆겉겊겋게겐겔겜겝겟겠겡겨격겪견겯결겸겹겻겼경곁계곈곌곕곗고곡곤곧골곪곬곯곰곱곳공곶과곽관괄괆괌괍괏광괘괜괠괩괬괭괴괵괸괼굄굅굇굉교굔굘굡굣구국군굳굴굵굶굻굼굽굿궁궂궈궉권궐궜궝궤궷귀귁귄귈귐귑귓규균귤그극근귿글긁금급긋긍긔기긱긴긷길긺김깁깃깅깆깊까깍깎깐깔깖깜깝깟깠깡깥깨깩깬깰깸깹깻깼깽꺄꺅꺌꺼꺽꺾껀껄껌껍껏껐껑께껙껜껨껫껭껴껸껼꼇꼈꼍꼐꼬꼭꼰꼲꼴꼼꼽꼿꽁꽂꽃꽈꽉꽐꽜꽝꽤꽥꽹꾀꾄꾈꾐꾑꾕꾜꾸꾹꾼꿀꿇꿈꿉꿋꿍꿎꿔꿜꿨꿩꿰꿱꿴꿸뀀뀁뀄뀌뀐뀔뀜뀝뀨끄끅끈끊끌끎끓끔끕끗끙끝끼끽낀낄낌낍낏낑나낙낚난낟날낡낢남납낫났낭낮낯낱낳내낵낸낼냄냅냇냈냉냐냑냔냘냠냥너넉넋넌널넒넓넘넙넛넜넝넣네넥넨넬넴넵넷넸넹녀녁년녈념녑녔녕녘녜녠노녹논놀놂놈놉놋농높놓놔놘놜놨뇌뇐뇔뇜뇝뇟뇨뇩뇬뇰뇹뇻뇽누눅눈눋눌눔눕눗눙눠눴눼뉘뉜뉠뉨뉩뉴뉵뉼늄늅늉느늑는늘늙늚늠늡늣능늦늪늬늰늴니닉닌닐닒님닙닛닝닢다닥닦단닫달닭닮닯닳담답닷닸당닺닻닿대댁댄댈댐댑댓댔댕댜더덕덖던덛덜덞덟덤덥덧덩덫덮데덱덴델뎀뎁뎃뎄뎅뎌뎐뎔뎠뎡뎨뎬도독돈돋돌돎돐돔돕돗동돛돝돠돤돨돼됐되된될됨됩됫됴두둑둔둘둠둡둣둥둬뒀뒈뒝뒤뒨뒬뒵뒷뒹듀듄듈듐듕드득든듣들듦듬듭듯등듸디딕딘딛딜딤딥딧딨딩딪따딱딴딸땀땁땃땄땅땋때땍땐땔땜땝땟땠땡떠떡떤떨떪떫떰떱떳떴떵떻떼떽뗀뗄뗌뗍뗏뗐뗑뗘뗬또똑똔똘똥똬똴뙈뙤뙨뚜뚝뚠뚤뚫뚬뚱뛔뛰뛴뛸뜀뜁뜅뜨뜩뜬뜯뜰뜸뜹뜻띄띈띌띔띕띠띤띨띰띱띳띵라락란랄람랍랏랐랑랒랖랗래랙랜랠램랩랫랬랭랴략랸럇량러럭런럴럼럽럿렀렁렇레렉렌렐렘렙렛렝려력련렬렴렵렷렸령례롄롑롓로록론롤롬롭롯롱롸롼뢍뢨뢰뢴뢸룀룁룃룅료룐룔룝룟룡루룩룬룰룸룹룻룽뤄뤘뤠뤼뤽륀륄륌륏륑류륙륜률륨륩륫륭르륵른를름릅릇릉릊릍릎리릭린릴림립릿링마막만많맏말맑맒맘맙맛망맞맡맣매맥맨맬맴맵맷맸맹맺먀먁먈먕머먹먼멀멂멈멉멋멍멎멓메멕멘멜멤멥멧멨멩며멱면멸몃몄명몇몌모목몫몬몰몲몸몹못몽뫄뫈뫘뫙뫼묀묄묍묏묑묘묜묠묩묫무묵묶문묻물묽묾뭄뭅뭇뭉뭍뭏뭐뭔뭘뭡뭣뭬뮈뮌뮐뮤뮨뮬뮴뮷므믄믈믐믓미믹민믿밀밂밈밉밋밌밍및밑바박밖밗반받발밝밞밟밤밥밧방밭배백밴밸뱀뱁뱃뱄뱅뱉뱌뱍뱐뱝버벅번벋벌벎범법벗벙벚베벡벤벧벨벰벱벳벴벵벼벽변별볍볏볐병볕볘볜보복볶본볼봄봅봇봉봐봔봤봬뵀뵈뵉뵌뵐뵘뵙뵤뵨부북분붇불붉붊붐붑붓붕붙붚붜붤붰붸뷔뷕뷘뷜뷩뷰뷴뷸븀븃븅브븍븐블븜븝븟비빅빈빌빎빔빕빗빙빚빛빠빡빤빨빪빰빱빳빴빵빻빼빽뺀뺄뺌뺍뺏뺐뺑뺘뺙뺨뻐뻑뻔뻗뻘뻠뻣뻤뻥뻬뼁뼈뼉뼘뼙뼛뼜뼝뽀뽁뽄뽈뽐뽑뽕뾔뾰뿅뿌뿍뿐뿔뿜뿟뿡쀼쁑쁘쁜쁠쁨쁩삐삑삔삘삠삡삣삥사삭삯산삳살삵삶삼삽삿샀상샅새색샌샐샘샙샛샜생샤샥샨샬샴샵샷샹섀섄섈섐섕서석섞섟선섣설섦섧섬섭섯섰성섶세섹센셀셈셉셋셌셍셔셕션셜셤셥셧셨셩셰셴셸솅소속솎손솔솖솜솝솟송솥솨솩솬솰솽쇄쇈쇌쇔쇗쇘쇠쇤쇨쇰쇱쇳쇼쇽숀숄숌숍숏숑수숙순숟술숨숩숫숭숯숱숲숴쉈쉐쉑쉔쉘쉠쉥쉬쉭쉰쉴쉼쉽쉿슁슈슉슐슘슛슝스슥슨슬슭슴습슷승시식신싣실싫심십싯싱싶싸싹싻싼쌀쌈쌉쌌쌍쌓쌔쌕쌘쌜쌤쌥쌨쌩썅써썩썬썰썲썸썹썼썽쎄쎈쎌쏀쏘쏙쏜쏟쏠쏢쏨쏩쏭쏴쏵쏸쐈쐐쐤쐬쐰쐴쐼쐽쑈쑤쑥쑨쑬쑴쑵쑹쒀쒔쒜쒸쒼쓩쓰쓱쓴쓸쓺쓿씀씁씌씐씔씜씨씩씬씰씸씹씻씽아악안앉않알앍앎앓암압앗았앙앝앞애액앤앨앰앱앳앴앵야약얀얄얇얌얍얏양얕얗얘얜얠얩어억언얹얻얼얽얾엄업없엇었엉엊엌엎에엑엔엘엠엡엣엥여역엮연열엶엷염엽엾엿였영옅옆옇예옌옐옘옙옛옜오옥온올옭옮옰옳옴옵옷옹옻와왁완왈왐왑왓왔왕왜왝왠왬왯왱외왹왼욀욈욉욋욍요욕욘욜욤욥욧용우욱운울욹욺움웁웃웅워웍원월웜웝웠웡웨웩웬웰웸웹웽위윅윈윌윔윕윗윙유육윤율윰윱윳융윷으윽은을읊음읍읏응읒읓읔읕읖읗의읜읠읨읫이익인일읽읾잃임입잇있잉잊잎자작잔잖잗잘잚잠잡잣잤장잦재잭잰잴잼잽잿쟀쟁쟈쟉쟌쟎쟐쟘쟝쟤쟨쟬저적전절젊점접젓정젖제젝젠젤젬젭젯젱져젼졀졈졉졌졍졔조족존졸졺좀좁좃종좆좇좋좌좍좔좝좟좡좨좼좽죄죈죌죔죕죗죙죠죡죤죵주죽준줄줅줆줌줍줏중줘줬줴쥐쥑쥔쥘쥠쥡쥣쥬쥰쥴쥼즈즉즌즐즘즙즛증지직진짇질짊짐집짓징짖짙짚짜짝짠짢짤짧짬짭짯짰짱째짹짼쨀쨈쨉쨋쨌쨍쨔쨘쨩쩌쩍쩐쩔쩜쩝쩟쩠쩡쩨쩽쪄쪘쪼쪽쫀쫄쫌쫍쫏쫑쫓쫘쫙쫠쫬쫴쬈쬐쬔쬘쬠쬡쭁쭈쭉쭌쭐쭘쭙쭝쭤쭸쭹쮜쮸쯔쯤쯧쯩찌찍찐찔찜찝찡찢찧차착찬찮찰참찹찻찼창찾채책챈챌챔챕챗챘챙챠챤챦챨챰챵처척천철첨첩첫첬청체첵첸첼쳄쳅쳇쳉쳐쳔쳤쳬쳰촁초촉촌촐촘촙촛총촤촨촬촹최쵠쵤쵬쵭쵯쵱쵸춈추축춘출춤춥춧충춰췄췌췐취췬췰췸췹췻췽츄츈츌츔츙츠측츤츨츰츱츳층치칙친칟칠칡침칩칫칭카칵칸칼캄캅캇캉캐캑캔캘캠캡캣캤캥캬캭컁커컥컨컫컬컴컵컷컸컹케켁켄켈켐켑켓켕켜켠켤켬켭켯켰켱켸코콕콘콜콤콥콧콩콰콱콴콸쾀쾅쾌쾡쾨쾰쿄쿠쿡쿤쿨쿰쿱쿳쿵쿼퀀퀄퀑퀘퀭퀴퀵퀸퀼큄큅큇큉큐큔큘큠크큭큰클큼큽킁키킥킨킬킴킵킷킹타탁탄탈탉탐탑탓탔탕태택탠탤탬탭탯탰탱탸턍터턱턴털턺텀텁텃텄텅테텍텐텔템텝텟텡텨텬텼톄톈토톡톤톨톰톱톳통톺톼퇀퇘퇴퇸툇툉툐투툭툰툴툼툽툿퉁퉈퉜퉤튀튁튄튈튐튑튕튜튠튤튬튱트특튼튿틀틂틈틉틋틔틘틜틤틥티틱틴틸팀팁팃팅파팍팎판팔팖팜팝팟팠팡팥패팩팬팰팸팹팻팼팽퍄퍅퍼퍽펀펄펌펍펏펐펑페펙펜펠펨펩펫펭펴편펼폄폅폈평폐폘폡폣포폭폰폴폼폽폿퐁퐈퐝푀푄표푠푤푭푯푸푹푼푿풀풂품풉풋풍풔풩퓌퓐퓔퓜퓟퓨퓬퓰퓸퓻퓽프픈플픔픕픗피픽핀필핌핍핏핑하학한할핥함합핫항해핵핸핼햄햅햇했행햐향허헉헌헐헒험헙헛헝헤헥헨헬헴헵헷헹혀혁현혈혐협혓혔형혜혠혤혭호혹혼홀홅홈홉홋홍홑화확환활홧황홰홱홴횃횅회획횐횔횝횟횡효횬횰횹횻후훅훈훌훑훔훗훙훠훤훨훰훵훼훽휀휄휑휘휙휜휠휨휩휫휭휴휵휸휼흄흇흉흐흑흔흖흗흘흙흠흡흣흥흩희흰흴흼흽힁히힉힌힐힘힙힛힝

부록 3: KS X 1001에 포함된 특수문자

KS X 1001에 포함된 특수문자 영역에 포함된 글자 목록입니다. 이 내용은 여기서 다운로드 받을 수 있습니다.

 、。·‥…¨〃­―∥\∼‘’“”〔〕〈〉《》「」『』【】±×÷≠≤≥∞∴°′″℃Å¢£¥♂♀∠⊥⌒∂∇≡≒§※☆★○●◎◇◆□■△▲▽▼→←↑↓↔〓≪≫√∽∝∵∫∬∈∋⊆⊇⊂⊃∪∩∧∨¬⇒⇔∀∃´~ˇ˘˝˚˙¸˛¡¿ː∮∑∏¤℉‰◁◀▷▶♤♠♡♥♧♣⊙◈▣◐◑▒▤▥▨▧▦▩♨☏☎☜☞¶†‡↕↗↙↖↘♭♩♪♬㉿㈜№㏇™㏂㏘℡€®㉾!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[₩]^_`abcdefghijklmnopqrstuvwxyz{|} ̄ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀㆁㆂㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌㆍㆎⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψω─│┌┐┘└├┬┤┴┼━┃┏┓┛┗┣┳┫┻╋┠┯┨┷┿┝┰┥┸╂┒┑┚┙┖┕┎┍┞┟┡┢┦┧┩┪┭┮┱┲┵┶┹┺┽┾╀╁╃╄╅╆╇╈╉╊㎕㎖㎗ℓ㎘㏄㎣㎤㎥㎦㎙㎚㎛㎜㎝㎞㎟㎠㎡㎢㏊㎍㎎㎏㏏㎈㎉㏈㎧㎨㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎀㎁㎂㎃㎄㎺㎻㎼㎽㎾㎿㎐㎑㎒㎓㎔Ω㏀㏁㎊㎋㎌㏖㏅㎭㎮㎯㏛㎩㎪㎫㎬㏝㏐㏓㏃㏉㏜㏆ÆЪĦIJĿŁØŒºÞŦŊ㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮½⅓⅔¼¾⅛⅜⅝⅞æđðħıijĸŀłøœßþŧŋʼn㈀㈁㈂㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌㈍㈎㈏㈐㈑㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛⒜⒝⒞⒟⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀⒁⒂¹²³⁴ⁿ₁₂₃₄ぁあぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとどなにぬねのはばぱひびぴふぶぷへべぺほぼぽまみむめもゃやゅゆょよらりるれろゎわゐゑをんァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタダチヂッツヅテデトドナニヌネノハバパヒビピフブプヘベペホボポマミムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя

부록 4: ’KS 코드 완성형 한글의 추가 글자 제안’에서 제안한 224자

KS 코드 완성형 한글의 추가 글자 제안(노민구, 윤민구)에서 제안한 KS X 1001에 포함되지 않은 표준말을 표기하기 위한 추가 글자 9자, 준말을 표기하기 위한 추가 글자 24자, 발음을 표기하기 위한 추가 글자 39자, 사투리를 표기하기 위한 추가 글자 41자, 한국어 활용형을 표기하기 위한 추가 글자 9자, 고유 명사, 외래어, 외국어 발음을 표기하기 위한 추가 글자 67자, 감탄사, 의성어, 신조어를 표기하기 위한 추가 글자 42자 등 224자(중복되는 7자 제외)의 목록입니다.

이 내용은 여기서 다운로드 받을 수 있습니다.

갋갣걥겷괐괢굠굥궸귕귬긂긇긓깄깯꺆꺍껓껕꼉꼳꽅꽸꿘뀰뀼낻냗냡냣냬넏넢넫녇녱놁놑놰뇄뇡뇸눍눝뉻늗늧늼닁닏닽댠됭둗둚뒙딮딷똠똡똣똭똰뙇뙜뚧뜳뜽뜾랃랟랲럔럲럳렜렫롣롹뢔뤤맜맟맫먄몱뫠뫴뭥뮊뮹믁믕믜밷뱜뱡볌볻볿봥뵴붠붴뷁븡븨빋빧뺜뽓뾱뿕뿝쀠쁭샏샾섁섿셱솀솁솓쇵숖슌싥싳싿쎔쎠쎤쎵쎼쏼쑝쒐쒬씃씿앋앜얬얭옏옝옦옫왘왭왰욷웇웟웻윾읩읭읻잌잍쟵젇젉좬즒즤짣짲쫃쫒쬲쮓찓찟쵀췍칢칮칰칻캨캰컄켘콛쾃쿈쿽퀌퀜퀠큲킄탇턻톧퇻툶퉷팓팤팯펵퐉핰핳핻햏햔햣헗헠헡헣헿홥홨횽훕흝힣

같이 읽으면 좋은 문서들

웹폰트 개념과 최적화를 이해하는 데 추천하는 문서들입니다.

GUI 도구를 사용한 폰트 서브셋팅 방법을 소개하는 문서들입니다.

웹폰트와 관련된 표준 문서들입니다.

아마존 웹 서비스 IAM 사용자의 액세스 키 발급 및 관리

🗒 기사, 2018-06-09 - 아마존 웹 서비스 계정은 하나의 루트 계정과 다수의 IAM 사용자로 구성됩니다. 각 사용자는 자신의 권한으로 외부에서 API를 호출할 수 있는 토큰을 발급받을 수 있습니다. 이 액세스 키를 발급하고 관리하는 법을 소개합니다.

아마존 S3(Amazon S3), path 형식의 API 호출 중지 예정

🗞 새소식, 2019-05-08 - 아마존 S3에서는 현재 경로 형식과 가상 호스트 형식 두 가지 방식의 객체 지정이 가능합니다. 2020년 9월 30일부터 AWS의 S3에 대한 경로 형식의 API 요청이 동작하지 않도록 변경됩니다. 이에 따라 AWS에서는 최신 SDK를 사용하고 경로 형식을 사용하는 코드를 변경하도록 권장하였습니다.

아마존 ECR(Amazon ECR), 도커 이미지 취약점 스캔 기능 추가

🗞 새소식, 2020-01-09 - 작년 10월 28일에 아마존 웹 서비스(Amazon Web Service)의 매니지드 도커 레지스트리 서비스 아마존 ECR(Amazon ECR)에 이미지 취약점 검사 기능이 추가되었습니다. 이 기능을 사용해 현재 등록된 이미지의 취약점을 스캔하거나, 새로 푸시되는 이미지를 자동적으로 스캔하는 것이 가능합니다.