見出し画像

【DaVinci Resolve API】GUIで画像をレイヤー表示する方法

まえがき

こんにちは。火注ゆかなです。
今回はPSDレイヤーを上手いことGUIで表示する方法を確立できたので、その説明になります。



画像をレイヤー表示する方法

画像を表示する方法

まずはTextEditを使って画像を表示します。
TextEditはHTML属性に文字列を設定すると、その内容に応じてHTML表示をしてくれます。

なので、imgタグを含む文字列をTextEdit.HTMLに代入して上げれば画像表示できます。
imgタグにwidth属性、height属性を指定すれば画像の拡大縮小も可能です。

# Python版
ui.TextEdit({
    'ID':'Layer1', 
    'ReadOnly':True,     # エディターのカーソルを非表示にするために読取専用にする
    'HTML':r'<img src="C:\test.png">',
})
-- Lua版
ui:TextEdit{
    ID = ImageLayer_1, 
    ReadOnly = true, 
    HTML = [['<img src="test.png">']]
}

さて、次はこの画像を別の画像の上に表示すれば良いのですが、TextEdit.HTMLにはCSSやStyleは設定できませんでした。私のやり方が良くないのかもしれません。

要素を重ねて表示する方法

HTMLのStyleで画像を重ねることができなかったので、今回はGroupウィジェットを使って重ねてみます。

Groupウィジェットを含めたレイアウト用ウィジェットは以下の4つです。

  1. VGroup:子要素を縦に並べる。

  2. HGroup:子要素を横に並べる

  3. Stack:子要素を一つだけ表示する。CurrentIndexで表示する子要素を切り替え可能。TabBarウィジェットなんかと組み合わせて使う。

  4. Group:子要素を重ねて表示する。Geometry属性で表示位置・サイズを固定できるが、他のレイアウト用ウィジェットと異なり、ウィンドウサイズを変えても表示位置やサイズを自動調整してくれない。

Groupも他のレイアウト用ウィジェットと同じように記述しても問題ありませんが、子要素はGeometry属性での位置・サイズ設定がほぼ必須になります。
あとWeight属性に0を設定すると非表示になるので注意してください。

# Python版
# Python版では属性は辞書型、子要素はリストに格納する必要がある。
# Pythonは辞書型に値を格納する際、キーが必要になるため。

ui.Group(
    {'ID':'PreviewGroup'},
    [
        ui.Button({
		    'ID' : "Group_1",
		    'Text' : "Group_1",
        }),
        ui.Button({
		    'ID' : "Group_2",
		    'Text' : "Group_2",
        }),
        ui.Button({
		    'ID' : "Group_3",
		    'Text' : "Group_3",
            'Geometry' : [10, 100, 100, 50]
        }),
    ]
)
-- Lua版
-- Lua版では属性も子要素も一つのテーブルに格納してもOK。

ui:Group{
    ID = 'PreviweGroup',

	ui:Button{
		ID = "Group_1",
		Text = "Group_1",
	},
	ui:Button{
		ID = "Group_2",
		Text = "Group_2",
	},
	ui:Button{
		ID = "Group_3",
		Text = "Group_3",
		Geometry = {10, 100, 100, 50},
	},	
}

画像をレイヤー表示する方法

では上記の要素を組み合わせて画像をレイヤー表示してましょう……と言いたいところですが、その前に画像の背景色を透過する必要があります。

各ウィジェットはBackgroundColor属性を持っていますが、TextEditはこれを設定しても背景を透過できません。
これはバグではなくて、背景色部分がエディタの下にあるためです。なので、エディタそのものを透過する必要があります。

エディタを透過するには以下のように、StyleSheet属性でbackground-colorを設定すればOKです。

# Python版
ui.TextEdit({
    'ID':'Layer1', 
    'ReadOnly':True,     # エディターのカーソルを非表示にするために読取専用にする
    'StyleSheet':"background-color: transparent;",    # エディタの背景色を透過する
    'HTML':r'<img src="C:\test.png">',
})
-- Lua版
ui:TextEdit{
    ID = ImageLayer_1, 
    ReadOnly = true, 
    StyleSheet="background-color: transparent;",    -- エディタの背景色を透過する
    HTML = [['<img src="test.png">']]
}

では今度こそ画像をレイヤー表示してみます。
表示する画像はボイスロイドの紲星あかりの立ち絵パーツ4枚です。(akihiyo様作:https://www.pixiv.net/artworks/87270373)

予め分割出力しておいたPSDレイヤー画像

コードは以下の通りになります。Luaの人はなんかこう、上手い具合に読み替えてください。

from curses import start_color
from operator import itemgetter
import pprint
import sys
sys.path.append("C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting\Modules")
import DaVinciResolveScript as bmd


# GUI設定
resolve = bmd.scriptapp('Resolve')
fusion = resolve.Fusion()
ui = fusion.UIManager
disp = bmd.UIDispatcher(ui)

# ウィンドウ設定
win = disp.AddWindow({
	    'ID': 'myWindow' ,
	    'WindowTitle' : 'My First Window',
	    'Geometry' : [ 100, 100, 700, 900 ],
	    'Spacing' : 10,
	    'BackgroundColor':{'R':0.6, 'G':0.1, 'B':0.2, 'A':0.2}
    },
    [
    	ui.Group({
    		'ID':'PreviewGroup', 
          	'BackgroundColor':{'R':1.0, 'G':1.0, 'B':1.0, 'A':1.0},
          	'DoAlpha':True,             # BackgroundColorの透明度を有効にするか
          	'AutoFillBackground':True,   # BackgroundColorでウィジェットの背景を塗りつぶすか
          },
	     [       # レイヤー表示用
			ui.TextEdit({
	                'ID':'Layer1', 
	                'Weight':1.0,
	                'ReadOnly':True, 
	                'StyleSheet':"background-color: transparent;",  # TextEditやLineEditで背景を透過させる場合はStyleSheetで指定しないと駄目。(BackgroundColor属性はこれの下に適用される)
	                'Geometry':[23, 51, 700, 900],
	                'HTML':r'<img src="C:\\0_0_0.png">',
	          }),
	          ui.TextEdit({
	              'ID':'Layer2', 
	              'ReadOnly':True, 
	              'StyleSheet':"background-color: transparent;",
	              'Geometry':[224, 129, 300, 100],
	              'HTML':r'<img src="C:\\0_1_0_2.png">',
	              }),
	          ui.TextEdit({
	              'ID':'Layer3', 
	              'ReadOnly':True, 
	              'StyleSheet':"background-color: transparent;",
	              'Geometry':[287, 333, 100, 100],
	              'HTML':r'<img src="C:\\0_1_1_7.png">'}),
	          ui.TextEdit({
	              'ID':'Layer4', 
	              'ReadOnly':True, 
	              'StyleSheet':"background-color: transparent;",
	              'Geometry':[192, 211, 400, 200],
	              'HTML':r'<img src="C:\\0_1_2_9.png">'}),
		])        
    ]    
)
itm = win.GetItems()

def OnWindowClose(ev) :
    disp.ExitLoop()

win.On.myWindow.Close = OnWindowClose

win.Show()
disp.RunLoop()
実行結果

ちゃんとレイヤー表示できました。

TextEditは画像サイズより少し大きめに表示しないとスクロールバーが表示されてしまうので気を付けてください。

あとは画像の拡大縮小についてですが、サイズはimgタグで属性指定すれば済みますが、表示位置についてはTextEditの位置を動かさないといけません。

あとがき

今回はそこそこ実用的かなぁと思います。
あとはTreeウィジェットと組み合わせれば、PSDToolライクなGUIも作れるでしょう(既にDavinciResolve向けの立ち絵操作スクリプトは4種類くらいありますけど)

Groupウィジェットを探すのが一番大変でした。該当する機能があること自体は確信していましたが、公式のウィジェット一覧がありませんからね……先達が探し出したGUIウィジェット一覧に載っていないし、dir関数でも表示されないし……。

この記事が皆様のお役に立てば幸いです。

サポートしていただけるとその分の価値を提供できてるんだなって励みになります。