「Krita」と「Python」でアーティスティックな絵を描こう
![](https://thinkit.co.jp/sites/default/files/styles/main_image_730x/public/main_images/ren_krita_python_cover_2.png?itok=-V8OgnpA)
はじめに
今回は前回の応用例として、もっと意味のある図形を描くために「三角関数」の「sin(正弦)」と「cos(余弦)」を使います。三角関数は要するに円周上の(X,Y)座標に関する計算を三角形を用いて計算するようなものです。
今回のサンプルはほとんど前回のテンプレートに書き足すだけです。まずラインを1本とSIN波とCOS波を描きます。次に円1個と色相12色の円を描いて、新規レイヤーを作成していきます。
SIN波とCOS波を描く
SIN波とCOS波は短い直線をたくさん繋げて曲線のように見せています。人間の人差し指を曲げてみてください。3本の直線の骨が曲がっていますが、少し曲線にも見えますね。
1本のラインを描く
前回のテンプレート「template.py」を参考に、サンプルスクリプト「line.py」のようにスクリプティングして「▷(実行)」ボタンを押すと、黒い1本のラインが描画されます(図1)。
今回は図形の境界が滑らかに見えるように「アンチエイリアス」をかけます。Windows標準の文字はズームしてみると塗りの境界がギザギザで、PDFファイルの文字の方が塗りの境界が滑らかに見えますよね。あれはアンチエイリアスがかかっているからです。
・サンプルスクリプト「line.py」# モジュール from PyQt5.Qt import * import math # ドキュメントの作成 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_line(doc): pixmap = QPixmap(doc.bounds().size()) pixmap.fill(QColor(255,255,255,255)) painter = QPainter() painter.begin(pixmap) painter.setRenderHint(QPainter.Antialiasing,True) pen = QPen(QColor(0,0,0,255)) pen.setWidth(50) painter.setPen(pen) painter.drawLine(0,0,800,800) painter.end() return pixmap.toImage() # レイヤーのセット def set_layer(doc,img): layer = doc.activeNode() 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') # メイン関数 def begin_draw(): doc = create_doc(800,800) img = draw_line(doc) set_layer(doc,img) doc.refreshProjection() # メイン関数の呼び出し begin_draw()
【サンプルスクリプトの解説】
「draw_line」関数で直線を描画します。
イメージのデータを「pixmap」変数に代入し、真っ白に塗り潰し(fill)ます。
「QPainter」クラスのインスタンスを「painter」変数に代入し、pixmap変数への図形の描画を開始(「begin」メソッド)します。
「setRenderHint」メソッドで図形にアンチエイリアスをかける設定をします。
「QPen」クラスで線(輪郭)の色を黒色に指定し、太さを50に指定して(X,Y)座標の(0,0)と(800,800)を繋いで直線を描画します。
「end」メソッドで「pixmap」変数への描画を終了し、「QImage」クラスに変換したデータを戻り値として返します。
「begin_draw」関数の「create_doc」関数で800x800pxのドキュメントを作成し、draw_line関数を呼び出します。
SIN波を描く
サンプルスクリプト「line.py」に追記し、サンプルスクリプト「sin.py」のようにスクリプティングして「▷(実行)」ボタンを押せば、SIN波の曲線が描かれます(図2)。
正弦を取得する「sin」関数には引数に角度ではなく円周率の「ラジアン」を渡します。ラジアンとは円1周の360度を「2π(パイ)」とした場合の度を表します。
・サンプルスクリプト「sin.py」(前略) # 曲線の描画 def draw_line(doc): pixmap = QPixmap(doc.bounds().size()) pixmap.fill(QColor(255,255,255,255)) painter = QPainter() painter.begin(pixmap) painter.setRenderHint(QPainter.Antialiasing,True) # pen = QPen(QColor(0,0,0,255)) # pen.setWidth(50) # painter.setPen(pen) # painter.drawLine(0,0,800,800) draw_sin(doc,painter) painter.end() return pixmap.toImage() # SIN波の描画 def draw_sin(doc,painter): for i in range(0,doc.width()): color = QColor.fromHsl(i%360, 255, 128, 255) pen = QPen(color) pen.setWidth(5) painter.setPen(pen) x1 = i radian = math.radians(x1) y1 = doc.height()/2-90*math.sin(radian) x2 = i+1 radian = math.radians(x2) y2 = doc.height()/2-90*math.sin(radian) painter.drawLine(x1,int(y1),x2,int(y2)) (後略)
【サンプルスクリプトの解説】
「draw_line」関数で「draw_sin」関数を呼び出します。
スクリプトを「#(コメントアウト)」すると、その行のスクリプトは実行されません。#を書く代わりにその1行を削除しても構いません。
「draw_sin」関数でSIN波を描画します。
曲線の色は色相を変えて描くので「fromHsl」クラスメソッドで0~360未満の整数で表します。
(X,Y)座標=(i,中心-90*sin(iのラジアン))です。ただし直線をひくので、そこから(i+1,中心-90*sin(i+1のラジアン))へのライン(drawLine)を描きます。
COS波を描く
サンプルスクリプト「sin.py」に追記し、サンプルスクリプト「cos.py」のようにスクリプティングして「▷(実行)」ボタンを押せば、SIN波に重なってCOS波も描かれます(図3)。
余弦を取得する「cos」関数も「sin」関数同様、引数にラジアンを渡します。角度からラジアンに変換する中身は「ラジアン=角度*2*π/360」で計算します。πは約3.141592です。
・サンプルスクリプト「cos.py」(前略) # 曲線の描画 def draw_line(doc): pixmap = QPixmap(doc.bounds().size()) pixmap.fill(QColor(255,255,255,255)) painter = QPainter() painter.begin(pixmap) painter.setRenderHint(QPainter.Antialiasing,True) draw_sin(doc,painter) draw_cos(doc,painter) painter.end() return pixmap.toImage() # COS波の描画 def draw_cos(doc,painter): for i in range(0,doc.width()): color = QColor.fromHsl(i%360, 255, 128, 255) pen = QPen(color) pen.setWidth(5) painter.setPen(pen) x1 = i radian = math.radians(x1) y1 = doc.height()/2-90*math.cos(radian) x2 = i+1 radian = math.radians(x2) y2 = doc.height()/2-90*math.cos(radian) painter.drawLine(x1,int(y1),x2,int(y2)) (後略)
【サンプルスクリプトの解説】
「draw_line」関数で「draw_cos」関数も呼び出します。
「draw_cos」関数でCOS波を描画します。
曲線の色は色相を変えて描くので「fromHsl」クラスメソッドで0~360未満の整数で表します。
(X,Y)座標=(i,中心-90*cos(iのラジアン))です。ただし直線をひくので、そこから(i+1,中心-90*cos(i+1のラジアン))へのラインを描きます。