はじめに
今回は「ベジェ曲線」を描きます。ベジェ曲線とは「始点」「終点」「コントロールポイント」を元に曲線を描きます。始点から終点にかけて線を描くのですが、コントロールポイントの位置によって磁石で引っ張られたように線が曲がります。
ベジェ曲線を扱うPythonの「Qt(キュート、クロスプラットフォームで動作するUIライブラリ)」の「QPainterPath」クラスには「quadTo」メソッドと「cubicTo」メソッドの2つがあります。quadToメソッドはコントロールポイントが1つだけのベジェ曲線で描かれます(図1)。
図1:コントロールポイントが1つだけのベジェ曲線「quadTo」メソッド
cubicToメソッドはコントロールポイントが2つのベジェ曲線で描かれます(図2)。2つコントロールポイントがあるため、quadToメソッドよりも自由な形の曲線が描けます。
図2:コントロールポイントが2つのベジェ曲線「cubicTo」メソッド
フキダシを描く
それでは、ベジェ曲線を使う例としてフキダシを描いてみます。まず思考中のフキダシをquadToメソッド(1個のコントロールポイントだけのベジェ曲線)で描き、次にフォントを指定して文字を書きます。最後に会話中のフキダシをcubicToメソッド(2個のコントロールポイントのベジェ曲線)で描きます。
思考中のフキダシを描く
次のサンプルスクリプト「thought.py」はquadToメソッドを使うサンプルで、第3回のテンプレート「template.py」ファイルに追記していきます。「create_doc」関数と「set_layer」関数はそのままで、「begin_draw」関数もほとんど同じです。quadToメソッドやcubicToメソッド、「lineTo」メソッドのラインは「QPen」の色で塗られ、囲った部分は「QBrush」の色で塗り潰されます(図3)。
図3:思考中のフキダシの描画
・サンプルスクリプト「thought.py」
04 | def create_doc(width,height): |
05 | doc = Krita.instance().createDocument(width,height, "Document name", "RGBA", "U8", "", 300.0) |
06 | Krita.instance().activeWindow().addView(doc) |
09 | def draw_fukidashi(doc): |
10 | pixmap = QPixmap(doc.bounds().size()) |
11 | pixmap.fill(QColor(255,255,255)) |
14 | painter.setRenderHint(QPainter.Antialiasing,True) |
15 | color = QColor(0, 0, 0, 255) |
19 | color = QColor(255, 255, 255, 255) |
21 | painter.setBrush(brush) |
24 | return pixmap.toImage() |
26 | def draw_bezier(painter): |
29 | path.quadTo(100,700,400,700) |
30 | path.quadTo(700,700,700,400) |
31 | path.quadTo(700,100,400,100) |
32 | path.quadTo(100,100,100,400) |
33 | painter.drawPath(path) |
34 | painter.drawEllipse(QPoint(660,660),30,30) |
35 | painter.drawEllipse(QPoint(710,710),20,20) |
37 | def set_layer(doc,img): |
41 | layer = root.childNodes()[0] |
42 | if img.sizeInBytes() == 4 * layer.channels()[0].channelSize() * doc.width() * doc.height(): |
44 | ptr.setsize(img.byteCount()) |
45 | layer.setPixelData(QByteArray(ptr.asstring()), 0, 0, doc.width() , doc.height()) |
48 | # メイン関数(main()という関数名にしたいところだが既に使われている) |
50 | doc = create_doc(800,800) |
51 | img = draw_fukidashi(doc) |
53 | doc.refreshProjection() |
【サンプルスクリプトの解説】
「draw_fukidashi」関数でイメージのインスタンスを用意して描画を開始します。ペンとブラシを設定して「draw_bezier」関数を呼び出し、描画を終了して「QImage」に変換し戻り値を返します。
「draw_bezier」関数でQPainterPathクラスのインスタンスを生成して(100,400)→(400,700)→(700,400)→(400,100)→(100,400)の順にベジェ曲線でフキダシを描き、さらに円を2個描きます。
「begin_draw」関数でdraw_fukidashi関数を呼び出します。
フォントで文字を書く
次のサンプルスクリプト「font.py」は文字を描画するサンプルで、thought.pyに追記していきます。OSによってフォントが違いますが、今回はWindows向けに「メイリオ」フォントだけ指定します(図4)。指定したフォントが存在しない場合は、デフォルトのフォントが使われます。
図4:フォントで文字の描画
・サンプルスクリプト「font.py」
03 | def draw_fukidashi(doc): |
04 | pixmap = QPixmap(doc.bounds().size()) |
05 | pixmap.fill(QColor(255,255,255)) |
08 | painter.setRenderHint(QPainter.Antialiasing,True) |
09 | color = QColor(0, 0, 0, 255) |
13 | color = QColor(255, 255, 255, 255) |
15 | painter.setBrush(brush) |
19 | return pixmap.toImage() |
21 | def draw_font(painter): |
23 | font.setPointSizeF(36) |
25 | fm = QFontMetricsF(font) |
27 | painter.drawText(QPointF(150,320),"安く買って") |
28 | painter.drawText(QPointF(150,420),"高く売るだけなのに") |
29 | painter.drawText(QPointF(150,520),"何て奥が深いんだろう") |
【サンプルスクリプトの解説】
「draw_fukidashi」関数で「draw_font」関数を呼び出します。
「draw_font」関数で、メイリオフォントを指定した「QFont」クラスのインスタンスを生成し、サイズを36ptにしてフォントをセットします。
「drawText」メソッドでQPointF(X,Y)座標に文字列を描画します。
「try」文は例外が起こらないか処理し、最終的に(finally)パス(pass)します。
会話中のフキダシを描く
次のサンプルスクリプト「fukidashi.py」はcubicToメソッドとlineToメソッドを使うサンプルで、font.pyに追記していきます。今度は会話中のフキダシで口を飛び出させて描きます(図5)。ここではやっていませんが、もちろんcubicToメソッドやlineToメソッドとともにquadToメソッドも使えます。
図5:会話中のフキダシの描画
・サンプルスクリプト「fukidashi.py」
03 | def draw_bezier(painter): |
06 | path.cubicTo(100,580,220,700,400,700) |
07 | path.cubicTo(460,700,530,700,620,620) |
10 | path.cubicTo(700,530,700,420,700,400) |
11 | path.cubicTo(700,280,580,100,400,100) |
12 | path.cubicTo(230,100,100,230,100,400) |
13 | painter.drawPath(path) |
【サンプルスクリプトの解説】
「draw_bezier」関数でQPainterPathクラスのインスタンスを生成し、(100,400)→(400,700)→(620,620)→(730,650)→(650,580)→(700,400)→(400,100)→(100,400)の順にベジェ曲線と直線でフキダシを描きます。lineToメソッドは直線を描きます。
おわりに
今回はコントロールポイントが1個と2個のベジェ曲線を描きました。プログラミングしてフキダシをデザインするのは、ものすごく面倒くさいです。2DCGツールを使えばフキダシをデザインするのは簡単ですが、プログラミングでデザインするのと、2DCGツールでグラフィカルにデザインするのとでは、それぞれ作りやすいデザインは異なります。第3回で作ったランダムに無数の正方形を描画するサンプルのような場合は、プログラミングした方がはるかに簡単な場合もあります。