フォントファイル(*.ttf)から文字のコードポイント(U+????)の一覧を出力する方法を紹介します。
使用する言語はPythonです。
fonttoolsのインストール
フォントファイルの処理にfonttoolsを使用します。pipなどを使ってインストールしてください。
pip install fonttools
virtualenvやgitを使った方法は以下にあります。
フォントファイルの準備
この記事では、サンプルのフォントファイルとして ipamjm.ttf(IPAmj明朝フォント) を使用します。
窓の杜などから事前にダウンロードして作業用のフォルダに置いてください。
IPAmj明朝フォント
https://forest.watch.impress.co.jp/library/software/ipamjfont/
ちなみに、Windowsの場合は、
C:\Windows\Fonts
に各種フォントファイルが置いてあります。
このフォルダをエクスプローラーで開くとフォントの一覧が表示され、右クリックからコピーできます。
ファイルの一覧を直接見たい場合は、コマンドプロンプトなどからCUIでアクセスします。
dir "C:\Windows\Fonts"
拡張子が*.ttcだった場合
拡張子*.ttcはTrueType Collectionファイルで、複数の*.ttfファイルを含んだフォントファイルです。
処理の前に個別の*.ttfファイルへ変換する必要がありますので、以下のページを参考に変換を行ってください。
フォントファイルの詳細な情報を取得
こちらのページにfonttoolsを使って個別のフォントファイルから詳細な情報を*.json形式で出力するサンプルコードがあります。
出力結果の例もありますので参考にしてください。
ただし、サンプルコードを実行する場合、出力に日本語を含んでいるとエラーとなるため、json.dump()関数の中にあるopen()関数を以下のように書き換えてください。
open('OcrB-Regular-Info.json', 'w')
↓
open('OcrB-Regular-Info.json', 'w',encoding="utf8")
テーブルデータ
フォントファイルはフォントについての各情報をテーブルデータという状態で保持しています。
このうち、nameテーブルとcmapテーブルの出力方法を紹介します。
nameテーブル
フォント名などの文字列の情報はnameテーブルに格納されています。
以下のコードで一覧出力することができます。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
print("platformID,platEncID,langID,nameID,name")
for name in font['name'].names:
print("{0},{1},0x{2:04x},{3},{4}".format(name.platformID,name.platEncID,name.langID,name.nameID,name))
実行結果
platformID,platEncID,langID,nameID,name
1,0,0x0000,0,Copyright(c) Information-technology Promotion Agency, Japan (IPA), 2011-2019. You must accept "https://opensource.org/licenses/IPA/" to use this product.
1,0,0x0000,1,IPAmjMincho
1,0,0x0000,2,Regular
1,0,0x0000,3,IPAmjMincho Version 006.01
1,0,0x0000,4,IPAmjMincho
1,0,0x0000,5,Version 006.01
1,0,0x0000,6,IPAmjMincho
1,0,0x0000,13,https://opensource.org/licenses/IPA/
1,0,0x0000,14,https://opensource.org/licenses/IPA/
1,1,0x000b,0,Copyright(c) Information-technology Promotion Agency, Japan (IPA), 2011-2019. You must accept "https://opensource.org/licenses/IPA/" to use this product.
1,1,0x000b,1,IPAmj明朝
1,1,0x000b,2,Regular
1,1,0x000b,3,IPAmjMincho Version 006.01
1,1,0x000b,4,IPAmj明朝
1,1,0x000b,5,Version 006.01
1,1,0x000b,6,IPAmjMincho
1,1,0x000b,13,https://opensource.org/licenses/IPA/
1,1,0x000b,14,https://opensource.org/licenses/IPA/
3,1,0x0409,0,Copyright(c) Information-technology Promotion Agency, Japan (IPA), 2011-2019. You must accept "https://opensource.org/licenses/IPA/" to use this product.
3,1,0x0409,1,IPAmjMincho
3,1,0x0409,2,Regular
3,1,0x0409,3,IPAmjMincho Version 006.01
3,1,0x0409,4,IPAmjMincho
3,1,0x0409,5,Version 006.01
3,1,0x0409,6,IPAmjMincho
3,1,0x0409,13,https://opensource.org/licenses/IPA/
3,1,0x0409,14,https://opensource.org/licenses/IPA/
3,1,0x0411,0,Copyright(c) Information-technology Promotion Agency, Japan (IPA), 2011-2019. You must accept "https://opensource.org/licenses/IPA/" to use this product.
3,1,0x0411,1,IPAmj明朝
3,1,0x0411,2,Regular
3,1,0x0411,3,IPAmjMincho Version 006.01
3,1,0x0411,4,IPAmj明朝
3,1,0x0411,5,Version 006.01
3,1,0x0411,6,IPAmjMincho
3,1,0x0411,13,https://opensource.org/licenses/IPA/
3,1,0x0411,14,https://opensource.org/licenses/IPA/
各IDの意味は以下のページを参照してください。
各IDがわかっていれば、文字列の情報を直接参照することもできます。
例えば、Windows(platformID=3,platEncID=1)の日本語(langID=0x0411)のフォントファミリー名(nameID=1)を取得する場合は、以下のようになります。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
print(font['name'].getName(1,3,1,0x0411))
実行結果
IPAmj明朝
getName()関数の詳細は以下のページを参照してください。
cmapテーブル
cmapテーブル、フォントファイルに含まれる文字のコードポイントとフォントのグリフ(形)の対応関係を格納したテーブルになります。ただし、実際の文字の形のデータはglyphテーブルに格納されており、cmapテーブルにはそれを参照するためのインデックスが格納されています。
cmapテーブルには複数のサブテーブルが含まれており、環境ごとに別々のリストが格納されいます。
以下のコードでサブテーブルを一覧出力することができます。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
print("format,platformID,platEncID")
for cmap in font['cmap'].tables:
print("{0},{1},{2}".format(cmap.format,cmap.platformID,cmap.platEncID))
実行結果
format,platformID,platEncID
4,0,3
14,0,5
4,3,1
12,3,10
各IDの意味は以下のページを参照してください。
このうち一番下のfomrmat=12,platformID=3,platEncID=10のデータが全体のデータを含んでいるサブテーブルになります。
これに含まれているリストを参照するには以下のコードを実行します。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
#platformIDとplatEncIDを指定
cmap = font['cmap'].getcmap(3,10)
print("code,glyph")
for code, glyph in cmap.cmap.items():
print("U+{0:X},{1}".format(code,glyph))
実行結果(一部)
U+53CA,mj007990
U+53CB,mj007992
U+53CC,mj007993
U+53CD,mj007994
U+53CE,mj007996
U+53CF,mj007997
U+53D0,mj007998
U+53D2,mj007999
U+53D3,mj008000
U+53D4,mj008002
U+53D5,mj008003
U+53D6,mj008004
U+53D7,mj008005
U+53D9,mj008007
U+53DA,mj008008
U+53DB,mj008010
U+53DC,mj008013
U+53DD,mj008014
U+53DE,mj008016
U+53DF,mj008018
U+53E0,mj008020
U+53E1,mj008021
U+53E2,mj008022
U+53E3,mj008023
[コードポイント],[glyphインデックス]の順に並んでいます。
また、getBestCmap()関数を使用すると、自動的に最適なサブテーブルを選んで取得することもできます。
IDを指定する必要がないため、こちらの方がシンプルです。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
cmap = font['cmap'].getBestCmap()
print("code,glyph")
for code, glyph in cmap.items():
print("U+{0:X},{1}".format(code,glyph))
getBestCmap()関数の詳細は以下のページを参照してください。
異体字セレクタ
最近の日本語フォントファイルの中にはcmapテーブルのサブテーブルとして異体字の情報含んでいるものがあります。
異体字の情報は元の文字に対応するコードポイント(異体字セレクタ)を持っています。
異体字セレクタを含むサブテーブルは、fomrmat=14のものです。
以下のコードで異体字セレクタの一覧を出力できます。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
for cmap in font['cmap'].tables:
if cmap.format==14:
print("code,uvs,glyph")
for uvs in cmap.uvsDict:
for code,glyph in cmap.uvsDict[uvs]:
print("U+{0:X},U+{1:X},{2}".format(code,uvs,glyph))
実行結果(一部)
U+83DF,U+E0107,mj022121
U+845B,U+E0107,mj022337
U+8612,U+E0107,mj030221
U+9038,U+E0107,mj030303
U+9052,U+E0107,mj026054
U+9055,U+E0107,mj026065
U+9077,U+E0107,mj026143
U+9083,U+E0107,mj026175
U+9760,U+E0107,mj027926
U+97FF,U+E0107,mj028144
U+990C,U+E0107,mj028413
U+9957,U+E0107,mj028568
U+9F08,U+E0107,mj029970
U+9F8D,U+E0107,mj030124
U+FA24,U+E0107,mj030228
U+908A,U+E0108,None
U+20525,U+E0108,None
U+51DE,U+E0108,mj030203
U+53A9,U+E0108,mj007951
U+6168,U+E0108,mj030258
[元の文字のコードポイント],[異体字セレクタのコードポイント],[glyphインデックス]の順に並んでいます。
一部、glyphインデックスが"None"となっているのは、異体字セレクタの割り当てはあってもglyphの情報を持っていない文字と思われます。
ファイルへ出力
以下のコードで異体字セレクタも含めたコードポイントの一覧をCSVファイルへ出力できます。
"cmap.csv"が出力されます。
from fontTools.ttLib import TTFont
font = TTFont("ipamjm.ttf")
with open("cmap.csv",mode='w') as fp:
cmap = font['cmap'].getBestCmap()
fp.write("code,uvs,glyph\n")
for code, glyph in cmap.items():
fp.write("U+{0:X},,{1}\n".format(code,glyph))
for cmap in font['cmap'].tables:
if cmap.format==14:
for uvs in cmap.uvsDict:
for code,glyph in cmap.uvsDict[uvs]:
fp.write("U+{0:X},U+{1:X},{2}\n".format(code,uvs,glyph))
その他
出力されたコードポイントの一覧の中には文字として表示されない制御コードやスペースなども含んでいます。表示される「文字」だけを抽出するには、この後に追加の処理が必要になります。
こちらのページのremove_control_characters()関数が参考になりそうです。
glyphインデックスからglyph(文字の形)のデータを取得する方法については、以下のページを参照してください。