2019年1月6日日曜日

KirtaのPythonを調べてみた

いつもはBlenderの話題の多い当サイトですが2019年最初の話題はKritaです。

Blenderと同じようにオープンソースのペイントソフトでPyhtonで操作できてアドオン等も作成できるのですが、
今回は ツール>Scripts>Scripterで実行してみたものをメモしておきます

KritaのリファレンスはKDE API Referenceにあるようですが
一覧を見てもさっぱりなのでdir()で属性を辿ってみました
from krita import *
print(dir(krita)) 
で返ってくるのは
['Canvas', 'Channel', 'CloneLayer', 'DockWidget', 'DockWidgetFactoryBase', 'Document', 'Extension', 'FileLayer', 'FillLayer', 'Filter', 'FilterLayer', 'FilterMask', 'GroupLayer', 'GroupShape', 'InfoObject', 'KisCubicCurve', 'KoColorSetEntry', 'Krita', 'ManagedColor', 'Node', 'Notifier', 'Palette', 'PaletteView', 'PresetChooser', 'Resource', 'Selection', 'SelectionMask', 'Shape', 'VectorLayer', 'View', 'Window', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__']
使いそうなものがいくつかあります

レイヤ

他のサンプルも参考にしたところによると
Krita.instance().activeDocument() で今編集中のドキュメントを取得でき
レイヤはスクリプト上は階層構造を持つNodeという扱いのようで
ドキュメントのrootNode()から子のchildNodes()を取得する感じのようです
一番上の階層のレイヤ情報を取得するスクリプト
from krita import*
doc =  Krita.instance().activeDocument()
print(doc.activeNode().visible())
for n in doc.rootNode().childNodes():
    print("name:%s Type:%s %s mode:%s" % ( n.name(), n.type(), n.opacity(), n.blendingMode() ) ) 
で、こういうレイヤ構造の 選択範囲があるファイルで取得すると
False
name:レイヤー 1 Type:paintlayer 255 mode:normal
name:レイヤー 2 Type:paintlayer 99 mode:multiply
name:レイヤー 6 Type:grouplayer 255 mode:normal
name:selection Type:selectionmask 255 mode:normal
typeがgrouplayerのノードをさらにchildNodesを取得すれば階層をたどれそうです
内部的にはレイヤの不透明度は0-255になっているようです
面白いのが 選択範囲もノード扱いなのですね

選択中のレイヤをファイルとして書き出しは
from krita import*
doc =  Krita().activeDocument()
file_path = "E:/Documents/TempItems/krita_test.png"
doc.activeNode().save(file_path, doc.xRes(), doc.yRes()) 
でできましたが
グループを選択した時にはグループの中にある内容が統合して書き出されるものの
ドキュメントのサイズではなく、描かれている範囲のみの書き出しになるようです
ここは もう少し調べる必要がありそうです。

レイヤとしてファイルを読み込むのは少々面倒なようです
from krita import *
file_path = "E:/Documents/TempItems/krita_test.png"
doc = Krita().activeDocument()
layers = [n for n in doc.rootNode().childNodes()]
new_doc = krita.Krita().openDocument(file_path)
layers.append(new_doc.rootNode().childNodes()[0].clone())
doc.rootNode().setChildNodes(layers)#レイヤの再構成
doc.refreshProjection()#ドキュメントの表示状態の更新
new_doc.close() 
動作したものの レイヤの再構成の部分で使う処理を間違うと
レイヤがアンドゥ不能な状態で焼失したりしました

選択範囲

次に自動処理に必要な選択範囲です
まずSelection().selectAll()があるので全選択を試してみましたが
画面に変化がありません

検索してみると
from krita import *
doc = Krita().activeDocument()
node = doc.activeNode()
sel = Selection()
sel.selectAll(node, 255)
sel.cut(node)#選択範囲をカット 
といった感じに処理対象を指定する操作は動くものの
選択範囲境界の表示が出ないことが話題になっていました
色々触ってみてると ドキュメントに選択範囲がある時には
from krita import *
doc =  Krita.instance().activeDocument()
doc.selection().move(150,10)#選択範囲の移動
 
とすると選択範囲は移動するのが確認できました
どうやら個別に存在する選択範囲をドキュメントに設定する必要があるようです
from krita import *
doc = Krita().activeDocument()
node = doc.activeNode()
sel = Selection()
sel.selectAll(node, 255)
doc.setSelection(sel)#Selectionオブジェクトをドキュメントに設定 
でき・・・ましたが
選択範囲は対象に指定したレイヤに描き込まれている範囲が選択範囲になっています

Kritaの仕様はこうなのですね 
別の方法でドキュメントの全選択してみます。
from krita import *
doc = Krita().activeDocument()
sel = Selection()
sel.select(0, 0, doc.width(), doc.height(), 255)
doc.setSelection(sel) 
矩形の選択範囲は左上位置と幅を高さを指定することで作成できそうです。

他の選択範囲の方式も試してみます
どうやら多角形選択といった操作をスクリプトで指定する方法は用意されていないようなので
選択範囲のデータがどうなっているか調べてみます
選択範囲を作成して矩形指定した範囲の選択範囲情報を出力させてみると
from krita import *
doc =  Krita.instance().activeDocument()
print(doc.selection().pixelData(0,0,10,10))#範囲の選択範囲の濃度をピクセルデータで。
b'\x00\x00\x00\x00\x00\x00\x00\x04\xb1\xff\x00\x00\x00\x00\x00\x00\x02\xa6\xff\xff\x00\x00\x00\x00\x00\x01\x9b\xff\xff\xff\x00\x00\x00\x00\x00\x90\xff\xff\xff\xff\x00\x00\x00\x00\x84\xff\xff\xff\xff\xff\x00\x00\x00w\xff\xff\xff\xff\xff\xff\x00\x00k\xff\xff\xff\xff\xff\xff\xff\x00`\xfe\xff\xff\xff\xff\xff\xff\xffU\xfc\xff\xff\xff\xff\xff\xff\xff\xff\xfa\xff\xff\xff\xff\xff\xff\xff\xff\xff'
グレースケールのバイナリデータですね・・・
とりあえず このデータから選択範囲を作るものを試してみます
from krita import *
doc = Krita().activeDocument()
sel_pix = doc.selection().pixelData(0,0,100,100)
doc.selection().clear()
sel = Selection()
sel.setPixelData( sel_pix,0,0,100,100 )
doc.setSelection(sel)
選択範囲としては動いているのですが
境界線が表示されないです 難しいものですね

中途半端ですが今回は動作確認までにします。
Blenderから画像やマスクを描き出す等の自動処置ができるようにしたいものです