Inkscape のエフェクトを書きました。
これまでのあらすじ。
「Inkscape ってクリッピングマスクがないのは痛いですよね」 → 「まあ SVG にない機能はなくてもしょうがなさそうですね……」 → 「ん? いや仕様書見たらありますよクリッピング」 → 「……あれ、試しにクリッピングありの SVG 開いたら開けちゃった」 → 「じゃあなに、Inkscape の UI の実装が追いつかないだけですか?」 → 「あ、拡張書くとしあわせかも」
で、出来上がったのがこれと。
Create Clipping / Destroy Clipping(例によって拡張子に .mid をつけているので削ってください。)
クリッピングマスクを設定するやつと、それを解除するやつ。
アーカイブを展開して、Inkscape のディレクトリの share/extensions の下に置いて Inkscape を再起動すればなんとなく使えるはず。
複数のオブジェクトを選択した状態で「Create 〜」すると、一番上の要素をクリッピングパスにして、他の全オブジェクトのクリッピング (clip-path 属性) にそのクリッピングパスを指定します、大概。
「Destroy 〜」は逆で、選択した要素にクリッピングパスが指定されている場合、そのクリッピングパスを削除(普通の要素に戻す)して、同じクリッピングパスを参照している要素すべてのクリッピングを解除します。
以下エフェクトについて大雑把に。
Inkscape には、バージョン 0.43 現在「EXPERIMENTAL」の但し書きつきですが、ユーザが実装したエフェクトを使う機能があります。
エフェクタというか拡張というか、多分 Illustrator で言うところのプラグインなのですが、これが異様に自由度が高くて。基本的にはフィルタとして「編集中の SVG を受け取って好きに弄くった後また SVG として出力する」という流れをとるのですが、実体は単に SVG ファイルと引数を渡して Python か Perl のスクリプトをキックしているだけ。しかもぶっちゃけ SVG って XML なので、DOM を持ってきてしまえばすごい簡単に編集できる=エフェクトが書けてしまいます。
作るにあたって唯一の問題は絶望的に資料がないことで、日本語の情報が絶無なのはともかく本家の wiki を見てもチュートリアルの乏しさに悩まされます。が、そこは Python 「
実行可能な擬似コード」の強みで幾つかソースを眺めればやってることは把握可能。share/extension/ の下の README と inkex.py, handles.py, simplepath.py, simplestyle.py くらいの順で大体骨格がつかめます。inkex.py と simple*.py は補助ライブラリ的なもので、特に inkex.py が核です。他に、
SVG の仕様の概略を抑えているのが前提だったりはしますが。
ついでに引っ掛かったとこなんかをメモ。
エフェクトの使用はデフォルトではオフになっていて、設定を変更しないと使えません。
「Inkscapeの設定」(Shift+Ctrl+P)で「その他」タブの「Enable script effects (requires restart) - EXPERIMENTAL」をチェックして、ご託宣通りに Inkscape を再起動すると、メニューに「Effects」が現れます。
私の環境 (Windows 2000) では、Effects を有効にしても Python が動きませんでした。
仕方がないので inkscape.exe と同じディレクトリの python24.dll を python24.dll_ にリネームして無効化し、インストールしてあった Windows 版の普通の(スタンドアロンの) Python 2.4 にパスを通して動かしました。(Python の拡張の PyXML も必要ですが、元から入っていたのか後で自前で足したのか失念しました。PyXML がどうの、というエラーが出たらそれも入れれば動くと思います。)
XML の話に飛びますが、エフェクト側で生成 (createElement()) した要素は、当然 id を持っていません。
生成後何もしなくても Inkscape から見ると id が振られていてちょっと騙されたのですが、エフェクト実行後 Inkscape が読み直すときに、id 属性のない要素には勝手に id が振られるようです。(python でエフェクトを直接実行すると出力に id 属性が入りませんでした。) なので、エフェクト内で生成した要素の id を使うような処理がしたければ、自前で適当な id を設定してやる必要があります。このあたり、ユニークな値を得る手段が提供されて欲しいような。いやもしかしたら既にあるのかもしれませんが。
それからそうそう、エフェクト実行時に複数選択していた要素が来る順番は、実は不定っぽいです。
今回書いたエフェクトは「重なり順で手前の要素から順に指定される」という前提で書いていて、大概はそれで問題ないのですが、「全て選択」とか「選択を逆転」とかメニューから要素を選択するとどうも逆「重なり順で奥の要素から」になるようです。なので実は「Create Clipping」の方は、場合によって一番奥の要素をクリッピングパスにしてしまうだめ具合。厳密には、全要素の XML 上での出現順番でも調べなければいけないような気がするのですが、ここでは面倒なので略です。
あと Inkscape 全体のルールに従ってか、inkex.py は GPL です。
Python でエフェクトを書くときに手を抜こうと思うと確実に import inkex することになりますが、恐らく import したら GPL に感染するのではないかと思います。GPL の解釈にはいつも悩まされますが。解釈に自信が持てずかつ GPL にしたくない場合は、ゼロから書く必要がありそうです。私は何もなければ修正 BSDL 辺りを使いたい(むしろこれだけ小さければ public domain にしたい)のですが、深いこと考えるのは面倒なのであっさり妥協。
ついでのついでにどうでもいいこともメモ。
*.inx に指定された記述から、さりげなく引数の設定用 UI を動的に生成してるのにちょっと感動しました。おお、これが GUI なアプリのプラグインですか、みたいな。Script-Fu とか触ったことがないのがバレバレな感じですが。
*.inx といえばあのファイル、Java のパッケージライク (URL をひっくり返したような表記) に id を指定する項目があるのですが、あれってドメイン持ってない人間は使うなってことなんでしょうか。適当に GMail のアドレスっぽいけれどありえない文字列を指定しましたが……。
Inkscape 全体についてもいえますが特にエフェクト、日本語の情報が本当にありませんね。需要ないのかしらん。
ていうか、Inkscape のバージョンが上がったら(きちんとクリッピングマスクだとかに対応したら)要らなくなるどころか、今でさえ XML エディタを叩けばちょいちょいで終わる作業の代物に私は手間をかけすぎだと思います。
2006/02/15 12:28
A:Logging
99コメント(0)