テキストの外形をsvgにする、text2svgをRubyで作った

テキストとフォントファイルを与えると、テキストの形をsvgで表現した出力が出てくる夢を見たことがありますよね?

作りました。

github.com

$ text2svg "Hello, World\!" --font="/Library/Fonts/Times New Roman.ttf" > test.svg
$ open test.svg -a /Applications/Google\ Chrome.app

sample

な感じで試すことができます。

freetypeを使っているのでこちらのインストールが事前に必要です。

$ brew install freetype

svgでは、<text>タグで文字を表現するのが普通ですが、表現したいフォントが決まっている場合フォントファイルのダウンロードを必要とします。

テキストの外形をsvgのpathにして<path>タグで表現することができれば、 サーバーでsvgファイルを生成してクライアントにフォントファイルをダウンロードさせること無しに文字を表現できます。

文字の並びやtext-align、改行やkerningにも自前で対応していて、

imagemagickなどで画像化した場合と遜色ない文字並びで扱うことができます。

f:id:ksss9:20151217182838p:plain

(上がtext2svgで作ったsvg、下がimagemagickで作ったpng画像)

実装

内部ではfreetypeAPIを呼んでいます。

freetypeAPIffi経由で呼ぶgemも作りました。

github.com

freetypeはフォントファイルを扱うCのライブラリーで、文字の外形pathやbitmap化なんかができます。

http://www.freetype.org/

https://ja.wikipedia.org/wiki/FreeType

ffiはCと他言語の間をとりもつやつ。

https://github.com/ffi/ffi

https://ja.wikipedia.org/wiki/Foreign_function_interface

TrueTypeだけならttfunkを使えばなんとか外形を取ることができますが、 .otfなPostScriptフォントに対応していません。

freetypeであればTrueTypeとPostScriptフォント両方の形式を同じAPIで扱うことができます。

今回はじめてffiで書いてみたけど、 コンパイル無しで(ffiコンパイルいる)CのAPIが呼べるのはよさげでした。

しかしながらStructの構成は自動でできてくれたらなあという感じ。

ffiは初めてなのでまだまだ至らぬ点もあるのかもしれないです。

ちなみにテストはRubyKaigiのLTで話したrgotを使っています。 メソッド一つづつテストするというよりは、ストーリー仕立てでテストするのに向いている気がする。

注意

フォントのSVGを公開してもいいかどうかはフォントの規約に依存します。 作成したSVGを公開する際は、フォントの規約にご注意ください。