「Krita」で「Python」をプログラミングしてはじめての画像を描こう

2024年7月23日(火)
大西 武 (オオニシ タケシ)
第3回の今回は、「Krita」で「Python」をプログラミングして、はじめてのドキュメントやイメージ、レイヤーを作る解説をします。

はじめに

第1回で予告した通り、今回から早速実際に「Python」をプログラミングして「Krita」にグラデーション矩形とランダムな正方形を描画していきます。

その前に、まずウィンドウにイメージを描画するテンプレート(ひな形)を作っていきます。そのためにはドキュメントを開いたり、開いたドキュメントを選択したりしてそのドキュメントでレイヤーを作り、そのレイヤーにイメージを描画します。

なお、KritaでPythonをスクリプティングするための「スクリプター」の使い方は第1回を参考にしてください。今後の連載では、スクリプターの使い方に関する説明は割愛させていただきます。

ドキュメントとイメージとレイヤー

ドキュメントとは、絵を描くウィンドウのことです。KritaではMDI(マルチドキュメントインターフェース)で複数のドキュメントを並行して処理できます。

イメージとは、ドット絵を描いたことがある方なら分かると思いますが、色の付いたドット(ピクセル、点)をたくさん描いた画像のことです。コンピュータのイメージはドットの集まりです。

一方のレイヤーとは、アニメでいうセル画のような透明な層のことです。例えば顔の絵を描くときレイヤーごとに皮膚、目、鼻、口、耳、眉毛、髪の毛などと層を重ねて描くと、それぞれのパーツの位置を変えたり形を変えたりなどが簡単にできるので、コンピュータで絵を描く場合には必須の機能です。

ドキュメントの作成

次のサンプルスクリプト「doc.py」をスクリプティングして「▷(実行)」ボタンを押すと、図1のような真っ白なイメージのレイヤーのあるドキュメントウィンドウが現れます。どのような幅高さのドキュメントを作っても、最初にウィンドウが表示されるときは描画領域がウィンドウのサイズにピッタリ拡大縮小されて表示されます。

図1:ドキュメントの作成

・サンプルスクリプト「doc.py」
# ドキュメントの作成
doc = Krita.instance().createDocument(256,256, "Document name", "RGBA", "U8", "", 300.0)
Krita.instance().activeWindow().addView(doc)

【サンプルスクリプトの解説】
「createDocument」メソッドで256x256pxのサイズで"Document name"という名前の赤(Red)、緑(Green)、青(Blue)、アルファ(Alpha)がU8(符号なし8ビット)、プロファイルなし、解像度300のドキュメントを作成します。
アクティブなウィンドウのビューにドキュメントを追加(addView)します。

イメージの作成

次のサンプルスクリプト「image.py」のように追記して「▷(実行)」ボタンを押すと、また図2のような真っ白なイメージのレイヤーのあるドキュメントウィンドウが現れます。透明な256x256pxのイメージを作ったのですが、まだレイヤーに描画していないため何も起こらず真っ白なままです。

ドキュメントの作成は「create_doc」関数にまとめました。この関数では戻り値でドキュメントのインスタンスを受け渡しします。

図2:イメージの作成

・サンプルスクリプト「image.py」
# モジュール
from PyQt5.Qt import *
# ドキュメントの作成
def create_doc(width,height):
  doc = Krita.instance().createDocument(width,height, "Document name", "RGBA", "U8", "", 300.0)
  Krita.instance().activeWindow().addView(doc)
  return doc
# ドキュメントの取得
doc = create_doc(256,256)
# イメージの用意
pixmap = QPixmap(doc.bounds().size())
pixmap.fill(QColor(Qt.transparent))
img = pixmap.toImage()

【サンプルスクリプトの解説】
「import」文で「PyQt5」モジュールを読み込みます。
「pixmap = QPixmap(doc.bounds().size())」は本来なら「pixmap = PyQt5.Qt.QPixmap(doc.bounds().size())」と書くところ、import文で「*」と書いているので「PyQt5.Qt」を書かなくてもこのモジュールの機能が使えます。
「QPixmap」クラスのインスタンスでイメージを生成し、透明で塗りつぶし(fill)、「QImage」形式に変換します。

レイヤーの作成

次のサンプルスクリプト「layer.py」のように追記して「▷(実行)」ボタンを押すと、図3のような透明なイメージのレイヤーのあるドキュメントウィンドウが現れます。ここで透明なイメージをアクティブなレイヤーに描画しました。

これで、ひと通りドキュメントを作成してイメージを描き、レイヤーにイメージをセットするところまでできました。イメージの用意は「draw_img」関数にまとめました。今後、たいていこういった名前の関数内で中心となる絵をプログラミングして形を描きます。

図3:レイヤーの作成

・サンプルスクリプト「layer.py」
# モジュール
from PyQt5.Qt import *
# ドキュメントの作成
def create_doc(width,height):
  doc = Krita.instance().createDocument(width,height, "Document name", "RGBA", "U8", "", 300.0)
  Krita.instance().activeWindow().addView(doc)
  return doc
# イメージの用意
def draw_img(doc):
  pixmap = QPixmap(doc.bounds().size())
  pixmap.fill(QColor(Qt.transparent))
  return pixmap.toImage()
# ドキュメントの取得
doc = create_doc(256,256)
# イメージの取得
img = draw_img(doc)
# 修正箇所
root = doc.rootNode()
# 修正箇所
layer = root.childNodes()[0]
# イメージのバイト長の検証
if img.sizeInBytes() == 4 * layer.channels()[0].channelSize() *  doc.width() * doc.height():
  ptr = img.bits()
  ptr.setsize(img.byteCount())
  layer.setPixelData(QByteArray(ptr.asstring()), 0, 0, doc.width() , doc.height()) 
else:
  print('Error')
# リフレッシュ
doc.refreshProjection()

【サンプルスクリプトの解説】
アクティブなレイヤーを取得します。他にもレイヤー名でアクティブとは限らないレイヤーも取得できます。
「if」文でイメージのバイト長が4×チャンネルサイズ×幅×高さと等しいか検証します。等しくなければ'Error'をターミナルに表示します。
イメージの幅高さと同じ大きさでレイヤーの中にイメージを描画します。
ドキュメントをリフレッシュ(refreshProjection)することでレイヤーへの描画を反映します。

テンプレートの完成

次のサンプルスクリプト「template.py」のように書き換えて「▷(実行)」ボタンを押すと、また透明なイメージのレイヤーのあるドキュメントウィンドウが現れます。プログラミングはテンプレートのような型になるスクリプトの部分まで深く理解していなくても大丈夫です。自分が書き足すスクリプトについてだけ理解していれば、他は後から何となく分かってくるものです。

レイヤーのセットは「set_layer」関数にまとめました。このテンプレートでKritaを使った基本的な描画処理はひと通り完成です。あとは主にこのテンプレートに肉付けしていくだけです。

・サンプルスクリプト「template.py」
# モジュール
from PyQt5.Qt import *
# ドキュメントの作成
def create_doc(width,height):
  doc = Krita.instance().createDocument(width,height, "Document name", "RGBA", "U8", "", 300.0)
  Krita.instance().activeWindow().addView(doc)
  return doc
# グラデーションの描画
def draw_img(doc):
  pixmap = QPixmap(doc.bounds().size())
  pixmap.fill(QColor(Qt.transparent))
  return pixmap.toImage()
# レイヤーのセット
def set_layer(doc,img):
  # 修正箇所
  root = doc.rootNode()
  # 修正箇所
  layer = root.childNodes()[0]
  if img.sizeInBytes() == 4 * layer.channels()[0].channelSize() *  doc.width() * doc.height():
    ptr = img.bits()
    ptr.setsize(img.byteCount())
    layer.setPixelData(QByteArray(ptr.asstring()), 0, 0, doc.width() , doc.height()) 
  else:
    print('Error')
# メイン関数(main()という関数名にしたいところだが既に使われている)
def begin_draw():
  doc = create_doc(256,256)
  img = draw_img(doc)
  set_layer(doc,img)
  # リフレッシュ
  doc.refreshProjection()
# メイン関数の呼び出し
begin_draw()
著者
大西 武 (オオニシ タケシ)
1975年香川県生まれ。大阪大学経済学部経営学科中退。プログラミング入門書など30冊以上を商業出版する作家。Microsoftで大賞やNTTドコモでグランプリなど20回以上全国区のコンテストに入賞するアーティスト。オリジナルの間違い探し「3Dクイズ」が全国放送のTVで約10回出題。
https://profile.vixar.jp

連載バックナンバー

開発言語技術解説
第8回

「Krita」と「Python」でUIパーツを構築してみよう

2024/11/1
第8回の今回は「Krita」で「Python」をプログラミングして、ボタンやスライダーなどのUIパーツを構築する解説をします。
開発言語技術解説
第7回

「Krita」と「Python」でダイアログUIを構築してみよう

2024/10/11
第7回の今回は「Krita」の「Python」で「PyQt5」モジュールの「ウィジェット」を使って、ダイアログUIを構築する解説をします。
開発言語技術解説
第6回

「Krita」と「Python」でアニメーションを描いてみよう

2024/9/24
第6回の今回は「Krita」で「Python」をプログラミングして、正方形が回転するアニメーションを作成する解説をします。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています