にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

OpenTypeフォントにSVGアニメーションを突っ込んでみる

Twitterを眺めてたらOpenType-SVGを実装した話が流れてきた。

ちなみにその実装ではラスタ画像をSVGのベクタ形式に変換しているが、SVGの<image>タグのxlink:href属性にPNG画像などをdata URI schemeを使って埋め込むとラスタ画像も利用できる。


最近はAdobeのソフトウェア(PhotoshopIndesignなど)がOpenType-SVGカラーフォントをサポートし始めたり、最新のWindows 10の描画エンジンでもサポートが始まり、Edgeなどでも表示できるようになっているらしく、今後が期待できる。


そういえば、OpenType-SVGではSMILによるアニメーションは問題なく突っ込めるという話があった*1

OpenType fonts with either TrueType or CFF outlines may also contain an optional 'SVG ' table, which allows some or all glyphs in the font to be defined with color, gradients, or animation.

https://www.microsoft.com/typography/otspec/svg.htm

せっかくなので試してみる。

SVGのアニメーションといえば前になんか作ってたなあと思ったので次のページで作成したSVGをフォントに突っ込んでみることにする。

手順

編集する下地のフォントとして、M+フォントのmplus-1p-medium.ttfからASCIIコード外のグリフをごっそり削除したものを利用した(編集にはFontforgeを利用した)。
これは次のリンクからダウンロードできる。

まず用意した下地のフォント(mplus-mod.ttf)をTTXでXML形式にダンプする。

ttx mplus-mod.ttf

するとmplus-mod.ttxが出来上がるので、このファイルをテキストエディタなどで開いて編集する。

今回はアルファベットの“W”の代わりにSVG画像が表示されるようにしてみる*2
まず、<GlyphOrder>タグで囲まれた要素を見て行って、WのglyphIDを調べる。今回は、次の記述から、58であることがわかった。

    <GlyphID id="58" name="W"/>


これをもとに、ルート要素である<ttFont>の子として次のように<SVG>タグを追加する。

  <SVG>
    <svgDoc endGlyphID="58" startGlyphID="58">
      <![CDATA[<svg xmlns="http://www.w3.org/2000/svg"
                    xmlns:xlink="http://www.w3.org/1999/xlink"
                    width="768" height="432" 
                    viewBox="0 600 764 432" id="glyph58">
        (SVGの描画される要素がここに入る)
      </svg>]]>
    </svgDoc>
  </SVG>

ここで、<svgDoc>タグにはstartGlyphIDおよびendGlyphID両属性に58(WのglyphID)を指定している。
また、<svg>タグはhttp://nixeneko.2-d.jp/hatenablog/20170330-svganim/animate.svgの中身を突っ込んだものであるが、viewBoxの2番目の値を600に変更し、さらにWのglyphIDの58に合わせてid="glyph58"の指定を追加している。<svg>タグの子孫要素は長いので記載を省略した。


最後に編集した.ttxファイルをTTXで.ttfフォントファイルに変換する。

ttx -o out.ttf mplus-base.ttx

完成したフォントは次のリンクからダウンロード可能:

サンプル

次のページで実際に試すことができる:


実際にFirefoxで見てみると次のようになった。
f:id:nixeneko:20171031204634g:plain
こいつ…動くぞ…!?


なお、Edgeで見てみたら次のような感じになり、アニメーションは動かなかった*3
f:id:nixeneko:20171031210837p:plain
ここで、SVG画像の表示される高さや大きさが、Firefoxの場合と異なっている。SVGファイルをそのまま突っ込んだだけで幅・高さの辻褄を合わせていないから実装依存になってしまっているのだと思う。

ちょっとした解説

OpenType-SVGでは複数のグリフに対して一つのSVG文書(画像)を指定することができる。

つまり、TTXの形式では、一つの<svgDoc>を複数のglyphIDに対応付けることができる。この対応付けはstartGlyphIDとendGlyphIDで指定し、指定されたstartGlyphID~endGlyphID間に含まれるglyphIDに対応するグリフがそのSVG文書に結び付けられる。

また、<svgDoc>内に埋め込まれるSVG文書には、id="glyph58"のように、idに“glyph<glyphID>”の形で(その<svgDoc>と結びつけられた)glyphIDに対応するid属性を指定した要素が含まれていないといけない。グリフが描画されるとき、そのglyphIDに対応するidを持つ要素が画面に表示されることになる。

詳しくは仕様書を参照: The SVG Glyph Outlines Table


あと、svgのviewBoxの2番目の要素を変化させると、SVGがフォントとして表示される際の位置を上下に動かすことができる。今回使ったSVG画像は最初viewBox="0 0 764 432"と指定されていたが、その状態では丁度ベースラインからぶら下がる位置に表示された。なので、もう少し上の位置に表示させるためにviewBox="0 600 764 432"を指定した。

今回はSVG画像の幅や高さは特に気にせず突っ込んだが(それでも動く…!)、高さはフォントのEMのユニット数、幅はグリフのadvanceWidthに合わせるといいのではないかという気がする。描画時にどのように描画サイズが計算されるのかはちゃんと確認した方がよさそう。

まとめ

  • SVG画像で表示したいグリフに対応するよう指定してSVG画像を突っ込めばOpenType-SVGカラーフォントは作成できる
  • FirefoxではSVGのアニメーションまで動く
  • EdgeではOpenType-SVGは表示できるがアニメーションは動かない
  • SVGの幅や高さの指定がフォントの高さやグリフの幅と合ってない場合、表示位置や大きさは実装依存っぽい

*1:セキュリティ上の理由から、Javascriptは動かない。

*2:なぜWかというと、Windowsのフォントビューアのサンプルテキストの最初に来る文字だからである。なお、Windowsのフォントビューア自体はSVGフォントに対応してないので普通にWが表示された。

*3:そもそもEdgeってSMILアニメーションに対応してなかった…。