gpdf에서 Source Han Sans JP(본고딕 JP)를 사용하려면?
Adobe의 GitHub 릴리스에서 TTF 버전을 받아 gpdf.WithFont로 등록한다. Noto Sans JP와 같은 글리프, 7가지 굵기, SIL OFL.
질문을 다시 말하면
gpdf 문서에서 Source Han Sans JP(본고딕 JP) — 2014년 Adobe와 Google 협력으로 공개된 pan-CJK 산세리프의 Adobe 측 브랜드 — 를 쓰고 싶다. 이유는 다양하다. 팀이 재현성을 위해 폰트를 GitHub 릴리스 태그에 핀 해두고 싶거나, 오래 전 Source Han으로 표준화된 디자인 시스템을 인수받았거나, 그냥 Adobe 릴리스 주기가 더 편하거나. 뭐든 상관없다. 다운로드하기 전에 세 가지만 정리해 두면 된다 — 어떤 파일을 받을지, Noto Sans JP와의 실제 관계, 그리고 gpdf가 읽을 수 있는 포맷이 무엇인지.
빠른 답
adobe-fonts/source-han-sans 릴리스 페이지에서 SourceHanSansJP-Regular.ttf를 받아(TTF 번들, OTF 아님), gpdf.WithFont("SourceHanSansJP", bytes)로 등록하고 기본 폰트로 설정한다. Source Han Sans JP와 Noto Sans JP는 글리프 윤곽이 같으므로, Adobe 배포 생태계에 특별히 얽매일 이유가 없다면 Noto Sans JP가 더 간단한 다운로드다.
완성된 예제
package main
import (
"log"
"os"
"github.com/gpdf-dev/gpdf"
"github.com/gpdf-dev/gpdf/document"
"github.com/gpdf-dev/gpdf/template"
)
func main() {
font, err := os.ReadFile("SourceHanSansJP-Regular.ttf")
if err != nil {
log.Fatal(err)
}
doc := gpdf.NewDocument(
gpdf.WithPageSize(gpdf.A4),
gpdf.WithMargins(document.UniformEdges(document.Mm(20))),
gpdf.WithFont("SourceHanSansJP", font),
gpdf.WithDefaultFont("SourceHanSansJP", 11),
)
page := doc.AddPage()
page.AutoRow(func(r *template.RowBuilder) {
r.Col(12, func(c *template.ColBuilder) {
c.Text("報告書", template.FontSize(24), template.Bold())
c.Text("Source Han Sans JP — Adobe 배포 무료 CJK 폰트.")
})
})
data, err := doc.Generate()
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("report.pdf", data, 0o644); err != nil {
log.Fatal(err)
}
}
TTF를 main.go 옆에 두고 go run main.go. 일본어가 들어간 한 페이지짜리 PDF가 report.pdf로 떨어진다.
Source Han Sans JP = Noto Sans CJK JP
검색 시간 몇 시간을 아껴줄 사실 하나: Source Han Sans와 Noto Sans CJK는 같은 폰트다. Adobe가 글리프 설계, 메트릭 테이블, 문자셋 커버리지를 담당했다. Google은 Noto 이름으로 병행 유통했다. 두 배포판 모두 2014-07-15에 출시되었다. 윤곽 데이터, hmtx, JIS X 0213 / Adobe-Japan1-6 커버리지는 비트 단위로 동일하다. Adobe가 버전을 올리면 Noto에도 몇 주 안에 반영된다.
차이는 전부 브랜딩과 패키징 층에 있다:
| Source Han Sans JP | Noto Sans JP | |
|---|---|---|
| 발행자 | Adobe | |
| 정식 출처 | adobe-fonts/source-han-sans | notofonts.github.io + Google Fonts |
| 기본 포맷 | OTF (CFF 윤곽) | TTF (static) + variable |
| 릴리스 모델 | GitHub 릴리스 태그로 수동 버전 관리 | Google Fonts CDN + git 저장소 |
| 언어 묶음 | 언어별 TTF + pan-CJK OTC | JP 전용 |
팀이 Adobe의 GitHub 태그에 폰트를 고정하려 하거나, 이미 github.com/adobe-fonts를 사내 미러링하거나, 파이프라인 다른 공정에서 pan-CJK OTC가 필요하다면 Source Han Sans JP가 맞다. 그렇지 않다면 TTF를 바로 받을 수 있는 Noto Sans JP 쪽이 손이 덜 간다.
왜 OTF가 아니라 TTF인가
Adobe의 기본 자산은 .otf, 정확히는 CFF 기반 OpenType이다. gpdf의 폰트 파서는 pdf/font/truetype.go 한 파일에 모여 있고 glyf, loca, cmap, hmtx와 복합 글리프를 읽는다. CFF / CFF2 윤곽은 읽지 않는다. CFF 기반 .otf를 넘기면 렌더 시점이 아니라 문서 생성 시점에 파싱 에러가 난다.
Adobe 릴리스 페이지는 OTF와 TTF를 모두 제공하므로 TTF 번들 쪽을 받는다. 특정 포인트 릴리스에 TTF가 없는 경우엔 깔끔한 대안이 둘 있다:
- Noto Sans JP로 바꾼다. Google Fonts가 정적 TTF를 직접 제공한다. 글리프 데이터는 동일하다. 변환이 필요 없다.
- 한 번만 변환하고 결과를 커밋한다.
fonttools의otf2ttf가 1분이면 TTF를 만든다. 결과를 저장소나 사내 아티팩트 서버에 올리고, 변환 단계는 빌드 파이프라인에서 빼둔다.
빌드 시점에 변환하는 건 피한다. 폰트 변환 도구는 버전 간 동작이 미세하게 다르고, hmtx 테이블이 조금만 바뀌어도 pip install -U 하나로 행 넘김 위치가 바뀐다.
일곱 굵기
Source Han Sans JP는 ExtraLight부터 Heavy까지 한 굵기당 한 파일로 배포한다:
SourceHanSansJP-ExtraLight.ttf
SourceHanSansJP-Light.ttf
SourceHanSansJP-Normal.ttf
SourceHanSansJP-Regular.ttf
SourceHanSansJP-Medium.ttf
SourceHanSansJP-Bold.ttf
SourceHanSansJP-Heavy.ttf
대부분의 업무 문서는 Regular와 Bold 둘이면 충분하다:
reg, _ := os.ReadFile("SourceHanSansJP-Regular.ttf")
bold, _ := os.ReadFile("SourceHanSansJP-Bold.ttf")
doc := gpdf.NewDocument(
gpdf.WithFont("SourceHanSansJP", reg),
gpdf.WithFont("SourceHanSansJP-Bold", bold),
gpdf.WithDefaultFont("SourceHanSansJP", 11),
)
-Bold 접미사가 template.Bold()와 Bold TTF를 연결하는 규약이다. 등록하지 않은 채 template.Bold()를 쓰면 Regular 글리프 위에 0.4 pt 획을 덧댄 합성 볼드로 대체된다 — 제목 정도는 버티지만, 큰 글자 크기에서는 진짜 Bold 윤곽보다 가늘어 보인다.
CJK 폰트는 관례적으로 이탤릭을 만들지 않고, Source Han Sans JP도 마찬가지다. 일본어에 이탤릭 강조가 필요한 레이아웃이라면 굵기나 색으로 대신한다. 한자에 기울임 변환을 걸면 강조가 아니라 깨진 글자로 보인다.
Pan-CJK, JP 전용, Super OTC
Adobe는 Source Han Sans를 여러 입도로 배포한다. Go PDF 생성에서는 혼용할 수 없다:
- SourceHanSans.ttc(Super OTC) — 모든 CJK 언어가 20 MB+ TrueType Collection 하나에 들어 있다. gpdf는
.ttc내부의 face 인덱스를 직접 풀지 않기 때문에, 먼저fonttools로 JP face를 추출해 TTF로 등록해야 한다. 보통은 쓰지 않는다. - 지역 통합 OTF(예:
SourceHanSans-Regular.otf) — 전체 CJK 통합, CFF 윤곽. gpdf가 못 읽는다. - 언어별 TTF(
SourceHanSansJP-Regular.ttf) — JP 전용,glyf윤곽. 이걸 쓴다.
한 페이지에서 일본어와 한국어/중국어가 섞이는 문서라면 pan-CJK OTF에 의존하지 말고 언어별 패밀리를 나란히 등록한다: SourceHanSansJP + SourceHanSansKR. 스크립트가 바뀌는 지점에서 template.FontFamily로 명시한다. pan-CJK OTF는 한자를 Han unification으로 하나의 형으로 묶어버리기 때문에, 일본어 본문에 있어야 할 일본어 자형의 한자가 중국어 자형으로 나오는 사고가 생긴다.
Noto 대신 Source Han을 고를 때
윤곽은 같고 유통 채널이 다르다. Source Han Sans JP가 자연스러운 경우:
- 운영 팀이 폰트를 Adobe의 GitHub 릴리스 태그에 고정하는 운용을 선호함(재현성, 감사성)
- 사내에서 이미
github.com/adobe-fonts를 미러링하고 있음(엄격한 아티팩트 정책의 기업에서 흔함) - 파이프라인 다른 단계에서도 pan-CJK OTC 번들이 필요함(DTP 핸드오프, Adobe 이름으로 통일된 브랜드 시스템 등)
Noto Sans JP가 더 잘 맞는 경우:
- TTF를 최단 경로로 받고 싶다(
fonts.google.com/noto/specimen/Noto+Sans+JP→ zip → 끝) - OTF → TTF 변환을 빌드에 끌어들이고 싶지 않다
- 프로젝트가 이미 기존 워크플로로 다른 Google Fonts를 받고 있다
렌더링 결과는 같다. 판단은 운영상의 것 — 파일이 어디에 있고 어떻게 버전을 관리하고 팀이 어느 쪽에 익숙한가 — 이지, 미감의 문제가 아니다.
관련 레시피
- gpdf에서 Noto Sans JP를 사용하려면? — 같은 글리프, 박스에서 꺼내면 TTF
- gpdf에서 일본어 폰트를 임베드하려면? — CJK 임베딩의 일반 레시피
- gpdf에서 IPAex 고딕을 사용하려면? — 일본 공공 제출용 IPA 라이선스 대안
- gpdf로 만든 PDF에서 일본어가 네모로 나올 때 — 글리프 누락 트러블슈팅
gpdf를 써보자
gpdf는 Go용 PDF 생성 라이브러리다. MIT 라이선스, 외부 의존성 0, 네이티브 CJK 지원.
go get github.com/gpdf-dev/gpdf