見出し画像

クリスタで画像生成する

クリスタのフィルターブラグインとして画像生成を試してみてるので、ざっくり解説しときます。(画像生成自体についての情報は少ないので、プラグインを書こうとしてるプログラマー向けかな)
とりあえずGitHubのリポジトリはこれ。

画像生成側

バックエンドはstable-diffusion.cppです。
これのDLLを動的リンクで呼び出す形に実装してます。
たぶん、中に取り込んでビルドしちゃった方が綺麗なんですけど、この形にしておくと環境に合わせてDLL差し替えたりできて便利なんですよね。

こっちは特に特殊な事やってないんで、むしろ解説不要かなと思ってます。
DLL呼びする人が居たら参考にしてください。

プラグイン側

ビルドするのにここからSDKをダウンロードしてくる必要があります。
追記:オープンソースでの開発が利用規約に触れるそうなので、SDKを使わずに開発するようにしました。今はSDKが無くてもビルドできる状態です。

サンプルコードと簡易なリファレンスくらいしか無いですが、プラグイン系に慣れてる人なら勘でなんとかなると思います。

API自体は最小限でシンプルなんだけど、ちょっと挙動に癖があるというか……
とりあえずUI周りは、ほとんど弄れないです。
特にテキスト入力が、1行限定だったり、毎回IMEがONになったり、とにかく画像生成と相性が悪すぎて頭抱えてます。

プラグイン実装のメモ

個人的にハマった部分……特にプラグインAPIの挙動について、SDKのドキュメントとかに書いてない部分のメモを残しておきます。

ブロックの単位

オフスクリーンへのアクセスが256×256単位のブロックなので、そのサイズに升目のレイヤー置いとくと検証しやすいです。(環境によってブロックのサイズは変わる可能性あるかも?)
後述、アドレスのオフセットの挙動でバグ取りに苦労したので……

これはブロック跨ぎの生成で何故か下半身だけ転送された例w

オフスクリーンサービス

getBlockImageProc()っていう画像データへのアクセスを提供するAPIがあって以下のような情報を返してくるんだけど……

address アドレス
rowBytes 次列ピクセルまでのバイト数
pixelBytes 次のピクセルまでのバイト数
blockRect ブロックのサイズ

ここで返ってくるアドレスは、ブロックの先頭じゃなくて対象座標にオフセットされたものなので注意が必要です。

ここで言う座標ってのは「pos」引数で渡してる座標です

でも、blockRect引数にはクリッピングされた描画領域じゃなくて、ブロック全体の座標が返ってくるので混乱しがち。

この挙動は、似たインターフェイスの getBlockAlphaProc() とか getBlockSelectAreaProc() とかも同じようです。

サーバー

ホスト側の情報として、以下のサーバー側オブジェクトが渡されてくるんだけど……

hostObject ホストオブジェクト
recordSuite レコードスイート(特定のセレクタ内専用のメソッド群)
serviceSuite サービススイート(各セレクタ共通のメソッド群)

このオブジェクト達、それぞれのアドレス自体は変わらないっぽいのだけど、それを渡してくるserver引数自体は呼び出される毎に変わる事が多い(たぶん毎回割り当てられてる)ので、キャッシュすると死にます。
中のオブジェクトもアドレス変わる前提で組んだ方が安全ですね。

オブジェクトの参照カウンタ

ここは一般的なAPIの挙動に倣ってるようです。
生成されたものは使用終了時にreleaseする必要あり。
取得したものはrelease不要……っぽいのだけど、スコープというかセレクタ跨ぐ場合とかは明示的にretain/releaseする形にしといた方が安全かもですね。(そうならないよう設計するのがベストではあり)

参考資料とか

とにかく情報が少ないんですけど、現在GitHub上で公開されてるものを貼っておきます。

NekoDraw

2年前に自分と同じような挑戦してた。

ClipStudioPaintExampleFilterPlugIn

シンプルなフィルタの例。
SDKのサンプルがOffscreenObjectを使ってるのに対して、BitmapObjectを扱うサンプルとして有用。

cspsdkxx

SDKをゴリッゴリにC++ラッピングした奴。こういうの大好き。
(うちも似たような思想でラッピングしてるけどここまで徹底はしてない)


この記事が気に入ったらサポートをしてみませんか?