Linuxのデスクトップとサーバーについて扱います。2014の参加記事です。さんの「東京の鉄道路線図SVGを作りました&パブリックドメインで配布します」でした。@hashccさんの力作の翌日を担当することになってしまいましたが、微力ながら相応の記事になるよう力を尽くす所存です。今回は、ルーン文字フォント制作に使用している手製のSVG画像の分割スクリプトを使うことになった経緯、その再実装(リファクタ)に至る過程、そしてその結果について書かせていただきます。RuneAMN_Pro_Blackletterよりオリジナルフォント作りと、SVG画像の分割スクリプトわたしが現在公開しているRuneAMNシリーズフォントは、イラスト・デザイン向けに作られたルーン文字フォントです。普通のアルファベットを入れてフォントを適用するだけで簡単に、ルーン文字をデザインに使えるようになっています。シリーズ構成は、独立したFree版とPro版(有償)があり、それぞれ重複しない独自の書体を収録しています。bell"の製品として、OlChikiAMN(オルチキ文字フリーフォント)も配布しています。これらのフォントを制作する際、Illustratorで書体デザインを行っています。SVG画像への書き出しを経由して、FontForgeに読み込ませてフォント化しています。フォントエディタの編集機能で完結させず、複雑なビルド手順を踏む選択をしたかといえば、FontForgeよりIllustratorのほうが、ベクタ画像のエディタとしては使い慣れており高機能だったという点に尽きます。Masterなど)もありますが、今回はそういったフォント機能を使う予定がなかったため、この手法を選択することができました。SVG分割スクリプト(svg_splitter.pl)の機能拡張フォントの制作プロセスにおいて、『すべてのグリフ(文字)を一枚のSVG画像に描いて、後から自動分割したい』という要求がありました。すべてのグリフを1枚の画像に描きたかったのは、そのほうがファイルの管理が簡単で、デザインを統一しやすいためです。自動分割というのは、スクリプトにより1枚の画像から、1文字につき1ファイルの状態に分割することができる、ということです。SVG画像の分割を、makeを使ったビルドプロセスに含めるために必須でした。試みられていないようです。・Illustrator(スクリプト)は、アートボードで範囲を区切って書き出しても、範囲外の表示されないすべての要素もSVGファイルに含めたまま出力する。InkScapeにはスクリプト化の方法が2種類ある。コマンドライン引数の方法では、詳細な制御ができない。Python拡張版(inkey)ではなぜかLGPL汚染が懸念されており、さらにAPIの網羅されたドキュメントを見つけることができない。・Perl、PythonにはSVGを処理する多くのライブラリが存在するが、そのほとんどが「SVGを圧縮」するか「SVGをラスタ画像に書き出す」機能しか持っていない。(参考として、PythonのSVG関連ライブラリを調べた方が作った一覧がこちら。)結果的に、SVG画像を画像として扱う"まともな"分割器を見つけることができませんでした。見つかったのは、mashabow@しろもじ氏の手書き文字「てきとうに書いてつくったフォント」用SVG分割器と、M+フォントのビルドシステムに含まれているSVG分割器でした。このどちらも、SVGを画像ではなくXMLテキストとして解析した後で、SVG要素を独自に計算することでSVG画像の分割を実現しています。M+の分割器は、SVGの多くの要素に対応していた反面、日本語フォント1万2000文字オーバーをすべて分割できる機能を持たせるために、複雑な構造となっています。(2ファイルに分割されており、内部動作もマルチスレッド化などがされている)。手書き文字フォントの分割器は、対応要素がpolygonだけである代わりに、1ファイルに完結しており動作も容易に追うことができました。以上のことから、RuneAMNでは、手書き文字フォントの分割器を、拡張しながら使っていくことにしました。リファクタ・PerlからPythonへの移植このスクリプトは、RuneAssingMN_Free、OhChikiAMN_Free、RuneAMN_Proの制作に、機能拡張しながら使われました。すべての拡張が「その場しのぎのやっつけ仕事」で行われました。そのため、コードベースは混乱を極めており、コピーペーストされた同じ処理がいくつもの場所に分散しており、機能拡張とバグ修正は困難を極める状態になっていました。etc...)『控えめに言ってこのスクリプトは公開することで私の(あって無いような)キャリアに傷をつけるのではないかと危惧するほど汚いfixやその場凌ぎのコードで満ちている。スクリプトがたとえ飛び出したクジラの内蔵の干物のようであったとしても、生成されたフォントの美しさはカケラも損なわれない。グリフのデザインは、1/10ピクセルも、まったく、狂わないからだ。リファクタリングは時間の無駄と言える。』(Pythonによる再実装を行う前の、本記事の原稿より。)もちろん、コードが汚いからといって、フォント自体は1ピクセルも変化したりはしないことは誰でもわかっています。コードが綺麗であろうがクジラの内蔵が飛び出した状態であろうが作られたフォントの美しさは全く損なわれることがないことは間違いありません。『しかし実のところ、svg_splitter.plの次の機能追加やバグフィックスは困難を極めるだろう。私は有名な「すべてを一から書き直したい病」にかかっており、誰かがこのスクリプトを使いたいと言ったならば、私は間違いなくすべてを書き直す。その時はPythonを使う。フォントプログラミングとPythonは相性がよく、例えばFontForgeはネイティブ言語とは別にPythonスクリプトによる制御を提供している。PythonにはPerlと同じように、SVGのベースであるXMLを処理するためのライブラリがあらかじめ用意されている。余録として、将来Windows環境をサポートする際に、FontForgeのWindowsポート版がPythonインタプリタを持っていることが期待できる。』(Pythonによる再実装を行う前の、本記事の原稿より。)RuneAMN_Free/Proのアップデートを決意した私は、そのためにはSVG分割スクリプトに新機能が必要であると判断しました。そこで、以前から考えていた、リファクタを兼ねたPythonへの再実装を行うことにしました。再実装中のPythonスクリプト版Pythonへの移植を行ったため、当然ながら、すべてのコードが1から書きなおされました。リファクタリングでは「新しい機能はひとつも追加しない」のが鉄則ですが、今回はいくつかの新機能・機能改善を含みます。以下が、リファクタ作業の結果です。・見通しの良いコード・すべての機能は関数に分割された。・新しいmain部は20行ほど・新フォントのための新機能を容易に追加できる・transform属性を処理する部分が関数に共通化された。・アプリケーション・ハンガリアン記法になった。リファクタリング以前、SVG分割器の機能は関数化されていませんでした。度重なる機能追加により同じ機能があちこちに散らばり、処理の流れが簡単にはわからない状態になっていました。変数名や関数名にもルールらしいものはなかったため、可読性が低く処理を追いかけることが困難になっていました。リファクタリングの後、多くの部分が適切に関数化され、処理を以前より容易に把握することができるようになりました。Softwareの受け売りですが、命名規約があることにより以前よりコードが読みやすくなったことは確かです。プログラム内部でも、設定値が読みやすくなった。・SVG要素の再配置の計算を正しい方法に直した「分割サイズで割って余りを出す」のではなく、「(分割セル上の行列位置×分割サイズ)を現在位置から引く」ことで、分割セルからはみ出したポイントなどを正しく分割後再配置できるようになりました。・グループ要素(<g>)を再帰的に探索できるようになった。perl版では、対象1グループの中に含まれる(つまり1レイヤーの)SVG要素しか対象にすることができませんでした。そこで、グループを再帰的に探索するよう機能拡張しました。IllustratorやInkScapeで、書き出し前にレイヤ統合やグループ化解除をする必要がなくなった。・ついでにいくつかの使っていないpolygonパスのコマンドに対応できたほかの未実装部も容易に追加できるはずです。・RuneAMN_Proを、.pl版と同じように、すべて問題なくビルドできる。bellのフォントプロジェクト専用であり、使われない機能は未実装のまま省略することができます。Python版がPerl版とまったく等価な出力が可能で、退行(リグレッション)していないことを確認できました。・分割スクリプトを通して、SVGの構文について学習することができた・Python(Python3)処理系について学習することができたPythonによるSVGの加工を学ぶことで、将来的にもっと高度なフォントデザイン支援を実現するための、足がかりにしようと考えています。SVGはWebデザインなどの分野でこれからより使われるようになると思われ、理解しておいて損はないはずです。忘れてしまいそうになりますが。)・SVG分割スクリプトのすべてを、自分でコントロールすることができる機能追加のために行ったことにリファクタリングにより、フォント制作でしか使われないであろうSVGへの処理を、ビルドのコアに含めることが簡単にできるようになりました。書籍)の系になるのかどうかはわかりませんが。ソースコードなどmain部分は、たったのこれだけになりました。実際のコード部分は20行以下になっています。透明なsvg要素も除去する。settings)SVG要素の読み出し部分も、以下のように関数化され、整理されました。再帰呼出しを使うことで複数レイヤに対応しました。dstsTable本スクリプトのコードは全体で559行あります。最後にGithubのRuneAssignMN_Series_Fonts他にて、フォント元画像、ビルドスクリプトなどのすべてを、自由なライセンスで公開しています。RuneAMN_Pro_Series_Fontsについても、やはりGithubにてビルドスクリプトとテスト用のフォント元画像を公開しています。class-2ライセンスで公開する予定です。リリースの告知はフォントと同じにTwitterなどで行う予定です。今欲しいという方がいれば、連絡をいただければ個別に差し上げたり公開を早めたり、対応します。bellのBOOTHまたはSourceForgeにて確認できます。このtwitterアカウントでフォント制作過程を毎日報告しています。質問などありましたら気軽にどうぞ。