前々からこれやろうやろうと思ってて先延ばしにしてたヤツ。
一応 Windows の話だけれど、Unix variant でも多分通用する話。
フォント指定が「ファミリ」と「スタイル」のペアで渡せるものは楽だ。「色んなとこで同じ知識が通用するから」ね。css だってそうであろ。matplotlib もこのタイプ。
けど「フォントごときについてはあんまし頑張ってないインフラ」には、ファイル名そのものを要求するものも多い。PIL (or Pillow) もそうだし、graphviz もそうだし、遠い記憶では svg も確かそうだったような。
ファイル名で「自明」な場合は別に困らんのよ。「DejaVuSansMono-BoldOblique.ttf」なんて名前が付いてりゃぁ、およそ見当が付くであろ。けど「cour.ttf」が「Courier New の Regular」であると確信を持てるか? そうなのだ、Windows は 21 世紀になってもいまだに「8+3」の呪縛から逃れられない。歴史あるフォントほど名前から中身を想像出来ないよ、っと。
今になってこんなことをやろうと思ったのはまさしくその「cour.ttf」が張本人。つまり mono space のフォントを Pillow から使いたかったんだけれど、「Microsoft Windows での mono space は Courier New」だとわかったとしても、それが「cour.ttf」である、という情報は一発では見つからない。そりゃそーだ、Windows の普通のアプリケーションで「フォントファイル名」を要求するユーザインターフェイスなんか皆無だから。
コントロールパネルでもこうな:
パスは頑なに見せないようにしてるし、無論それが正解。ファイル名を要求しちゃってることの方が本来は「愚の骨頂」なわけで。
まぁ「ファイル名を要求しちゃうヤツ」のためだけに、ほんの少し情報が欲しいだけだからな、すぐに一覧出来るスクリプトさえありゃぁいいか、てことで:
1 import os
2 from PIL.ImageFont import FreeTypeFont
3 import matplotlib.font_manager as FM
4
5 if __name__ == '__main__':
6
7 _all_fonts = set()
8 _dejav = set()
9
10 ttf_files = FM.list_fonts(FM.win32FontDirectory(), ["ttf", "ttc"])
11
12 for fn in ttf_files:
13 ttf = FreeTypeFont(font=fn)
14 dn, _, bn = fn.rpartition(os.sep)
15
16 if bn.upper() in _dejav:
17 # the same but having different case should be the same...
18 # really? i don't know...
19 continue
20
21 _dejav.add(bn.upper())
22 family, style = ttf.getname()
23 _all_fonts.add((family, style, bn))
24
25 for family, style, bn in sorted(_all_fonts):
26 print("{:36s}|{:24s}|{}".format(family, style, bn))
1 me@host: ~$ python enum_windows_fonts.py
2 (...snip...)
3 Courier New |Bold |courbd.ttf
4 Courier New |Bold Italic |courbi.ttf
5 Courier New |Italic |couri.ttf
6 Courier New |Regular |cour.ttf
7 (...snip...)
8 MS Gothic |Regular |msgothic.ttc
9 MS Mincho |Regular |msmincho.ttc
10 (...snip...)
11 Meiryo |Bold |meiryob.ttc
12 Meiryo |Regular |meiryo.ttc
13 (...snip...)
14 Times New Roman |Bold |timesbd.ttf
15 Times New Roman |Bold Italic |timesbi.ttf
16 Times New Roman |Italic |timesi.ttf
17 Times New Roman |Regular |times.ttf
18 (...snip...)
名前とスタイル、なのが今ひとつというか「惜しい」が、まぁ別にいいか、てことで。(脳内でわかってりゃよかろうと。)
ワタシにしては珍しく、全然出力の再利用性は考えてなくて、コンソールに出力して読みやすい形に整形してる。そういう使い方しかしないだろうなぁ、と思ったんで。だって何十種類も使いこなすわけじゃないじゃん、たまーに「いつものとは違う一つ」を使いたいだけよね、今回のワタシの「cour.ttf」みたいにさ。
やろうと思えばまさに「ファミリとスタイルから候補一覧」みたいなスクリプトは書けるけれど、別に全部出てる中から探り当てるの、大変ではないもん。アタシの場合は less にパイプして使うんで、less の検索で済ませちゃう。
ちなみにスクリプトが matplotlib 使ってみたり Pillow 使ってみたりとしてること自体が「各 OSS の得手不得手」を表していたりする。matplotlib はファイルそのものの列挙と検索が得意だが、「情報一覧」は(隠蔽されてるために)取れず、Pillow はファイル名を与えれば情報をくれるが検索のサポートはないし、(場所は知っているくせに)一覧はさせてくれない。
2017-07-27追記:
ここに少し詳しく書いておいたが、face 指定出来るのね。のでこの方がいい:
1 #! /bin/env python
2 import os
3 from PIL.ImageFont import FreeTypeFont
4 import matplotlib.font_manager as FM
5
6 if __name__ == '__main__':
7
8 _all_fonts = set()
9 _dejav = set()
10
11 ttf_files = FM.list_fonts(FM.win32FontDirectory(), ["ttf", "ttc"])
12
13 for fn in ttf_files:
14 for i in range(10):
15 try:
16 ttf = FreeTypeFont(font=fn, index=i)
17 except IOError as e:
18 break
19 dn, _, bn = fn.rpartition(os.sep)
20
21 if (bn.upper(), i) in _dejav:
22 # the same but having different case should be the same...
23 # really? i don't know...
24 continue
25
26 _dejav.add((bn.upper(), i))
27 family, style = ttf.getname()
28 _all_fonts.add((bn, i, family, style))
29
30 for bn, i, family, style in sorted(_all_fonts):
31 print("{:36s}|{:24s}|{}, face={}".format(family, style, bn, i))
1 me@host: ~$ python enum_windows_fonts.py
2 (...snip...)
3 Batang |Regular |batang.ttc, face=0
4 BatangChe |Regular |batang.ttc, face=1
5 Gungsuh |Regular |batang.ttc, face=2
6 GungsuhChe |Regular |batang.ttc, face=3
7 (...snip...)
8 Courier New |Regular |cour.ttf, face=0
9 Courier New |Bold |courbd.ttf, face=0
10 Courier New |Bold Italic |courbi.ttf, face=0
11 Courier New |Italic |couri.ttf, face=0
12 (...snip...)
13 Meiryo |Regular |meiryo.ttc, face=0
14 Meiryo |Italic |meiryo.ttc, face=1
15 Meiryo UI |Regular |meiryo.ttc, face=2
16 Meiryo UI |Italic |meiryo.ttc, face=3
17 Meiryo |Bold |meiryob.ttc, face=0
18 Meiryo |Bold Italic |meiryob.ttc, face=1
19 Meiryo UI |Bold |meiryob.ttc, face=2
20 Meiryo UI |Bold Italic |meiryob.ttc, face=3
21 (...snip...)
22 MS Mincho |Regular |msmincho.ttc, face=0
23 MS PMincho |Regular |msmincho.ttc, face=1
24 (...snip...)
2022-02-28追記:
ずっと Popular Posts に上がり続けてたネタなのだから、もちっと早く追記しときゃ良かったかね…。このネタに喰い付いている人には ffmpeg ユーザ、もしくは「fontconfig ユーザ」が結構含まれるんではないかと思う。であれば、Drawing texts (元ネタ)も読んでもらえると役に立つかも、と思う。