gpdf で Source Han Sans JP (源ノ角ゴシック JP) を使うには?
Adobe の GitHub リリースから TTF 版 Source Han Sans JP を取得して gpdf.WithFont で登録する。Noto Sans JP と同じグリフ、7 ウェイト、SIL OFL。
質問を言い換えると
gpdf のドキュメントで Source Han Sans JP (源ノ角ゴシック JP) — Adobe と Google の提携で 2014 年に公開された汎 CJK サンセリフの Adobe 側ブランド — を使いたい。GitHub のリリースタグで再現性を確保したい、Source Han を標準化してきたデザインシステムを受け継いでいる、あるいは Adobe の配布サイクルが好み。理由はどれでも構わない。ダウンロードする前に押さえておきたいのは 3 点だけ — どのファイルを取るか、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。日本語入り 1 ページの PDF が report.pdf として出力される。
Source Han Sans JP = Noto Sans CJK JP
最初に押さえておきたい事実は 1 つ。Source Han Sans と Noto Sans CJK は同じフォント。グリフ設計・メトリクス・文字セットは Adobe が担当し、Google が Noto ブランドで並行配布した。リリース日は両者とも 2014-07-15。アウトライン、hmtx テーブル、JIS X 0213 / Adobe-Japan1-6 のカバレッジは 1 bit 単位で同一で、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 + 汎 CJK OTC | JP のみ |
Adobe の GitHub タグを固定する運用、社内で github.com/adobe-fonts をミラーリング済み、あるいは別パイプラインで汎 CJK OTC も使う — こういう事情があれば Source Han Sans JP。そうでなければ TTF が直接落とせる Noto Sans JP のほうが手間が少ない。
なぜ OTF ではなく TTF なのか
Adobe の既定配布は .otf、正確には CFF ベースの OpenType。一方 gpdf のフォントパーサは pdf/font/truetype.go 1 ファイルにまとまっており、扱うのは glyf / loca / cmap / hmtx と複合グリフ。CFF / CFF2 アウトラインは読まない。CFF 系 .otf を渡すと、レンダリング時ではなくドキュメント構築時点でパースエラーになる。
Adobe のリリースページは OTF と TTF の両方を公開しているので、TTF バンドル を選ぶ。ポイントリリースで TTF が落ちていないケース用に、きれいな代替は 2 つ:
- Noto Sans JP に切り替える。 Google Fonts が static TTF を直接配信しており、グリフデータは完全に同じ。変換不要、出力も同じ。
- 一度変換してコミットする。
fonttoolsのotf2ttfで 1 分。結果をリポジトリか社内のアーティファクトサーバに置いて、ビルドパイプラインから変換処理を追い出す。
ビルド時にその場で変換するのは避ける。フォント変換ツールはバージョンをまたぐと挙動が微妙に変わり、hmtx テーブルがわずかに違うだけで改行位置が pip install -U のタイミングで動く。
7 ウェイト
Source Han Sans JP は ExtraLight から Heavy まで 7 ウェイトを個別 TTF で配布:
SourceHanSansJP-ExtraLight.ttf
SourceHanSansJP-Light.ttf
SourceHanSansJP-Normal.ttf
SourceHanSansJP-Regular.ttf
SourceHanSansJP-Medium.ttf
SourceHanSansJP-Bold.ttf
SourceHanSansJP-Heavy.ttf
ほとんどの業務文書では Regular と Bold の 2 本で足りる:
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() とボールド TTF を結びつける規約。登録しないまま template.Bold() を使うと、Regular グリフに 0.4 pt のストロークを重ねた合成ボールドにフォールバックする。見出し程度なら通用するが、大きな級数では本物のボールドアウトラインに比べて明らかに痩せて見える。
CJK フォントはイタリック版を出さないのが定石で、Source Han Sans JP も例外ではない。日本語の強調にイタリックが欲しい場面は、ウェイトか色に振り替えるほうが自然。漢字に斜体変形をかけると強調ではなく破綻して見える。
Pan-CJK か JP 単体か SuperOTC か
Adobe は Source Han Sans を複数の粒度で配布している。Go の PDF 生成では使い分けが重要:
- SourceHanSans.ttc (Super OTC) — CJK 全言語を 1 つの 20 MB 超の TrueType Collection に収めたファイル。gpdf は
.ttcの内部フェースインデックスを解決しないため、先にfonttoolsで JP フェースを切り出して TTF として渡す必要がある。通常は選ばない。 - 地域別 OTF (例:
SourceHanSans-Regular.otf) — CJK 言語統合、CFF アウトライン。gpdf では読めない。 - 言語別 TTF (
SourceHanSansJP-Regular.ttf) — JP 単体、glyfアウトライン。これを選ぶ。
1 ページに日本語と韓国語 / 中国語が混在する場合は、汎 CJK OTF に頼らず言語別ファミリを並べて登録する: SourceHanSansJP と SourceHanSansKR を登録し、スクリプトが切り替わる箇所で template.FontFamily を明示する。汎 CJK OTF は漢字を Han unification で 1 つの形に寄せるため、日本語本文の中で「これは日本語の漢字のはず」と読者が感じる文字が中国語の字形で出てしまう事故が起きる。
Noto ではなく Source Han を選ぶべき場面
アウトラインは同じ、違うのは配布経路。Source Han Sans JP を選ぶと自然なのは:
- Adobe の GitHub リリースタグにフォントを固定する運用を取りたい (再現性・監査性)
- 社内で
github.com/adobe-fontsをすでにミラーしている (厳しいアーティファクトポリシーのある企業で多い) - 汎 CJK OTC バンドルがパイプラインの別工程でも役立つ (DTP 連携、ブランドシステムが Adobe 名で統一されている等)
逆に Noto Sans JP が正解なのは:
- TTF を最短経路で入手したい (
fonts.google.com/noto/specimen/Noto+Sans+JP→ zip → 完了) - OTF→TTF 変換をビルドに持ち込みたくない
- すでに他の Google Fonts を既存ワークフローで取得している
レンダリング結果はどちらでも同じ。判断軸は運用上のもの — ファイルをどこから取るか、どうバージョニングするか、運用チームがどちらに慣れているか — で、美的なものではない。
関連記事
- Noto Sans JP を gpdf で使うには? — 同じグリフ、TTF でそのまま配布されている選択肢
- gpdf で日本語フォントを埋め込むには? — CJK 全般の一般的な埋め込みレシピ
- gpdf で IPAex ゴシックを使うには? — IPA ライセンスの選択肢 (官公庁提出向け)
- gpdf で日本語が豆腐文字になる原因と直し方 — グリフが出ないときのトラブルシュート
gpdf を使ってみる
gpdf は Go の PDF 生成ライブラリ。MIT、外部依存ゼロ、ネイティブ CJK 対応。
go get github.com/gpdf-dev/gpdf