ワープロ専用機風フォントを作ったときに色々調べたのでまとめてみます。
自分でフォントをデザインするときはGUIのフォントエディタを使うのだと思いますが、この記事ではアウトラインデータが手元にあって(もしくはプログラムで生成するつもりで)、そこからPythonスクリプトでフォントを作る方法を紹介します。
基礎知識
OpenType
OpenTypeは現在最も広く使われているフォントの規格で、フォントを作る場合は通常これがターゲット形式になります。
ちなみにWebフォントの形式であるWOFFやWOFF2は独立したフォント形式というわけではなく、OpenTypeに含まれるデータを再構成して圧縮率を上げたものです。
Unified Font Object (UFO)
OpenTypeは完成したフォントを配布するためのフォーマットであり、編集用として必ずしも便利なものではありません。各フォントエディタは編集用にはそれぞれ独自の形式を使っていましたが、こうした用途でのオープンな汎用フォーマットとして考えられたのがUFOです。フォントを扱うPythonライブラリでも目にすることが多い形式です。
ライブラリ
defcon
とufo2ft
というライブラリを使います。pip
でインストールできます。
$ pip install defcon ufo2ft
defcon
はUFOデータをPythonから便利に扱えるライブラリです。フォントエディタなどでオブジェクトモデルとして使われることを想定しているようです。
ufo2ft
は、defcon
のフォントオブジェクトからOpenType形式への変換を提供するライブラリです。
フォントを作る
以下は、ufo2ft
でフォントを生成する最小限のプログラムです。文字 a
を塗りつぶされた正方形で表示するだけのフォントを生成します。
#!/usr/bin/env python
import defcon
import ufo2ft
font = defcon.Font()
# フォント名、基本メトリックの設定
font.info.familyName = 'Sample Font'
font.info.unitsPerEm = 1000
font.info.descender = -120
font.info.ascender = 880
font.info.xHeight = 500
font.info.capHeight = 800
# 文字 'a' 用のグリフを追加
glyph = font.newGlyph('a')
glyph.unicode = ord('a')
glyph.width = 1000
# グリフにアウトラインを追加
contour = defcon.Contour()
contour.appendPoint(defcon.Point((0, -120), 'line'))
contour.appendPoint(defcon.Point((1000, -120), 'line'))
contour.appendPoint(defcon.Point((1000, 880), 'line'))
contour.appendPoint(defcon.Point((0, 880), 'line'))
glyph.appendContour(contour)
# OTFファイルを書き出す
otf = ufo2ft.compileOTF(font)
otf.save('sample.otf')
部分ごとに見ていきましょう。
Fontオブジェクトの作成
import defcon
import ufo2ft
font = defcon.Font()
必要なライブラリをインポートして、defcon.Font
オブジェクトを作成します。これがフォント全体を表すオブジェクトで、この中にメトリック情報や各文字のデータを設定していきます。
フォント名、基本メトリックの設定
font.info.familyName = 'Sample Font'
font.info.unitsPerEm = 1000
font.info.descender = -120
font.info.ascender = 880
font.info.xHeight = 500
font.info.capHeight = 800
font.info
は defcon.Info
オブジェクトで、フォントの基本情報や各種メトリック値を保持します。ここでは最低限の情報として、以下を設定しています。
-
familyName
(フォントファミリー名) -
unitsPerEm
(emあたりの単位数、1000や1024が一般的) -
descender
(ディセンダー、負の値になる) -
ascender
(アセンダー) -
xHeight
(エックスハイト、小文字の高さ) -
capHeight
(キャップハイト、大文字の高さ)
設定できる値の一覧や意味は defcon.Info
のドキュメント や UFOのfontinfo.plist
の仕様 を参照してください。これらの値がOpenTypeのテーブルにどう反映されるかは、ufo2ftのこのあたりを読むとわかるかもしれません。
文字 'a' 用のグリフを追加
glyph = font.newGlyph('a')
glyph.unicode = ord('a')
glyph.width = 1000
次にfont.newGlyph()
を呼び出して、フォントに新しいグリフ(字形)を追加します。引数'a'
はグリフの名前です。
グリフと文字コードとの対応づけは、グリフのunicode
プロパティにUnicodeコードポイントを設定することで行います。ここではa
の文字コード(ord('a')
= 0x61)を設定しています。
グリフのwidth
プロパティには、グリフの幅を設定します。ここでは1em(1 * unitsPerEm
)を設定しています。
グリフにアウトラインを追加
contour = defcon.Contour()
contour.appendPoint(defcon.Point((0, -120), 'line'))
contour.appendPoint(defcon.Point((1000, -120), 'line'))
contour.appendPoint(defcon.Point((1000, 880), 'line'))
contour.appendPoint(defcon.Point((0, 880), 'line'))
glyph.appendContour(contour)
作成したグリフにアウトライン情報を追加していきます。defcon.Contour
はひと繋がりの輪郭線を表し、複数のdefcon.Point
で構成されます。ここでは、4つの頂点 (0, -120), (1000, -120), (1000, 880), (0, 880) を直線で結んだ正方形の輪郭線を定義しています。ちなみにSVG等とは異なり、y座標の大きいほうが上になります。
作成した輪郭線は、appendContour()
でグリフに追加します。
OTFファイルを書き出す
otf = ufo2ft.compileOTF(font)
otf.save('sample.otf')
最後に、ufo2ft.compileOTF()
メソッドでOpenType形式にコンパイルし、save()
でファイルに書き出します。
作成したフォントの確認
前節のPythonプログラムを実行するとsample.otf
という名前でフォントファイルが生成されます。
フォントの確認は、ブラウザでWebフォントとして読み込ませてみるのが簡単です。以下のHTMLファイルをsample.otf
と同じフォルダに置いて、ブラウザで開いてみてください。
<!DOCTYPE html>
<style>
@font-face {
font-family: 'sample';
src: url('sample.otf');
}
p {
font-family: 'sample';
}
</style>
<p>
abcabc
</p>
以下が表示結果です。bとcはグリフがないので、フォールバックフォントで表示されています。