試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

pycairoのContextクラスで描画を行う上での幾つかのメモ

ここではpycairoのContextクラスを用いたCairoの描画に関する幾つかのメモを扱う。一部の内容は「PyGTKでGUI部品を自前で描画する(前半)」と重なる。
Vala言語でもCairo.Contextクラスが同様に利用可能で、基本的に同じ要領で使用できるが、一部関数の引数や戻り値の渡し方/受け取り方が異なる*1他、円周率の値の指定の仕方などにおいてもPythonと異なる部分がある。
使用例(GTK+のDrawingArea上の表示)は「PyGTKでGUI部品を自前で描画する(後半)」を参照。本家のC言語のサンプルも参照になる。

色/透明度の指定

set_source_rgb()でContextオブジェクトの赤,緑,青の各成分について0から1の範囲内で指定する形で色の指定が行える。set_source_rgba()では更にアルファ成分(アルファ値)も指定できる。

パス

線を描画するときの線の形や図形を塗り潰す際の輪郭となる線をパス(path)と言い、Inkscapeなどのドロー系描画ソフトウェアにおけるパスと同じ概念となる。線を引いたり図形を描いたりする場合、はじめにこれを初期化してから形を描き、これに対して輪郭線描画や塗り潰しを行うことになる。
パスはContextオブジェクトの内部に存在し、直接パスのオブジェクトに対して操作を行うことはせず、Contextオブジェクトのメンバ関数を用いてパス操作を行うことになる。

パスの初期化と管理

パスの初期化にはContextクラスのメンバ関数new_path()を用いる。呼び出した時点で既にパスが存在する場合、それは消される。
事前にcopy_path()copy_path_flat()の戻り値としてパスオブジェクトを得ておき、これを後でappend_path()に入れることで、パスを追加することができる。
また、new_sub_path()を用いた後move_to()で開始位置を指定してサブパスを作り始めることもできる。

移動しながらパスを描く

パスを初期化した後は現在位置(current point)*2move_to()(絶対座標指定)やrel_move_to()(呼び出し前の現在位置からの相対座標)で指定し、そこからline_to()*3curve_to()*4といったメンバ関数を呼び出していくと、現在位置を移動しながらパスが描かれていく。
rel_line_to()rel_curve_to()では移動先(引数)を呼び出し前の現在位置からの相対座標で表現できる。

パスを閉じる

パスはclose_path()で閉じる(現在位置とパス開始点とを結ぶ)ことができる。四角形を描画する場合は3回rel_line_to()line_to()を呼んだ後で閉じることになる。

パスを内部的に作る関数

円(の一部)を描画するarc()や四角形を描画するrectangle()などは、呼び出すとその図形を作成し、パスを内部的に作る。
rectangle()の引数には、四角形の左上のX,Y座標と幅,高さを指定する。
arc()arc_negative()はともに中心のX,Y座標と半径,開始角度,終了角度を引数にとり、角度は3時の方向から時計回りで、円周率の値(Pythonではmath.pi)が180度となる。arc_negative()arc()と表示される/されない領域が逆になる。角度の回り方は同じく3時の方向から時計回り。

輪郭線描画と塗り潰し

作成済みのパスに対してstroke()で輪郭線描画、fill()で塗り潰しを行う。
Inkscapeに「ストローク(輪郭線)」と「フィル(塗り潰し)」という概念があるが、これと同様。

文字列の描画

文字列を描画するには以下の流れで処理を行う。

  1. 事前に、必要に応じてset_source_rgb()set_source_rgba()で色を指定
  2. select_font_face()でフォントのファミリ,スタイル,太さを指定し、set_font_size()でサイズを指定
  3. 必要に応じて、レイアウトを調整するためにtext_extents()を呼ぶ
  4. move_to()で描画位置を指定
  5. show_text()で引数にUTF-8エンコーディングのテキストを指定

テキストの中央寄せをしたい場合、X方向ではmove_to()でX座標を「[中央のX座標] - width / 2 - x_bearing」、Y方向ではY座標を「[中央のY座標] - height / 2 - y_bearing」とする(width, height, x_bearing, y_bearingはtext_extents()から得られたもの)
スタイルは標準ではcairo.FONT_SLANT_NORMAL(Valaではcairo.FontSlant.NORMAL)で、「NORMAL」の部分を「ITALIC」か「OBLIQUE」にするとそれぞれに変更される。
太さは標準ではcairo.FONT_WEIGHT_NORMAL(Valaではcairo.FontWeight.NORMAL)で、「NORMAL」の部分を「BOLD」にすると太字になる。

関連:Vala言語と円周率

Valaではバージョン0.7.10の時点では言語バインディングから円周率の値を利用できない*5が、下のような.vapiファイルを作成して
[任意]ファイル名: mathpi.vapi

[CCode (cheader_filename = "math.h")]
namespace Math
{
  [CCode (cname = "M_PI")]
  public const double PI;
}

下のようにしてコンパイルをすると「Math.PI」として用いることができる。

$ valac --vapidir [上のファイルのあるディレクトリ] --pkg mathpi ([その他オプション...]) -o [出力実行ファイル] [ソース].vala

--pkgの後ろは.vapiファイルのファイル名の「.」の手前の部分に合わせる。

関連記事:

使用したバージョン:

  • pycairo 1.8.6
  • Python 2.6.4
  • Vala 0.7.10

*1:Vala言語にはタプルはないため、「out」の引数で渡して関数の中で値が代入されるようになっている

*2:絵/図形を描くときに(描く道具という広い意味での)ペンの先が当たる位置と考えることができる

*3:現在位置から指定座標に向けて直線のパスを描き、そこに移動する

*4:現在位置と残り3つの(X,Y)座標、合計4つの(X,Y)座標を用いて3次ベジェ曲線のパスを描き、最後に指定した(X,Y)座標に移動する・C言語のサンプルも参照

*5:一部の外部パッケージ/ライブラリ経由では利用可能だが、math.hの中のM_PIは利用できない