お絵描きソフトInkscape(インクスケープ)の使い方を初級レベルから上級レベルまで広く紹介しています。
情報追加のリクエストや分かりにくい点があれば下のCONTACTフォームからどうぞ。

Inkscapeの自作エクステンション(オブジェクトの全探索)

  Inkscapeでエクステンションを自作する方法を試してみました。

 ここでは、その時点で編集中のレイヤ上の要素(オブジェクトやオブジェクトグループ)を網羅的に探索して(スキャンして)、そのIDとオブジェクトクラスを出力するエクステンションを作ってみました。これを拡張すれば、レイヤ上のすべてのオブジェクトに好きな処理を加えることができると思います。

 ポイントはエクステンションからアクセス可能な要素(SvgDocumentElementオブジェクト)はいわゆる「イテラブル(iterable)」なオブジェクトなので、forループを使って特定の要素(SvgDocumentElementオブジェクト)の1つ下位の要素を順番に取り出しながら、その属性などを参照して、自由に処理することができるということです。

 forループで取り出される順番がどんなルールにしたがっているのかは説明を見つけられていませんが、実際に動かしてみるとどうやらSVG形式データの中で上から順番に取り出しているようです。オブジェクト同士の重なり順(いわゆるZ-オーダ)とは逆の順になっています。

 エクステンションのPythonコードはこんなふうに書いてみました。

import inkex
import sys
class ExhaustiveSearchExtension(inkex.extensions.EffectExtension):
    
    def effect(self):
        ly = self.svg.get_current_layer() # 編集中のレイヤオブジェクトをGET
        
        print(ly.get('id')+": "+str(ly.__class__), file=sys.stderr)
        for obj1 in ly:   # 下位の要素を順に取り出す
            print(obj1.get('id')+": "+str(obj1.__class__), file=sys.stderr)
            
            # 下位要素がオブジェクトグループの場合はさらに下位の要素を取り出す
            if isinstance(obj1, inkex.elements._groups.Group):
                for obj2 in obj1:
                    print("      "+obj2.get('id')+": "+str(obj2.__class__), file=sys.stderr)
                    if isinstance(obj2, inkex.elements._groups.Group):
                        for obj3 in obj2:
                            print("            "+obj3.get('id')+": "+str(obj3.__class__), file=sys.stderr)         
                            
if __name__ == '__main__':  # エクステンションはここから実行される
    ExhaustiveSearchExtension().run()

 オブジェクトグループについては3階層まで探索しています。再帰呼び出しするようなメソッドを書けばきれいになると思いますが、余分な工夫をしすぎるとパッと見て理解しにくいコードになってしまうので、だらだらと書いてみました。

 次のようなドキュメントにこのエクステンションを実行してみます。

 すると、次のようなprint関数の出力が表示されます。

 Inkscapeの画面で見えている重なり順(Z-オーダ)とは逆の順にオブジェクトが取り出されていることが分かります。