Cairoを使う：（その3）透過とグラデーション

### 単色で塗る

図形を単色で塗りつぶす場合は、すでに見ているようにcairo_set_source_rgb()を用いればOKです。
コンテクスト（cairo_tインスタンス）へのポインタに続けてRGB濃度（全て0〜1のdouble型、負値は0で、1より大きい値は1でそれぞれ打ち切られます）を指定し、ソースにします。

### 色を透過させる

cairo_set_source_rgba()を用いて色を透過させることも可能です。draw()関数を次のようにしてみましょう。

```C
void draw(cairo_t *c, int width, int height)
{
  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );
  /* red rectangle */
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  cairo_set_source_rgb( c, 1, 0.6, 0.8 );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_set_line_width( c, 10 );
  cairo_stroke( c );
  /* green circle */
  cairo_arc( c, 2*width/3, height/2, height/3, 0, 2*M_PI );
  cairo_set_source_rgba( c, 0, 1, 0, 0.5 );
  cairo_fill_preserve( c );
  cairo_set_source_rgba( c, 0, 0.5, 0, 1 );
  cairo_stroke( c );
  /* cyan triangle */
  cairo_set_source_rgba( c, 0.5, 1, 1, 0.5 );
  cairo_move_to( c, width/8, 3*height/8 );
  cairo_rel_line_to( c, 0, height/2 );
  cairo_rel_line_to( c, 2*width/3, 0 );
  cairo_close_path( c );
  cairo_fill_preserve( c );
  cairo_set_source_rgba( c, 0.5, 1, 1, 1 );
  cairo_stroke( c );
}
```
cairo_set_source_rgba()の第1〜4引数はcairo_set_source_rgb()と同じ。第5引数にはいわゆるアルファ値（透過率、0〜1の範囲で指定）を与えます。RGB濃度と同じく0〜1で自動的に打ち切られます。出力は次の通りです。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/9b04ef38-bf09-00e8-de6b-d83c43f50a63.png)


### 線形グラデーション

領域の中で色が徐々に変わるグラデーション効果をソースにするには、cairo_pattern_tインスタンス（パターン）を使います。
次のdraw()関数を試してみて下さい。

```C
void draw(cairo_t *c, int width, int height)
{
  cairo_pattern_t *p;

  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );
  /* red rectangle */
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  p = cairo_pattern_create_linear( width/4, height/4, 3*width/4, 3*height/4 );
  cairo_pattern_add_color_stop_rgb( p, 0, 1, 1, 1 );
  cairo_pattern_add_color_stop_rgb( p, 1, 1, 0.6, 0.8 );
  cairo_set_source( c, p );
  cairo_pattern_destroy( p );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_set_line_width( c, 10 );
  cairo_stroke( c );
}
```
出力は次のようになります。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/e940bf91-68f5-6967-a522-6b6af8725334.png)

この例では、グラデーションパターンを作るのにcairo_pattern_create_linear()関数を用いています。第1,第2引数はグラデーション開始座標(x0,y0)、第3、第4引数はグラデーション終了座標(x1,y1)です。それぞれcairo_rectangle()で作っている長方形の左上隅、右上隅と一致させていることに注意して下さい。これに続くcairo_pattern_add_color_stop_rgb()で、グラデーションの経由点（グラデーション・ストップ）を作っています。作成したパターンはcairo_set_source()でソースに設定します。

グラデーションは線分(x0,y0)-(x1,y1)に沿ってかかり、直線に垂直な方向には色が変化しません。
グラデーション・ストップは、この線分上の幾つかの点の色を陽に指定するためのもので、それらの間を線形補間するようにパスないしその内部が着色されます。cairo_pattern_add_color_stop_rgb()の第2引数は線分上の相対位置を示すもので、0のとき始点(x0,y0)、1のとき終点(x1,y1)になります。続く第3〜5引数はRGB濃度です。上の例では、始点が白（R:G:B=1:1:1）、終点がピンク色（R:G:B=1:0.6:0.8）になるよう指定されています。

幾つか他の例を試してみましょう。パターン作成部を

```C
  p = cairo_pattern_create_linear( 3*width/8, 3*height/8, 5*width/8, 5*height/8 );
```
とすると、出力は次のようになります。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/2239ff2b-3d9a-ccb3-e986-daa92316dd1c.png)

この場合、線分の始点と終点が長方形の内側にオフセットするので、それよりも外側は両端点の色（始点側は白、終点側はピンク色）になっています。パターン作成部を

```C
  p = cairo_pattern_create_linear( width/4, height/4, 3*width/4, 3*height/4 );
```
に戻して、グラデーション・ストップを

```C
  cairo_pattern_add_color_stop_rgb( p, 0.25, 1, 1, 1 );
  cairo_pattern_add_color_stop_rgb( p, 0.75, 1, 0.6, 0.8 );
```
のように指定することでも同じ出力が得られます。

次のようにして、グラデーション・ストップを3つに増やしてみましょう。

```C
  p = cairo_pattern_create_linear( width/4, height/4, 3*width/4, 3*height/4 );
  cairo_pattern_add_color_stop_rgb( p, 0, 1, 1, 1 );
  cairo_pattern_add_color_stop_rgb( p, 0.5, 0.6, 0.8, 1 );
  cairo_pattern_add_color_stop_rgb( p, 1, 1, 0.6, 0.8 );
```
出力は次のようになります。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/23137855-ff15-94dd-710e-c1aef29e8262.png)

中間点に水色（R:G:B=0.6:0.8:1）が現れています。

### 放射状グラデーション

draw()関数を次のように変えてみましょう。

```C
void draw(cairo_t *c, int width, int height)
{
  cairo_pattern_t *p;

  /* background */
  cairo_set_source_rgb( c, 1, 1, 1 );
  cairo_rectangle( c, 0, 0, width, height );
  cairo_fill( c );
  /* red rectangle */
  cairo_rectangle( c, width/4, height/4, width/2, height/2 );
  p = cairo_pattern_create_radial( width/2, height/2, height/8, width/2, height/2, height/4 );
  cairo_pattern_add_color_stop_rgb( p, 0, 1, 1, 1 );
  cairo_pattern_add_color_stop_rgb( p, 0.5, 0.6, 0.8, 1 );
  cairo_pattern_add_color_stop_rgb( p, 1, 1, 0.6, 0.8 );
  cairo_set_source( c, p );
  cairo_pattern_destroy( p );
  cairo_fill_preserve( c );
  cairo_set_source_rgb( c, 1, 0, 0 );
  cairo_set_line_width( c, 10 );
  cairo_stroke( c );
}
```

パターン作成部のみがcairo_pattern_create_radial()を使うように変わっています。出力は次のようになります。
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/d8664fa5-c427-4933-e231-44b2eae37b50.png)

この例から分かるように、cairo_pattern_create_radial()は引数で指定された二つの円を補間するようにグラデーションパターンを作成します。第1〜3引数で開始円の中心座標(x0,y0)および半径r0を、第4〜6引数で終端円の中心座標(x1,y1)および半径r1を、それぞれ指定します。開始円の内側は最初のグラデーション・ストップの色（白）、終端円の外側は最後のグラデーション・ストップの色（ピンク色）でそれぞれ塗りつぶされています。

例えばパターン作成部を

```C
  p = cairo_pattern_create_radial( width/2, height/2, height/8, width/2-30, height/2, height/4 );
```
と変えて終端円の中心を左に30ずらすと、出力は
![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/4436f49e-c74f-bcc7-54b6-1d443ebbf16d.png)
となります。さらに

```C
  p = cairo_pattern_create_radial( width/2, height/2, height/8, width/4, height/2, height/4 );
```

として終端円を開始円と交差するぐらい左にずらすと`

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/706455/91604b9d-3bea-24fd-1074-6599ee782f8f.png)

となります。これはこれで面白い効果ですね。