ターミナルでアイコンフォントを使う理由

2017年03月15日 水曜日


【この記事を書いた人】
藤本 彬頌

クラウドサービス本部 分散システム技術課 開発エンジニア 分散システムを活用したスケーラビリティの高いWebサービスの設計・開発や機械学習、IoTの調査・サービス化に従事してます。

「ターミナルでアイコンフォントを使う理由」のイメージ

分散システム技術課の藤本です。
以前に書いた記事と同様、今回も業務とあまり関係ないことを書いてしまいました。もちろん仕事もちゃんとしていますので誤解なきようよろしくお願いいたします。

この記事は

  • Nerd FontsでPowerlineなどのフォントのズレを解消するFont Mergerの紹介
  • ターミナルでアイコンフォントを使うメリット
  • Font Mergerを作る過程で得られたFontForgeスクリプトの知見

について書いています。少し長くなってしまったので適当に読み飛ばしてください。

和文フォントとアイコンフォントを綺麗に合成する方法

これは欧文フォントにも言えることですが、全てのフォントは同じ大きさというわけではなく、フォント毎に大きさや位置が異なります。和文フォントにおいては、欧文フォントと比べてサイズが大きく、位置も少し高めものが多いため表示のズレが顕著に現れやすいと思います。そのため、そのままの状態で合成してしまうと元々異なるフォントの文字を並べて表示した時に均一に表示されない(ズレてしまう)といった問題が発生します。フォントを綺麗に合成するには、その問題となっている大きさと位置を合成する時に調整すれば良いのです。

これから紹介するアイコンフォントとの合成においても同様の問題がありますので、綺麗に合成する方法を紹介したいと思います。

アイコンフォントとは

フォントアイコンやアイコン型Webフォントとも呼ばれ、ロゴマークや記号を中心とするグリフ(文字)を収録したフォントのことです。
位置付けとしてはWebフォントの一部(アイコンに絞ったもの)で、正式な呼び方が見つからなかったためこの記事ではアイコンフォントと呼んでいます。

ターミナルでアイコンフォントを使う

ターミナルでアイコンフォントを使うためにFont Mergerというものを作りました。
これは、ベースとなる任意のフォントにWebフォント等の一部のグリフ(文字)を合成するスクリプトです。

もとはNerd Fontsプロジェクトで公開されているスクリプトを和文フォントでも綺麗に表示されるようにフォントの大きさと位置を調整する処理を加えたものでしたが、さらに様々なフォントを扱えるように汎用化して合成フォントを作れるように拡張したものがFont Mergerです。

必要なソフトウェア

  • FontForge
  • Python 2.7以降
  • Git

macOSであればbrewを使用して以下のようにFontForgeをインストールすることができます。

$ brew install fontforge

使い方

Font Mergerは以下のようにGithubから取得します。標準でいくつかのアイコンフォントを使えるようにプロジェクトのレポジトリをsubmoduleとして登録しているため以下のようにgit cloneしてください。

$ git clone https://github.com/iij/fontmerger
$ cd fontmerger

以下のようにfontforgeの-scriptオプションに指定して利用します。

$ bin/fontmerger -h

usage: mergefonts.py [-h] [-V] [-v] [-x [EXT_FONT [EXT_FONT ...]]] [-i]
                     [-o OUTPUT_DIR] [-l] [--all] [--suffix SUFFIX]
                     [BASE_FONT [BASE_FONT ...]]

positional arguments:
  BASE_FONT             target fonts (default: [])

optional arguments:
  -h, --help            show this help message and exit
  -V, --version         show version (default: False)
  -v, --verbose         verbose mode (default: False)
  -x [EXT_FONT [EXT_FONT ...]], --ext_fonts [EXT_FONT [EXT_FONT ...]]
                        extend fonts (default: [])
  -i, --info            show base font information (default: False)
  -o OUTPUT_DIR, --output OUTPUT_DIR
                        output directory (default: ./)
  -l, --list            show available additional fonts (default: False)
  --all                 extend all fonts (default: False)
  --suffix SUFFIX       font name suffix (default: None)

使用例

$ bin/fontmerger -x fa fae linux powerline-extra powerline pomicons octicons -o ~/Library/Fonts/ --suffix=with-icons -- Ricty.ttf

-xオプションでマージするフォントを指定するか、--allオプションで全てのフォントを合成するか指定します。この時に指定できるフォントは-lオプションで確認することができます。
現在は以下フォントに対応しています。

$ bin/fontmerger -l

------------------------------- Available Fonts --------------------------------
         seti-ui: Seti UI
                   - a set of icons for Seti UI. https://atom.io/themes/seti-ui
         devicon: Devicon
                   - a set of icons representing programming languages, designing & development tools. http://devicon.fr/
 powerline-extra: Powerline Extra Symbols
                   - Extra glyphs for the powerline separators. https://github.com/ryanoasis/powerline-extra-symbols
       powerline: Powerline Symbols
                   - https://github.com/powerline/powerline
        pomicons: Pomicons
                   - A set of icons for Pomodoro Technique. https://github.com/gabrielelana/pomicons
              fa: Font Awesome
                   - http://fontawesome.io/
             fae: Font Awesome Extension
                   - http://andrelgava.github.io/font-awesome-extension/
           linux: Font Linux
                   - https://github.com/Lukas-W/font-linux
        octicons: Github Octicons
                   - https://octicons.github.com

fonts.jsonという設定ファイルを変更することで他のフォントにも対応します。ただし、フォントの幅や高さはベースとなるフォント(BASE_FONT)が基準になるため表示が崩れる場合があります。

注意

適用するフォントの利用条件を確認の上ご利用ください。

Ricty Diminished with icons

簡単にお試しできるようにプログラミング用フォント「Ricty Diminished」にアイコンフォントを合成したものを用意いたしました。
https://github.com/iij/fontmerger/tree/master/sample
ライセンス等を確認の上、ご利用ください。

ターミナルでアイコンフォントを使う理由

より良い作業環境を求めて

今でも多くのエンジニアはターミナル(コマンドライン)で作業することが多いと思いますが、
テキストエディタと同様に多くの時間を過ごすターミナルでも見映えや利便性を追求したいと考えている人は多いのはないでしょうか?

とくに見映えに関わるフォントやプロンプトの表示などは視認性を向上させ、表示されている情報をより速く整理することができ、ミスの防止や作業速度の向上が見込めると考えています。

私にとっては、格好よく表示したいという理由だけでもフォントアイコンを使う十分な動機になりました。

アイコンフォントで視認性をさらに上げる

見やすいフォントでも、「晴れ」と「」のように文字列よりも同じ事柄を表す記号の方が分かりやすい場合が多くあります。
また、このような記号もフォントの一部なので色や下線などの装飾、背景色を変えるといった表現をすることで、より分かりやすく表示させることができます。

最近では、Unicodeのアップデートにより扱える絵文字も増えさらにフォントを使用した表現が多彩になってきました。
しかし、製品・ソフトウェアのロゴや開発現場で使う記号など存在しないものも多数あります。
そこで、Webアプリケーション等でよく使用されているアイコンフォントを使用することで必要な記号を補完し、より使いやすい環境へと昇華させることができるのではないかと考えています。

主要なアイコンフォント

  • Font Awesome
    • Webアプリケーションでよく利用されているアイコンフォント
    • 種類が豊富で品質も非常に高い
  • Github Octicons
    • Githubで使用されているアイコン
    • Gitに関連したアイコンは最も分かりやすい
  • Powerline
    • ターミナルやエディタ(vim,Emacs)の区切りや行頭、行末を格好良く表示する山括弧の記号

上記以外にも既に様々な種類のアイコンフォントが公開されていますので、自分で作らずとも必要なアイコンが見つかると思います。
(フォントを使用、公開する場合はライセンスにご注意ください。)

Nerd Fontsプロジェクト

Nerd Fontsは、上記のような既存のアイコンフォントと合成するためのスクリプトと、それを使用して生成した合成済みの欧文フォント(ここでは総称してNerd Fontと呼ぶことにします)を公開しているプロジェクトです。
既に多くの開発者がNerd Fontを使用しており、Powerlevel9ktheme-bobthefishなどNerd Fontに対応したZshやFishのテーマも公開されているので、すぐに利用できる環境が整っています。

ただし、Font Mergerの紹介で触れたように和文フォントに適用するとアイコンフォントと高さや位置がずれてしまう場合があります。その時はFont Mergerをお試しください。

参考

アイコンフォントは基本的にUnicodeの私用領域(Private Use Area U+E000 ~ U+F8FF)に割り当てられています。一部のアイコンフォントは使用している領域が重なっているため、Nerd Fontでは位置をずらしてグリフをマッピングしています。

FontForgeスクリプトの概要

FontForgeスクリプトを書いた時に調べた必要だった情報を書いておきます。これからFontForgeスクリプトを書く人の参考になれば幸いです。

FontForgeのPythonライブラリ

FontForgeはスクリプトでマクロ操作をする機能が用意されており、現時点で使用可能な言語はFontForge独自のものとPythonです。
PythonでFontForgeの操作を行うには

  • fontforge
  • psMat

という2つのライブラリを使用します。ちなみに、psMatはグリフの変形や移動時に指定するパラメータを生成するための補助ライブラリです。

フォントとグリフの大きさを表すパラメータ

FontForgeにおいてグリフ(Glyph)とはフォントの1つの文字情報を表します。
このフォントとグリフの大きさ(サイズ)を表す多くのパラメータがあり、Font Mergerで使用しているパラメータを紹介します。

ベースライン(baseline)

フォントの高さの基準となるy = 0の位置で、高さに関するパラメータの値はこの位置からの距離を数値化したものです。

アセント(ascent)

全てのアルファベットの最大の高さを表します。
余白を含むグリフ全体の最大の高さはHHead Ascent (hhea_ascent) / Win Ascent (os2_win_ascent)というパラメータで確認することができます。

ディセント(descent)

全てのアルファベットのベースラインから下方向の最大距離を表します。
HHEA Ascent, Win Ascent と同様にグリフ全体の下方向の最大距離はHHead Descent (hhea_descent) / Win Descent (os2_win_descent)というパラメータで表します。

グリフの変形(transform)

グリフの変形には、psMatライブラリを使用して変形するためのパラメータを生成し、このパラメータをグリフオブジェクトのtransformメソッドに指定してグリフを変形させます。

主に使う関数を紹介すると、

  • scale(x, y)
    • 1.0を基準に割合でグリフの大きさを変更する
  • translate(x, y)
    • 指定の距離を移動させる

 

Font Mergerでは2つのフォントの大きさや位置を比較し以下のようにグリフを変形させています。

サンプルコード(Python)

以下に示すのはシンプルな変形処理を行うサンプルコードです。
前述の通りマクロなのでグリフのコピー&ペーストの部分は分かりづらいと思いますが、GUI操作をイメージしながら見てみてください。

import sourceforge
import psMat
 
# 合成先のフォント
base_font = fontforge.open('base_font.ttf')
  
# アイコンフォント(合成するフォント)
sym_font = fontforge.open('symbol_font.otf')
 
# 幅を揃える
sym_font.em = src_font.em
 
# 高さを 3/4 に縮小
trans_scale = psMat.scale(1.0, 0.75)
 
# 100 points 下へ移動
trans_move = psMat.translate((0, -100))
 
# コピーするグリフを選択
sym_font.selection.select(('ranges', 'unicode'), 0xE000, 0xF000)
 
for sym_glyph in list(sym_font.selection.byGlyphs):
    index = sym_glyph.encoding
 
    # 変換処理(resize -> move)
    sym_glyph.transform(trans_scale)
    sym_glyph.transform(trans_move)
 
    # コピーするグリフを選択
    sym_font.selection.select(index)
 
    # 選択グリフをコピー
    sym_font.copy()
 
    # コピー先のグリフを選択
    base_font.selection.select(index)
  
    # コピーしたグリフ(sym_glyph)をペースト
    base_font.paste()
 
sym_font.close()
base_font.generate('generated-base_font.ttf', flags=('opentype'))
base_font.close()

まとめ

わーい!これでみんなもかっこいーターミナルをつかうフレンズだねー!
フォント合成、すごーい!たーのしー!

参考

藤本 彬頌

2017年03月15日 水曜日

クラウドサービス本部 分散システム技術課 開発エンジニア 分散システムを活用したスケーラビリティの高いWebサービスの設計・開発や機械学習、IoTの調査・サービス化に従事してます。

Related
関連記事